import React from 'react'; import { Box, Typography, Card, CardContent, Chip, List, ListItem, ListItemText, Link, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, IconButton, Collapse, } from '@mui/material'; import { ExpandMore, ExpandLess, Code as CodeIcon, Link as LinkIcon, TableChart as TableIcon, } from '@mui/icons-material'; type SectionType = | 'header' | 'subheader' | 'text' | 'list' | 'code' | 'table' | 'link' | 'metric' | 'highlight'; interface Section { type: SectionType; content?: string; level?: number; items?: string[]; language?: string; headers?: string[]; rows?: string[][]; url?: string; title?: string; } interface ResponseRendererProps { content: string; isBotMessage?: boolean; } const ResponseRenderer: React.FC = ({ content, isBotMessage = true }) => { const [expandedSections, setExpandedSections] = React.useState<{ [key: string]: boolean }>({}); const toggleSection = (sectionId: string) => { setExpandedSections((prev) => ({ ...prev, [sectionId]: !prev[sectionId], })); }; // Parse different content types const parseContent = (text: string): Section[] => { const sections: Section[] = []; const lines = text.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (!line) { sections.push({ type: 'text', content: '' }); continue; } if (line.startsWith('# ')) { sections.push({ type: 'header', content: line.substring(2), level: 1 }); } else if (line.startsWith('## ')) { sections.push({ type: 'subheader', content: line.substring(3), level: 2 }); } else if (line.startsWith('### ')) { sections.push({ type: 'subheader', content: line.substring(4), level: 3 }); } else if (line.startsWith('**') && line.endsWith('**')) { sections.push({ type: 'highlight', content: line.substring(2, line.length - 2) }); } else if (line.startsWith('• ') || line.startsWith('- ') || line.startsWith('* ')) { const listItems = [line.substring(2)]; let j = i + 1; while ( j < lines.length && (lines[j].trim().startsWith('• ') || lines[j].trim().startsWith('- ') || lines[j].trim().startsWith('* ')) ) { listItems.push(lines[j].trim().substring(2)); j++; } i = j - 1; sections.push({ type: 'list', content: '', items: listItems }); } else if (line.startsWith('```')) { const language = line.substring(3).trim(); let codeContent = ''; let j = i + 1; while (j < lines.length && !lines[j].trim().startsWith('```')) { codeContent += lines[j] + '\n'; j++; } i = j; sections.push({ type: 'code', content: codeContent.trim(), language }); } else if (line.includes('|') && lines[i + 1]?.includes('|') && lines[i + 1]?.includes('-')) { const headers = line .split('|') .map((h) => h.trim()) .filter((h) => h); let j = i + 2; const rows: string[][] = []; while (j < lines.length && lines[j].trim().includes('|')) { const row = lines[j] .split('|') .map((cell) => cell.trim()) .filter((cell) => cell); if (row.length > 0) rows.push(row); j++; } i = j - 1; sections.push({ type: 'table', content: '', headers, rows }); } else if (line.match(/https?:\/\/[^\s]+/)) { const urlMatch = line.match(/(https?:\/\/[^\s]+)/); if (urlMatch) { const url = urlMatch[1]; const title = line.replace(url, '').trim(); sections.push({ type: 'link', content: title, url }); } else { sections.push({ type: 'text', content: line }); } } else if (line.includes('•') && line.includes(':')) { sections.push({ type: 'metric', content: line }); } else { sections.push({ type: 'text', content: line }); } } return sections; }; const sections = parseContent(content); const renderSection = (section: Section, index: number) => { const sectionId = `section-${index}`; switch (section.type) { case 'header': return ( {section.content} ); case 'subheader': return ( {section.content} ); case 'highlight': return ( ); case 'list': return ( {section.items?.map((item, idx) => ( ))} ); case 'code': return ( {section.language || 'code'}
                {section.content}
              
); case 'table': return ( {section.headers?.map((header, idx) => ( {header} ))} {section.rows?.map((row, rowIdx) => ( {row.map((cell, cellIdx) => ( {cell} ))} ))}
); case 'link': return ( {section.content || section.url} ); case 'metric': return ( {section.content} ); default: return ( {section.content} ); } }; return ( *:not(:last-child)': { mb: 2, }, }} > {sections.map((section, index) => renderSection(section, index))} ); }; export default ResponseRenderer;