import React, { useState } from 'react'; import { Layers, Wand2, ArrowRight, Image as ImageIcon, Box, Cuboid } from 'lucide-react'; import { useMutation } from '@tanstack/react-query'; import { apiClient } from '../../utils/apiClient'; import { Card } from '../../components/ui/Card'; import { Button } from '../../components/ui/Button'; import { Badge } from '../../components/ui/Badge'; import { useTranslation } from 'react-i18next'; import '@google/model-viewer'; declare global { namespace JSX { interface IntrinsicElements { 'model-viewer': React.DetailedHTMLProps & { src?: string; alt?: string; 'auto-rotate'?: boolean; 'camera-controls'?: boolean; style?: React.CSSProperties; }, HTMLElement>; } } namespace React { namespace JSX { interface IntrinsicElements { 'model-viewer': React.DetailedHTMLProps & { src?: string; alt?: string; 'auto-rotate'?: boolean; 'camera-controls'?: boolean; style?: React.CSSProperties; }, HTMLElement>; } } } } interface SpatialResult { original?: string; depth_map?: string; status: string; } interface Model3DResult { status: string; task_id: string; mode: string; model_url: string; preview_video: string | null; polycount: string | number; format: string; } const SpatialLabPage: React.FC = () => { const { t } = useTranslation(); const [image, setImage] = useState(null); const [imageFile, setImageFile] = useState(null); const [depthResult, setDepthResult] = useState(null); const [modelResult, setModelResult] = useState(null); const depthMutation = useMutation({ mutationFn: async () => { if (!image && !imageFile) return; const formData = new FormData(); if (imageFile) formData.append('image_file', imageFile); else if (image) formData.append('image_url', image); return apiClient('/api/v1/spatial-lab/', { method: 'POST', body: formData, headers: {} }); }, onSuccess: (data) => { setDepthResult(data); } }); const model3dMutation = useMutation({ mutationFn: async () => { if (!image && !imageFile) return; const formData = new FormData(); if (imageFile) formData.append('image_file', imageFile); else if (image) formData.append('image_url', image); formData.append('mode', 'mesh'); // 'gaussian_splatting' is also supported if viewing via WebGL, but model-viewer uses GLB return apiClient('/api/v1/spatial-lab/generate-3d/', { method: 'POST', body: formData, headers: {} }); }, onSuccess: (data) => { setModelResult(data); } }); const handleUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setImageFile(file); setImage(URL.createObjectURL(file)); setDepthResult(null); setModelResult(null); } }; const isLoading = depthMutation.isPending || model3dMutation.isPending; return (

SPATIAL LAB

{/* Controls */}

Analyseur 3D

Reconstruisez la géométrie 3D à partir d'une image 2D grâce aux modèles monoculaires.

NEW: La "Génération Modèle 3D" utilise l'IA Gaussian Splatting pour créer un objet complet manipulable.

{/* Viewport */}
{isLoading && (
{model3dMutation.isPending ? "Génération 3D en cours (peut prendre ~15s)..." : "Analyse IA Profondeur..."}
)} {!image ? (
Aucune source chargée
) : (
{!modelResult && (
Original Original
)} {modelResult ? (
Modèle 3D Interactif ({modelResult.format})
) : (
Profondeur (IA) {depthResult ? ( Depth Map ) : (
)}
)}
)}
); }; export default SpatialLabPage;