import { ReactNode, useCallback } from 'react' import { Message } from '@/api/lightrag' import useTheme from '@/hooks/useTheme' import Button from '@/components/ui/Button' import { cn } from '@/lib/utils' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import rehypeReact from 'rehype-react' import remarkMath from 'remark-math' import type { Element } from 'hast' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { oneLight, oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' import { LoaderIcon, CopyIcon } from 'lucide-react' import { useTranslation } from 'react-i18next' export type MessageWithError = Message & { isError?: boolean } export const ChatMessage = ({ message }: { message: MessageWithError }) => { const { t } = useTranslation() const handleCopyMarkdown = useCallback(async () => { if (message.content) { try { await navigator.clipboard.writeText(message.content) } catch (err) { console.error(t('chat.copyError'), err) } } }, [message]) return (
        
          {message.content}
        
        {message.role === 'assistant' && message.content.length > 0 && (
          
        )}
      
{message.content.length === 0 && }
) } interface CodeHighlightProps { inline?: boolean className?: string children?: ReactNode node?: Element } const isInlineCode = (node: Element): boolean => { const textContent = (node.children || []) .filter((child) => child.type === 'text') .map((child) => (child as any).value) .join('') return !textContent.includes('\n') } const CodeHighlight = ({ className, children, node, ...props }: CodeHighlightProps) => { const { theme } = useTheme() const match = className?.match(/language-(\w+)/) const language = match ? match[1] : undefined const inline = node ? isInlineCode(node) : false return !inline ? ( {String(children).replace(/\n$/, '')} ) : ( {children} ) }