import React, { useState, useEffect, useRef, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Camera, LayoutDashboard, Database, Image as ImageIcon, Crosshair, Settings, Play, BarChart2, Eye, GitBranch, Box, Upload, AlertCircle, Sparkles, Network, Target, Activity, Layout, Rocket, Download, Cpu, TrendingUp, Zap, Clock, Layers, Shield, Server, HardDrive, CheckCircle2, XCircle } from 'lucide-react'; import { useUserStore } from '@/store/userStore'; import { useCVStore } from '@/store/cvStore'; import { useToast } from '@/contexts/ToastContext'; import apiService, { api } from '@/services/api'; import { TrainingMode, CVTrainingConfig } from '@/types/cv'; // Components import CVDatasetUpload from '@/components/cv/CVDatasetUpload'; import CVDatasetGallery from '@/components/cv/CVDatasetGallery'; import CVTrainingConfigPanel from '@/components/cv/CVTrainingConfig'; import CVTrainingMonitor from '@/components/cv/CVTrainingMonitor'; import CVResultsDashboard from '@/components/cv/CVResultsDashboard'; import CVPredictionPanel from '@/components/cv/CVPredictionPanel'; import CVExperimentTracker from '@/components/cv/CVExperimentTracker'; import CVDeployPanel from '@/components/cv/CVDeployPanel'; import CVModelHub from '@/components/cv/CVModelHub'; const ComputerVision: React.FC = () => { const { isDark } = useUserStore(); const toast = useToast(); const { activeTab, setActiveTab, datasets, setDatasets, addDataset, activeDatasetId, setActiveDatasetId, activeJobId, setActiveJobId, trainingJobs, addTrainingJob, updateTrainingJob } = useCVStore(); const pollIntervalRef = useRef(null); // Theme classes const bg = isDark ? 'bg-[#0a0b10]' : 'bg-slate-50'; const bgCard = isDark ? 'bg-white/[0.03]' : 'bg-white'; const border = isDark ? 'border-white/[0.06]' : 'border-slate-200'; const textH = isDark ? 'text-white' : 'text-slate-900'; const textM = isDark ? 'text-slate-400' : 'text-slate-600'; const textS = isDark ? 'text-slate-500' : 'text-slate-500'; useEffect(() => { fetchDatasets(); }, []); useEffect(() => { let eventSource: EventSource | null = null; const activeJob = trainingJobs.find(j => j.id === activeJobId); if (activeJob && (activeJob.status === 'running' || activeJob.status === 'starting')) { eventSource = new EventSource(`${api.defaults.baseURL || ''}/api/v1/cv/train/${activeJobId}/progress`); eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.error) { eventSource?.close(); return; } if (activeJobId) { updateTrainingJob(activeJobId, { status: data.status, progress: data.progress, metrics: data.metrics, modelPath: data.model_path, completedAt: data.completed_at }); } if (['completed', 'failed', 'cancelled'].includes(data.status)) { eventSource?.close(); if (data.status === 'completed') { toast.success('Training completed!'); setActiveTab('results'); } else if (data.status === 'failed') { toast.error('Training failed.'); } } } catch(e) {} }; eventSource.onerror = () => { eventSource?.close(); }; } return () => { if (eventSource) eventSource.close(); }; }, [activeJobId]); const fetchDatasets = async () => { try { const res = await api.get('/api/v1/cv/datasets'); if (res.data.datasets) { setDatasets(res.data.datasets); if (res.data.datasets.length > 0 && !activeDatasetId) setActiveDatasetId(res.data.datasets[0].id); } } catch (e) { console.error("Failed to fetch datasets", e); } }; const [selectedTaskType, setSelectedTaskType] = useState(null); const handleDatasetUploadComplete = (dataset: any) => { addDataset(dataset); setActiveDatasetId(dataset.id); if (dataset.taskType) setSelectedTaskType(dataset.taskType); setActiveTab('vision_tasks'); }; const handleStartTraining = async (mode: TrainingMode, config: CVTrainingConfig, chosenTaskType?: string) => { if (!activeDatasetId) return; try { const activeDs = datasets.find(d => d.id === activeDatasetId); const taskType = chosenTaskType || selectedTaskType || activeDs?.taskType || 'classification'; const res = await api.post('/api/v1/cv/train', { dataset_id: activeDatasetId, mode, config, task_type: taskType }); if (res.data.success) { const jobId = res.data.job_id; addTrainingJob({ id: jobId, datasetId: activeDatasetId, userId: 'current', mode, config, status: 'starting', progress: { status: 'starting', epoch: 0, totalEpochs: config.epochs, loss: 0, valLoss: 0, metrics: {}, logs: [`Initializing ${mode.toUpperCase()} training job for task: ${taskType.toUpperCase()}...`], systemStats: { gpuUsage: 0, vramUsage: '0GB', cpuUsage: 0, ramUsage: '0GB' }, startedAt: new Date().toISOString() }, startedAt: new Date().toISOString() }); setActiveJobId(jobId); setActiveTab('live_training'); toast.success(`Started ${mode} training for ${taskType.replace(/_/g, ' ')}`); } } catch (e: any) { toast.error(e.response?.data?.detail || 'Failed to start training'); } }; const handleStopTraining = async () => { if (!activeJobId) return; try { await api.post(`/api/v1/cv/train/${activeJobId}/stop`); toast.success('Training stopped'); } catch (e) {} }; const handlePauseTraining = async () => { if (!activeJobId) return; try { await api.post(`/api/v1/cv/train/${activeJobId}/pause`); } catch (e) {} }; const handleResumeTraining = async () => { if (!activeJobId) return; try { await api.post(`/api/v1/cv/train/${activeJobId}/resume`); } catch (e) {} }; // Computed stats const completedJobs = trainingJobs.filter(j => j.status === 'completed'); const bestModel = useMemo(() => { if (completedJobs.length === 0) return null; return completedJobs.reduce((best, j) => (j.metrics?.mAP50 || 0) > (best.metrics?.mAP50 || 0) ? j : best, completedJobs[0]); }, [completedJobs]); const tabs = [ { id: 'overview', label: 'Overview', icon: LayoutDashboard }, { id: 'data', label: 'Dataset', icon: Database }, { id: 'vision_tasks', label: 'Vision Tasks', icon: Crosshair }, { id: 'training', label: 'Training', icon: Settings }, { id: 'live_training', label: 'Live Training', icon: Activity }, { id: 'results', label: 'Results', icon: BarChart2 }, { id: 'prediction', label: 'Prediction', icon: Eye }, { id: 'experiments', label: 'Experiments', icon: GitBranch }, { id: 'model_hub', label: 'Model Hub', icon: Layers }, { id: 'deploy', label: 'Deploy & Export', icon: Rocket }, ]; const activeJob = trainingJobs.find(j => j.id === activeJobId); return (
{/* Header */}

