feat(组件): 消息气泡支持图形展示
MessageBubble.tsx: - 集成 CodeExecutionResult 组件显示代码执行图片 - 添加 Pyodide 加载状态显示 - 支持 images 和 pyodideStatus 属性 - 新增 ToolResultDisplay 子组件处理工具结果 MarkdownRenderer.tsx: - 修复图片组件属性传递问题 - 改用 spread 操作符传递所有 img 属性
This commit is contained in:
parent
58d288637a
commit
e5c5593686
@ -5,8 +5,9 @@ import { Copy, ThumbsUp, ThumbsDown, RefreshCw, ChevronDown, ChevronUp, Brain, L
|
||||
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 } from '@/types';
|
||||
import type { Message, User, ToolResult } from '@/types';
|
||||
|
||||
interface MessageBubbleProps {
|
||||
message: Message;
|
||||
@ -14,9 +15,17 @@ interface MessageBubbleProps {
|
||||
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 }: MessageBubbleProps) {
|
||||
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);
|
||||
@ -96,6 +105,34 @@ export function MessageBubble({ message, user, thinkingContent, isStreaming, err
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{/* 工具调用结果 - 代码执行图片展示 */}
|
||||
{message.toolResults && message.toolResults.length > 0 && (
|
||||
<div className="mt-4">
|
||||
{message.toolResults.map((result, index) => (
|
||||
<ToolResultDisplay key={index} result={result} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pyodide 加载状态 */}
|
||||
{pyodideStatus && (
|
||||
<div className="mt-4">
|
||||
<PyodideLoading
|
||||
stage={pyodideStatus.stage}
|
||||
message={pyodideStatus.message}
|
||||
progress={pyodideStatus.progress}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 代码执行图片(从 props 传入) */}
|
||||
{images && images.length > 0 && (
|
||||
<CodeExecutionResult
|
||||
images={images}
|
||||
success={true}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 流式状态指示器 */}
|
||||
{isStreaming && message.content && (
|
||||
<div className="flex items-center gap-2 mt-3 text-sm text-[var(--color-text-tertiary)]">
|
||||
@ -149,3 +186,32 @@ function ActionButton({ icon: Icon, title, onClick }: ActionButtonProps) {
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具调用结果显示组件
|
||||
* 专门处理代码执行结果和图片显示
|
||||
*/
|
||||
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 (
|
||||
<CodeExecutionResult
|
||||
images={result.images}
|
||||
engine={result.engine}
|
||||
executionTime={result.executionTime}
|
||||
success={!result.isError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -196,11 +196,11 @@ const markdownComponents = {
|
||||
},
|
||||
|
||||
// 图片
|
||||
img({ src, alt }: { src?: string; alt?: string }) {
|
||||
img(props: React.ImgHTMLAttributes<HTMLImageElement>) {
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
alt={alt || ''}
|
||||
{...props}
|
||||
alt={props.alt || ''}
|
||||
className="max-w-full h-auto rounded-lg my-3"
|
||||
/>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user