"use client"; import { useEffect, useRef, useState } from "react"; import { useTheme } from "next-themes"; import { formatMarkdown } from "@/lib/markdown"; import { streamChat, type ChatMessage } from "@/lib/api"; interface DisplayMessage { role: "user" | "assistant"; content: string; } const QUICK_QUESTIONS = [ "结合今日作战结论,告诉我今天应该重点看什么。", "诊断一下 300750.SZ,给出触发条件和失效条件。", "看看我的自选股里哪些需要明天优先盯盘。", "复盘当前推荐池,哪些信号最近更有效?", ]; const CHAT_SCENES = [ { title: "市场", description: "打法 / 仓位 / 风险", }, { title: "个股", description: "诊断 / 触发 / 失效", }, { title: "自选", description: "推荐池 / 自选股 / 复盘", }, ]; export default function ChatPage() { const { theme } = useTheme(); const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [streaming, setStreaming] = useState(false); const [status, setStatus] = useState(""); const scrollRef = useRef(null); const inputRef = useRef(null); const scrollToBottom = () => { scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth", }); }; useEffect(() => { scrollToBottom(); }, [messages, status]); const sendMessage = async (text: string) => { const content = text.trim(); if (!content || streaming) return; const userMsg: DisplayMessage = { role: "user", content }; const newMessages = [...messages, userMsg]; setMessages([...newMessages, { role: "assistant", content: "" }]); setInput(""); setStreaming(true); setStatus(""); try { const chatMessages: ChatMessage[] = newMessages.map((message) => ({ role: message.role, content: message.content, })); let fullContent = ""; for await (const event of streamChat(chatMessages)) { if (event.type === "status") { setStatus(event.content); continue; } fullContent += event.content; setMessages([ ...newMessages, { role: "assistant", content: fullContent }, ]); } } catch (error) { console.error("Chat error:", error); setMessages([ ...newMessages, { role: "assistant", content: "连接失败,暂时无法读取作战数据,请稍后重试。" }, ]); } finally { setStreaming(false); setStatus(""); } }; const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); sendMessage(input); } }; return (

A股研究助手

市场 / 推荐 / 自选 / 个股诊断

{messages.length > 0 ? ( ) : null}
{messages.length === 0 ? (

问市场、主线或个股

{QUICK_QUESTIONS.map((question) => ( ))}
) : (
{messages.map((message, index) => (
{message.role === "assistant" ? ( message.content ? (
) : ( {status || "读取作战上下文中..."} ) ) : ( {message.content} )} {streaming && index === messages.length - 1 && message.role === "assistant" && message.content ? ( ) : null}
))} {streaming && status && messages[messages.length - 1]?.content ? (
{status}
) : null}
)}