File size: 3,419 Bytes
04e0266
ae80634
04e0266
9510bea
04e0266
 
 
ae80634
 
 
 
 
 
 
04e0266
bf51166
04e0266
 
 
 
 
 
 
bf51166
 
 
 
 
04e0266
9510bea
bf51166
04e0266
 
9510bea
04e0266
 
9510bea
 
04e0266
 
9510bea
 
 
bf51166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9510bea
bf51166
 
 
9510bea
 
bf51166
 
 
 
 
 
 
 
 
 
9510bea
 
 
 
 
 
 
 
 
 
 
 
 
 
04e0266
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { NextRequest, NextResponse } from "next/server";
import { createClient } from "@/lib/supabase/server";

const GRADIO_URL = process.env.CLAUSEGUARD_GRADIO_URL || "https://gaurv007-clauseguard.hf.space";

export async function POST(req: NextRequest) {
  try {
    const supabase = await createClient();
    const { data: { user } } = await supabase.auth.getUser();

    if (!user) {
      return NextResponse.json({ error: "Unauthorized. Please log in." }, { status: 401 });
    }

    const body = await req.json();
    const { text_a, text_b } = body;

    if (!text_a || !text_b || text_a.trim().length < 50 || text_b.trim().length < 50) {
      return NextResponse.json(
        { error: "Both contracts must have at least 50 characters." },
        { status: 400 }
      );
    }

    // FIX v4.3: REMOVED HTML-escaping that CORRUPTED contract text before analysis.
    // The old code did text_a.replace(/</g, "&lt;") which permanently mutated
    // the text (e.g., ">$10,000" → "&gt;$10,000"). Sanitization is the
    // frontend's job — React auto-escapes in JSX. Never mutate analysis input.

    // Call Gradio Space API
    const submitRes = await fetch(`${GRADIO_URL}/gradio_api/call/compare`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ data: [text_a, text_b] }),
    });

    if (!submitRes.ok) {
      throw new Error(`Gradio submit failed: ${submitRes.status}`);
    }

    const { event_id } = await submitRes.json();
    if (!event_id) throw new Error("No event_id from Gradio");

    // Poll for result with retry
    let resultText = "";
    let attempts = 0;
    const maxAttempts = 60;
    let delay = 500;

    while (attempts < maxAttempts) {
      const resultRes = await fetch(
        `${GRADIO_URL}/gradio_api/call/compare/${event_id}`,
        { headers: { Accept: "text/event-stream" } }
      );

      resultText = await resultRes.text();

      if (resultText.includes("event: complete")) break;
      if (resultText.includes("event: error")) {
        const errMatch = resultText.match(/data:\s*(.+)/);
        throw new Error(errMatch ? errMatch[1] : "Comparison failed in backend");
      }

      await new Promise(r => setTimeout(r, delay));
      delay = Math.min(delay * 1.2, 2000);
      attempts++;
    }

    if (!resultText.includes("event: complete")) {
      throw new Error("Comparison timed out. Please try again.");
    }

    const completeIdx = resultText.indexOf("event: complete");
    const dataIdx = resultText.indexOf("data: ", completeIdx);
    if (dataIdx === -1) throw new Error("No data in response");

    const dataStr = resultText.substring(dataIdx + 6).trim();
    const gradioData = JSON.parse(dataStr);

    // gradioData[0] = comparison HTML
    // gradioData[1] = raw JSON comparison data
    const comparisonResult = gradioData[1];
    if (typeof comparisonResult === "object" && comparisonResult !== null) {
      return NextResponse.json(comparisonResult);
    }

    // If it's a string (JSON stringified), parse it
    if (typeof comparisonResult === "string") {
      return NextResponse.json(JSON.parse(comparisonResult));
    }

    throw new Error("Unexpected comparison result format");
  } catch (error: any) {
    console.error("Compare error:", error.message);
    return NextResponse.json({ error: error.message || "Comparison failed" }, { status: 500 });
  }
}