From 66668d85d603c5841d755a6023aa1925559fc6d4 Mon Sep 17 00:00:00 2001 From: 苏向夜 Date: Wed, 25 Feb 2026 01:32:51 +0800 Subject: chore(workspace): replace legacy codes --- packages/ui/src/pages/assistant-view.tsx.bk | 485 ++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 packages/ui/src/pages/assistant-view.tsx.bk (limited to 'packages/ui/src/pages/assistant-view.tsx.bk') diff --git a/packages/ui/src/pages/assistant-view.tsx.bk b/packages/ui/src/pages/assistant-view.tsx.bk new file mode 100644 index 0000000..56f827b --- /dev/null +++ b/packages/ui/src/pages/assistant-view.tsx.bk @@ -0,0 +1,485 @@ +import { + AlertTriangle, + Bot, + Brain, + ChevronDown, + Loader2, + RefreshCw, + Send, + Settings, + Trash2, +} from "lucide-react"; +import { marked } from "marked"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Separator } from "@/components/ui/separator"; +import { Textarea } from "@/components/ui/textarea"; +import { toNumber } from "@/lib/tsrs-utils"; +import { type Message, useAssistantStore } from "../stores/assistant-store"; +import { useSettingsStore } from "../stores/settings-store"; +import { useUiStore } from "../stores/ui-store"; + +interface ParsedMessage { + thinking: string | null; + content: string; + isThinking: boolean; +} + +function parseMessageContent(content: string): ParsedMessage { + if (!content) return { thinking: null, content: "", isThinking: false }; + + // Support both and (DeepSeek uses ) + let startTag = ""; + let endTag = ""; + let startIndex = content.indexOf(startTag); + + if (startIndex === -1) { + startTag = ""; + endTag = ""; + startIndex = content.indexOf(startTag); + } + + // Also check for encoded tags if they weren't decoded properly + if (startIndex === -1) { + startTag = "\u003cthink\u003e"; + endTag = "\u003c/think\u003e"; + startIndex = content.indexOf(startTag); + } + + if (startIndex !== -1) { + const endIndex = content.indexOf(endTag, startIndex); + + if (endIndex !== -1) { + // Completed thinking block + const before = content.substring(0, startIndex); + const thinking = content + .substring(startIndex + startTag.length, endIndex) + .trim(); + const after = content.substring(endIndex + endTag.length); + + return { + thinking, + content: (before + after).trim(), + isThinking: false, + }; + } else { + // Incomplete thinking block (still streaming) + const before = content.substring(0, startIndex); + const thinking = content.substring(startIndex + startTag.length).trim(); + + return { + thinking, + content: before.trim(), + isThinking: true, + }; + } + } + + return { thinking: null, content, isThinking: false }; +} + +function renderMarkdown(content: string): string { + if (!content) return ""; + try { + return marked(content, { breaks: true, gfm: true }) as string; + } catch { + return content; + } +} + +export function AssistantView() { + const { + messages, + isProcessing, + isProviderHealthy, + streamingContent, + init, + checkHealth, + sendMessage, + clearHistory, + } = useAssistantStore(); + const { settings } = useSettingsStore(); + const { setView } = useUiStore(); + + const [input, setInput] = useState(""); + const messagesEndRef = useRef(null); + const messagesContainerRef = useRef(null); + + const provider = settings.assistant.llmProvider; + const endpoint = + provider === "ollama" + ? settings.assistant.ollamaEndpoint + : settings.assistant.openaiEndpoint; + const model = + provider === "ollama" + ? settings.assistant.ollamaModel + : settings.assistant.openaiModel; + + const getProviderName = (): string => { + if (provider === "ollama") { + return `Ollama (${model})`; + } else if (provider === "openai") { + return `OpenAI (${model})`; + } + return provider; + }; + + const getProviderHelpText = (): string => { + if (provider === "ollama") { + return `Please ensure Ollama is installed and running at ${endpoint}.`; + } else if (provider === "openai") { + return "Please check your OpenAI API key in Settings > AI Assistant."; + } + return ""; + }; + + const scrollToBottom = useCallback(() => { + if (messagesContainerRef.current) { + setTimeout(() => { + if (messagesContainerRef.current) { + messagesContainerRef.current.scrollTop = + messagesContainerRef.current.scrollHeight; + } + }, 0); + } + }, []); + + useEffect(() => { + init(); + }, [init]); + + useEffect(() => { + if (messages.length > 0 || isProcessing) { + scrollToBottom(); + } + }, [messages.length, isProcessing, scrollToBottom]); + + const handleSubmit = async () => { + if (!input.trim() || isProcessing) return; + const text = input; + setInput(""); + await sendMessage(text, settings.assistant.enabled, provider, endpoint); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSubmit(); + } + }; + + const renderMessage = (message: Message, index: number) => { + const isUser = message.role === "user"; + const parsed = parseMessageContent(message.content); + + return ( +
+
+ {!isUser && parsed.thinking && ( +
+
+ + + Thinking Process + + +
+ {parsed.thinking} + {parsed.isThinking && ( + + )} +
+
+
+ )} +
+ {!isUser && message.stats && ( +
+
+ {message.stats.evalCount} tokens ·{" "} + {Math.round(toNumber(message.stats.totalDuration) / 1000000)} + ms +
+
+ )} +
+
+ ); + }; + + return ( +
+
+
+
+ +
+
+

Game Assistant

+

+ Powered by {getProviderName()} +

+
+
+ +
+ {!settings.assistant.enabled ? ( + + + Disabled + + ) : !isProviderHealthy ? ( + + + Offline + + ) : ( + +
+ Online + + )} + + + + + + +
+
+ + {/* Chat Area */} +
+ {/* Warning when assistant is disabled */} + {!settings.assistant.enabled && ( +
+ + + + + Assistant is disabled. Enable it in Settings > AI + Assistant. + + + +
+ )} + + {/* Provider offline warning */} + {settings.assistant.enabled && !isProviderHealthy && ( +
+ + + +
+ + Assistant is offline + + + {getProviderHelpText()} + +
+
+
+
+ )} + + {/* Messages Container */} + + {messages.length === 0 ? ( +
+
+ +
+

How can I help you today?

+

+ I can analyze your game logs, diagnose crashes, or explain mod + features. + {!settings.assistant.enabled && ( + + Assistant is disabled. Enable it in{" "} + + . + + )} +

+
+ + + + +
+
+ ) : ( + <> + {messages.map((message, index) => renderMessage(message, index))} + {isProcessing && streamingContent && ( +
+
+
+
+ + Assistant is typing... +
+
+
+ )} + + )} +
+ + + + + {/* Input Area */} +
+
+