import { useState, useEffect, useRef } from "react"; import { streamChat } from "../api"; import MessageBubble from "./MessageBubble"; export default function ChatArea({ onEvalEntry, hasDocuments, suggestedQuestion, onSuggestedQuestionUsed, currentWorkspace = "default", filterDocs = [], onFilterClear, }) { const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [loading, setLoading] = useState(false); const bottomRef = useRef(null); useEffect(() => { if (suggestedQuestion) { setInput(suggestedQuestion); onSuggestedQuestionUsed?.(); } }, [suggestedQuestion, onSuggestedQuestionUsed]); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); async function handleSend(e) { e.preventDefault(); if (!input.trim() || loading || !hasDocuments) return; const question = input.trim(); setInput(""); const msgId = crypto.randomUUID(); const tokenBuffer = []; setMessages((prev) => [ ...prev, { role: "user", content: question }, { id: msgId, role: "assistant", content: "", sources: [], loading: true }, ]); setLoading(true); try { await streamChat( question, currentWorkspace, { onToken: (token) => { tokenBuffer.push(token); setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, content: m.content + token } : m ) ); }, onDone: (event) => { setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, sources: event.sources ?? [], retrieval_method: event.retrieval_method, loading: false, } : m ) ); onEvalEntry?.({ query: question, answer: tokenBuffer.join("") }); }, onError: (message) => { setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, content: `Error: ${message}`, loading: false } : m ) ); }, }, filterDocs.length > 0 ? filterDocs : null ); } finally { setLoading(false); } } return (
{hasDocuments ? "Ask a question about your documents" : "Upload documents to get started"}
{hasDocuments ? "Prism will find answers and cite sources" : "Drop PDF, TXT, CSV files or paste a URL in the sidebar"}