From 6e3f5d941522c0034e49c19979d45a1058597dac Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Thu, 7 May 2026 02:41:01 +0800 Subject: [PATCH] feat(web): add chat UI with WebSocket streaming and conversation persistence Co-Authored-By: Claude Opus 4.7 --- web/client/src/components/chat/ChatInput.tsx | 41 ++++++++++++++ .../src/components/chat/ChatMessage.tsx | 19 +++++++ web/client/src/components/chat/ChatView.tsx | 55 ++++++++++++++++++- web/client/src/hooks/useChat.ts | 46 ++++++++++++++++ web/client/src/lib/websocket.ts | 55 +++++++++++++++++++ web/server/routes/pipeline.ts | 55 +++++++++++++++++++ 6 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 web/client/src/components/chat/ChatInput.tsx create mode 100644 web/client/src/components/chat/ChatMessage.tsx create mode 100644 web/client/src/hooks/useChat.ts create mode 100644 web/client/src/lib/websocket.ts create mode 100644 web/server/routes/pipeline.ts diff --git a/web/client/src/components/chat/ChatInput.tsx b/web/client/src/components/chat/ChatInput.tsx new file mode 100644 index 0000000..0c64acf --- /dev/null +++ b/web/client/src/components/chat/ChatInput.tsx @@ -0,0 +1,41 @@ +import { useState, useRef } from 'react'; +import { Send } from 'lucide-react'; +import { Button } from '@/components/ui/button'; + +export function ChatInput({ onSend }: { onSend: (content: string) => void }) { + const [input, setInput] = useState(''); + const ref = useRef(null); + + const handleSend = () => { + if (!input.trim()) return; + onSend(input.trim()); + setInput(''); + ref.current?.focus(); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }; + + return ( +
+
+