import { IconBrain, IconCheck, IconChevronDown, IconCopy, IconDownload, IconFileText, IconTool, } from "@tabler/icons-react" import { useState } from "react" import { useTranslation } from "react-i18next" import ReactMarkdown from "react-markdown" import rehypeHighlight from "rehype-highlight" import rehypeRaw from "rehype-raw" import rehypeSanitize from "rehype-sanitize" import remarkGfm from "remark-gfm" import { Button } from "@/components/ui/button" import { formatMessageTime } from "@/hooks/use-pico-chat" import { cn } from "@/lib/utils" import { type AssistantMessageKind, type ChatAttachment, type ChatToolCall, } from "@/store/chat" interface AssistantMessageProps { content: string attachments?: ChatAttachment[] kind?: AssistantMessageKind toolCalls?: ChatToolCall[] timestamp?: string | number } export function AssistantMessage({ content, attachments = [], kind = "normal", toolCalls = [], timestamp = "", }: AssistantMessageProps) { const { t } = useTranslation() const [isCopied, setIsCopied] = useState(false) const isThought = kind === "thought" const isToolCalls = kind === "tool_calls" const isCollapsedBlock = isThought || isToolCalls const hasText = content.trim().length > 0 const hasToolCalls = toolCalls.length > 0 const imageAttachments = attachments.filter( (attachment) => attachment.type === "image", ) const fileAttachments = attachments.filter( (attachment) => attachment.type !== "image", ) const [isExpanded, setIsExpanded] = useState(true) const formattedTimestamp = timestamp !== "" ? formatMessageTime(timestamp) : "" const handleCopy = async () => { const markCopied = () => { setIsCopied(true) setTimeout(() => setIsCopied(false), 2000) } try { if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(content) markCopied() return } } catch { // HTTP 或受限环境下可能不支持 Clipboard API,继续走降级方案 } const textArea = document.createElement("textarea") textArea.value = content textArea.setAttribute("readonly", "") textArea.style.position = "fixed" textArea.style.left = "-9999px" document.body.appendChild(textArea) textArea.select() try { const copied = document.execCommand("copy") if (copied) { markCopied() } } finally { document.body.removeChild(textArea) } } const collapsedLabel = isThought ? t("chat.reasoningLabel") : t("chat.toolCallsLabel") return (
{toolArguments}
)}