import React, { useState, useEffect } from 'react'; import { Search, Filter, Download, Star, Clock, Target, Cpu, HardDrive, ShieldCheck, Trash2 } from 'lucide-react'; import { useUserStore } from '@/store/userStore'; import apiService, { api } from '@/services/api'; import { useToast } from '@/contexts/ToastContext'; const CVModelHub: React.FC = () => { const { isDark } = useUserStore(); const toast = useToast(); const [searchTerm, setSearchTerm] = useState(''); const [activeTab, setActiveTab] = useState('my_models'); const [models, setModels] = useState([]); const [isLoading, setIsLoading] = useState(false); useEffect(() => { fetchModels(); }, []); const fetchModels = async () => { setIsLoading(true); try { const res = await api.get('/api/v1/cv/models'); if (res.data.models) { setModels(res.data.models); } } catch (e) { // Mock models fallback setModels([ { id: 'm1', name: 'YOLOv8s Helmet Detection', task: 'object_detection', mAP50: 0.942, size_mb: 22.5, tag: 'Trained', completed_at: '2026-07-27' }, { id: 'm2', name: 'ResNet50 Brain Tumor Classifier', task: 'classification', mAP50: 0.985, size_mb: 98.1, tag: 'High Acc', completed_at: '2026-07-26' } ]); } finally { setIsLoading(false); } }; const handleDownloadModel = async (modelId: string) => { try { await api.post(`/api/v1/cv/models/${modelId}/export`, { formats: ['pytorch', 'onnx'] }); const res = await api.get(`/api/v1/cv/export/${modelId}/download`, { responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([res.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `model_${modelId}.zip`); document.body.appendChild(link); link.click(); link.parentNode?.removeChild(link); toast.success('Model downloaded successfully!'); } catch (e: any) { toast.error('Failed to download model.'); } }; const handleDeleteModel = (modelId: string) => { if (window.confirm('Are you sure you want to delete this trained model?')) { setModels(prev => prev.filter(m => m.id !== modelId)); toast.success('Model deleted from hub.'); } }; const tabs = [ { id: 'my_models', label: 'My Models' }, { id: 'community', label: 'Community' }, { id: 'pretrained', label: 'Pre-trained SOTA' } ]; const pretrainedModels = [ { name: 'YOLOv11x', task: 'Object Detection', mAP50: 0.985, size_mb: 180, isVerified: true, downloads: '1.2M', tag: 'SOTA' }, { name: 'SAM 2 (Large)', task: 'Zero-Shot Segmentation', mAP50: 0.99, size_mb: 350, isVerified: true, downloads: '850K', tag: 'Meta AI' }, { name: 'Florence-2', task: 'Vision-Language', mAP50: 0.96, size_mb: 420, isVerified: true, downloads: '500K', tag: 'Microsoft' }, { name: 'YOLO-World', task: 'Open-Vocabulary Detection', mAP50: 0.94, size_mb: 220, isVerified: true, downloads: '410K', tag: 'Real-time' }, { name: 'RT-DETR', task: 'Object Detection', mAP50: 0.95, size_mb: 140, isVerified: true, downloads: '320K', tag: 'Transformer' } ]; const communityModels = [ { name: 'Medical Mask Detect', task: 'Object Detection', mAP50: 0.89, size_mb: 45, author: 'Dr. Jane Smith', downloads: '12K' }, { name: 'Retail Shelf Scanner', task: 'Object Detection', mAP50: 0.91, size_mb: 60, author: 'RetailCorp', downloads: '8K' }, { name: 'Plant Disease Seg', task: 'Segmentation', mAP50: 0.85, size_mb: 110, author: 'AgriTech Labs', downloads: '5K' }, ]; const displayModels = activeTab === 'my_models' ? models : activeTab === 'community' ? communityModels : pretrainedModels; return (
{/* Header Actions */}
setSearchTerm(e.target.value)} className="w-full pl-10 pr-4 py-2.5 rounded-xl border focus:ring-2 focus:ring-emerald-500/50 outline-none transition-all" style={{ backgroundColor: 'var(--bg-card)', borderColor: 'var(--border-color)', color: 'var(--text-primary)' }} />
{tabs.map((tab) => ( ))}
{/* Model Grid */}
{displayModels.length === 0 && !isLoading ? (
No models found.
) : ( displayModels.map((model, i) => (
{model.tag && (
{model.tag}
)}

{model.name || model.config?.model?.toUpperCase() || 'Unknown Model'} {model.isVerified && }

{model.job_id ? model.job_id.substring(0, 8) : model.author || 'Official'} {model.downloads && • {model.downloads} dl}
{model.task || model.config?.task || 'object_detection'}
mAP50 Score
{((model.metrics?.mAP50 || model.mAP50 || 0) * 100).toFixed(1)}%
Model Size
{model.metrics?.modelSizeMB || model.size_mb || '?'} MB
{new Date(model.completed_at || Date.now()).toLocaleDateString()} 4.9
)) )}
); }; export default CVModelHub;