zka-detection-full / webapp /test_simple.html
root16285
Add complete FastAPI Docker app (model downloaded at build)
7d6df10
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🧪 Test YOLOv5 - Détection Simple</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
</head>
<body class="bg-gray-100 p-8">
<div class="max-w-4xl mx-auto">
<div class="bg-white rounded-lg shadow-lg p-6">
<h1 class="text-3xl font-bold mb-4 text-center text-blue-600">
<i class="fas fa-vial mr-2"></i> Test YOLOv5 - Détection Simple
</h1>
<div class="mb-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
<p class="text-sm font-medium text-yellow-800">
<i class="fas fa-info-circle mr-2"></i>
<strong>Important :</strong> YOLOv5 détecte uniquement des objets physiques (personnes, voitures, animaux, objets du quotidien).
</p>
<p class="text-xs text-yellow-700 mt-2">
❌ Ne fonctionne PAS avec : documents, texte, visages spécifiques<br>
✅ Fonctionne avec : personnes, véhicules, animaux, téléphones, ordinateurs, etc.
</p>
</div>
<!-- Upload d'image -->
<div class="mb-6">
<label class="block text-gray-700 font-medium mb-2">
<i class="fas fa-upload mr-2"></i> Sélectionnez une image :
</label>
<input type="file" id="imageInput" accept="image/*"
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
</div>
<!-- Réglages -->
<div class="grid grid-cols-2 gap-4 mb-6">
<div>
<label class="block text-gray-700 text-sm font-medium mb-2">Modèle :</label>
<select id="modelSelect" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="yolov5n">YOLOv5n (très rapide)</option>
<option value="yolov5s" selected>YOLOv5s (rapide)</option>
<option value="yolov5m">YOLOv5m (moyen)</option>
<option value="yolov5l">YOLOv5l (précis)</option>
</select>
</div>
<div>
<label class="block text-gray-700 text-sm font-medium mb-2">
Confiance : <span id="confidenceValue">0.25</span>
</label>
<input type="range" id="confidenceSlider" min="0.1" max="0.9" step="0.05" value="0.25"
class="w-full">
</div>
</div>
<!-- Bouton d'analyse -->
<button id="detectBtn"
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed">
<i class="fas fa-search mr-2"></i> Détecter les objets
</button>
<!-- Résultats -->
<div id="results" class="mt-6 hidden">
<h2 class="text-xl font-bold mb-4 text-gray-800">
<i class="fas fa-chart-bar mr-2"></i> Résultats :
</h2>
<div id="resultContent"></div>
</div>
</div>
<!-- Guide rapide -->
<div class="mt-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
<h3 class="font-bold text-blue-800 mb-2">
<i class="fas fa-lightbulb mr-2"></i> Testez avec ces objets :
</h3>
<div class="grid grid-cols-2 gap-2 text-sm text-blue-700">
<div>✅ Photo de vous-même</div>
<div>✅ Photo de voiture</div>
<div>✅ Votre téléphone</div>
<div>✅ Une bouteille/tasse</div>
<div>✅ Un animal (chat/chien)</div>
<div>✅ Un ordinateur portable</div>
</div>
</div>
</div>
<script>
const imageInput = document.getElementById('imageInput');
const detectBtn = document.getElementById('detectBtn');
const modelSelect = document.getElementById('modelSelect');
const confidenceSlider = document.getElementById('confidenceSlider');
const confidenceValue = document.getElementById('confidenceValue');
const results = document.getElementById('results');
const resultContent = document.getElementById('resultContent');
let selectedFile = null;
// Mise à jour de l'affichage de la confiance
confidenceSlider.addEventListener('input', (e) => {
confidenceValue.textContent = e.target.value;
});
// Sélection de fichier
imageInput.addEventListener('change', (e) => {
selectedFile = e.target.files[0];
detectBtn.disabled = !selectedFile;
});
// Détection
detectBtn.addEventListener('click', async () => {
if (!selectedFile) return;
detectBtn.disabled = true;
detectBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Analyse en cours...';
const formData = new FormData();
formData.append('files', selectedFile);
const model = modelSelect.value;
const confidence = confidenceSlider.value;
try {
const response = await fetch(`http://localhost:8001/detect/batch?model=${model}&confidence=${confidence}`, {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status}`);
}
const data = await response.json();
displayResults(data);
} catch (error) {
console.error('Erreur:', error);
resultContent.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
<p class="text-red-800 font-medium">
<i class="fas fa-exclamation-circle mr-2"></i> Erreur de connexion
</p>
<p class="text-sm text-red-600 mt-2">
${error.message}<br>
Vérifiez que le serveur est bien lancé sur http://localhost:8001
</p>
</div>
`;
results.classList.remove('hidden');
} finally {
detectBtn.disabled = false;
detectBtn.innerHTML = '<i class="fas fa-search mr-2"></i> Détecter les objets';
}
});
function displayResults(data) {
if (!data.results || data.results.length === 0) {
resultContent.innerHTML = `
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
<p class="text-gray-800">Aucun résultat reçu</p>
</div>
`;
results.classList.remove('hidden');
return;
}
const result = data.results[0];
const hasDetections = result.detections && result.detections.length > 0;
let html = '';
// Affichage de l'image
html += `
<div class="mb-4">
<img src="data:image/jpeg;base64,${result.image_base64}"
class="w-full rounded-lg shadow-md"
alt="Image analysée">
</div>
`;
if (hasDetections) {
// Objets détectés
html += `
<div class="bg-green-50 border border-green-200 rounded-lg p-4 mb-4">
<p class="text-green-800 font-bold text-lg mb-2">
<i class="fas fa-check-circle mr-2"></i>
${result.detections.length} objet(s) détecté(s) !
</p>
</div>
<div class="space-y-2">
`;
result.detections.forEach((det, idx) => {
html += `
<div class="flex items-center justify-between p-3 bg-white border border-gray-200 rounded-lg hover:shadow-md transition-shadow">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center text-blue-600 font-bold">
${idx + 1}
</div>
<div>
<p class="font-bold text-gray-800">${det.class}</p>
<p class="text-xs text-gray-500">Position: (${det.bbox.join(', ')})</p>
</div>
</div>
<div class="text-right">
<div class="text-2xl font-bold text-blue-600">${(det.confidence * 100).toFixed(1)}%</div>
<div class="text-xs text-gray-500">confiance</div>
</div>
</div>
`;
});
html += `</div>`;
} else {
// Aucun objet détecté
html += `
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6 text-center">
<i class="fas fa-exclamation-triangle text-5xl text-yellow-500 mb-3"></i>
<p class="text-yellow-800 font-bold text-lg mb-2">Aucun objet détecté</p>
<p class="text-sm text-yellow-700 mb-3">
YOLOv5 ne détecte que 80 types d'objets physiques spécifiques
</p>
<div class="bg-white rounded-lg p-4 text-left">
<p class="font-semibold text-gray-800 mb-2">
<i class="fas fa-question-circle mr-2"></i> Pourquoi aucune détection ?
</p>
<ul class="text-sm text-gray-700 space-y-1 ml-5">
<li>❌ Image de document ou texte</li>
<li>❌ Objets trop petits ou flous</li>
<li>❌ Mauvais éclairage</li>
<li>❌ Objets non inclus dans les 80 classes COCO</li>
</ul>
<div class="mt-3 pt-3 border-t border-gray-200">
<p class="font-semibold text-gray-800 mb-1">
<i class="fas fa-lightbulb mr-2"></i> Essayez avec :
</p>
<p class="text-sm text-gray-600">
Une photo de <strong>personne, voiture, téléphone, ordinateur, bouteille, animal</strong>
</p>
</div>
</div>
<div class="mt-4">
<p class="text-xs text-yellow-600">
💡 Conseil : Baissez le seuil de confiance à 0.15 pour détecter plus d'objets
</p>
</div>
</div>
`;
}
// Statistiques
html += `
<div class="mt-4 grid grid-cols-3 gap-2 text-center">
<div class="bg-gray-50 rounded-lg p-2">
<p class="text-xs text-gray-600">Modèle</p>
<p class="text-sm font-bold text-gray-800">${modelSelect.value}</p>
</div>
<div class="bg-gray-50 rounded-lg p-2">
<p class="text-xs text-gray-600">Confiance min.</p>
<p class="text-sm font-bold text-gray-800">${(confidence * 100).toFixed(0)}%</p>
</div>
<div class="bg-gray-50 rounded-lg p-2">
<p class="text-xs text-gray-600">Temps</p>
<p class="text-sm font-bold text-gray-800">${result.processing_time.toFixed(2)}s</p>
</div>
</div>
`;
resultContent.innerHTML = html;
results.classList.remove('hidden');
}
</script>
</body>
</html>