|
|
@@ -47,6 +47,57 @@ export const DetailPanel = ({ node, edge, messages = [], onClose }: DetailPanelP
|
|
|
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 (
|
|
|
+ <div className={styles.knowledgeList}>
|
|
|
+ {knowledge.map((item) => (
|
|
|
+ <div
|
|
|
+ key={item.id}
|
|
|
+ className={styles.knowledgeItem}
|
|
|
+ >
|
|
|
+ <div className={styles.knowledgeHeader}>
|
|
|
+ <span className={styles.knowledgeId}>{item.id}</span>
|
|
|
+ <div className={styles.knowledgeMetrics}>
|
|
|
+ {item.score !== undefined && (
|
|
|
+ <span className={styles.metricScore}>⭐ {item.score}</span>
|
|
|
+ )}
|
|
|
+ {item.quality_score !== undefined && (
|
|
|
+ <span className={styles.metricQuality}>✨ {item.quality_score.toFixed(1)}</span>
|
|
|
+ )}
|
|
|
+ {item.metrics?.helpful !== undefined && (
|
|
|
+ <span className={styles.metricHelpful}>👍 {item.metrics.helpful}</span>
|
|
|
+ )}
|
|
|
+ {item.metrics?.harmful !== undefined && (
|
|
|
+ <span className={styles.metricHarmful}>👎 {item.metrics.harmful}</span>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {item.tags?.type && item.tags.type.length > 0 && (
|
|
|
+ <div className={styles.knowledgeTags}>
|
|
|
+ {item.tags.type.map((tag) => (
|
|
|
+ <span
|
|
|
+ key={tag}
|
|
|
+ className={styles.tag}
|
|
|
+ >
|
|
|
+ {tag}
|
|
|
+ </span>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <div className={styles.knowledgeScenario}>
|
|
|
+ <strong>场景:</strong> {item.scenario}
|
|
|
+ </div>
|
|
|
+ <div className={styles.knowledgeContent}>
|
|
|
+ <ReactMarkdown>{item.content}</ReactMarkdown>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<aside className={styles.panel}>
|
|
|
<div className={styles.header}>
|
|
|
@@ -67,27 +118,69 @@ export const DetailPanel = ({ node, edge, messages = [], onClose }: DetailPanelP
|
|
|
<div className={styles.label}>ID</div>
|
|
|
<div className={styles.value}>{isMessageNode(node) ? node.message_id || node.id : node.id}</div>
|
|
|
</div>
|
|
|
- <div className={styles.section}>
|
|
|
- <div className={styles.label}>目标描述</div>
|
|
|
- <div className={styles.value}>{node.description}</div>
|
|
|
- </div>
|
|
|
- {isGoal(node) && node.reason && (
|
|
|
- <div className={styles.section}>
|
|
|
- <div className={styles.label}>创建理由</div>
|
|
|
- <div className={styles.value}>{node.reason}</div>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- {isGoal(node) && node.summary && (
|
|
|
- <div className={styles.section}>
|
|
|
- <div className={styles.label}>总结</div>
|
|
|
- <div className={styles.value}>{node.summary}</div>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- {isGoal(node) && (
|
|
|
- <div className={styles.section}>
|
|
|
- <div className={styles.label}>状态</div>
|
|
|
- <div className={styles.value}>{node.status}</div>
|
|
|
- </div>
|
|
|
+
|
|
|
+ {isGoal(node) ? (
|
|
|
+ <>
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>目标描述</div>
|
|
|
+ <div className={styles.value}>{node.description}</div>
|
|
|
+ </div>
|
|
|
+ {node.reason && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>创建理由</div>
|
|
|
+ <div className={styles.value}>{node.reason}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {node.summary && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>总结</div>
|
|
|
+ <div className={styles.value}>{node.summary}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>状态</div>
|
|
|
+ <div className={styles.value}>{node.status}</div>
|
|
|
+ </div>
|
|
|
+ {node.knowledge && node.knowledge.length > 0 && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.sectionTitle}>相关知识</div>
|
|
|
+ {renderKnowledge(node.knowledge)}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ {node.description && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>描述</div>
|
|
|
+ <div className={styles.value}>{node.description}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {node.role && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>角色</div>
|
|
|
+ <div className={styles.value}>{node.role}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {node.content && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>内容</div>
|
|
|
+ <div className={styles.value}>{renderMessageContent(node.content)}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {node.goal_id && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>所属目标</div>
|
|
|
+ <div className={styles.value}>{node.goal_id}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {node.tokens !== undefined && node.tokens !== null && (
|
|
|
+ <div className={styles.section}>
|
|
|
+ <div className={styles.label}>Token数</div>
|
|
|
+ <div className={styles.value}>{node.tokens}</div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
)}
|
|
|
</>
|
|
|
)}
|