# Core Framework
Flask==3.0.0
Flask-SocketIO==5.3.6
Flask-CORS==4.0.0
# Computer Vision & AI
opencv-python==4.9.0.80
mediapipe==0.10.9
tensorflow==2.15.0
torch==2.1.2
torchvision==0.16.2
insightface==0.7.3
ultralytics==8.0.224 # YOLOv8 latest
# Image Processing
Pillow==10.2.0
numpy==1.26.3
scipy==1.12.0
# Utilities
python-dotenv==1.0.0
requests==2.31.0
redis==5.0.1
psutil==5.9.7
# Development
pytest==7.4.4
black==23.12.1
flake8==7.0.0{
"dependencies": {
"next": "^15.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.3",
"@types/node": "^20.10.6",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
"tailwindcss": "^3.4.0",
"framer-motion": "^11.0.0",
"lucide-react": "^0.309.0",
"socket.io-client": "^4.7.4",
"zustand": "^4.4.7",
"jotai": "^2.6.2",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-switch": "^1.0.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"tailwind-merge": "^2.2.0",
"recharts": "^2.10.3",
"react-webcam": "^7.2.0",
"canvas-confetti": "^1.9.2"
},
"devDependencies": {
"@next/eslint-config-next": "^15.0.0",
"eslint": "^8.56.0",
"prettier": "^3.1.1",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32"
}
}# MediaPipe Face Detection (Google's latest)
import mediapipe as mp
class MediaPipeFaceDetector:
def __init__(self):
self.mp_face_detection = mp.solutions.face_detection
self.mp_drawing = mp.solutions.drawing_utils
self.face_detection = self.mp_face_detection.FaceDetection(
model_selection=1, # 0 for close-range, 1 for full-range
min_detection_confidence=0.7
)
def detect_faces(self, image):
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = self.face_detection.process(rgb_image)
return results.detections if results.detections else []
# Alternative: YOLOv8 Face Detection
from ultralytics import YOLO
class YOLOv8FaceDetector:
def __init__(self):
self.model = YOLO('yolov8n-face.pt') # Latest YOLOv8 face model
def detect_faces(self, image):
results = self.model(image)
return results[0].boxes if results[0].boxes is not None else []# InsightFace (2024 SOTA)
import insightface
class InsightFaceAnalyzer:
def __init__(self):
self.app = insightface.app.FaceAnalysis(
providers=['CUDAExecutionProvider', 'CPUExecutionProvider']
)
self.app.prepare(ctx_id=0, det_size=(640, 640))
def analyze_face(self, image):
faces = self.app.get(image)
results = []
for face in faces:
result = {
'age': face.age,
'gender': 'Male' if face.gender == 1 else 'Female',
'bbox': face.bbox.astype(int).tolist(),
'confidence': float(face.det_score),
'embedding': face.embedding
}
results.append(result)
return results# FER2013+ with Vision Transformer
import torch
import torch.nn as nn
from transformers import ViTForImageClassification, ViTImageProcessor
class ViTEmotionDetector:
def __init__(self):
self.processor = ViTImageProcessor.from_pretrained('trpakov/vit-face-expression')
self.model = ViTForImageClassification.from_pretrained('trpakov/vit-face-expression')
self.emotions = ['angry', 'disgust', 'fear', 'happy', 'neutral', 'sad', 'surprise']
def predict_emotion(self, face_image):
inputs = self.processor(images=face_image, return_tensors="pt")
with torch.no_grad():
outputs = self.model(**inputs)
predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
emotion_scores = {
emotion: float(score)
for emotion, score in zip(self.emotions, predictions[0])
}
return emotion_scoressrc/
├── app/
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Main camera page
│ ├── globals.css # Global styles
│ └── api/
│ └── socket/
│ └── route.ts # Socket.IO integration
├── components/
│ ├── ui/ # Shadcn/ui components
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── progress.tsx
│ │ └── slider.tsx
│ ├── camera/
│ │ ├── camera-feed.tsx # Main camera component
│ │ ├── face-overlay.tsx # Detection overlays
│ │ └── camera-controls.tsx # Camera settings
│ ├── analysis/
│ │ ├── age-display.tsx # Age visualization
│ │ ├── emotion-radar.tsx # Emotion radar chart
│ │ ├── confidence-meter.tsx # Confidence indicators
│ │ └── results-panel.tsx # Combined results
│ └── effects/
│ ├── particle-system.tsx # Background effects
│ ├── glow-effects.tsx # Futuristic glows
│ └── scan-lines.tsx # Sci-fi scan effects
├── hooks/
│ ├── use-camera.ts # Camera management
│ ├── use-websocket.ts # Real-time communication
│ ├── use-face-analysis.ts # Analysis state
│ └── use-performance.ts # Performance monitoring
├── lib/
│ ├── socket.ts # Socket.IO client
│ ├── utils.ts # Utility functions
│ ├── types.ts # TypeScript definitions
│ └── constants.ts # App constants
└── stores/
├── camera-store.ts # Camera state (Zustand)
├── analysis-store.ts # Analysis results
└── ui-store.ts # UI preferences
// Server Components with Suspense (Next.js 15)
import { Suspense } from 'react'
import { CameraFeed } from '@/components/camera/camera-feed'
import { LoadingSpinner } from '@/components/ui/loading-spinner'
export default function HomePage() {
return (
<main className="min-h-screen bg-gradient-to-br from-slate-950 to-slate-900">
<Suspense fallback={<LoadingSpinner />}>
<CameraFeed />
</Suspense>
</main>
)
}
// Modern Zustand Store with TypeScript
import { create } from 'zustand'
import { subscribeWithSelector } from 'zustand/middleware'
interface FaceAnalysis {
id: string
bbox: [number, number, number, number]
age: number
gender: 'Male' | 'Female'
emotions: Record<string, number>
confidence: number
timestamp: number
}
interface AnalysisStore {
faces: FaceAnalysis[]
isProcessing: boolean
performance: {
fps: number
latency: number
memoryUsage: number
}
updateFaces: (faces: FaceAnalysis[]) => void
setProcessing: (processing: boolean) => void
updatePerformance: (perf: Partial<AnalysisStore['performance']>) => void
}
export const useAnalysisStore = create<AnalysisStore>()(
subscribeWithSelector((set) => ({
faces: [],
isProcessing: false,
performance: { fps: 0, latency: 0, memoryUsage: 0 },
updateFaces: (faces) => set({ faces }),
setProcessing: (isProcessing) => set({ isProcessing }),
updatePerformance: (perf) =>
set((state) => ({
performance: { ...state.performance, ...perf }
}))
}))
)'use client'
import { motion, AnimatePresence } from 'framer-motion'
import { useAnalysisStore } from '@/stores/analysis-store'
import { cn } from '@/lib/utils'
export function FaceDetectionOverlay() {
const faces = useAnalysisStore((state) => state.faces)
return (
<div className="absolute inset-0 pointer-events-none">
<AnimatePresence>
{faces.map((face) => (
<motion.div
key={face.id}
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0, opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className={cn(
"absolute border-2 border-cyan-400",
"shadow-[0_0_20px_rgba(34,211,238,0.5)]",
"before:absolute before:inset-0",
"before:border-2 before:border-cyan-400/30",
"before:animate-pulse"
)}
style={{
left: face.bbox[0],
top: face.bbox[1],
width: face.bbox[2] - face.bbox[0],
height: face.bbox[3] - face.bbox[1],
}}
>
{/* Corner indicators */}
<div className="absolute -top-1 -left-1 w-4 h-4 border-l-2 border-t-2 border-cyan-400" />
<div className="absolute -top-1 -right-1 w-4 h-4 border-r-2 border-t-2 border-cyan-400" />
<div className="absolute -bottom-1 -left-1 w-4 h-4 border-l-2 border-b-2 border-cyan-400" />
<div className="absolute -bottom-1 -right-1 w-4 h-4 border-r-2 border-b-2 border-cyan-400" />
{/* Scanning line effect */}
<motion.div
className="absolute inset-x-0 h-0.5 bg-gradient-to-r from-transparent via-cyan-400 to-transparent"
animate={{ y: [0, face.bbox[3] - face.bbox[1]] }}
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
/>
</motion.div>
))}
</AnimatePresence>
</div>
)
}import { Radar, RadarChart, PolarGrid, PolarAngleAxis, ResponsiveContainer } from 'recharts'
import { motion } from 'framer-motion'
interface EmotionRadarProps {
emotions: Record<string, number>
}
export function EmotionRadar({ emotions }: EmotionRadarProps) {
const data = Object.entries(emotions).map(([emotion, value]) => ({
emotion: emotion.charAt(0).toUpperCase() + emotion.slice(1),
value: Math.round(value * 100)
}))
return (
<motion.div
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ type: "spring", stiffness: 200 }}
className="w-full h-64"
>
<ResponsiveContainer width="100%" height="100%">
<RadarChart data={data}>
<PolarGrid
stroke="#334155"
strokeWidth={1}
className="opacity-50"
/>
<PolarAngleAxis
dataKey="emotion"
tick={{ fill: '#e2e8f0', fontSize: 12 }}
/>
<Radar
name="Emotions"
dataKey="value"
stroke="#00d4ff"
fill="#00d4ff"
fillOpacity={0.2}
strokeWidth={2}
dot={{ fill: '#00d4ff', strokeWidth: 2, r: 4 }}
/>
</RadarChart>
</ResponsiveContainer>
</motion.div>
)
}# Async Flask with modern patterns
from flask import Flask
from flask_socketio import SocketIO
import asyncio
import cv2
from concurrent.futures import ThreadPoolExecutor
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')
class OptimizedVideoProcessor:
def __init__(self):
self.executor = ThreadPoolExecutor(max_workers=4)
self.frame_queue = asyncio.Queue(maxsize=10)
self.result_cache = {}
async def process_frame_async(self, frame):
# Use thread pool for CPU-intensive CV operations
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
self.executor,
self._process_frame_sync,
frame
)
return result
def _process_frame_sync(self, frame):
# Optimized processing pipeline
# 1. Resize for speed
small_frame = cv2.resize(frame, (640, 480))
# 2. Face detection with caching
frame_hash = hash(small_frame.tobytes())
if frame_hash in self.result_cache:
return self.result_cache[frame_hash]
# 3. Process and cache result
result = self.analyze_faces(small_frame)
self.result_cache[frame_hash] = result
# 4. Limit cache size
if len(self.result_cache) > 100:
oldest_key = next(iter(self.result_cache))
del self.result_cache[oldest_key]
return result// React 18 Concurrent Features
import { useDeferredValue, useTransition, startTransition } from 'react'
import { useAnalysisStore } from '@/stores/analysis-store'
export function OptimizedCameraFeed() {
const [isPending, startTransition] = useTransition()
const faces = useAnalysisStore((state) => state.faces)
const deferredFaces = useDeferredValue(faces)
const handleNewFrame = useCallback((frameData: string) => {
startTransition(() => {
// Non-urgent updates won't block the UI
updateAnalysis(frameData)
})
}, [])
return (
<div className="relative">
<video
ref={videoRef}
className="w-full h-auto"
style={{ opacity: isPending ? 0.7 : 1 }}
/>
<FaceDetectionOverlay faces={deferredFaces} />
</div>
)
}
// Web Workers for heavy computations
// workers/image-processor.ts
self.onmessage = function(e) {
const { imageData, type } = e.data
switch (type) {
case 'preprocess':
const processed = preprocessImage(imageData)
self.postMessage({ type: 'preprocessed', data: processed })
break
case 'analyze':
const analysis = analyzeImage(imageData)
self.postMessage({ type: 'analyzed', data: analysis })
break
}
}This implementation plan uses all the latest technologies and follows modern best practices for building a high-performance, engaging facial analysis platform perfect for your robotics club event!