MicroMicro / templates /index.html
AliSakr9997's picture
Create templates/index.html
0930008 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MicroMind Vision Sentinel</title>
<style>
body { font-family: sans-serif; background: #111; color: white; text-align: center; }
#container { position: relative; display: inline-block; margin-top: 20px; }
video { border: 2px solid #333; border-radius: 8px; }
canvas { position: absolute; top: 0; left: 0; pointer-events: none; }
#status { margin: 10px; font-weight: bold; color: #0f0; }
#config { color: #888; font-size: 0.9em; }
</style>
</head>
<body>
<h1>👁️ MicroMind Vision Sentinel</h1>
<div id="status">System Status: CONNECTING...</div>
<div id="config">Target: Unknown | Conf: 0.0</div>
<div id="container">
<video id="video" width="640" height="480" autoplay playsinline></video>
<canvas id="canvas" width="640" height="480"></canvas>
</div>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const statusEl = document.getElementById('status');
const configEl = document.getElementById('config');
// 1. Start Webcam
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => { video.srcObject = stream; })
.catch(err => { console.error("Camera Error:", err); statusEl.innerText = "CAMERA ERROR"; statusEl.style.color = "red"; });
// 2. Processing Loop
setInterval(() => {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
// Draw video frame to hidden canvas to convert to blob
const tempCanvas = document.createElement('canvas');
tempCanvas.width = video.videoWidth;
tempCanvas.height = video.videoHeight;
tempCanvas.getContext('2d').drawImage(video, 0, 0);
tempCanvas.toBlob(blob => {
const formData = new FormData();
formData.append('image', blob);
// Send to Python Backend
fetch('/process_frame', { method: 'POST', body: formData })
.then(res => res.json())
.then(data => {
// Update UI
statusEl.innerText = `STATUS: ${data.status}`;
statusEl.style.color = data.status === "ARMED" ? "#0f0" : "#fa0";
if (data.target) {
configEl.innerText = `Target: ${data.target.toUpperCase()}`;
}
// Clear previous drawings
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw detections
if (data.detections) {
data.detections.forEach(det => {
const [x1, y1, x2, y2] = det.bbox;
// Scale coordinates if video size differs from canvas
const scaleX = canvas.width / video.videoWidth;
const scaleY = canvas.height / video.videoHeight;
ctx.strokeStyle = '#00FF00';
ctx.lineWidth = 3;
ctx.strokeRect(x1 * scaleX, y1 * scaleY, (x2-x1) * scaleX, (y2-y1) * scaleY);
ctx.fillStyle = '#00FF00';
ctx.font = '16px Arial';
ctx.fillText(`${det.label} (${det.confidence})`, x1 * scaleX, (y1 * scaleY) - 5);
});
}
})
.catch(err => console.error("API Error", err));
}, 'image/jpeg');
}
}, 500); // Process every 500ms (2 FPS)
</script>
</body>
</html>