'use client'; import { useEffect, useState } from 'react'; import { Document } from '@langchain/core/documents'; import Navbar from './Navbar'; import Chat from './Chat'; import EmptyChat from './EmptyChat'; export type Message = { id: string; createdAt: Date; content: string; role: 'user' | 'assistant'; sources?: Document[]; }; const useSocket = (url: string) => { const [ws, setWs] = useState(null); useEffect(() => { if (!ws) { const ws = new WebSocket(url); ws.onopen = () => { console.log('[DEBUG] open'); setWs(ws); }; } return () => { ws?.close(); console.log('[DEBUG] closed'); }; }, [ws, url]); return ws; }; const ChatWindow = () => { const ws = useSocket(process.env.NEXT_PUBLIC_WS_URL!); const [chatHistory, setChatHistory] = useState<[string, string][]>([]); const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(false); const [messageAppeared, setMessageAppeared] = useState(false); const [focusMode, setFocusMode] = useState('webSearch'); const sendMessage = async (message: string) => { if (loading) return; setLoading(true); setMessageAppeared(false); let sources: Document[] | undefined = undefined; let recievedMessage = ''; let added = false; ws?.send( JSON.stringify({ type: 'message', content: message, focusMode: focusMode, history: [...chatHistory, ['human', message]], }), ); setMessages((prevMessages) => [ ...prevMessages, { content: message, id: Math.random().toString(36).substring(7), role: 'user', createdAt: new Date(), }, ]); const messageHandler = (e: MessageEvent) => { const data = JSON.parse(e.data); if (data.type === 'sources') { sources = data.data; if (!added) { setMessages((prevMessages) => [ ...prevMessages, { content: '', id: data.messageId, role: 'assistant', sources: sources, createdAt: new Date(), }, ]); added = true; } setMessageAppeared(true); } if (data.type === 'message') { if (!added) { setMessages((prevMessages) => [ ...prevMessages, { content: data.data, id: data.messageId, role: 'assistant', sources: sources, createdAt: new Date(), }, ]); added = true; } setMessages((prev) => prev.map((message) => { if (message.id === data.messageId) { return { ...message, content: message.content + data.data }; } return message; }), ); recievedMessage += data.data; setMessageAppeared(true); } if (data.type === 'messageEnd') { setChatHistory((prevHistory) => [ ...prevHistory, ['human', message], ['assistant', recievedMessage], ]); ws?.removeEventListener('message', messageHandler); setLoading(false); } }; ws?.addEventListener('message', messageHandler); }; const rewrite = (messageId: string) => { const index = messages.findIndex((msg) => msg.id === messageId); if (index === -1) return; const message = messages[index - 1]; setMessages((prev) => { return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)]; }); setChatHistory((prev) => { return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)]; }); sendMessage(message.content); }; return (
{messages.length > 0 ? ( <> ) : ( )}
); }; export default ChatWindow;