import { useState, useRef, useEffect } from 'react' import { Send, ChevronDown, ChevronRight } from 'lucide-react' import { api } from '../api' import type { AppSettings, ChatResponse, CausalChain } from '../types' interface Props { documentId: string settings: AppSettings } interface Message { role: 'user' | 'assistant' content: string response?: ChatResponse } function ChainCard({ chain, index }: { chain: CausalChain; index: number }) { const [open, setOpen] = useState(index === 0) return (
{open && (
{chain.path.map((node, i) => ( {node} {i < chain.path.length - 1 && } ))}
{chain.edges.map((edge, i) => (
{edge.cause} {edge.relation} {edge.effect} [{edge.confidence.toFixed(2)}]
{edge.evidence && (
"{edge.evidence}"
)}
))}
)}
) } export function ChatPanel({ documentId, settings }: Props) { const [messages, setMessages] = useState([]) const [input, setInput] = useState('') const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const bottomRef = useRef(null) useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages]) const send = async () => { const msg = input.trim() if (!msg || loading) return setInput('') setError(null) setMessages(prev => [...prev, { role: 'user', content: msg }]) setLoading(true) try { const res = await api.chat(documentId, msg, settings) setMessages(prev => [...prev, { role: 'assistant', content: res.answer, response: res }]) } catch (e: any) { setError(String(e.message)) } finally { setLoading(false) } } const SAMPLES = [ 'Why did quarterly revenue decrease?', 'What caused inventory shortages?', 'What are the downstream effects of port congestion?', ] return (
{messages.length === 0 && (
Sample Questions
{SAMPLES.map(q => ( ))}
)}
{messages.map((m, i) => (
{m.role === 'user' ? (
{m.content}
) : (
{m.content}
{m.response && m.response.chains.length > 0 && (
Retrieved Causal Chains ({m.response.chains.length})
{m.response.chains.map((chain, ci) => ( ))}
)}
)}
))} {loading && (
Retrieving causal chains...
)} {error &&
{error}
}
setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} disabled={loading} style={{ flex: 1 }} />
) }