// src/AssistantMessage.jsx import React, { useState, useEffect } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; // Prism.js per syntax highlight import Prism from "prismjs"; import "prismjs/themes/prism.css"; // Linguaggi base import "prismjs/components/prism-sql"; import "prismjs/components/prism-javascript"; import "prismjs/components/prism-css"; import "prismjs/components/prism-json"; import "prismjs/components/prism-markdown"; import "prismjs/components/prism-csharp"; import "prismjs/components/prism-lua"; import "prismjs/components/prism-c"; import "prismjs/components/prism-cpp"; import "prismjs/components/prism-python"; import "prismjs/components/prism-basic"; import "prismjs/components/prism-javascript"; // Aggiungo alias "vb" che punta a "vbnet" Prism.languages.vb = Prism.languages.vbnet; export default function AssistantMessage({ content, theme, timestamp, startedAt, endedAt, isFinal }) { const [showThink, setShowThink] = useState(false); const [fadeOut, setFadeOut] = useState(false); const ts = timestamp ?? endedAt ?? startedAt; const thinkMatch = content?.match(/([\s\S]*?)<\/think>/i); const thinkContent = thinkMatch ? thinkMatch[1].trim() : null; const isComplete = isFinal || Boolean(timestamp || endedAt); const visibleContent = isComplete ? content?.replace(/[\s\S]*?<\/think>/i, "").trim() : content; useEffect(() => { if (thinkContent && !isComplete) { setShowThink(true); setFadeOut(false); } if (thinkContent && isComplete) { setFadeOut(true); const timer = setTimeout(() => setShowThink(false), 600); return () => clearTimeout(timer); } }, [thinkContent, isComplete]); return (
{showThink && (
🤔 {thinkContent}
)} ( ), th: (props) =>
, code: CodeWithCopy }} > {visibleContent} {ts != null && (
{formatDateTime(ts)}
)} ); } function CodeWithCopy({ inline, className = "", children, ...props }) { const [copied, setCopied] = useState(false); const codeText = String(children).replace(/\n$/, ""); const isFencedBlock = !inline && /^language-/.test(className); // Evidenziazione con Prism useEffect(() => { if (isFencedBlock) { Prism.highlightAll(); } }, [codeText, isFencedBlock]); if (!isFencedBlock) { return ( {children} ); } const handleCopy = async () => { try { await navigator.clipboard.writeText(codeText); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch (err) { console.error("Copy failed", err); } }; return (
        {codeText}
      
{copied && ( Copied! )}
); } function formatDateTime(dateTime) { const date = dateTime instanceof Date ? dateTime : new Date(dateTime); if (Number.isNaN(date.getTime())) return String(dateTime); return date.toLocaleString(undefined, { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit" }); }