'use client'; import { useState } from 'react'; import { Copy, ThumbsUp, ThumbsDown, RefreshCw, ChevronDown, ChevronUp, Brain, Loader2, AlertCircle, Check } from 'lucide-react'; import { Avatar } from '@/components/ui/Avatar'; import { AILogo } from '@/components/ui/AILogo'; import { MarkdownRenderer } from '@/components/markdown/MarkdownRenderer'; import { CodeExecutionResult, PyodideLoading } from '@/components/features/CodeExecutionResult'; import { cn } from '@/lib/utils'; import type { Message, User, ToolResult } from '@/types'; interface MessageBubbleProps { message: Message; user?: User; thinkingContent?: string; isStreaming?: boolean; error?: string; /** 代码执行产生的图片(Base64) */ images?: string[]; /** Pyodide 加载状态 */ pyodideStatus?: { stage: 'loading' | 'ready' | 'error'; message: string; progress?: number; }; } export function MessageBubble({ message, user, thinkingContent, isStreaming, error, images, pyodideStatus }: MessageBubbleProps) { const isUser = message.role === 'user'; const [thinkingExpanded, setThinkingExpanded] = useState(false); const [copied, setCopied] = useState(false); // 复制消息内容 const handleCopy = async () => { try { await navigator.clipboard.writeText(message.content); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch (error) { console.error('Failed to copy:', error); } }; if (isUser) { return (
{message.content}
{user && }
); } return (
{/* AI 图标 */}
{/* 消息内容 */}
{/* 思考内容 */} {thinkingContent && (
{thinkingExpanded && (
                  {thinkingContent}
                
)}
)} {/* 错误提示 */} {error && (
{error}
)} {/* 主要内容 */}
{message.content ? ( ) : isStreaming ? (
正在思考...
) : null}
{/* 工具调用结果 - 代码执行图片展示 */} {message.toolResults && message.toolResults.length > 0 && (
{message.toolResults.map((result, index) => ( ))}
)} {/* Pyodide 加载状态 */} {pyodideStatus && (
)} {/* 代码执行图片(从 props 传入) */} {images && images.length > 0 && ( )} {/* 流式状态指示器 */} {isStreaming && message.content && (
生成中...
)} {/* 操作按钮(非流式状态下显示) */} {!isStreaming && message.content && ( <>
{/* 免责声明 */}
LionCode can make mistakes
)}
); } interface ActionButtonProps { icon: React.ComponentType<{ size?: number }>; title: string; onClick?: () => void; } function ActionButton({ icon: Icon, title, onClick }: ActionButtonProps) { return ( ); } /** * 工具调用结果显示组件 * 专门处理代码执行结果和图片显示 */ interface ToolResultDisplayProps { result: ToolResult; } function ToolResultDisplay({ result }: ToolResultDisplayProps) { // 只有代码执行工具才显示图片 if (result.toolName !== 'code_execution') { return null; } // 如果没有图片,不显示 if (!result.images || result.images.length === 0) { return null; } return ( ); }