feat(web): add chat UI with WebSocket streaming and conversation persistence

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 02:41:01 +08:00
parent 10685ea866
commit 6e3f5d9415
6 changed files with 270 additions and 1 deletions

View File

@@ -1,3 +1,56 @@
import { useEffect } from 'react';
import { useAppStore } from '@/store';
import { useChat } from '@/hooks/useChat';
import { ChatMessage } from './ChatMessage';
import { ChatInput } from './ChatInput';
import { ScrollArea } from '@/components/ui/scroll-area';
export function ChatView() {
return <div className="flex-1 flex items-center justify-center text-zinc-500"></div>;
const { activeConversationId, conversations, setConversations } = useAppStore();
const { messages, connected, send, createConversation } = useChat(activeConversationId);
useEffect(() => {
fetch('/api/pipeline/conversations')
.then((r) => r.json())
.then(setConversations)
.catch(() => {});
}, [messages]);
const handleNewConversation = () => {
createConversation('新对话');
setTimeout(() => {
fetch('/api/pipeline/conversations')
.then((r) => r.json())
.then(setConversations);
}, 300);
};
if (!activeConversationId) {
return (
<div className="flex-1 flex flex-col items-center justify-center gap-4 text-zinc-500">
<p></p>
<button
onClick={handleNewConversation}
className="px-4 py-2 rounded-md bg-zinc-800 text-sm hover:bg-zinc-700 transition-colors"
>
</button>
</div>
);
}
return (
<div className="flex-1 flex flex-col">
<div className="px-4 py-2 border-b border-zinc-800 flex items-center gap-2">
<div className={`w-2 h-2 rounded-full ${connected ? 'bg-green-500' : 'bg-red-500'}`} />
<span className="text-xs text-zinc-500">{connected ? '已连接' : '连接中...'}</span>
</div>
<ScrollArea className="flex-1 px-4 py-4">
{messages.map((msg) => (
<ChatMessage key={msg.id} message={msg} />
))}
</ScrollArea>
<ChatInput onSend={send} />
</div>
);
}