import React from 'react'; import { Typography } from 'antd'; import '../../styles/components/chat-with-llm/markdown.css'; const { Paragraph, Text, Title } = Typography; interface MarkdownProps { content: string; className?: string; } /** * Markdown 渲染组件 * 简化版本,支持基本的 Markdown 语法 */ export default function Markdown({ content, className = '' }: MarkdownProps) { if (!content) return null; /** * 简单的 Markdown 解析器 */ const parseMarkdown = (text: string): React.ReactNode => { // 分割成行 const lines = text.split('\n'); const elements: React.ReactNode[] = []; let currentParagraph: string[] = []; let inCodeBlock = false; let codeBlockContent: string[] = []; let codeBlockLanguage = ''; const flushParagraph = () => { if (currentParagraph.length > 0) { const paragraphText = currentParagraph.join('\n'); elements.push( {parseInlineElements(paragraphText)} ); currentParagraph = []; } }; const flushCodeBlock = () => { if (codeBlockContent.length > 0) { elements.push(
                        
                            {codeBlockContent.join('\n')}
                        
                    
); codeBlockContent = []; codeBlockLanguage = ''; } }; lines.forEach((line, index) => { // 处理代码块 if (line.startsWith('```')) { if (inCodeBlock) { // 结束代码块 flushCodeBlock(); inCodeBlock = false; } else { // 开始代码块 flushParagraph(); inCodeBlock = true; codeBlockLanguage = line.slice(3).trim(); } return; } if (inCodeBlock) { codeBlockContent.push(line); return; } // 处理标题 if (line.startsWith('# ')) { flushParagraph(); elements.push( {parseInlineElements(line.slice(2))} ); return; } if (line.startsWith('## ')) { flushParagraph(); elements.push( {parseInlineElements(line.slice(3))} ); return; } if (line.startsWith('### ')) { flushParagraph(); elements.push( {parseInlineElements(line.slice(4))} ); return; } // 处理列表 if (line.startsWith('- ') || line.startsWith('* ')) { flushParagraph(); elements.push( ); return; } if (/^\d+\.\s/.test(line)) { flushParagraph(); const match = line.match(/^\d+\.\s(.*)$/); if (match) { elements.push(
  1. {parseInlineElements(match[1])}
); } return; } // 处理空行 if (line.trim() === '') { flushParagraph(); return; } // 普通段落 currentParagraph.push(line); }); // 处理剩余内容 flushParagraph(); flushCodeBlock(); return elements; }; /** * 解析行内元素(粗体、斜体、代码、链接等) */ const parseInlineElements = (text: string): React.ReactNode => { const parts: React.ReactNode[] = []; let currentText = text; let key = 0; // 处理行内代码 currentText = currentText.replace(/`([^`]+)`/g, (match, code) => { const placeholder = `__CODE_${key}__`; parts.push( {code} ); key++; return placeholder; }); // 处理粗体 currentText = currentText.replace(/\*\*([^*]+)\*\*/g, (match, bold) => { const placeholder = `__BOLD_${key}__`; parts.push( {bold} ); key++; return placeholder; }); // 处理斜体 currentText = currentText.replace(/\*([^*]+)\*/g, (match, italic) => { const placeholder = `__ITALIC_${key}__`; parts.push( {italic} ); key++; return placeholder; }); // 处理链接 currentText = currentText.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => { const placeholder = `__LINK_${key}__`; parts.push( {linkText} ); key++; return placeholder; }); // 重新组装文本 const finalParts: React.ReactNode[] = []; const textParts = currentText.split(/(__(?:CODE|BOLD|ITALIC|LINK)_\d+__)/); textParts.forEach((part, index) => { const match = part.match(/^__(\w+)_(\d+)__$/); if (match) { const [, type, partKey] = match; const component = parts.find((p: any) => p.key === `${type.toLowerCase()}-${partKey}` ); if (component) { finalParts.push(component); } } else if (part) { finalParts.push(part); } }); return finalParts.length === 1 ? finalParts[0] : finalParts; }; return (
{parseMarkdown(content)}
); }