import React, { useMemo } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { useAgentGraph } from "@/context/AgentGraphContext"; import { GitBranch, ArrowRight, Network, TrendingUp } from "lucide-react"; interface RelationStats { [relationType: string]: { count: number; percentage: number; sourceTypes: Set; targetTypes: Set; }; } interface FlowPattern { source: string; target: string; relation: string; count: number; percentage: number; } interface RelationFlowData { totalRelations: number; relationStats: RelationStats; mostCommonRelation: string; topFlowPatterns: FlowPattern[]; networkComplexity: number; } export function RelationFlowAnalysis() { const { state } = useAgentGraph(); const flowData = useMemo(() => { const relationStats: RelationStats = {}; const flowPatterns: { [key: string]: FlowPattern } = {}; let totalRelations = 0; const allEntityTypes = new Set(); // Process all traces and their knowledge graphs state.traces.forEach((trace) => { trace.knowledge_graphs?.forEach((kg: any) => { if (kg.graph_data) { try { const graphData = typeof kg.graph_data === "string" ? JSON.parse(kg.graph_data) : kg.graph_data; // First pass: collect all entity types if (graphData.entities && Array.isArray(graphData.entities)) { graphData.entities.forEach((entity: any) => { allEntityTypes.add(entity.type || "Unknown"); }); } if (graphData.relations && Array.isArray(graphData.relations)) { // Create entity lookup map const entityLookup = new Map(); if (graphData.entities && Array.isArray(graphData.entities)) { graphData.entities.forEach((entity: any) => { entityLookup.set(entity.id, entity.type || "Unknown"); }); } graphData.relations.forEach((relation: any) => { const type = relation.type || "Unknown"; const sourceType = entityLookup.get(relation.source) || "Unknown"; const targetType = entityLookup.get(relation.target) || "Unknown"; // Track relation statistics if (!relationStats[type]) { relationStats[type] = { count: 0, percentage: 0, sourceTypes: new Set(), targetTypes: new Set(), }; } relationStats[type].count++; relationStats[type].sourceTypes.add(sourceType); relationStats[type].targetTypes.add(targetType); totalRelations++; // Track flow patterns const flowKey = `${sourceType}_${type}_${targetType}`; if (!flowPatterns[flowKey]) { flowPatterns[flowKey] = { source: sourceType, target: targetType, relation: type, count: 0, percentage: 0, }; } flowPatterns[flowKey].count++; }); } } catch (error) { console.warn("Error parsing graph_data:", error); } } }); }); // Calculate percentages Object.values(relationStats).forEach((stats) => { stats.percentage = totalRelations > 0 ? Math.round((stats.count / totalRelations) * 100) : 0; }); Object.values(flowPatterns).forEach((pattern) => { pattern.percentage = totalRelations > 0 ? Math.round((pattern.count / totalRelations) * 100) : 0; }); // Get top flow patterns const topFlowPatterns = Object.values(flowPatterns) .sort((a, b) => b.count - a.count) .slice(0, 8); const mostCommonRelation = Object.entries(relationStats).sort( ([, a], [, b]) => b.count - a.count )[0]?.[0] || "None"; const networkComplexity = allEntityTypes.size > 0 ? Math.round((totalRelations / allEntityTypes.size) * 10) / 10 : 0; return { totalRelations, relationStats, mostCommonRelation, topFlowPatterns, networkComplexity, }; }, [state.traces]); const getRelationColor = (index: number) => { const colors = [ "bg-emerald-500", "bg-cyan-500", "bg-violet-500", "bg-rose-500", "bg-amber-500", "bg-indigo-500", ]; return colors[index % colors.length]; }; const getImportanceIcon = (percentage: number) => { if (percentage > 20) return ; if (percentage > 10) return ; return ; }; if (flowData.totalRelations === 0) { return ( Relation Flow Analysis

No relation data available

Generate some knowledge graphs to see relationship analysis

); } return (
{/* Summary Stats */}

Total Relations

{flowData.totalRelations}

Relation Types

{Object.keys(flowData.relationStats).length}

Network Complexity

{flowData.networkComplexity}

{/* Relation Types Distribution */} Relation Types Distribution
{Object.entries(flowData.relationStats) .sort(([, a], [, b]) => b.count - a.count) .map(([type, stats], index) => (
{type.replace(/_/g, " ")}
{stats.sourceTypes.size} → {stats.targetTypes.size}{" "} entity types
{getImportanceIcon(stats.percentage)} {stats.count} relations {stats.percentage}%
))}
{/* Top Flow Patterns */} Top Flow Patterns
{flowData.topFlowPatterns.map((pattern, index) => (
{pattern.source} {pattern.relation.replace(/_/g, " ")} {pattern.target}
{pattern.count} occurrences {pattern.percentage}%
))}
); }