import { useState, useEffect, useCallback, useRef } from 'react'; import { chatSocket } from '@/lib/websocket'; import type { Message } from '@/types'; interface StreamingMessage { id: string; role: 'assistant'; content: string; created_at: string; streaming: boolean; } export function useChat(conversationId: string | null) { const [messages, setMessages] = useState([]); const [connected, setConnected] = useState(false); const [thinking, setThinking] = useState(false); const [toolStatus, setToolStatus] = useState(null); const pendingRef = useRef(false); useEffect(() => { chatSocket.connect(); chatSocket.on('connected', () => setConnected(true)); chatSocket.on('history', (data) => { setMessages((data.messages as Message[]) || []); }); chatSocket.on('message', (data) => { setMessages((prev) => [...prev, data as unknown as Message]); }); // Streaming handlers chatSocket.on('status', (data) => { if (data.status === 'thinking') setThinking(true); }); chatSocket.on('message_start', (data) => { setThinking(false); // Add placeholder for streaming setMessages((prev) => [...prev, { id: data.id as string, role: 'assistant', content: '', created_at: new Date().toISOString(), conversation_id: '', } as Message]); }); chatSocket.on('text_delta', (data) => { setMessages((prev) => prev.map((m) => m.id === data.id ? { ...m, content: m.content + (data.text as string) } : m )); }); chatSocket.on('message_end', () => { setThinking(false); }); chatSocket.on('tool_start', (data) => { setToolStatus(`正在执行: ${data.tool}...`); }); chatSocket.on('tool_result', () => { setToolStatus(null); setThinking(true); }); chatSocket.on('tool_error', (data) => { setToolStatus(`工具执行失败: ${data.tool}`); setTimeout(() => setToolStatus(null), 3000); }); return () => { chatSocket.disconnect(); }; }, []); useEffect(() => { if (conversationId && connected && !pendingRef.current) { pendingRef.current = true; chatSocket.send('init', { conversationId }); } if (!conversationId) { pendingRef.current = false; setMessages([]); } }, [conversationId, connected]); const send = useCallback((content: string) => { chatSocket.send('chat', { content }); }, []); const createConversation = useCallback((title: string, accountId?: string) => { chatSocket.send('create_conversation', { title, accountId }); }, []); return { messages, connected, thinking, toolStatus, send, createConversation }; }