Computer Vision Studio

Zero-code, end-to-end vision AI pipelines

{activeDatasetId && (
{datasets.find(d => d.id === activeDatasetId)?.name || 'Unknown'}
)} {completedJobs.length > 0 && (
{completedJobs.length} trained
)}
{/* Navigation Tabs */}
{tabs.map((tab) => ( ))}
{/* ════════ OVERVIEW ════════ */} {activeTab === 'overview' && (
{/* Quick Stats Row */}
Datasets

{datasets.length}

{datasets.reduce((s, d) => s + d.numImages, 0)} total images

Models

{completedJobs.length}

{trainingJobs.filter(j => j.status === 'running').length} training now

Best mAP50

{bestModel ? `${((bestModel.metrics?.mAP50 || 0) * 100).toFixed(1)}%` : '—'}

{bestModel ? bestModel.config.model.toUpperCase() : 'No models yet'}

setActiveTab('data')}>

New Project

Upload Dataset

{/* Quick Actions */}
{[ { icon: Crosshair, title: 'Object Detection', desc: 'YOLOv8 · RT-DETR · YOLO-World', badge: 'Most Popular', onClick: () => setActiveTab('vision_tasks') }, { icon: ImageIcon, title: 'Image Classification', desc: 'ResNet · EfficientNet · ViT', badge: 'Fast Training', onClick: () => setActiveTab('vision_tasks') }, { icon: Network, title: 'Instance Segmentation', desc: 'YOLO-Seg · Mask R-CNN · SAM 2', badge: 'Pixel-Perfect', onClick: () => setActiveTab('vision_tasks') }, ].map((action, i) => ( ))}
{/* Recent Datasets */}

Recent Datasets

{datasets.length === 0 ? (
No datasets uploaded yet. Upload your first dataset to get started.
) : (
{datasets.slice(0, 6).map(d => (
{ setActiveDatasetId(d.id); setActiveTab('data'); }} className={`p-4 rounded-xl border cursor-pointer transition-all hover:border-emerald-500/40 hover:-translate-y-0.5 ${border} ${isDark ? 'hover:bg-white/[0.02]' : 'hover:bg-slate-50'} ${ activeDatasetId === d.id ? 'border-emerald-500/50 ring-1 ring-emerald-500/20' : '' }`}>
{d.name}
{d.numImages} imgs {d.numClasses} cls
))}
)}
{/* Recent Training Runs */} {trainingJobs.length > 0 && (

Training History

{trainingJobs.slice(0, 5).map(job => (
{job.config.model.toUpperCase()} {job.mode} · {job.progress.totalEpochs} epochs
{job.metrics?.mAP50 && ( mAP: {((job.metrics.mAP50) * 100).toFixed(1)}% )} {job.status}
))}
)}
)} {/* ════════ DATASET ════════ */} {activeTab === 'data' && (
)} {/* ════════ VISION TASKS ════════ */} {activeTab === 'vision_tasks' && (

Vision Tasks

Auto-detected from your dataset. Override if needed.

{[ { type: 'object_detection', icon: Crosshair, title: 'Object Detection', desc: 'Find and locate multiple objects using bounding boxes.', format: 'YOLO, COCO', models: 'YOLOv8, RT-DETR' }, { type: 'classification', icon: ImageIcon, title: 'Image Classification', desc: 'Categorize images into predefined classes.', format: 'Folder Structure', models: 'ResNet, EfficientNet' }, { type: ['semantic_segmentation', 'instance_segmentation'], icon: Network, title: 'Instance Segmentation', desc: 'Pixel-perfect masks for object boundaries.', format: 'YOLO, COCO', models: 'YOLO-Seg, Mask R-CNN' }, { type: 'pose_estimation', icon: Activity, title: 'Keypoint Detection', desc: 'Detect and track specific points on objects.', format: 'COCO Keypoints', models: 'YOLO-Pose, HRNet' }, { type: 'ocr', icon: Layout, title: 'OCR', desc: 'Extract text from images.', format: 'JSON/TXT', models: 'TrOCR, PaddleOCR' }, ].map((task, i) => { const currentTaskType = datasets.find(d => d.id === activeDatasetId)?.taskType; const isActive = Array.isArray(task.type) ? task.type.includes(currentTaskType || '') : currentTaskType === task.type; return (
{isActive &&
AUTO-DETECTED
}

{task.title}

{task.desc}

Format:{task.format}
Models:{task.models}
); })}
)} {/* ════════ TRAINING CONFIG ════════ */} {activeTab === 'training' && ( )} {/* ════════ LIVE TRAINING ════════ */} {activeTab === 'live_training' && ( activeJob ? ( ) : (

No Active Training

Start a training job to monitor it live.

) )} {/* ════════ RESULTS ════════ */} {activeTab === 'results' && ( activeJob?.status === 'completed' ? ( ) : (

No Results Yet

Complete a training job to view results.

) )} {/* ════════ PREDICTION ════════ */} {activeTab === 'prediction' && } {/* ════════ EXPERIMENTS ════════ */} {activeTab === 'experiments' && } {/* ════════ MODEL HUB ════════ */} {activeTab === 'model_hub' && } {/* ════════ DEPLOY & EXPORT ════════ */} {activeTab === 'deploy' && }
); }; export default ComputerVision;