import { useEffect, useRef, useState } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Slider } from "@/components/ui/slider"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import { Network, GitBranch, Zap, Eye, Play, Pause, Search } from "lucide-react"; import { Input } from "@/components/ui/input"; import ForceGraph2D from "react-force-graph-2d"; import ForceGraph3D from "react-force-graph-3d"; import * as d3 from "d3"; interface GraphNode { id: string; label: string; type: "document" | "concept" | "author" | "topic" | "query"; size: number; color: string; metadata?: any; x?: number; y?: number; z?: number; } interface GraphLink { source: string | GraphNode; target: string | GraphNode; relationship: string; strength: number; color: string; } interface GraphData { nodes: GraphNode[]; links: GraphLink[]; } interface GraphStats { totalDocuments: number; totalConcepts: number; totalResearchTeams: number; totalSourceTypes: number; } const NODE_COLORS = { document: "#3b82f6", // blue concept: "#10b981", // emerald author: "#f59e0b", // amber topic: "#8b5cf6", // violet query: "#ef4444", // red }; const RELATIONSHIP_COLORS = { "cites": "#64748b", "authored_by": "#f59e0b", "contains_concept": "#10b981", "related_to": "#8b5cf6", "searched_for": "#ef4444", "similar_to": "#06b6d4", }; export function KnowledgeGraph() { const [graphData, setGraphData] = useState({ nodes: [], links: [] }); const [view3D, setView3D] = useState(false); const [isAnimating, setIsAnimating] = useState(true); const [selectedNode, setSelectedNode] = useState(null); const [linkDistance, setLinkDistance] = useState([150]); const [chargeStrength, setChargeStrength] = useState([-300]); const [showLabels, setShowLabels] = useState(true); const [isLoading, setIsLoading] = useState(true); const [stats, setStats] = useState({ totalDocuments: 0, totalConcepts: 0, totalResearchTeams: 0, totalSourceTypes: 0 }); const [searchTerm, setSearchTerm] = useState(""); const [filteredGraphData, setFilteredGraphData] = useState({ nodes: [], links: [] }); const [hoveredNode, setHoveredNode] = useState(null); const [highlightNodes, setHighlightNodes] = useState(new Set()); const [highlightLinks, setHighlightLinks] = useState(new Set()); const fgRef = useRef(); useEffect(() => { fetchKnowledgeGraph(); }, []); useEffect(() => { filterGraphData(); }, [searchTerm, graphData]); const filterGraphData = () => { if (!searchTerm) { setFilteredGraphData({ nodes: [], links: [] }); return; } const term = searchTerm.toLowerCase(); const filteredNodes = graphData.nodes.filter(node => node.label.toLowerCase().includes(term) || node.type.toLowerCase().includes(term) || (node.metadata?.concept && node.metadata.concept.toLowerCase().includes(term)) || (node.metadata?.title && node.metadata.title.toLowerCase().includes(term)) ); const nodeIds = new Set(filteredNodes.map(n => n.id)); const filteredLinks = graphData.links.filter(link => { const sourceId = typeof link.source === 'string' ? link.source : (link.source as GraphNode).id; const targetId = typeof link.target === 'string' ? link.target : (link.target as GraphNode).id; return nodeIds.has(sourceId) && nodeIds.has(targetId); }); setFilteredGraphData({ nodes: filteredNodes, links: filteredLinks }); }; const fetchKnowledgeGraph = async () => { try { setIsLoading(true); const response = await fetch('/api/knowledge-graph'); const data = await response.json(); if (data.nodes && data.links) { setGraphData({ nodes: data.nodes, links: data.links }); setStats(data.stats || { totalDocuments: 0, totalConcepts: 0, totalResearchTeams: 0, totalSourceTypes: 0 }); } else { // Fallback to sample data if API fails generateKnowledgeGraph(); } } catch (error) { console.error('Failed to fetch knowledge graph:', error); // Fallback to sample data generateKnowledgeGraph(); } finally { setIsLoading(false); } }; const generateKnowledgeGraph = () => { // Extract concepts from KnowledgeBridge sample documents const documents = [ { id: "deepseek-r1", title: "DeepSeek-R1: Advanced Reasoning Model", concepts: ["reasoning", "thinking", "chain-of-thought"], authors: ["DeepSeek Team"], year: 2024, sourceType: "arxiv" }, { id: "nebius-ai", title: "Nebius AI Platform", concepts: ["cloud-ai", "scaling", "embeddings"], authors: ["Nebius Team"], year: 2024, sourceType: "github" }, { id: "semantic-search", title: "Semantic Search with BGE Models", concepts: ["embeddings", "similarity", "retrieval"], authors: ["BAAI Team"], year: 2024, sourceType: "arxiv" }, { id: "modal-compute", title: "Modal Distributed Computing", concepts: ["serverless", "scaling", "distributed"], authors: ["Modal Team"], year: 2024, sourceType: "github" }, { id: "url-validation", title: "Smart URL Validation Systems", concepts: ["validation", "filtering", "content-verification"], authors: ["Web Research Group"], year: 2024, sourceType: "web" }, { id: "multi-source", title: "Multi-Source Information Retrieval", concepts: ["search", "aggregation", "ranking"], authors: ["IR Conference"], year: 2024, sourceType: "academic" }, { id: "ai-security", title: "AI Application Security", concepts: ["rate-limiting", "validation", "middleware"], authors: ["Security Researchers"], year: 2024, sourceType: "github" }, { id: "react-query", title: "TanStack Query for Data Fetching", concepts: ["caching", "state-management", "performance"], authors: ["TanStack Team"], year: 2024, sourceType: "github" }, { id: "typescript-safety", title: "TypeScript for Type Safety", concepts: ["type-safety", "compilation", "validation"], authors: ["TypeScript Team"], year: 2024, sourceType: "web" }, { id: "knowledge-graphs", title: "Interactive Knowledge Graphs", concepts: ["visualization", "relationships", "d3js"], authors: ["DataViz Community"], year: 2024, sourceType: "github" }, { id: "github-api", title: "GitHub API for Repository Search", concepts: ["api-integration", "search", "filtering"], authors: ["GitHub Team"], year: 2024, sourceType: "web" }, { id: "arxiv-papers", title: "ArXiv Academic Paper Search", concepts: ["academic-search", "paper-validation", "research"], authors: ["arXiv Team"], year: 2024, sourceType: "academic" }, ]; const nodes: GraphNode[] = []; const links: GraphLink[] = []; // Add document nodes documents.forEach(doc => { nodes.push({ id: doc.id, label: doc.title, type: "document", size: 12, color: NODE_COLORS.document, metadata: doc }); }); // Extract unique concepts and create concept nodes const allConcepts = new Set(); documents.forEach(doc => doc.concepts.forEach(concept => allConcepts.add(concept))); allConcepts.forEach(concept => { const relatedDocs = documents.filter(doc => doc.concepts.includes(concept)); nodes.push({ id: `concept_${concept}`, label: concept, type: "concept", size: 8 + relatedDocs.length * 2, color: NODE_COLORS.concept, metadata: { relatedDocuments: relatedDocs.length } }); // Link concepts to documents relatedDocs.forEach(doc => { links.push({ source: doc.id, target: `concept_${concept}`, relationship: "contains_concept", strength: 1, color: RELATIONSHIP_COLORS.contains_concept }); }); }); // Extract unique authors and create author nodes const allAuthors = new Set(); documents.forEach(doc => doc.authors.forEach(author => allAuthors.add(author))); allAuthors.forEach(author => { const authoredDocs = documents.filter(doc => doc.authors.includes(author)); nodes.push({ id: `author_${author}`, label: author, type: "author", size: 6 + authoredDocs.length, color: NODE_COLORS.author, metadata: { publications: authoredDocs.length } }); // Link authors to documents authoredDocs.forEach(doc => { links.push({ source: `author_${author}`, target: doc.id, relationship: "authored_by", strength: 0.8, color: RELATIONSHIP_COLORS.authored_by }); }); }); // Create topic clusters for KnowledgeBridge features const topics = [ { id: "ai_models", name: "AI Models & Processing", docs: ["deepseek-r1", "nebius-ai", "semantic-search"] }, { id: "infrastructure", name: "Infrastructure & Scaling", docs: ["modal-compute", "ai-security", "react-query"] }, { id: "search_systems", name: "Search & Retrieval", docs: ["multi-source", "url-validation", "github-api"] }, { id: "data_visualization", name: "Data & Visualization", docs: ["knowledge-graphs", "typescript-safety"] }, { id: "academic_integration", name: "Academic Integration", docs: ["arxiv-papers", "semantic-search"] }, { id: "web_technologies", name: "Web Technologies", docs: ["react-query", "typescript-safety", "ai-security"] } ]; topics.forEach(topic => { nodes.push({ id: topic.id, label: topic.name, type: "topic", size: 10, color: NODE_COLORS.topic, metadata: { documentCount: topic.docs.length } }); // Link topics to documents topic.docs.forEach(docId => { if (documents.find(d => d.id === docId)) { links.push({ source: topic.id, target: docId, relationship: "related_to", strength: 0.6, color: RELATIONSHIP_COLORS.related_to }); } }); }); // Add similarity links between documents with shared concepts documents.forEach(doc1 => { documents.forEach(doc2 => { if (doc1.id !== doc2.id) { const sharedConcepts = doc1.concepts.filter(c => doc2.concepts.includes(c)); if (sharedConcepts.length >= 2) { links.push({ source: doc1.id, target: doc2.id, relationship: "similar_to", strength: sharedConcepts.length * 0.3, color: RELATIONSHIP_COLORS.similar_to }); } } }); }); // Add sample search queries for KnowledgeBridge const sampleQueries = [ { id: "query_semantic", text: "semantic search with embeddings", relatedDocs: ["semantic-search", "nebius-ai"] }, { id: "query_security", text: "AI application security middleware", relatedDocs: ["ai-security", "url-validation"] }, { id: "query_distributed", text: "distributed AI processing", relatedDocs: ["modal-compute", "nebius-ai"] } ]; sampleQueries.forEach(query => { nodes.push({ id: query.id, label: query.text, type: "query", size: 6, color: NODE_COLORS.query, metadata: { searchText: query.text } }); query.relatedDocs.forEach(docId => { links.push({ source: query.id, target: docId, relationship: "searched_for", strength: 0.4, color: RELATIONSHIP_COLORS.searched_for }); }); }); setGraphData({ nodes, links }); }; const handleNodeClick = (node: any) => { setSelectedNode(node); if (fgRef.current) { // Center the camera on the clicked node if (view3D) { fgRef.current.cameraPosition( { x: node.x, y: node.y, z: node.z + 100 }, node, 3000 ); } else { fgRef.current.centerAt(node.x, node.y, 1000); fgRef.current.zoom(2, 1000); } } }; const updateHighlight = () => { const currentData = filteredGraphData.nodes.length > 0 ? filteredGraphData : graphData; setHighlightNodes(highlightNodes); setHighlightLinks(highlightLinks); }; const handleNodeHover = (node: any) => { if (!node) { setHoveredNode(null); setHighlightNodes(new Set()); setHighlightLinks(new Set()); return; } setHoveredNode(node.id); const newHighlightNodes = new Set(); const newHighlightLinks = new Set(); newHighlightNodes.add(node.id); const currentData = filteredGraphData.nodes.length > 0 ? filteredGraphData : graphData; currentData.links.forEach(link => { const sourceId = typeof link.source === 'string' ? link.source : link.source.id; const targetId = typeof link.target === 'string' ? link.target : link.target.id; if (sourceId === node.id || targetId === node.id) { newHighlightLinks.add(`${sourceId}-${targetId}`); newHighlightNodes.add(sourceId); newHighlightNodes.add(targetId); } }); setHighlightNodes(newHighlightNodes); setHighlightLinks(newHighlightLinks); }; const resetView = () => { if (fgRef.current) { if (view3D) { fgRef.current.cameraPosition({ x: 0, y: 0, z: 300 }, { x: 0, y: 0, z: 0 }, 2000); } else { fgRef.current.zoomToFit(2000); } } setSelectedNode(null); }; const toggleAnimation = () => { setIsAnimating(!isAnimating); if (fgRef.current) { if (isAnimating) { fgRef.current.pauseAnimation(); } else { fgRef.current.resumeAnimation(); } } }; const getNodeLabel = (node: any) => { if (!showLabels) return ""; return node.label.length > 20 ? node.label.substring(0, 20) + "..." : node.label; }; const getNodeSize = (node: any) => { return node.size || 8; }; const getNodeColor = (node: any) => { if (hoveredNode === node.id) return "#ff6b6b"; // Red for hovered node if (highlightNodes.has(node.id)) return "#4ecdc4"; // Teal for connected nodes return node.color; // Original color }; const getLinkWidth = (link: any) => { const baseWidth = Math.max(0.5, link.strength * 3); const linkId = `${link.source}-${link.target}`; return highlightLinks.has(linkId) ? baseWidth * 2 : baseWidth; }; const getLinkColor = (link: any) => { const linkId = `${link.source}-${link.target}`; return highlightLinks.has(linkId) ? "#ff6b6b" : link.color; }; return (
{/* Header */}

KnowledgeBridge Knowledge Graph

Explore relationships between technologies, research sources, and concepts in KnowledgeBridge

{/* Controls Panel */} Graph Controls {/* Search Filter */}
setSearchTerm(e.target.value)} className="pl-8" />
{filteredGraphData.nodes.length > 0 && (
Showing {filteredGraphData.nodes.length} of {graphData.nodes.length} nodes
)}
{/* View Toggle */}
{/* Show Labels Toggle */}
{/* Link Distance */}
{linkDistance[0]}px
{/* Charge Strength */}
{chargeStrength[0]}
{/* Legend */}
{Object.entries(NODE_COLORS).map(([type, color]) => (
{type}
))}
{/* Graph Stats */}
Nodes: {graphData.nodes.length}
Links: {graphData.links.length}
{/* Graph Visualization */}
{isLoading && (

Building knowledge graph...

)} {view3D ? ( 0 ? filteredGraphData : graphData} nodeLabel={getNodeLabel} nodeColor={getNodeColor} nodeVal={getNodeSize} linkColor={getLinkColor} linkWidth={getLinkWidth} linkDirectionalParticles={2} linkDirectionalParticleSpeed={0.01} onNodeClick={handleNodeClick} onNodeHover={handleNodeHover} d3AlphaDecay={0.01} d3VelocityDecay={0.1} enableNodeDrag={true} enableNavigationControls={true} controlType="orbit" backgroundColor="rgba(0,0,0,0)" onEngineStop={() => { if (fgRef.current) { // Center the 3D graph with proper camera positioning setTimeout(() => { const distance = Math.max(400, graphData.nodes.length * 20); fgRef.current.cameraPosition({ x: 0, y: 0, z: distance }, { x: 0, y: 0, z: 0 }, 1500); }, 100); } }} /> ) : ( 0 ? filteredGraphData : graphData} nodeLabel={getNodeLabel} nodeColor={getNodeColor} nodeVal={getNodeSize} linkColor={getLinkColor} linkWidth={getLinkWidth} linkDirectionalParticles={1} linkDirectionalParticleSpeed={0.005} onNodeClick={handleNodeClick} onNodeHover={handleNodeHover} d3AlphaDecay={0.01} d3VelocityDecay={0.1} enableNodeDrag={true} enableZoomInteraction={true} backgroundColor="rgba(0,0,0,0)" linkDirectionalArrowLength={3} linkDirectionalArrowRelPos={1} onEngineStop={() => { if (fgRef.current) { // Center the graph with proper zoom setTimeout(() => { fgRef.current.zoomToFit(400, 80); }, 100); } }} /> )}
{/* Node Details Panel */} Node Details Click on a node to view details {selectedNode ? (
{selectedNode.type}

{selectedNode.label}

{selectedNode.metadata && (
{selectedNode.type === "document" && ( <> {selectedNode.metadata.year && (
Year: {selectedNode.metadata.year}
)} {selectedNode.metadata.authors && Array.isArray(selectedNode.metadata.authors) && (
Authors:
{selectedNode.metadata.authors.map((author: string) => ( {author} ))}
)} {selectedNode.metadata.venue && (
Venue: {selectedNode.metadata.venue}
)} {selectedNode.metadata.sourceType && (
Source Type: {selectedNode.metadata.sourceType}
)} {selectedNode.metadata.title && selectedNode.metadata.title !== selectedNode.label && (
Full Title:
{selectedNode.metadata.title}
)} )} {selectedNode.type === "concept" && (
Related Documents: {selectedNode.metadata.relatedDocuments}
)} {selectedNode.type === "author" && ( <> {selectedNode.metadata.teamName && (
Team: {selectedNode.metadata.teamName}
)} {selectedNode.metadata.publicationCount && (
Publications: {selectedNode.metadata.publicationCount}
)} {selectedNode.metadata.publications && (
Publications: {selectedNode.metadata.publications}
)} )} {selectedNode.type === "topic" && (
Documents: {selectedNode.metadata.documentCount}
)} {selectedNode.type === "query" && (
Search Text: {selectedNode.metadata.searchText}
)}
)} {/* Connected Nodes */}

Connected Nodes

{graphData.links .filter(link => { // Handle both string and object references for source/target const sourceId = typeof link.source === 'string' ? link.source : (link.source as GraphNode).id; const targetId = typeof link.target === 'string' ? link.target : (link.target as GraphNode).id; return sourceId === selectedNode.id || targetId === selectedNode.id; }) .map((link, idx) => { const sourceId = typeof link.source === 'string' ? link.source : (link.source as GraphNode).id; const targetId = typeof link.target === 'string' ? link.target : (link.target as GraphNode).id; const connectedNodeId = sourceId === selectedNode.id ? targetId : sourceId; const connectedNode = graphData.nodes.find(n => n.id === connectedNodeId); return connectedNode ? (
setSelectedNode(connectedNode)}>
{connectedNode.label}
{link.relationship?.replace(/_/g, ' ') || 'related'}
) : null; })} {graphData.links.filter(link => { const sourceId = typeof link.source === 'string' ? link.source : (link.source as GraphNode).id; const targetId = typeof link.target === 'string' ? link.target : (link.target as GraphNode).id; return sourceId === selectedNode.id || targetId === selectedNode.id; }).length === 0 && (
No connected nodes found
)}
) : (

Select a node to view its details and connections

)}
{/* Insights Panel */} Graph Insights
{stats.totalDocuments || graphData.nodes.filter(n => n.type === "document").length}
Knowledge Sources
{stats.totalConcepts || graphData.nodes.filter(n => n.type === "concept").length}
Technical Concepts
{stats.totalResearchTeams || graphData.nodes.filter(n => n.type === "author").length}
Technology Teams
{stats.totalSourceTypes || graphData.nodes.filter(n => n.type === "topic").length}
Technology Areas
); }