Spaces:
Sleeping
Sleeping
| 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, "<") which permanently mutated | |
| // the text (e.g., ">$10,000" β ">$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 }); | |
| } | |
| } | |