import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeHighlight from "rehype-highlight"; import rehypeKatex from "rehype-katex"; import "katex/dist/katex.min.css"; import Mermaid from "./Mermaid"; function preprocessContent(text) { if (!text) return ""; let processedText = text; const imageBlockRegex = /((?:!\[.*?\]\(.*?\)(?:\s| )*){2,})/g; processedText = processedText.replace(imageBlockRegex, (match) => { return `\n\`\`\`slider\n${match.trim()}\n\`\`\`\n`; }); const parts = processedText.split(/(```[\s\S]*?```|`[^`\n]+`|!\[[\s\S]*?\]\([\s\S]*?\))/g); const processedParts = parts.map(part => { if (part.startsWith("```") || part.startsWith("`") || part.startsWith("![")) return part; let processed = part; const mermaidRegex = /^(?:graph|flowchart|classDiagram|stateDiagram|erDiagram|sequenceDiagram|gantt|pie|quadrantChart|xychart|mindmap|timeline)[\s\S]+?(?=\n\n|\n$|$)/gm; processed = processed.replace(mermaidRegex, (match) => { if (match.trim().split("\n").length > 1) { return `\n\`\`\`mermaid\n${match.trim()}\n\`\`\`\n`; } return match; }); const treeRegex = /((?:^[ \t]*[│├└┌┐┘┤┼|].*$\n?)+)/gm; processed = processed.replace(treeRegex, (match) => { const lines = match.trim().split("\n"); const hasStrongTreeChars = /[│├└┌┐┘┤┼├─]/.test(match); if (lines.length > 1 || hasStrongTreeChars) { return `\n\`\`\`tree\n${match.trim()}\n\`\`\`\n`; } return match; }); processed = processed.replace(/^[ \t\u00a0]*[•●○·][ \t\u00a0]*/gm, "- "); processed = processed.replace(/\\\[([\s\S]*?)\\\]/g, "$$$$1$$"); processed = processed.replace(/\\\(([\s\S]*?)\\\)/g, "$$1$"); processed = processed.replace(/(\((.+?)\)|\[(.+?)\])/g, (match, full, p1, p2) => { const content = (p1 || p2 || "").trim(); if (!content) return match; const hasMathOperator = /[\\_^={}+\-*/]/.test(content); const isSingleVar = /^[a-z]$/i.test(content); const isExpression = /^[a-z0-9] *[+\-*/=] *[a-z0-9]/i.test(content); if (hasMathOperator || isSingleVar || isExpression) { const delim = (match.startsWith("[") || content.length > 50) ? "$$" : "$"; return `${delim}${match}${delim}`; } return match; }); const lines = processed.split("\n"); const resultLines = lines.map(line => { const trimmed = line.trim(); if ( (trimmed.includes("\\") || /[_^]/.test(trimmed) || /^[a-z] *=/i.test(trimmed)) && !trimmed.includes("$") && !trimmed.startsWith("#") && !trimmed.startsWith("-") && !trimmed.startsWith("*") && trimmed.length > 0 ) { if (/^[a-zA-Z0-9] *=/.test(trimmed) || /^\\[a-zA-Z]+/.test(trimmed)) { return `$$${trimmed}$$`; } } return line; }); return resultLines.join("\n"); }); let finalProcessed = processedParts.join(""); finalProcessed = finalProcessed.replace(/([^\n])\n- /g, "$1\n\n- "); return finalProcessed; } export function AnswerRenderer({ answer }) { const processedAnswer = preprocessContent(answer); return (
; } if (!inline && match?.[1] === "slider") { const imageMatches = content.match(/!\[.*?\]\((.*?)\)/g) || []; const imageUrls = imageMatches.map(m => { const urlMatch = m.match(/\((.*?)\)/); return urlMatch ? urlMatch[1] : null; }).filter(Boolean); return (
{imageUrls.map((url, idx) => (
{`Image
))}
); } const isTree = match?.[1] === "tree" || /[│├└┌┐┘┤┼├─]/.test(content) || (content.includes("|") && /[─━]/.test(content)) || /^[ \t]*[|│].*$/m.test(content); if (!inline && isTree) { const handleCopy = () => { navigator.clipboard.writeText(content); }; return (
STRUCTURE
                    {children}
                  
); } return !inline && match ? (
                
                  {children}
                
              
) : ( {children} ); }, }} > {processedAnswer}
); }