import ReactMarkdown from "react-markdown"; import { useState } from "react"; import type { Goal } from "../../types/goal"; import type { Edge, Message } from "../../types/message"; import styles from "./DetailPanel.module.css"; import { ImagePreviewModal } from "../ImagePreview/ImagePreviewModal"; import { extractImagesFromMessage } from "../../utils/imageExtraction"; interface DetailPanelProps { node: Goal | Message | null; edge: Edge | null; messages?: Message[]; onClose: () => void; } export const DetailPanel = ({ node, edge, messages = [], onClose }: DetailPanelProps) => { const [previewImage, setPreviewImage] = useState(null); const renderImages = (msg: Message) => { const images = extractImagesFromMessage(msg); if (images.length === 0) return null; return (
{images.map((img, idx) => ( {img.alt setPreviewImage(img.url)} /> ))}
); }; const title = node ? "节点详情" : edge ? "连线详情" : "详情"; const renderMessageContent = (content: Message["content"]) => { if (!content) return ""; if (typeof content === "string") return {content}; // 如果有 text,优先显示 text if (content.text) return {content.text}; // 如果有 tool_calls,展示 tool_calls 信息 if (content.tool_calls && content.tool_calls.length > 0) { return (
{content.tool_calls.map((call) => (
工具调用: {call.name}
{JSON.stringify(call.arguments, null, 2)}
))}
); } return {JSON.stringify(content)}; }; const isGoal = (node: Goal | Message): node is Goal => { return "status" in node; }; const isMessageNode = (node: Goal | Message): node is Message => "message_id" in node || "role" in node || "content" in node || "goal_id" in node || "tokens" in node; const renderKnowledge = (knowledge: Goal["knowledge"]) => { if (!knowledge || knowledge.length === 0) return null; return (
{knowledge.map((item) => (
{item.id}
{item.score !== undefined && ⭐ {item.score}} {item.quality_score !== undefined && ( ✨ {item.quality_score.toFixed(1)} )} {item.metrics?.helpful !== undefined && ( 👍 {item.metrics.helpful} )} {item.metrics?.harmful !== undefined && ( 👎 {item.metrics.harmful} )}
{item.tags?.type && item.tags.type.length > 0 && (
{item.tags.type.map((tag) => ( {tag} ))}
)}
场景: {item.scenario}
{item.content}
))}
); }; return ( ); };