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(/$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 }); } }