UNPKG

ruvector-extensions

Version:

Advanced features for ruvector: embeddings, UI, exports, temporal tracking, and persistence

147 lines (118 loc) • 5.2 kB
import { VectorDB } from 'ruvector'; import { startUIServer } from '../ui-server.js'; /** * Example: Interactive Graph Explorer UI * * This example demonstrates how to launch the interactive web UI * for exploring vector embeddings as a force-directed graph. */ async function main() { console.log('šŸš€ Starting RuVector Graph Explorer Example\n'); // Initialize database const db = new VectorDB({ dimension: 384, distanceMetric: 'cosine' }); console.log('šŸ“Š Populating database with sample data...\n'); // Create sample embeddings with different categories const categories = ['research', 'code', 'documentation', 'test']; const sampleData = []; for (let i = 0; i < 50; i++) { const category = categories[i % categories.length]; // Generate random embedding with some structure const baseVector = Array.from({ length: 384 }, () => Math.random() - 0.5); // Add category-specific bias to make similar items cluster const categoryBias = i % categories.length; for (let j = 0; j < 96; j++) { baseVector[j + categoryBias * 96] += 0.5; } // Normalize vector const magnitude = Math.sqrt(baseVector.reduce((sum, val) => sum + val * val, 0)); const embedding = baseVector.map(val => val / magnitude); const id = `node-${i.toString().padStart(3, '0')}`; const metadata = { label: `${category} ${i}`, category, timestamp: Date.now() - Math.random() * 86400000 * 30, importance: Math.random(), tags: [category, `tag-${Math.floor(Math.random() * 5)}`] }; sampleData.push({ id, embedding, metadata }); } // Add all vectors to database for (const { id, embedding, metadata } of sampleData) { await db.add(id, embedding, metadata); } console.log(`āœ… Added ${sampleData.length} sample nodes\n`); // Get database statistics const stats = await db.getStats(); console.log('šŸ“ˆ Database Statistics:'); console.log(` Total vectors: ${stats.totalVectors}`); console.log(` Dimension: ${stats.dimension}`); console.log(` Distance metric: ${stats.distanceMetric}\n`); // Start UI server console.log('🌐 Starting UI server...\n'); const port = parseInt(process.env.PORT || '3000'); const server = await startUIServer(db, port); console.log('✨ UI Features:'); console.log(' • Interactive force-directed graph visualization'); console.log(' • Drag nodes to reposition'); console.log(' • Zoom and pan with mouse/touch'); console.log(' • Search nodes by ID or metadata'); console.log(' • Click nodes to view metadata'); console.log(' • Double-click or use "Find Similar" to highlight similar nodes'); console.log(' • Export graph as PNG or SVG'); console.log(' • Real-time updates via WebSocket'); console.log(' • Responsive design for mobile devices\n'); console.log('šŸ’” Try these actions:'); console.log(' 1. Search for "research" to filter nodes'); console.log(' 2. Click any node to see its metadata'); console.log(' 3. Click "Find Similar Nodes" to discover connections'); console.log(' 4. Adjust the similarity threshold slider'); console.log(' 5. Export the visualization as PNG or SVG\n'); // Demonstrate adding nodes in real-time console.log('šŸ”„ Adding nodes in real-time (every 10 seconds)...\n'); let counter = 50; const interval = setInterval(async () => { const category = categories[counter % categories.length]; const baseVector = Array.from({ length: 384 }, () => Math.random() - 0.5); const categoryBias = counter % categories.length; for (let j = 0; j < 96; j++) { baseVector[j + categoryBias * 96] += 0.5; } const magnitude = Math.sqrt(baseVector.reduce((sum, val) => sum + val * val, 0)); const embedding = baseVector.map(val => val / magnitude); const id = `node-${counter.toString().padStart(3, '0')}`; const metadata = { label: `${category} ${counter}`, category, timestamp: Date.now(), importance: Math.random(), tags: [category, `tag-${Math.floor(Math.random() * 5)}`] }; await db.add(id, embedding, metadata); // Notify UI of update server.notifyGraphUpdate(); console.log(`āœ… Added new node: ${id} (${category})`); counter++; // Stop after adding 10 more nodes if (counter >= 60) { clearInterval(interval); console.log('\n✨ Real-time updates complete!\n'); } }, 10000); // Handle graceful shutdown process.on('SIGINT', async () => { console.log('\n\nšŸ›‘ Shutting down gracefully...'); clearInterval(interval); await server.stop(); await db.close(); console.log('šŸ‘‹ Goodbye!\n'); process.exit(0); }); } // Run example main().catch(error => { console.error('āŒ Error:', error); process.exit(1); });