'use client'; import { streamChat } from '@/lib/api'; import { useState, useRef, useEffect, useCallback } from 'react'; import { Send, Loader2, Bot, User, BookOpen } from 'lucide-react'; interface Message { role: 'user' | 'assistant'; content: string; sources?: { title: string; path: string; score: number }[]; } export default function ChatPage() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [streaming, setStreaming] = useState(false); const cancelRef = useRef<(() => void) | null>(null); const bottomRef = useRef(null); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); const sendMessage = useCallback(async () => { const text = input.trim(); if (!text || streaming) return; setInput(''); const userMsg: Message = { role: 'user', content: text }; setMessages((prev) => [...prev, userMsg]); setStreaming(true); const assistantMsg: Message = { role: 'assistant', content: '', sources: [] }; setMessages((prev) => [...prev, assistantMsg]); cancelRef.current = streamChat( text, 5, (token) => { setMessages((prev) => { const next = [...prev]; const last = next[next.length - 1]; next[next.length - 1] = { ...last, content: last.content + token }; return next; }); }, (sources) => { setMessages((prev) => { const next = [...prev]; next[next.length - 1] = { ...next[next.length - 1], sources }; return next; }); }, () => setStreaming(false), ); }, [input, streaming]); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; return (

AI Chat

{messages.length === 0 && (

Ask anything about your knowledge base

)} {messages.map((msg, i) => (
{msg.role === 'assistant' && (
)}
{msg.content} {msg.role === 'assistant' && streaming && i === messages.length - 1 && ( )}
{msg.sources && msg.sources.length > 0 && (
{msg.sources.map((src, si) => ( {src.title} ))}
)}
{msg.role === 'user' && (
)}
))}