import React, { useState } from 'react' import { Card, CardContent, 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 { MemoryTreeView } from '@/components/MemoryTreeView' import { MemoryNetworkGraph } from '@/components/MemoryNetworkGraph' import { MemoryClusterView } from '@/components/MemoryClusterView' import { Memory, MemoryCategory } from '@/types' import { TreePine, Network, Layers, BarChart3, Eye, Filter, Download, Share, Settings, RefreshCw, Info } from 'lucide-react' interface MemoryVisualizationDashboardProps { memories: Memory[] onMemorySelect?: (memory: Memory) => void extractTitle?: (content: string, memory?: Memory) => string extractTags?: (memory: Memory) => string[] extractSummary?: (content: string, memory?: Memory) => string className?: string } interface VisualizationMetrics { totalMemories: number totalConnections: number categories: number avgConnectionsPerMemory: number mostConnectedMemory: Memory | null largestCluster: number memoryDistribution: Record } export function MemoryVisualizationDashboard({ memories, onMemorySelect, extractTitle = (content: string) => content.substring(0, 50) + '...', extractTags = (memory: Memory) => memory.tags || [], extractSummary = (content: string) => content.substring(0, 100) + '...', className = '' }: MemoryVisualizationDashboardProps) { const [activeTab, setActiveTab] = useState('overview') const [selectedMemory, setSelectedMemory] = useState(null) const [showMetrics, setShowMetrics] = useState(true) const [filterCategory, setFilterCategory] = useState('all') // Calculate visualization metrics const metrics: VisualizationMetrics = React.useMemo(() => { const connections = new Map() let totalConnections = 0 memories.forEach(memory => { const memoryTags = extractTags(memory) let memoryConnections = 0 // Count direct relationships if (memory.metadata?.related_memories && Array.isArray(memory.metadata.related_memories)) { memoryConnections += memory.metadata.related_memories.length totalConnections += memory.metadata.related_memories.length } // Count tag-based connections if (memoryTags.length > 0) { memories.forEach(otherMemory => { if (otherMemory.id === memory.id) return const otherTags = extractTags(otherMemory) const sharedTags = memoryTags.filter(tag => otherTags.includes(tag)) if (sharedTags.length > 0) { memoryConnections += 0.5 // Half weight for tag connections } }) } connections.set(memory.id, memoryConnections) }) const mostConnected = Array.from(connections.entries()) .sort(([,a], [,b]) => b - a)[0] const memoryDistribution = memories.reduce((acc, memory) => { const category = memory.category || 'personal' acc[category] = (acc[category] || 0) + 1 return acc }, {} as Record) return { totalMemories: memories.length, totalConnections: Math.round(totalConnections), categories: new Set(memories.map(m => m.category || 'personal')).size, avgConnectionsPerMemory: memories.length > 0 ? Math.round((Array.from(connections.values()).reduce((a, b) => a + b, 0) / memories.length) * 10) / 10 : 0, mostConnectedMemory: mostConnected ? memories.find(m => m.id === mostConnected[0]) || null : null, largestCluster: Math.max(...Object.values(memoryDistribution), 0), memoryDistribution } }, [memories, extractTags]) // Filter memories based on category const filteredMemories = React.useMemo(() => { if (filterCategory === 'all') return memories return memories.filter(memory => memory.category === filterCategory) }, [memories, filterCategory]) const handleMemorySelect = (memory: Memory) => { setSelectedMemory(memory) onMemorySelect?.(memory) } const exportVisualization = () => { const data = { timestamp: new Date().toISOString(), metrics, memories: filteredMemories.length, filters: { category: filterCategory } } const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `memory-visualization-${new Date().toISOString().split('T')[0]}.json` a.click() URL.revokeObjectURL(url) } const getCategoryColor = (category: MemoryCategory): string => { const colors: Record = { personal: '#3B82F6', work: '#10B981', code: '#8B5CF6', research: '#F59E0B', conversations: '#EF4444', preferences: '#6B7280' } return colors[category] || '#9CA3AF' } return (
{/* Header */}

Memory Visualization

Explore connections and patterns in your memory collection

{/* Metrics Overview */} {showMetrics && (
{metrics.totalMemories}
Total Memories
{metrics.totalConnections}
Connections
{metrics.categories}
Categories
{metrics.avgConnectionsPerMemory}
Avg Connections
{metrics.largestCluster}
Largest Group
{filteredMemories.length !== memories.length ? filteredMemories.length : 'All'}
Filtered
)} {/* Category Distribution */} {showMetrics && Object.keys(metrics.memoryDistribution).length > 1 && ( Memory Distribution by Category
{Object.entries(metrics.memoryDistribution) .sort(([,a], [,b]) => b - a) .map(([category, count]) => { const percentage = Math.round((count / metrics.totalMemories) * 100) return (
{category} {count} ({percentage}%)
) })}
)} {/* Visualization Tabs */} Overview Tree View Network Clusters Memory Collection Overview

Key Insights

Most connected memory: {metrics.mostConnectedMemory ? extractTitle(metrics.mostConnectedMemory.content, metrics.mostConnectedMemory) : 'None' }
Network density: {metrics.totalMemories > 1 ? Math.round((metrics.totalConnections / (metrics.totalMemories * (metrics.totalMemories - 1) / 2)) * 100) : 0 }%
Most common category: {Object.entries(metrics.memoryDistribution) .sort(([,a], [,b]) => b - a)[0]?.[0] || 'None' }

Recommendations

{metrics.avgConnectionsPerMemory < 1 && (
💡 Consider adding more tags to increase memory connections
)} {metrics.categories < 3 && (
📂 Try categorizing memories for better organization
)} {metrics.totalMemories > 50 && metrics.totalConnections < 10 && (
🔗 Use related_memories field to create explicit connections
)}
{/* Recent Activity */} Recent Memories
{memories .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) .slice(0, 5) .map(memory => (
handleMemorySelect(memory)} >
{extractTitle(memory.content, memory)}
{new Date(memory.timestamp).toLocaleDateString()} • {memory.category || 'personal'}
{extractTags(memory).length > 0 && ( {extractTags(memory).length} tags )}
))}
{/* Selected Memory Details */} {selectedMemory && ( Selected Memory

{extractTitle(selectedMemory.content, selectedMemory)}

{extractSummary(selectedMemory.content, selectedMemory)}

Category: {selectedMemory.category || 'personal'}
Created: {new Date(selectedMemory.timestamp).toLocaleDateString()}
Size: {selectedMemory.content.length} characters
Project: {selectedMemory.project || 'None'}
{extractTags(selectedMemory).length > 0 && (
Tags:
{extractTags(selectedMemory).map(tag => ( #{tag} ))}
)}
)}
) }