import React, { useState } from 'react'; import { Download, Box, Server, Smartphone, Cpu, CheckCircle2, Loader2, Code2, Terminal, Copy, Check, ShieldCheck, Zap, FileCode } from 'lucide-react'; import { useUserStore } from '@/store/userStore'; import { useCVStore } from '@/store/cvStore'; import { api } from '@/services/api'; import { useToast } from '@/contexts/ToastContext'; const CVDeployPanel: React.FC = () => { const { isDark } = useUserStore(); const toast = useToast(); const { activeJobId, trainingJobs } = useCVStore(); const [selectedFormats, setSelectedFormats] = useState(['pytorch', 'onnx']); const [isExporting, setIsExporting] = useState(false); const [exportResult, setExportResult] = useState(null); const [copiedCode, setCopiedCode] = useState(false); const activeJob = trainingJobs.find(j => j.id === activeJobId); const exportOptions = [ { id: 'pytorch', name: 'PyTorch (.pt)', icon: Box, desc: 'Original weights, best for Python.' }, { id: 'onnx', name: 'ONNX', icon: Cpu, desc: 'Universal format for C++/C#/Python.' }, { id: 'fastapi', name: 'FastAPI Server (app.py)', icon: Server, desc: 'Ready-to-deploy REST API server.' }, { id: 'docker', name: 'Docker Container', icon: Box, desc: 'Dockerfile & container setup.' }, { id: 'tensorrt', name: 'TensorRT', icon: Zap, desc: 'NVIDIA GPU optimized engine.' }, { id: 'tflite', name: 'TFLite', icon: Smartphone, desc: 'Android / iOS mobile format.' } ]; const toggleFormat = (id: string) => { setSelectedFormats(prev => prev.includes(id) ? prev.filter(f => f !== id) : [...prev, id] ); }; const handleExport = async () => { if (!activeJobId) return; setIsExporting(true); setExportResult(null); try { const res = await api.post(`/api/v1/cv/models/${activeJobId}/export`, { formats: selectedFormats }); if (res.data.success) { setExportResult(res.data); toast.success('Export ZIP package generated successfully!'); } else { toast.error(res.data.error || 'Export failed'); } } catch (err: any) { toast.error(err.response?.data?.detail || 'API Error'); } finally { setIsExporting(false); } }; const handleDownload = async () => { const jobId = activeJobId || (trainingJobs.length > 0 ? trainingJobs[0].id : null); if (!jobId) { toast.error('No trained model available to download. Please train a model first.'); return; } setIsExporting(true); try { // 1. Auto-generate export package await api.post(`/api/v1/cv/models/${jobId}/export`, { formats: selectedFormats }); // 2. Download generated ZIP file const res = await api.get(`/api/v1/cv/export/${jobId}/download`, { responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([res.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `datavision_cv_model_${jobId}.zip`); document.body.appendChild(link); link.click(); link.parentNode?.removeChild(link); toast.success('Model ZIP package downloaded successfully!'); } catch (err: any) { toast.error(err.response?.data?.detail || 'Download failed. Please try again.'); } finally { setIsExporting(false); } }; const pyCodeSnippet = `import cv2 from ultralytics import YOLO # Load the trained model weights model = YOLO('models/best.pt') # Run inference on any image def predict(image_path): results = model(image_path) for r in results: # Print predictions if hasattr(r, 'probs') and r.probs is not None: top1_id = int(r.probs.top1) print(f"Prediction: {r.names[top1_id]} ({float(r.probs.top1conf)*100:.1f}%)") else: for box in r.boxes: print(f"Detected: {r.names[int(box.cls[0])]} ({float(box.conf[0]):.2f})") if __name__ == '__main__': predict('test_image.jpg')`; const copyCode = () => { navigator.clipboard.writeText(pyCodeSnippet); setCopiedCode(true); toast.success('Python code copied!'); setTimeout(() => setCopiedCode(false), 2000); }; if (!activeJobId || !activeJob || activeJob.status !== 'completed') { return (

No Model Available

You need to complete a training job first before you can export model code & weights.

); } return (
{/* Export Formats Selector */}

Model Export & Package Generator

Select output formats to package into a standalone, runnable ZIP bundle.

{exportOptions.map((opt) => { const isSelected = selectedFormats.includes(opt.id); return (
toggleFormat(opt.id)} className={`p-4 rounded-xl border cursor-pointer transition-all flex flex-col gap-2 ${ isSelected ? 'border-emerald-500 bg-emerald-500/10 shadow-sm' : 'hover:border-emerald-500/50' }`} style={{ borderColor: isSelected ? '' : 'var(--border-color)' }} >
{isSelected && }
{opt.name}
{opt.desc}
); })}
{/* Python Runnable Code Snippet */}

Runnable Inference Code (inference.py)

            {pyCodeSnippet}
          

Package Download Manifest

{!exportResult ? (

Click "Generate Model ZIP Package" to prepare downloadable code & model

) : (

Model ZIP Ready

{exportResult.filename} ({exportResult.size_mb?.toFixed(2)} MB)

ZIP Package Includes:

  • Trained Model Checkpoint Weights (`models/best.pt`)
  • {selectedFormats.map(fmt => (
  • {exportOptions.find(o => o.id === fmt)?.name} exported format
  • ))}
  • Python Inference Script (`inference.py`)
  • FastAPI REST Server (`app.py`)
  • `requirements.txt` & `README.md` Setup Instructions
)}
); }; export default CVDeployPanel;