Spaces:
Sleeping
Sleeping
File size: 4,421 Bytes
f782685 | 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 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";
/**
* FIX v4.1: The chat endpoint now properly documents its limitations.
*
* ARCHITECTURE NOTE:
* The Gradio ChatInterface uses gr.State to store RAG embeddings per-session.
* This state is NOT accessible via the Gradio API from an external caller —
* each API call creates a new session with empty state.
*
* For the Next.js web app, chat should either:
* 1. Use the FastAPI backend (/api/chat) which manages its own RAG sessions, OR
* 2. Embed the Gradio Space in an iframe for direct interaction
*
* This route attempts to use the Gradio API as a best-effort fallback,
* but will clearly communicate to the user if the session is unavailable.
*/
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 { message, history, session_id } = body;
if (!message) {
return NextResponse.json(
{ error: "message is required" },
{ status: 400 }
);
}
// FIX v4.1: Input validation
if (message.length > 2000) {
return NextResponse.json(
{ error: "Message too long (max 2000 characters)" },
{ status: 400 }
);
}
// Try the FastAPI backend first (it has proper RAG session management)
const apiUrl = process.env.CLAUSEGUARD_API_URL || "";
if (apiUrl && session_id) {
try {
const apiRes = await fetch(`${apiUrl}/api/chat`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message, session_id, history: history || [] }),
});
if (apiRes.ok) {
const data = await apiRes.json();
return NextResponse.json({ response: data.response });
}
} catch {
// Fall through to Gradio attempt
}
}
// Fallback: Try the Gradio API
const submitRes = await fetch(`${GRADIO_URL}/gradio_api/call/chat`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ data: [message] }),
});
if (!submitRes.ok) {
const errText = await submitRes.text().catch(() => "");
throw new Error(`Chat submit failed (${submitRes.status}): ${errText}`);
}
const { event_id } = await submitRes.json();
if (!event_id) throw new Error("No event_id from Gradio chat");
// Poll for result with timeout
let resultText = "";
let attempts = 0;
const maxAttempts = 30;
while (attempts < maxAttempts) {
const resultRes = await fetch(
`${GRADIO_URL}/gradio_api/call/chat/${event_id}`,
{ headers: { Accept: "text/event-stream" } }
);
if (!resultRes.ok) {
throw new Error(`Chat result failed: ${resultRes.status}`);
}
resultText = await resultRes.text();
if (resultText.includes("event: complete")) break;
if (resultText.includes("event: error")) {
const errMatch = resultText.match(/event:\s*error\s*\ndata:\s*(.+)/);
if (errMatch) throw new Error(`Chat error: ${errMatch[1]}`);
throw new Error("Chat error from backend");
}
await new Promise(r => setTimeout(r, 1000));
attempts++;
}
// Find the complete event data
const dataMatch = resultText.match(/event:\s*complete\s*\ndata:\s*(.+)/);
if (!dataMatch) {
return NextResponse.json({
response: "⚠️ Chat is unavailable. The contract needs to be analyzed in the same session. " +
"Please analyze a contract first in the Gradio Space, then use the chat tab there directly."
});
}
const responseData = JSON.parse(dataMatch[1]);
const responseText = typeof responseData === "string" ? responseData : responseData[0] || "";
return NextResponse.json({ response: responseText });
} catch (error: any) {
console.error("Chat error:", error.message);
return NextResponse.json(
{ error: error.message || "Chat failed. Make sure you analyzed a contract first." },
{ status: 500 }
);
}
}
|