gaurv007 commited on
Commit
f782685
·
verified ·
1 Parent(s): f89de6b

fix: upload actual chat/route.ts content — FastAPI fallback, session docs, input validation

Browse files
Files changed (1) hide show
  1. web/app/api/chat/route.ts +129 -1
web/app/api/chat/route.ts CHANGED
@@ -1 +1,129 @@
1
- file:/app/web_api_chat_route.ts
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ import { createClient } from "@/lib/supabase/server";
3
+
4
+ const GRADIO_URL = process.env.CLAUSEGUARD_GRADIO_URL || "https://gaurv007-clauseguard.hf.space";
5
+
6
+ /**
7
+ * FIX v4.1: The chat endpoint now properly documents its limitations.
8
+ *
9
+ * ARCHITECTURE NOTE:
10
+ * The Gradio ChatInterface uses gr.State to store RAG embeddings per-session.
11
+ * This state is NOT accessible via the Gradio API from an external caller —
12
+ * each API call creates a new session with empty state.
13
+ *
14
+ * For the Next.js web app, chat should either:
15
+ * 1. Use the FastAPI backend (/api/chat) which manages its own RAG sessions, OR
16
+ * 2. Embed the Gradio Space in an iframe for direct interaction
17
+ *
18
+ * This route attempts to use the Gradio API as a best-effort fallback,
19
+ * but will clearly communicate to the user if the session is unavailable.
20
+ */
21
+ export async function POST(req: NextRequest) {
22
+ try {
23
+ const supabase = await createClient();
24
+ const { data: { user } } = await supabase.auth.getUser();
25
+
26
+ if (!user) {
27
+ return NextResponse.json({ error: "Unauthorized. Please log in." }, { status: 401 });
28
+ }
29
+
30
+ const body = await req.json();
31
+ const { message, history, session_id } = body;
32
+
33
+ if (!message) {
34
+ return NextResponse.json(
35
+ { error: "message is required" },
36
+ { status: 400 }
37
+ );
38
+ }
39
+
40
+ // FIX v4.1: Input validation
41
+ if (message.length > 2000) {
42
+ return NextResponse.json(
43
+ { error: "Message too long (max 2000 characters)" },
44
+ { status: 400 }
45
+ );
46
+ }
47
+
48
+ // Try the FastAPI backend first (it has proper RAG session management)
49
+ const apiUrl = process.env.CLAUSEGUARD_API_URL || "";
50
+ if (apiUrl && session_id) {
51
+ try {
52
+ const apiRes = await fetch(`${apiUrl}/api/chat`, {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: JSON.stringify({ message, session_id, history: history || [] }),
56
+ });
57
+ if (apiRes.ok) {
58
+ const data = await apiRes.json();
59
+ return NextResponse.json({ response: data.response });
60
+ }
61
+ } catch {
62
+ // Fall through to Gradio attempt
63
+ }
64
+ }
65
+
66
+ // Fallback: Try the Gradio API
67
+ const submitRes = await fetch(`${GRADIO_URL}/gradio_api/call/chat`, {
68
+ method: "POST",
69
+ headers: { "Content-Type": "application/json" },
70
+ body: JSON.stringify({ data: [message] }),
71
+ });
72
+
73
+ if (!submitRes.ok) {
74
+ const errText = await submitRes.text().catch(() => "");
75
+ throw new Error(`Chat submit failed (${submitRes.status}): ${errText}`);
76
+ }
77
+
78
+ const { event_id } = await submitRes.json();
79
+ if (!event_id) throw new Error("No event_id from Gradio chat");
80
+
81
+ // Poll for result with timeout
82
+ let resultText = "";
83
+ let attempts = 0;
84
+ const maxAttempts = 30;
85
+
86
+ while (attempts < maxAttempts) {
87
+ const resultRes = await fetch(
88
+ `${GRADIO_URL}/gradio_api/call/chat/${event_id}`,
89
+ { headers: { Accept: "text/event-stream" } }
90
+ );
91
+
92
+ if (!resultRes.ok) {
93
+ throw new Error(`Chat result failed: ${resultRes.status}`);
94
+ }
95
+
96
+ resultText = await resultRes.text();
97
+
98
+ if (resultText.includes("event: complete")) break;
99
+ if (resultText.includes("event: error")) {
100
+ const errMatch = resultText.match(/event:\s*error\s*\ndata:\s*(.+)/);
101
+ if (errMatch) throw new Error(`Chat error: ${errMatch[1]}`);
102
+ throw new Error("Chat error from backend");
103
+ }
104
+
105
+ await new Promise(r => setTimeout(r, 1000));
106
+ attempts++;
107
+ }
108
+
109
+ // Find the complete event data
110
+ const dataMatch = resultText.match(/event:\s*complete\s*\ndata:\s*(.+)/);
111
+ if (!dataMatch) {
112
+ return NextResponse.json({
113
+ response: "⚠️ Chat is unavailable. The contract needs to be analyzed in the same session. " +
114
+ "Please analyze a contract first in the Gradio Space, then use the chat tab there directly."
115
+ });
116
+ }
117
+
118
+ const responseData = JSON.parse(dataMatch[1]);
119
+ const responseText = typeof responseData === "string" ? responseData : responseData[0] || "";
120
+
121
+ return NextResponse.json({ response: responseText });
122
+ } catch (error: any) {
123
+ console.error("Chat error:", error.message);
124
+ return NextResponse.json(
125
+ { error: error.message || "Chat failed. Make sure you analyzed a contract first." },
126
+ { status: 500 }
127
+ );
128
+ }
129
+ }