Logo addition
This commit is contained in:
330
app/page.tsx
330
app/page.tsx
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { Camera, History, VideoOff, Settings, Video } from 'lucide-react';
|
||||
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
@@ -17,6 +18,9 @@ import type { DetectionResult, DetectionConfig } from '@/lib/ml/types';
|
||||
type CameraStatus = 'loading' | 'active' | 'denied' | 'no_devices';
|
||||
|
||||
export default function HomePage() {
|
||||
const searchParams = useSearchParams();
|
||||
const isDev = searchParams.get('dev') === 'true';
|
||||
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const [stream, setStream] = useState<MediaStream | null>(null);
|
||||
const [cameraStatus, setCameraStatus] = useState<CameraStatus>('loading');
|
||||
@@ -371,13 +375,82 @@ export default function HomePage() {
|
||||
<>
|
||||
<video ref={videoRef} autoPlay playsInline muted onCanPlay={() => videoRef.current?.play()} className="h-full w-full object-cover" />
|
||||
|
||||
|
||||
{/* Detection Counters */}
|
||||
<div className="absolute top-4 right-4 bg-black/60 backdrop-blur-sm rounded-lg px-3 py-2 text-white text-xs space-y-1">
|
||||
<div className="text-green-400">👟 Shoes Found: {shoeDetectionCount}</div>
|
||||
<div className="text-gray-400">🔄 Inference Runs: {metrics?.detectionCount || 0}</div>
|
||||
<div className="text-blue-400">⚡ Avg Speed: {metrics?.inferenceTime ? `${metrics.inferenceTime.toFixed(0)}ms` : 'N/A'}</div>
|
||||
{/* Impuls Logo - Top Left */}
|
||||
<div className="absolute top-3 left-6 z-10 pointer-events-none">
|
||||
<img
|
||||
src="/Impuls Logo.png"
|
||||
alt="Impuls Logo"
|
||||
className="h-12 w-auto opacity-80"
|
||||
style={{ filter: 'brightness(0) invert(1)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Simple Camera Frame Overlay - Like Reference Image */}
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
{/* Simple Corner Frames */}
|
||||
<div className="absolute inset-0">
|
||||
{/* Top Left Corner */}
|
||||
<div className="absolute w-8 h-8" style={{ top: '30%', left: '25%' }}>
|
||||
<div className="absolute top-0 left-0 w-6 h-0.5 bg-white opacity-80"></div>
|
||||
<div className="absolute top-0 left-0 w-0.5 h-6 bg-white opacity-80"></div>
|
||||
</div>
|
||||
|
||||
{/* Top Right Corner */}
|
||||
<div className="absolute w-8 h-8" style={{ top: '30%', right: '25%' }}>
|
||||
<div className="absolute top-0 right-0 w-6 h-0.5 bg-white opacity-80"></div>
|
||||
<div className="absolute top-0 right-0 w-0.5 h-6 bg-white opacity-80"></div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Left Corner */}
|
||||
<div className="absolute w-8 h-8" style={{ bottom: '45%', left: '25%' }}>
|
||||
<div className="absolute bottom-0 left-0 w-6 h-0.5 bg-white opacity-80"></div>
|
||||
<div className="absolute bottom-0 left-0 w-0.5 h-6 bg-white opacity-80"></div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Right Corner */}
|
||||
<div className="absolute w-8 h-8" style={{ bottom: '45%', right: '25%' }}>
|
||||
<div className="absolute bottom-0 right-0 w-6 h-0.5 bg-white opacity-80"></div>
|
||||
<div className="absolute bottom-0 right-0 w-0.5 h-6 bg-white opacity-80"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Center Rotating 3D Shoe Logo */}
|
||||
<div className="absolute w-16 h-16" style={{ top: '42.5%', left: '50%', transform: 'translate(-50%, -50%)' }}>
|
||||
{/* 3D Rotating Shoe Logo */}
|
||||
<div className="relative w-full h-full" style={{
|
||||
transformStyle: 'preserve-3d',
|
||||
animation: 'rotate3D 6s infinite linear'
|
||||
}}>
|
||||
{/* Shoe Logo Image */}
|
||||
<img
|
||||
src="/zapatillas.png"
|
||||
alt="Shoe Logo"
|
||||
className="absolute inset-0 w-full h-full object-contain opacity-60"
|
||||
style={{ filter: 'brightness(0) invert(1)' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 3D Animation Keyframes */}
|
||||
<style jsx>{`
|
||||
@keyframes rotate3D {
|
||||
0% { transform: rotateY(0deg) rotateX(0deg); }
|
||||
25% { transform: rotateY(90deg) rotateX(15deg); }
|
||||
50% { transform: rotateY(180deg) rotateX(0deg); }
|
||||
75% { transform: rotateY(270deg) rotateX(-15deg); }
|
||||
100% { transform: rotateY(360deg) rotateX(0deg); }
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
|
||||
{/* Detection Counters - Only show in dev mode */}
|
||||
{isDev && (
|
||||
<div className="absolute top-4 right-4 bg-black/60 backdrop-blur-sm rounded-lg px-3 py-2 text-white text-xs space-y-1">
|
||||
<div className="text-green-400">👟 Shoes Found: {shoeDetectionCount}</div>
|
||||
<div className="text-gray-400">🔄 Inference Runs: {metrics?.detectionCount || 0}</div>
|
||||
<div className="text-blue-400">⚡ Avg Speed: {metrics?.inferenceTime ? `${metrics.inferenceTime.toFixed(0)}ms` : 'N/A'}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Settings Panel */}
|
||||
<div className={`absolute left-0 top-0 bottom-0 w-80 bg-black/80 backdrop-blur-xl border-r border-white/20 transform transition-transform duration-500 ease-out z-40 ${
|
||||
@@ -422,139 +495,140 @@ export default function HomePage() {
|
||||
<div className="space-y-4 flex-1">
|
||||
|
||||
|
||||
{/* ML Detection Settings */}
|
||||
<div className="bg-white/5 rounded-lg p-4 border border-white/10">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Camera size={20} className="text-blue-400" />
|
||||
<span className="text-white font-medium">Detección IA</span>
|
||||
{isMLLoading && <span className="text-xs text-yellow-400">Cargando...</span>}
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
setDetectionEnabled(!detectionEnabled);
|
||||
if (!detectionEnabled) {
|
||||
console.log('Enabling ML detection');
|
||||
} else {
|
||||
console.log('Disabling ML detection');
|
||||
stopContinuous();
|
||||
}
|
||||
}}
|
||||
className={`text-sm py-2 px-4 rounded-md transition-colors border ${
|
||||
detectionEnabled
|
||||
? 'bg-green-500/20 text-green-300 border-green-500/30 hover:bg-green-500/30'
|
||||
: 'bg-white/10 text-white border-white/20 hover:bg-blue-500/30'
|
||||
}`}
|
||||
>
|
||||
{detectionEnabled ? 'Activado' : 'Activar'}
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
{detectionEnabled && (
|
||||
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||
)}
|
||||
<span className="text-white/60 text-sm">
|
||||
{detectionEnabled ? 'Detectando zapatos automáticamente' : 'Click para activar detección IA'}
|
||||
</span>
|
||||
</div>
|
||||
{/* ML Detection Settings - Only show in dev mode */}
|
||||
{isDev && (
|
||||
<div className="bg-white/5 rounded-lg p-4 border border-white/10">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Camera size={20} className="text-blue-400" />
|
||||
<span className="text-white font-medium">Detección IA</span>
|
||||
{isMLLoading && <span className="text-xs text-yellow-400">Cargando...</span>}
|
||||
</div>
|
||||
|
||||
{/* ML Metrics */}
|
||||
{detectionEnabled && metrics && (
|
||||
<div className="text-xs space-y-1 text-white/50 bg-black/20 p-2 rounded">
|
||||
<div>FPS: {metrics.fps.toFixed(1)}</div>
|
||||
<div>Inferencia: {metrics.inferenceTime.toFixed(0)}ms</div>
|
||||
{metrics.memoryUsage > 0 && <div>Memoria: {metrics.memoryUsage.toFixed(0)}MB</div>}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
setDetectionEnabled(!detectionEnabled);
|
||||
if (!detectionEnabled) {
|
||||
console.log('Enabling ML detection');
|
||||
} else {
|
||||
console.log('Disabling ML detection');
|
||||
stopContinuous();
|
||||
}
|
||||
}}
|
||||
className={`text-sm py-2 px-4 rounded-md transition-colors border ${
|
||||
detectionEnabled
|
||||
? 'bg-green-500/20 text-green-300 border-green-500/30 hover:bg-green-500/30'
|
||||
: 'bg-white/10 text-white border-white/20 hover:bg-blue-500/30'
|
||||
}`}
|
||||
>
|
||||
{detectionEnabled ? 'Activado' : 'Activar'}
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
{detectionEnabled && (
|
||||
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||
)}
|
||||
<span className="text-white/60 text-sm">
|
||||
{detectionEnabled ? 'Detectando zapatos automáticamente' : 'Click para activar detección IA'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ML Metrics */}
|
||||
{detectionEnabled && metrics && (
|
||||
<div className="text-xs space-y-1 text-white/50 bg-black/20 p-2 rounded">
|
||||
<div>FPS: {metrics.fps.toFixed(1)}</div>
|
||||
<div>Inferencia: {metrics.inferenceTime.toFixed(0)}ms</div>
|
||||
{metrics.memoryUsage > 0 && <div>Memoria: {metrics.memoryUsage.toFixed(0)}MB</div>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* Detection Confidence Indicator */}
|
||||
{detectionEnabled && currentDetection && (
|
||||
<div className="space-y-2 pt-2">
|
||||
<label className="text-sm font-medium text-white/80">Confianza de Detección</label>
|
||||
<div className="bg-white/10 rounded-lg p-3 border border-white/20">
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-xs text-white/60">Confianza</span>
|
||||
<span className="text-xs text-white font-bold">{(currentDetection.confidence * 100).toFixed(1)}%</span>
|
||||
{/* Detection Confidence Indicator */}
|
||||
{detectionEnabled && currentDetection && (
|
||||
<div className="space-y-2 pt-2">
|
||||
<label className="text-sm font-medium text-white/80">Confianza de Detección</label>
|
||||
<div className="bg-white/10 rounded-lg p-3 border border-white/20">
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-xs text-white/60">Confianza</span>
|
||||
<span className="text-xs text-white font-bold">{(currentDetection.confidence * 100).toFixed(1)}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-black/30 rounded-full h-2">
|
||||
<div
|
||||
className={`h-2 rounded-full transition-all duration-300 ${
|
||||
currentDetection.confidence > 0.8 ? 'bg-green-500' :
|
||||
currentDetection.confidence > 0.6 ? 'bg-yellow-500' : 'bg-red-500'
|
||||
}`}
|
||||
style={{ width: `${currentDetection.confidence * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-white/40 mt-1">
|
||||
<span>Bajo</span>
|
||||
<span>Alto</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full bg-black/30 rounded-full h-2">
|
||||
<div
|
||||
className={`h-2 rounded-full transition-all duration-300 ${
|
||||
currentDetection.confidence > 0.8 ? 'bg-green-500' :
|
||||
currentDetection.confidence > 0.6 ? 'bg-yellow-500' : 'bg-red-500'
|
||||
}`}
|
||||
style={{ width: `${currentDetection.confidence * 100}%` }}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Other settings */}
|
||||
{detectionEnabled && config && (
|
||||
<div className="space-y-4 pt-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-white/80">Sensibilidad ({(config.confidenceThreshold * 100).toFixed(0)}%)</label>
|
||||
<Slider
|
||||
min={0.3}
|
||||
max={0.9}
|
||||
step={0.05}
|
||||
value={[config.confidenceThreshold]}
|
||||
onValueChange={([value]) => updateConfig({ confidenceThreshold: value })}
|
||||
disabled={!detectionEnabled}
|
||||
className="mt-2"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-white/40 mt-1">
|
||||
<span>Bajo</span>
|
||||
<span>Alto</span>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-white/80">Frames a saltar ({config.frameSkip})</label>
|
||||
<Slider
|
||||
min={1}
|
||||
max={10}
|
||||
step={1}
|
||||
value={[config.frameSkip]}
|
||||
onValueChange={([value]) => updateConfig({ frameSkip: value })}
|
||||
disabled={!detectionEnabled}
|
||||
className="mt-2"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-white/80">Detección continua</label>
|
||||
<Switch
|
||||
checked={config.enableContinuous}
|
||||
onCheckedChange={(checked) => updateConfig({ enableContinuous: checked })}
|
||||
disabled={!detectionEnabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-white/80">Detección por trigger</label>
|
||||
<Switch
|
||||
checked={config.enableTrigger}
|
||||
onCheckedChange={(checked) => updateConfig({ enableTrigger: checked })}
|
||||
disabled={!detectionEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Other settings */}
|
||||
{detectionEnabled && config && (
|
||||
<div className="space-y-4 pt-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-white/80">Sensibilidad ({(config.confidenceThreshold * 100).toFixed(0)}%)</label>
|
||||
<Slider
|
||||
min={0.3}
|
||||
max={0.9}
|
||||
step={0.05}
|
||||
value={[config.confidenceThreshold]}
|
||||
onValueChange={([value]) => updateConfig({ confidenceThreshold: value })}
|
||||
disabled={!detectionEnabled}
|
||||
className="mt-2"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Detection Status */}
|
||||
{currentDetection && (
|
||||
<div className="text-xs bg-green-500/10 text-green-300 p-2 rounded border border-green-500/20">
|
||||
🎯 Zapato detectado (confianza: {(currentDetection.confidence * 100).toFixed(1)}%)
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-white/80">Frames a saltar ({config.frameSkip})</label>
|
||||
<Slider
|
||||
min={1}
|
||||
max={10}
|
||||
step={1}
|
||||
value={[config.frameSkip]}
|
||||
onValueChange={([value]) => updateConfig({ frameSkip: value })}
|
||||
disabled={!detectionEnabled}
|
||||
className="mt-2"
|
||||
/>
|
||||
)}
|
||||
|
||||
{mlError && (
|
||||
<div className="text-xs bg-red-500/10 text-red-300 p-2 rounded border border-red-500/20">
|
||||
❌ {mlError}
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-white/80">Detección continua</label>
|
||||
<Switch
|
||||
checked={config.enableContinuous}
|
||||
onCheckedChange={(checked) => updateConfig({ enableContinuous: checked })}
|
||||
disabled={!detectionEnabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-white/80">Detección por trigger</label>
|
||||
<Switch
|
||||
checked={config.enableTrigger}
|
||||
onCheckedChange={(checked) => updateConfig({ enableTrigger: checked })}
|
||||
disabled={!detectionEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Detection Status */}
|
||||
{currentDetection && (
|
||||
<div className="text-xs bg-green-500/10 text-green-300 p-2 rounded border border-green-500/20">
|
||||
🎯 Zapato detectado (confianza: {(currentDetection.confidence * 100).toFixed(1)}%)
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mlError && (
|
||||
<div className="text-xs bg-red-500/10 text-red-300 p-2 rounded border border-red-500/20">
|
||||
❌ {mlError}
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* App Info */}
|
||||
|
||||
@@ -44,14 +44,14 @@ export function getRecommendedConfig(capabilities: DeviceCapabilities): typeof D
|
||||
...baseConfig,
|
||||
modelVariant: 'standard',
|
||||
frameSkip: 6,
|
||||
confidenceThreshold: 0.6,
|
||||
confidenceThreshold: 0.8,
|
||||
};
|
||||
case 'mid':
|
||||
return {
|
||||
...baseConfig,
|
||||
modelVariant: 'standard',
|
||||
frameSkip: 6,
|
||||
confidenceThreshold: 0.5,
|
||||
confidenceThreshold: 0.8,
|
||||
};
|
||||
case 'low':
|
||||
default:
|
||||
@@ -59,7 +59,7 @@ export function getRecommendedConfig(capabilities: DeviceCapabilities): typeof D
|
||||
...baseConfig,
|
||||
modelVariant: 'quantized',
|
||||
frameSkip: 6,
|
||||
confidenceThreshold: 0.4,
|
||||
confidenceThreshold: 0.8,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export const MODEL_VARIANTS: Record<'quantized' | 'standard' | 'full', ModelInfo
|
||||
*/
|
||||
export const DEFAULT_CONFIG: DetectionConfig = {
|
||||
frameSkip: 6,
|
||||
confidenceThreshold: 0.3, // Match the working implementation (30%)
|
||||
confidenceThreshold: 0.8, // Default to 80% confidence
|
||||
modelVariant: 'standard',
|
||||
maxDetections: 5, // Match the working implementation (process up to 5 detections)
|
||||
inputSize: [300, 300], // Match the working implementation
|
||||
|
||||
BIN
public/Impuls Logo.png
Normal file
BIN
public/Impuls Logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
public/Impuls Logo_.png
Normal file
BIN
public/Impuls Logo_.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
public/zapatillas.png
Normal file
BIN
public/zapatillas.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Reference in New Issue
Block a user