Spaces:
Running
Running
| import React, { useEffect, useRef } from "react"; | |
| import { KnowledgeGraph, Entity, Relation } from "@/types"; | |
| import { detectSchemaType } from "@/lib/schema-detection"; | |
| interface SimpleGraphVisualizationProps { | |
| knowledgeGraph: KnowledgeGraph; | |
| width?: number; | |
| height?: number; | |
| graphData?: { | |
| entities: Entity[]; | |
| relations: Relation[]; | |
| metadata?: Record<string, any>; | |
| } | null; | |
| } | |
| export function SimpleGraphVisualization({ | |
| knowledgeGraph, | |
| width = 500, | |
| height = 350, | |
| graphData, | |
| }: SimpleGraphVisualizationProps) { | |
| const svgRef = useRef<SVGSVGElement>(null); | |
| useEffect(() => { | |
| if (!svgRef.current) return; | |
| // Clear previous content | |
| const svg = svgRef.current; | |
| svg.innerHTML = ""; | |
| // Only render if we have real data | |
| if (!graphData || !graphData.entities || !graphData.relations) { | |
| return; // Don't render anything if no data | |
| } | |
| // Detect schema type for future enhancements | |
| const schemaType = detectSchemaType(graphData); | |
| console.log("SimpleGraphVisualization: Detected schema type:", schemaType); | |
| // Use real data | |
| const nodes = graphData.entities.map((entity, index) => ({ | |
| id: entity.id, | |
| name: entity.name, | |
| type: entity.type, | |
| x: 100 + (index % 4) * 120, // Simple grid layout | |
| y: 100 + Math.floor(index / 4) * 100, | |
| })); | |
| const links = graphData.relations.map((relation) => ({ | |
| source: relation.source, | |
| target: relation.target, | |
| type: relation.type, | |
| })); | |
| // Create SVG elements | |
| const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); | |
| svg.appendChild(g); | |
| // Draw links | |
| links.forEach((link) => { | |
| const sourceNode = nodes.find((n) => n.id === link.source); | |
| const targetNode = nodes.find((n) => n.id === link.target); | |
| if (sourceNode && targetNode) { | |
| const line = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "line" | |
| ); | |
| line.setAttribute("x1", sourceNode.x.toString()); | |
| line.setAttribute("y1", sourceNode.y.toString()); | |
| line.setAttribute("x2", targetNode.x.toString()); | |
| line.setAttribute("y2", targetNode.y.toString()); | |
| line.setAttribute("stroke", "#94a3b8"); | |
| line.setAttribute("stroke-width", "2"); | |
| g.appendChild(line); | |
| // Add link label | |
| const text = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "text" | |
| ); | |
| text.setAttribute("x", ((sourceNode.x + targetNode.x) / 2).toString()); | |
| text.setAttribute("y", ((sourceNode.y + targetNode.y) / 2).toString()); | |
| text.setAttribute("text-anchor", "middle"); | |
| text.setAttribute("font-size", "10"); | |
| text.setAttribute("fill", "#6b7280"); | |
| text.textContent = link.type.replace("_", " "); | |
| g.appendChild(text); | |
| } | |
| }); | |
| // Draw nodes | |
| nodes.forEach((node) => { | |
| const nodeGroup = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "g" | |
| ); | |
| // Node circle | |
| const circle = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "circle" | |
| ); | |
| circle.setAttribute("cx", node.x.toString()); | |
| circle.setAttribute("cy", node.y.toString()); | |
| circle.setAttribute("r", "20"); | |
| circle.setAttribute("fill", getNodeColor(node.type)); | |
| circle.setAttribute("stroke", "#ffffff"); | |
| circle.setAttribute("stroke-width", "2"); | |
| nodeGroup.appendChild(circle); | |
| // Node label | |
| const text = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "text" | |
| ); | |
| text.setAttribute("x", node.x.toString()); | |
| text.setAttribute("y", (node.y + 35).toString()); | |
| text.setAttribute("text-anchor", "middle"); | |
| text.setAttribute("font-size", "12"); | |
| text.setAttribute("font-weight", "bold"); | |
| text.setAttribute("fill", "#1f2937"); | |
| text.textContent = node.name; | |
| nodeGroup.appendChild(text); | |
| // Node type | |
| const typeText = document.createElementNS( | |
| "http://www.w3.org/2000/svg", | |
| "text" | |
| ); | |
| typeText.setAttribute("x", node.x.toString()); | |
| typeText.setAttribute("y", (node.y + 50).toString()); | |
| typeText.setAttribute("text-anchor", "middle"); | |
| typeText.setAttribute("font-size", "10"); | |
| typeText.setAttribute("fill", "#6b7280"); | |
| typeText.textContent = node.type; | |
| nodeGroup.appendChild(typeText); | |
| g.appendChild(nodeGroup); | |
| }); | |
| }, [knowledgeGraph, graphData]); | |
| const getNodeColor = (type: string): string => { | |
| switch (type) { | |
| case "person": | |
| return "#3b82f6"; | |
| case "organization": | |
| return "#10b981"; | |
| case "location": | |
| return "#f59e0b"; | |
| case "concept": | |
| return "#8b5cf6"; | |
| case "event": | |
| return "#ef4444"; | |
| default: | |
| return "#6b7280"; | |
| } | |
| }; | |
| // Use real counts if available | |
| const entityCount = | |
| graphData?.entities?.length || knowledgeGraph.entity_count || 0; | |
| const relationCount = | |
| graphData?.relations?.length || knowledgeGraph.relation_count || 0; | |
| return ( | |
| <div className="flex flex-col items-center space-y-4"> | |
| <div className="text-center"> | |
| <h3 className="text-lg font-semibold">Agent Graph Visualization</h3> | |
| <p className="text-sm text-muted-foreground"> | |
| {entityCount} entities, {relationCount} relationships | |
| </p> | |
| </div> | |
| <div className="border rounded-lg p-4 bg-gray-50"> | |
| <svg | |
| ref={svgRef} | |
| width={width} | |
| height={height} | |
| className="bg-white rounded" | |
| style={{ maxWidth: "100%", height: "auto" }} | |
| > | |
| {/* Content will be generated dynamically */} | |
| </svg> | |
| </div> | |
| <div className="text-xs text-muted-foreground text-center"> | |
| <p>Interactive visualization - Click and drag nodes to explore</p> | |
| <p>Colors represent different entity types</p> | |
| </div> | |
| </div> | |
| ); | |
| } | |