Spaces:
Runtime error
Runtime error
| import { useState, useCallback, useRef } from "react"; | |
| import { sendChatMessage } from "../services/api"; | |
| import { v4 as uuidv4 } from "uuid"; | |
| export function useChat(sessionId) { | |
| const [messages, setMessages] = useState([]); | |
| const [isStreaming, setIsStreaming] = useState(false); | |
| const [streamingContent, setStreamingContent] = useState(""); | |
| const [error, setError] = useState(null); | |
| const sendMessage = useCallback( | |
| async (content, model, overrideSessionId) => { | |
| if (!content.trim() || isStreaming) return; | |
| // Use override (newly created) session id if provided | |
| const activeSessionId = overrideSessionId || sessionId; | |
| if (!activeSessionId) { | |
| console.error("No session ID available"); | |
| return; | |
| } | |
| setError(null); | |
| // Add user message immediately | |
| const userMessage = { | |
| id: uuidv4(), | |
| role: "user", | |
| content: content.trim(), | |
| timestamp: new Date().toISOString(), | |
| }; | |
| setMessages((prev) => [...prev, userMessage]); | |
| setIsStreaming(true); | |
| setStreamingContent(""); | |
| const assistantId = uuidv4(); | |
| try { | |
| console.log("Sending to session:", activeSessionId); | |
| const response = await sendChatMessage({ | |
| message: content.trim(), | |
| session_id: activeSessionId, | |
| model: model || "llama3", | |
| stream: true, | |
| }); | |
| const reader = response.body.getReader(); | |
| const decoder = new TextDecoder(); | |
| let fullContent = ""; | |
| let metadata = null; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| const chunk = decoder.decode(value, { stream: true }); | |
| const lines = chunk.split("\n"); | |
| for (const line of lines) { | |
| if (!line.startsWith("data: ")) continue; | |
| const jsonStr = line.slice(6).trim(); | |
| if (!jsonStr) continue; | |
| try { | |
| const event = JSON.parse(jsonStr); | |
| if (event.type === "metadata") { | |
| metadata = event; | |
| } else if (event.type === "token") { | |
| fullContent += event.content; | |
| setStreamingContent(fullContent); | |
| } else if (event.type === "done") { | |
| const assistantMessage = { | |
| id: assistantId, | |
| role: "assistant", | |
| content: fullContent, | |
| timestamp: new Date().toISOString(), | |
| metadata: metadata, | |
| }; | |
| setMessages((prev) => [...prev, assistantMessage]); | |
| setStreamingContent(""); | |
| } else if (event.type === "error") { | |
| throw new Error(event.content); | |
| } | |
| } catch (parseError) { | |
| if (parseError.message !== "Unexpected end of JSON input") { | |
| console.warn("SSE parse warning:", parseError.message); | |
| } | |
| } | |
| } | |
| } | |
| } catch (err) { | |
| console.error("Chat error:", err); | |
| // Extract readable error message | |
| let errorMsg = "Something went wrong. Please try again."; | |
| if (err.message && err.message !== "[object Object]") { | |
| errorMsg = err.message; | |
| } | |
| setError(errorMsg); | |
| setStreamingContent(""); | |
| setMessages((prev) => [ | |
| ...prev, | |
| { | |
| id: assistantId, | |
| role: "assistant", | |
| content: `⚠️ Error: ${errorMsg}`, | |
| timestamp: new Date().toISOString(), | |
| isError: true, | |
| }, | |
| ]); | |
| } finally { | |
| setIsStreaming(false); | |
| setStreamingContent(""); | |
| } | |
| }, | |
| [sessionId, isStreaming], | |
| ); | |
| const clearMessages = useCallback(() => { | |
| setMessages([]); | |
| setStreamingContent(""); | |
| setError(null); | |
| }, []); | |
| return { | |
| messages, | |
| setMessages, | |
| isStreaming, | |
| streamingContent, | |
| error, | |
| sendMessage, | |
| clearMessages, | |
| }; | |
| } | |