import { useEffect, useState, useCallback, useRef } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useAppStore } from '@/store'; import { useChat } from '@/hooks/useChat'; import { ChatMessage } from './ChatMessage'; import { ChatInput } from './ChatInput'; import { PipelineProgress } from './PipelineProgress'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Button } from '@/components/ui/button'; import { RefreshCw, Loader2, StopCircle, X } from 'lucide-react'; import { api } from '@/lib/api'; import type { Account, Message } from '@/types'; export function ChatView() { const { conversationId } = useParams<{ conversationId?: string }>(); const navigate = useNavigate(); const { setConversations, selectedAccountId, setSelectedAccountId } = useAppStore(); const { messages, connected, thinking, toolStatus, pipeline, send, stop, createConversation } = useChat(conversationId || null); const [manifestPath, setManifestPath] = useState(null); const [accounts, setAccounts] = useState([]); const [quote, setQuote] = useState(null); const creatingRef = useRef(false); useEffect(() => { api.listAccounts().then(setAccounts).catch(() => {}); }, []); useEffect(() => { fetch('/api/pipeline/conversations') .then((r) => r.json()).then(setConversations).catch(() => {}); }, [messages]); useEffect(() => { const toolMsgs = messages.filter((m) => m.role === 'tool'); if (toolMsgs.length > 0) { try { const lastTool = JSON.parse(toolMsgs[toolMsgs.length - 1].content); if (lastTool.manifest) setManifestPath(lastTool.manifest); } catch {} } }, [messages]); useEffect(() => { if (selectedAccountId && conversationId && connected && messages.length === 0) { const account = accounts.find((a) => a.id === selectedAccountId); if (account) { send(`已选择账号「${account.name}」:${account.description || ''}。生图:${account.imageModel} 视频:${account.videoModel} 画幅:${account.defaultFormat}`); } } }, [selectedAccountId, conversationId, connected]); const handleNewConversation = useCallback(() => { if (creatingRef.current) return; creatingRef.current = true; createConversation('新对话', selectedAccountId || undefined); setTimeout(() => { fetch('/api/pipeline/conversations').then((r) => r.json()).then((list) => { setConversations(list); if (list.length > 0) navigate(`/chat/${list[0].id}`); creatingRef.current = false; }); }, 500); }, [createConversation, selectedAccountId]); const handleResume = async () => { if (!manifestPath) return; await fetch('/api/pipeline/resume', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ manifest: manifestPath }), }); }; const findPrecedingUser = useCallback((msgId: string): Message | null => { const idx = messages.findIndex((m) => m.id === msgId); if (idx <= 0) return null; for (let i = idx - 1; i >= 0; i--) { if (messages[i].role === 'user') return messages[i]; } return null; }, [messages]); const handleRegenerate = useCallback((msgId: string) => { const prev = findPrecedingUser(msgId); if (prev) send(prev.content); }, [findPrecedingUser, send]); const handleContinue = useCallback(() => { send('请继续'); }, [send]); const handleQuote = useCallback((content: string) => { setQuote(content.slice(0, 200)); }, []); const handleSend = useCallback((content: string) => { if (quote) { send(`> ${quote}\n\n${content}`); setQuote(null); } else send(content); }, [send, quote]); const handleStop = useCallback(() => { stop(); }, [stop]); if (!conversationId) { return (
💬

开始新对话

选择左侧对话或创建新的创作会话

{accounts.length > 0 && ( )}
); } return (
{connected ? '在线' : '连接中'}
{manifestPath && ( )} {thinking && ( )}
{messages.map((msg) => ( ))} {pipeline && ( )} {thinking && !pipeline && (
{toolStatus || '思考中...'}
)}
{quote && (
引用: {quote}
)}
); }