|
|
|
import React, { useState, useEffect } from 'react'; |
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; |
|
import { Button } from '@/components/ui/button'; |
|
import { Badge } from '@/components/ui/badge'; |
|
import { Progress } from '@/components/ui/progress'; |
|
import { |
|
Search, |
|
Database, |
|
Brain, |
|
ArrowRight, |
|
FileText, |
|
Zap, |
|
GitBranch, |
|
Target, |
|
Layers, |
|
RotateCcw |
|
} from 'lucide-react'; |
|
|
|
interface FlowStep { |
|
id: string; |
|
title: string; |
|
description: string; |
|
icon: React.ReactNode; |
|
details: string[]; |
|
tech: string[]; |
|
active: boolean; |
|
completed: boolean; |
|
} |
|
|
|
const SystemFlowDiagram: React.FC = () => { |
|
const [currentStep, setCurrentStep] = useState(0); |
|
const [isPlaying, setIsPlaying] = useState(false); |
|
const [progress, setProgress] = useState(0); |
|
const [userQuery, setUserQuery] = useState("How does semantic search work?"); |
|
|
|
|
|
const generateEmbedding = (text: string) => { |
|
const seed = text.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); |
|
const random = (s: number) => { |
|
const x = Math.sin(s) * 10000; |
|
return x - Math.floor(x); |
|
}; |
|
|
|
return Array.from({length: 8}, (_, i) => |
|
Number((random(seed + i) * 2 - 1).toFixed(3)) |
|
); |
|
}; |
|
|
|
const flowSteps: FlowStep[] = [ |
|
{ |
|
id: 'input', |
|
title: '1. Document Upload / Query Input', |
|
description: 'Upload documents or enter search query', |
|
icon: <Search className="w-6 h-6" />, |
|
details: [ |
|
'Upload PDFs, images, text files with drag-and-drop', |
|
'OCR processing via Modal for images and PDFs', |
|
`Search query: "${userQuery}"`, |
|
'Real-time file validation and error handling' |
|
], |
|
tech: ['Modal OCR', 'Multer Upload', 'File Validation', 'React'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'processing', |
|
title: '2. Document Processing', |
|
description: 'Extract text and generate embeddings', |
|
icon: <FileText className="w-6 h-6" />, |
|
details: [ |
|
'Modal serverless functions for heavy processing', |
|
'PyPDF2 for PDF text extraction', |
|
'Tesseract OCR for images', |
|
'Nebius AI embedding generation (BAAI/bge-en-icl)', |
|
'SQLite storage with metadata tracking' |
|
], |
|
tech: ['Modal', 'PyPDF2', 'Tesseract', 'Nebius AI', 'SQLite'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'indexing', |
|
title: '3. Vector Index Building', |
|
description: 'Build FAISS vector index for semantic search', |
|
icon: <Database className="w-6 h-6" />, |
|
details: [ |
|
'FAISS IndexFlatIP for cosine similarity', |
|
'Sentence Transformers (all-MiniLM-L6-v2)', |
|
'Modal distributed computing for large datasets', |
|
'Persistent storage with fallback paths', |
|
'Batch processing optimization' |
|
], |
|
tech: ['FAISS', 'Modal', 'SentenceTransformers', 'Vector Storage'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'enhancement', |
|
title: '4. AI Query Enhancement', |
|
description: 'Enhance query with AI (optional)', |
|
icon: <Brain className="w-6 h-6" />, |
|
details: [ |
|
`Nebius AI analyzes "${userQuery}"`, |
|
'DeepSeek-R1-0528 model provides query improvements', |
|
'Suggests keywords and alternative phrasings', |
|
'Intent detection and query expansion' |
|
], |
|
tech: ['Nebius AI', 'DeepSeek-R1-0528', 'Query Analysis'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'search', |
|
title: '5. Hybrid Multi-Source Search', |
|
description: 'Search across vector index and external sources', |
|
icon: <Layers className="w-6 h-6" />, |
|
details: [ |
|
'Vector similarity search in uploaded documents', |
|
'Parallel search across GitHub, Wikipedia, ArXiv', |
|
'Smart query routing based on content type', |
|
'Relevance scoring and result ranking' |
|
], |
|
tech: ['Vector Search', 'GitHub API', 'Wikipedia API', 'ArXiv API'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'validation', |
|
title: '6. URL Validation & Filtering', |
|
description: 'Validate and verify result URLs', |
|
icon: <Target className="w-6 h-6" />, |
|
details: [ |
|
'Smart URL validation with ArXiv format checking', |
|
'Content verification to detect error pages', |
|
'Concurrent processing with rate limits', |
|
'Trusted domain fast-path for reliable sources' |
|
], |
|
tech: ['URL Validation', 'Content Verification', 'Rate Limiting'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'analysis', |
|
title: '7. AI-Powered Analysis', |
|
description: 'Generate insights and explanations', |
|
icon: <Brain className="w-6 h-6" />, |
|
details: [ |
|
'Nebius DeepSeek-R1 analyzes document content', |
|
'Research synthesis across multiple sources', |
|
'Audio-friendly explanations generation', |
|
'Knowledge graph relationship mapping' |
|
], |
|
tech: ['Nebius AI', 'DeepSeek-R1', 'Research Synthesis'], |
|
active: false, |
|
completed: false |
|
}, |
|
{ |
|
id: 'display', |
|
title: '8. Results & Visualization', |
|
description: 'Present results with interactive features', |
|
icon: <Zap className="w-6 h-6" />, |
|
details: [ |
|
'Interactive knowledge graph visualization', |
|
'Relevance-scored result cards with snippets', |
|
'Citation tracking and source attribution', |
|
'Real-time AI explanations and insights' |
|
], |
|
tech: ['D3.js', 'React', 'Knowledge Graph', 'UI Components'], |
|
active: false, |
|
completed: false |
|
} |
|
]; |
|
|
|
const [steps, setSteps] = useState(flowSteps); |
|
|
|
useEffect(() => { |
|
if (isPlaying) { |
|
const interval = setInterval(() => { |
|
setCurrentStep((prev) => { |
|
if (prev < steps.length - 1) { |
|
return prev + 1; |
|
} else { |
|
setIsPlaying(false); |
|
return prev; |
|
} |
|
}); |
|
}, 2000); |
|
|
|
return () => clearInterval(interval); |
|
} |
|
}, [isPlaying, steps.length]); |
|
|
|
useEffect(() => { |
|
setSteps(prevSteps => |
|
prevSteps.map((step, index) => ({ |
|
...step, |
|
active: index === currentStep, |
|
completed: index < currentStep |
|
})) |
|
); |
|
setProgress(((currentStep + 1) / steps.length) * 100); |
|
}, [currentStep, steps.length]); |
|
|
|
const resetAnimation = () => { |
|
setCurrentStep(0); |
|
setIsPlaying(false); |
|
setProgress(0); |
|
}; |
|
|
|
const playAnimation = () => { |
|
if (currentStep === steps.length - 1) { |
|
resetAnimation(); |
|
} |
|
setIsPlaying(true); |
|
}; |
|
|
|
return ( |
|
<div className="w-full max-w-7xl mx-auto p-6 space-y-6"> |
|
{/* Header */} |
|
<div className="text-center space-y-4"> |
|
<h2 className="text-3xl font-bold text-gray-900 dark:text-gray-100"> |
|
KnowledgeBridge System Flow |
|
</h2> |
|
<p className="text-lg text-gray-600 dark:text-gray-400"> |
|
How your query becomes intelligent multi-source research with AI enhancement |
|
</p> |
|
|
|
{/* Query Input */} |
|
<div className="max-w-md mx-auto mb-6"> |
|
<label htmlFor="demo-query" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> |
|
Demo Query: |
|
</label> |
|
<input |
|
id="demo-query" |
|
type="text" |
|
value={userQuery} |
|
onChange={(e) => setUserQuery(e.target.value)} |
|
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white" |
|
placeholder="Enter your query to see the process" |
|
/> |
|
</div> |
|
|
|
{/* Controls */} |
|
<div className="flex justify-center gap-4"> |
|
<Button |
|
onClick={playAnimation} |
|
disabled={isPlaying} |
|
className="flex items-center gap-2" |
|
> |
|
{isPlaying ? <RotateCcw className="w-4 h-4 animate-spin" /> : <Zap className="w-4 h-4" />} |
|
{isPlaying ? 'Processing...' : 'Process Query'} |
|
</Button> |
|
<Button |
|
variant="outline" |
|
onClick={resetAnimation} |
|
className="flex items-center gap-2" |
|
> |
|
<RotateCcw className="w-4 h-4" /> |
|
Reset |
|
</Button> |
|
</div> |
|
|
|
{/* Progress Bar */} |
|
<div className="w-full max-w-md mx-auto"> |
|
<Progress value={progress} className="h-2" /> |
|
<p className="text-sm text-gray-500 mt-2"> |
|
Step {currentStep + 1} of {steps.length} |
|
</p> |
|
</div> |
|
</div> |
|
|
|
{/* Flow Diagram */} |
|
<div className="grid grid-cols-1 lg:grid-cols-7 gap-4"> |
|
{steps.map((step, index) => ( |
|
<div key={step.id} className="relative"> |
|
{/* Connection Arrow */} |
|
{index < steps.length - 1 && ( |
|
<div className="hidden lg:flex absolute top-1/2 -right-2 transform -translate-y-1/2 z-10"> |
|
<ArrowRight className={`w-4 h-4 ${ |
|
step.completed ? 'text-green-500' : 'text-gray-300' |
|
}`} /> |
|
</div> |
|
)} |
|
|
|
{/* Step Card */} |
|
<Card className={` |
|
transition-all duration-500 cursor-pointer |
|
${step.active ? 'ring-2 ring-blue-500 shadow-lg scale-105' : ''} |
|
${step.completed ? 'bg-green-50 dark:bg-green-900/20' : ''} |
|
${!step.active && !step.completed ? 'opacity-60' : ''} |
|
`} |
|
onClick={() => setCurrentStep(index)} |
|
> |
|
<CardHeader className="pb-2"> |
|
<div className="flex items-center justify-between"> |
|
<div className={` |
|
p-2 rounded-full transition-colors |
|
${step.active ? 'bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400' : |
|
step.completed ? 'bg-green-100 text-green-600 dark:bg-green-900 dark:text-green-400' : |
|
'bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-600'} |
|
`}> |
|
{step.icon} |
|
</div> |
|
{step.completed && ( |
|
<div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center"> |
|
<svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20"> |
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" /> |
|
</svg> |
|
</div> |
|
)} |
|
</div> |
|
<CardTitle className="text-sm font-semibold"> |
|
{step.title} |
|
</CardTitle> |
|
</CardHeader> |
|
<CardContent className="space-y-3"> |
|
<p className="text-xs text-gray-600 dark:text-gray-400"> |
|
{step.description} |
|
</p> |
|
|
|
{/* Technology Tags */} |
|
<div className="flex flex-wrap gap-1"> |
|
{step.tech.map((tech) => ( |
|
<Badge key={tech} variant="secondary" className="text-xs"> |
|
{tech} |
|
</Badge> |
|
))} |
|
</div> |
|
|
|
{/* Details (shown when active) */} |
|
{step.active && ( |
|
<div className="space-y-2 animate-in slide-in-from-top-2 duration-300"> |
|
<h4 className="text-xs font-semibold text-gray-700 dark:text-gray-300"> |
|
Process Details: |
|
</h4> |
|
<ul className="text-xs text-gray-600 dark:text-gray-400 space-y-1"> |
|
{step.details.map((detail, i) => ( |
|
<li key={i} className="flex items-start gap-1"> |
|
<span className="text-blue-500 mt-1">β’</span> |
|
<span>{detail}</span> |
|
</li> |
|
))} |
|
</ul> |
|
|
|
{/* Special visualization for embeddings step */} |
|
{step.id === 'embeddings' && ( |
|
<div className="mt-3 p-2 bg-gray-100 dark:bg-gray-800 rounded text-xs"> |
|
<div className="font-mono text-purple-600 dark:text-purple-400"> |
|
Vector: [{generateEmbedding(userQuery).slice(0, 4).join(', ')}, ...] |
|
</div> |
|
<div className="text-gray-500 mt-1"> |
|
Dimensions: 1536 | Magnitude: {Math.sqrt(generateEmbedding(userQuery).reduce((sum, val) => sum + val * val, 0)).toFixed(3)} |
|
</div> |
|
</div> |
|
)} |
|
|
|
{/* Special visualization for validation step */} |
|
{step.id === 'validation' && ( |
|
<div className="mt-3 space-y-1"> |
|
{[ |
|
{ doc: 'github.com/research/ai', status: 'valid' }, |
|
{ doc: 'arxiv.org/abs/2024.12345', status: 'verified' }, |
|
{ doc: 'invalid-url.broken', status: 'filtered' } |
|
].map((result, i) => ( |
|
<div key={i} className="flex justify-between items-center p-1 bg-gray-100 dark:bg-gray-800 rounded text-xs"> |
|
<span className="truncate">{result.doc}</span> |
|
<span className={`font-mono ${result.status === 'filtered' ? 'text-red-600' : 'text-green-600'}`}>{result.status}</span> |
|
</div> |
|
))} |
|
</div> |
|
)} |
|
</div> |
|
)} |
|
</CardContent> |
|
</Card> |
|
</div> |
|
))} |
|
</div> |
|
|
|
{/* Live Embedding Demo */} |
|
<div className="bg-gradient-to-r from-blue-50 to-purple-50 dark:from-blue-900/20 dark:to-purple-900/20 rounded-xl p-6 mt-8"> |
|
<h3 className="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2"> |
|
<Brain className="w-5 h-5 text-purple-600" /> |
|
Live Embedding Calculator |
|
</h3> |
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> |
|
{/* Text to Vector */} |
|
<div className="space-y-3"> |
|
<h4 className="font-semibold text-gray-700 dark:text-gray-300">Text β Vector Conversion</h4> |
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-4 space-y-3"> |
|
<div> |
|
<label className="text-sm text-gray-600 dark:text-gray-400 block mb-2">Input:</label> |
|
<input |
|
type="text" |
|
value={userQuery} |
|
onChange={(e) => setUserQuery(e.target.value)} |
|
className="w-full font-mono text-sm bg-gray-100 dark:bg-gray-700 p-2 rounded border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-purple-500 dark:text-gray-100" |
|
placeholder="Enter text to generate embeddings..." |
|
/> |
|
</div> |
|
<div> |
|
<span className="text-sm text-gray-600 dark:text-gray-400">Embedding (first 8 dims):</span> |
|
<div className="font-mono text-xs bg-purple-100 dark:bg-purple-900/50 p-2 rounded overflow-x-auto"> |
|
[{generateEmbedding(userQuery).join(', ')}] |
|
</div> |
|
</div> |
|
<div className="text-xs text-gray-500"> |
|
Vector magnitude: {Math.sqrt(generateEmbedding(userQuery).reduce((sum, val) => sum + val * val, 0)).toFixed(3)} |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{/* Similarity Calculations */} |
|
<div className="space-y-3"> |
|
<h4 className="font-semibold text-gray-700 dark:text-gray-300">Similarity Scores</h4> |
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-4 space-y-2"> |
|
{[ |
|
{ doc: 'AI Research Paper', vector: [0.2, 0.8, -0.1, 0.5, 0.3, -0.4, 0.7, 0.1] }, |
|
{ doc: 'GitHub Repository', vector: [0.1, 0.6, 0.2, -0.3, 0.8, 0.4, -0.2, 0.5] }, |
|
{ doc: 'Wikipedia Article', vector: [-0.3, 0.4, 0.7, 0.2, -0.1, 0.6, 0.3, -0.5] } |
|
].map((doc, i) => { |
|
const queryVec = generateEmbedding(userQuery); |
|
const dotProduct = queryVec.reduce((sum, val, idx) => sum + val * doc.vector[idx], 0); |
|
const queryMag = Math.sqrt(queryVec.reduce((sum, val) => sum + val * val, 0)); |
|
const docMag = Math.sqrt(doc.vector.reduce((sum, val) => sum + val * val, 0)); |
|
const similarity = dotProduct / (queryMag * docMag); |
|
|
|
return ( |
|
<div key={i} className="flex justify-between items-center p-2 bg-gray-50 dark:bg-gray-700 rounded"> |
|
<span className="text-sm">{doc.doc}</span> |
|
<div className="flex items-center gap-2"> |
|
<div className={`w-16 h-2 rounded-full ${similarity > 0.3 ? 'bg-green-400' : similarity > 0.1 ? 'bg-yellow-400' : 'bg-gray-300'}`} |
|
style={{width: `${Math.max(20, Math.abs(similarity) * 60)}px`}}></div> |
|
<span className="font-mono text-xs w-12 text-right">{similarity.toFixed(2)}</span> |
|
</div> |
|
</div> |
|
); |
|
})} |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{/* Key Concepts */} |
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8"> |
|
<Card> |
|
<CardHeader> |
|
<CardTitle className="flex items-center gap-2 text-lg"> |
|
<Brain className="w-5 h-5 text-purple-600" /> |
|
Embeddings |
|
</CardTitle> |
|
</CardHeader> |
|
<CardContent className="space-y-2"> |
|
<p className="text-sm text-gray-600 dark:text-gray-400"> |
|
Nebius BAAI/bge-en-icl generates semantic vectors. Similar concepts have similar vector values. |
|
</p> |
|
<div className="bg-gray-100 dark:bg-gray-800 p-2 rounded text-xs font-mono"> |
|
"AI research" β [0.1, 0.3, 0.8, ...]<br/> |
|
"machine learning" β [0.2, 0.4, 0.7, ...] |
|
</div> |
|
</CardContent> |
|
</Card> |
|
|
|
<Card> |
|
<CardHeader> |
|
<CardTitle className="flex items-center gap-2 text-lg"> |
|
<Database className="w-5 h-5 text-blue-600" /> |
|
Vector Search |
|
</CardTitle> |
|
</CardHeader> |
|
<CardContent className="space-y-2"> |
|
<p className="text-sm text-gray-600 dark:text-gray-400"> |
|
Multi-source search across GitHub, ArXiv, Wikipedia with smart URL validation. |
|
</p> |
|
<div className="bg-gray-100 dark:bg-gray-800 p-2 rounded text-xs"> |
|
GitHub API: repositories + code<br/> |
|
ArXiv API: academic papers<br/> |
|
Wikipedia: authoritative content |
|
</div> |
|
</CardContent> |
|
</Card> |
|
|
|
<Card> |
|
<CardHeader> |
|
<CardTitle className="flex items-center gap-2 text-lg"> |
|
<GitBranch className="w-5 h-5 text-green-600" /> |
|
AI Pipeline |
|
</CardTitle> |
|
</CardHeader> |
|
<CardContent className="space-y-2"> |
|
<p className="text-sm text-gray-600 dark:text-gray-400"> |
|
KnowledgeBridge combines multi-source search with Nebius AI for intelligent research synthesis. |
|
</p> |
|
<div className="bg-gray-100 dark:bg-gray-800 p-2 rounded text-xs"> |
|
Query β Enhance β Search β Validate β Analyze |
|
</div> |
|
</CardContent> |
|
</Card> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
export default SystemFlowDiagram; |
|
|