"""
Browse filesSystème de détection d'incendie avec YOLOv8
Code production-ready basé sur les modèles HuggingFace
"""
import cv2
import numpy as np
from ultralytics import YOLO
import sqlite3
from datetime import datetime
from pathlib import Path
import logging
from typing import Tuple, Dict, Optional
from contextlib import contextmanager
# Configuration du logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class FireDetectionSystem:
"""
Système de détection d'incendie utilisant YOLOv8
Basé sur: https://huggingface.co/spaces/SoulPerforms/Fire_Detection_YOLOv8_Model_Inference_with_Gradio
"""
def __init__(self, model_path: str = 'best.pt', db_path: str = 'fire_crm.db'):
self.model_path = model_path
self.db_path = db_path
self.model = None
self.confidence_threshold = 0.5
self._load_model()
self._init_database()
def _load_model(self):
"""Charge le modèle YOLO avec fallback"""
try:
# Tentative de chargement du modèle custom
if Path(self.model_path).exists():
self.model = YOLO(self.model_path)
logger.info(f"Modèle chargé: {self.model_path}")
else:
# Fallback sur YOLOv8n
logger.warning(f"Modèle {self.model_path} introuvable. Utilisation de YOLOv8n")
self.model = YOLO('yolov8n.pt')
except Exception as e:
logger.error(f"Erreur chargement modèle: {e}")
raise
def _init_database(self):
"""Initialise la base de données"""
with self._get_db_connection() as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS detections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
location TEXT NOT NULL,
confidence REAL NOT NULL,
class_detected TEXT NOT NULL,
image_path TEXT,
status TEXT DEFAULT 'ACTIVE',
response_time TEXT
)
''')
conn.execute('''
CREATE TABLE IF NOT EXISTS alerts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
detection_id INTEGER,
alert_type TEXT NOT NULL,
sent_at TEXT NOT NULL,
recipient TEXT,
FOREIGN KEY (detection_id) REFERENCES detections (id)
)
''')
@contextmanager
def _get_db_connection(self):
"""Context manager pour gérer les connexions DB proprement"""
conn = sqlite3.connect(self.db_path)
try:
yield conn
conn.commit()
except Exception as e:
conn.rollback()
logger.error(f"Erreur DB: {e}")
raise
finally:
conn.close()
def detect_fire(self, image_path: str) -> Tuple[bool, float, Optional[Dict]]:
"""
Détecte le feu dans une image
Returns:
Tuple[bool, float, Optional[Dict]]: (feu_détecté, confiance, détails)
"""
try:
if not Path(image_path).exists():
raise FileNotFoundError(f"Image introuvable: {image_path}")
# Chargement de l'image
image = cv2.imread(image_path)
if image is None:
raise ValueError(f"Impossible de charger l'image: {image_path}")
# Inférence YOLO
results = self.model(image, conf=self.confidence_threshold)
# Analyse des résultats
fire_detected = False
max_confidence = 0.0
detection_details = None
for result in results:
boxes = result.boxes
for box in boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
confidence = float(box.conf[0])
# Classes liées au feu (dépend du modèle)
fire_classes = ['fire', 'smoke', 'flame']
if any(fc in class_name.lower() for fc in fire_classes):
fire_detected = True
if confidence > max_confidence:
max_confidence = confidence
detection_details = {
'class': class_name,
'confidence': confidence,
'bbox': box.xyxy[0].tolist()
}
return fire_detected, max_confidence, detection_details
except Exception as e:
logger.error(f"Erreur détection: {e}")
return False, 0.0, None
def detect_fire_stream(self, frame: np.ndarray) -> Tuple[bool, float, np.ndarray]:
"""
Détection sur un frame vidéo (pour stream caméra)
Returns:
Tuple[bool, float, np.ndarray]: (feu_détecté, confiance, frame_annoté)
"""
try:
results = self.model(frame, conf=self.confidence_threshold)
fire_detected = False
max_confidence = 0.0
# Annotation du frame
annotated_frame = frame.copy()
for result in results:
boxes = result.boxes
for box in boxes:
class_id = int(box.cls[0])
class_name = result.names[class_id]
confidence = float(box.conf[0])
fire_classes = ['fire', 'smoke', 'flame']
if any(fc in class_name.lower() for fc in fire_classes):
fire_detected = True
max_confidence = max(max_confidence, confidence)
# Dessiner bbox
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
color = (0, 0, 255) if 'fire' in class_name.lower() else (0, 165, 255)
cv2.rectangle(annotated_frame, (x1, y1), (x2, y2), color, 2)
label = f"{class_name}: {confidence:.2f}"
cv2.putText(annotated_frame, label, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
return fire_detected, max_confidence, annotated_frame
except Exception as e:
logger.error(f"Erreur stream: {e}")
return False, 0.0, frame
def process_detection(self, image_path: str, location: str) -> Dict:
"""Traite une détection et enregistre dans la DB"""
fire_detected, confidence, details = self.detect_fire(image_path)
if not fire_detected:
return {
'status': 'no_fire',
'message': 'Aucun feu détecté'
}
# Enregistrement dans la DB
try:
with self._get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO detections
(timestamp, location, confidence, class_detected, image_path)
VALUES (?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
location,
confidence,
details['class'] if details else 'unknown',
image_path
))
detection_id = cursor.lastrowid
# Création de l'alerte
cursor.execute('''
INSERT INTO alerts (detection_id, alert_type, sent_at)
VALUES (?, ?, ?)
''', (detection_id, 'EMAIL', datetime.now().isoformat()))
logger.warning(f"🔥 FEU DÉTECTÉ à {location} - Confiance: {confidence:.2%}")
return {
'status': 'fire_detected',
'detection_id': detection_id,
'confidence': confidence,
'details': details,
'message': f'🔥 Alerte incendie à {location}'
}
except Exception as e:
logger.error(f"Erreur enregistrement: {e}")
return {'status': 'error', 'message': str(e)}
def get_active_alerts(self) -> list:
"""Récupère les alertes actives"""
with self._get_db_connection() as conn:
cursor = conn.execute('''
SELECT id, timestamp, location, confidence, class_detected
FROM detections
WHERE status = 'ACTIVE'
ORDER BY timestamp DESC
LIMIT 50
''')
return cursor.fetchall()
def update_alert_status(self, detection_id: int, status: str, response_time: str = None):
"""Met à jour le statut d'une alerte"""
with self._get_db_connection() as conn:
conn.execute('''
UPDATE detections
SET status = ?, response_time = ?
WHERE id = ?
''', (status, response_time, detection_id))
# Exemple d'utilisation
if __name__ == "__main__":
# Initialisation du système
fire_system = FireDetectionSystem()
# Test sur une image
result = fire_system.process_detection(
image_path='test_fire.jpg',
location='Entrepôt Zone A'
)
print(result)
# Exemple stream caméra (commenté car nécessite une caméra)
"""
cap = cv2.VideoCapture(0) # 0 pour webcam, ou URL RTSP
while True:
ret, frame = cap.read()
if not ret:
bre
- README.md +8 -5
- index.html +347 -18
|
@@ -1,10 +1,13 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: FlameGuardian AI Vigilance 🔥
|
| 3 |
+
colorFrom: red
|
| 4 |
+
colorTo: pink
|
| 5 |
+
emoji: 🐳
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite-v3
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Welcome to your new DeepSite project!
|
| 13 |
+
This project was created with [DeepSite](https://deepsite.hf.co).
|
|
@@ -1,19 +1,348 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>FlameGuardian - Fire Detection Dashboard</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<script src="https://unpkg.com/feather-icons"></script>
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 10 |
+
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.waves.min.js"></script>
|
| 11 |
+
<style>
|
| 12 |
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
| 13 |
+
body {
|
| 14 |
+
font-family: 'Poppins', sans-serif;
|
| 15 |
+
}
|
| 16 |
+
.heat-gradient {
|
| 17 |
+
background: linear-gradient(135deg, #f5f7fa 0%, #f8c537 50%, #f44336 100%);
|
| 18 |
+
}
|
| 19 |
+
.alert-pulse {
|
| 20 |
+
animation: pulse 2s infinite;
|
| 21 |
+
}
|
| 22 |
+
@keyframes pulse {
|
| 23 |
+
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
|
| 24 |
+
70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
|
| 25 |
+
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body class="bg-gray-50 min-h-screen">
|
| 30 |
+
<div id="vanta-bg" class="fixed inset-0 z-0"></div>
|
| 31 |
+
<div class="relative z-10">
|
| 32 |
+
<!-- Header -->
|
| 33 |
+
<header class="bg-white/80 backdrop-blur-md shadow-sm">
|
| 34 |
+
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
|
| 35 |
+
<div class="flex items-center space-x-2">
|
| 36 |
+
<div class="bg-red-500 rounded-full p-2">
|
| 37 |
+
<i data-feather="alert-triangle" class="text-white"></i>
|
| 38 |
+
</div>
|
| 39 |
+
<h1 class="text-2xl font-bold text-gray-800">FlameGuardian</h1>
|
| 40 |
+
</div>
|
| 41 |
+
<div class="flex items-center space-x-4">
|
| 42 |
+
<button class="p-2 rounded-full bg-gray-100 hover:bg-gray-200">
|
| 43 |
+
<i data-feather="settings"></i>
|
| 44 |
+
</button>
|
| 45 |
+
<div class="flex items-center space-x-2">
|
| 46 |
+
<div class="w-8 h-8 rounded-full bg-red-500 flex items-center justify-center text-white font-medium">JD</div>
|
| 47 |
+
<span class="hidden md:inline">John Doe</span>
|
| 48 |
+
</div>
|
| 49 |
+
</div>
|
| 50 |
+
</div>
|
| 51 |
+
</header>
|
| 52 |
+
|
| 53 |
+
<!-- Main Content -->
|
| 54 |
+
<main class="container mx-auto px-4 py-8">
|
| 55 |
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 56 |
+
<!-- Left Column -->
|
| 57 |
+
<div class="lg:col-span-2 space-y-6">
|
| 58 |
+
<!-- Detection Feed -->
|
| 59 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
| 60 |
+
<div class="p-4 border-b border-gray-200 flex justify-between items-center">
|
| 61 |
+
<h2 class="text-lg font-semibold text-gray-800">Live Detection Feed</h2>
|
| 62 |
+
<div class="flex items-center space-x-2">
|
| 63 |
+
<span class="text-sm text-gray-500">Status:</span>
|
| 64 |
+
<span class="px-2 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full">ACTIVE</span>
|
| 65 |
+
</div>
|
| 66 |
+
</div>
|
| 67 |
+
<div class="relative">
|
| 68 |
+
<div class="aspect-video bg-gray-200 flex items-center justify-center">
|
| 69 |
+
<img src="http://static.photos/industry/640x360" alt="Camera Feed" class="w-full h-full object-cover">
|
| 70 |
+
<div class="absolute inset-0 flex items-center justify-center">
|
| 71 |
+
<div class="bg-red-500 text-white px-4 py-2 rounded-lg opacity-90">
|
| 72 |
+
<div class="flex items-center space-x-2">
|
| 73 |
+
<i data-feather="alert-triangle"></i>
|
| 74 |
+
<span>FIRE DETECTED (87%)</span>
|
| 75 |
+
</div>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
<div class="absolute top-4 right-4 bg-black/50 text-white px-2 py-1 rounded text-xs">
|
| 79 |
+
<i data-feather="video" class="w-3 h-3 inline mr-1"></i>
|
| 80 |
+
CAM-03
|
| 81 |
+
</div>
|
| 82 |
+
</div>
|
| 83 |
+
</div>
|
| 84 |
+
<div class="p-4 flex justify-between items-center">
|
| 85 |
+
<div class="flex space-x-2">
|
| 86 |
+
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center">
|
| 87 |
+
<i data-feather="alert-circle" class="w-4 h-4 mr-2"></i>
|
| 88 |
+
Send Alert
|
| 89 |
+
</button>
|
| 90 |
+
<button class="px-4 py-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition flex items-center">
|
| 91 |
+
<i data-feather="maximize" class="w-4 h-4 mr-2"></i>
|
| 92 |
+
Fullscreen
|
| 93 |
+
</button>
|
| 94 |
+
</div>
|
| 95 |
+
<div class="text-sm text-gray-500">
|
| 96 |
+
Last updated: Just now
|
| 97 |
+
</div>
|
| 98 |
+
</div>
|
| 99 |
+
</div>
|
| 100 |
+
|
| 101 |
+
<!-- Recent Alerts -->
|
| 102 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
| 103 |
+
<div class="p-4 border-b border-gray-200">
|
| 104 |
+
<h2 class="text-lg font-semibold text-gray-800 flex items-center">
|
| 105 |
+
<i data-feather="bell" class="w-5 h-5 mr-2 text-red-500"></i>
|
| 106 |
+
Recent Alerts
|
| 107 |
+
</h2>
|
| 108 |
+
</div>
|
| 109 |
+
<div class="divide-y divide-gray-200">
|
| 110 |
+
<!-- Alert Item -->
|
| 111 |
+
<div class="p-4 hover:bg-red-50 transition cursor-pointer">
|
| 112 |
+
<div class="flex justify-between items-start">
|
| 113 |
+
<div class="flex items-start space-x-3">
|
| 114 |
+
<div class="mt-1">
|
| 115 |
+
<div class="w-8 h-8 rounded-full bg-red-100 flex items-center justify-center">
|
| 116 |
+
<i data-feather="alert-triangle" class="w-4 h-4 text-red-500"></i>
|
| 117 |
+
</div>
|
| 118 |
+
</div>
|
| 119 |
+
<div>
|
| 120 |
+
<h3 class="font-medium text-gray-800">Fire detected in Warehouse A</h3>
|
| 121 |
+
<p class="text-sm text-gray-500">Confidence: 87% | Location: Sector 4</p>
|
| 122 |
+
</div>
|
| 123 |
+
</div>
|
| 124 |
+
<span class="text-xs text-gray-400">2 min ago</span>
|
| 125 |
+
</div>
|
| 126 |
+
</div>
|
| 127 |
+
<!-- Alert Item -->
|
| 128 |
+
<div class="p-4 hover:bg-orange-50 transition cursor-pointer">
|
| 129 |
+
<div class="flex justify-between items-start">
|
| 130 |
+
<div class="flex items-start space-x-3">
|
| 131 |
+
<div class="mt-1">
|
| 132 |
+
<div class="w-8 h-8 rounded-full bg-orange-100 flex items-center justify-center">
|
| 133 |
+
<i data-feather="cloud" class="w-4 h-4 text-orange-500"></i>
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
<div>
|
| 137 |
+
<h3 class="font-medium text-gray-800">Smoke detected in Storage Room 2</h3>
|
| 138 |
+
<p class="text-sm text-gray-500">Confidence: 72% | Location: Sector 1</p>
|
| 139 |
+
</div>
|
| 140 |
+
</div>
|
| 141 |
+
<span class="text-xs text-gray-400">15 min ago</span>
|
| 142 |
+
</div>
|
| 143 |
+
</div>
|
| 144 |
+
<!-- Alert Item -->
|
| 145 |
+
<div class="p-4 hover:bg-yellow-50 transition cursor-pointer">
|
| 146 |
+
<div class="flex justify-between items-start">
|
| 147 |
+
<div class="flex items-start space-x-3">
|
| 148 |
+
<div class="mt-1">
|
| 149 |
+
<div class="w-8 h-8 rounded-full bg-yellow-100 flex items-center justify-center">
|
| 150 |
+
<i data-feather="alert-octagon" class="w-4 h-4 text-yellow-500"></i>
|
| 151 |
+
</div>
|
| 152 |
+
</div>
|
| 153 |
+
<div>
|
| 154 |
+
<h3 class="font-medium text-gray-800">Heat anomaly in Office Area</h3>
|
| 155 |
+
<p class="text-sm text-gray-500">Confidence: 65% | Location: Sector 3</p>
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
<span class="text-xs text-gray-400">42 min ago</span>
|
| 159 |
+
</div>
|
| 160 |
+
</div>
|
| 161 |
+
</div>
|
| 162 |
+
<div class="p-4 text-center">
|
| 163 |
+
<button class="text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center justify-center mx-auto">
|
| 164 |
+
View all alerts
|
| 165 |
+
<i data-feather="chevron-right" class="w-4 h-4 ml-1"></i>
|
| 166 |
+
</button>
|
| 167 |
+
</div>
|
| 168 |
+
</div>
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
<!-- Right Column -->
|
| 172 |
+
<div class="space-y-6">
|
| 173 |
+
<!-- Status Overview -->
|
| 174 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
| 175 |
+
<div class="p-4 border-b border-gray-200">
|
| 176 |
+
<h2 class="text-lg font-semibold text-gray-800 flex items-center">
|
| 177 |
+
<i data-feather="activity" class="w-5 h-5 mr-2 text-blue-500"></i>
|
| 178 |
+
System Overview
|
| 179 |
+
</h2>
|
| 180 |
+
</div>
|
| 181 |
+
<div class="p-4 grid grid-cols-2 gap-4">
|
| 182 |
+
<div class="bg-green-50 p-4 rounded-lg">
|
| 183 |
+
<div class="flex items-center justify-between">
|
| 184 |
+
<span class="text-sm text-gray-600">Cameras</span>
|
| 185 |
+
<div class="w-8 h-8 rounded-full bg-green-100 flex items-center justify-center">
|
| 186 |
+
<i data-feather="video" class="w-4 h-4 text-green-500"></i>
|
| 187 |
+
</div>
|
| 188 |
+
</div>
|
| 189 |
+
<h3 class="text-2xl font-bold mt-2 text-gray-800">8/8</h3>
|
| 190 |
+
<p class="text-xs text-green-600 mt-1">All systems operational</p>
|
| 191 |
+
</div>
|
| 192 |
+
<div class="bg-blue-50 p-4 rounded-lg">
|
| 193 |
+
<div class="flex items-center justify-between">
|
| 194 |
+
<span class="text-sm text-gray-600">Detections</span>
|
| 195 |
+
<div class="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center">
|
| 196 |
+
<i data-feather="eye" class="w-4 h-4 text-blue-500"></i>
|
| 197 |
+
</div>
|
| 198 |
+
</div>
|
| 199 |
+
<h3 class="text-2xl font-bold mt-2 text-gray-800">24</h3>
|
| 200 |
+
<p class="text-xs text-blue-600 mt-1">Today</p>
|
| 201 |
+
</div>
|
| 202 |
+
<div class="bg-yellow-50 p-4 rounded-lg">
|
| 203 |
+
<div class="flex items-center justify-between">
|
| 204 |
+
<span class="text-sm text-gray-600">Alerts</span>
|
| 205 |
+
<div class="w-8 h-8 rounded-full bg-yellow-100 flex items-center justify-center">
|
| 206 |
+
<i data-feather="bell" class="w-4 h-4 text-yellow-500"></i>
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
<h3 class="text-2xl font-bold mt-2 text-gray-800">3</h3>
|
| 210 |
+
<p class="text-xs text-yellow-600 mt-1">Active</p>
|
| 211 |
+
</div>
|
| 212 |
+
<div class="bg-red-50 p-4 rounded-lg">
|
| 213 |
+
<div class="flex items-center justify-between">
|
| 214 |
+
<span class="text-sm text-gray-600">Response Time</span>
|
| 215 |
+
<div class="w-8 h-8 rounded-full bg-red-100 flex items-center justify-center">
|
| 216 |
+
<i data-feather="clock" class="w-4 h-4 text-red-500"></i>
|
| 217 |
+
</div>
|
| 218 |
+
</div>
|
| 219 |
+
<h3 class="text-2xl font-bold mt-2 text-gray-800">1.2m</h3>
|
| 220 |
+
<p class="text-xs text-red-600 mt-1">Avg. response</p>
|
| 221 |
+
</div>
|
| 222 |
+
</div>
|
| 223 |
+
</div>
|
| 224 |
+
|
| 225 |
+
<!-- Model Performance -->
|
| 226 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
| 227 |
+
<div class="p-4 border-b border-gray-200">
|
| 228 |
+
<h2 class="text-lg font-semibold text-gray-800 flex items-center">
|
| 229 |
+
<i data-feather="cpu" class="w-5 h-5 mr-2 text-purple-500"></i>
|
| 230 |
+
Model Performance
|
| 231 |
+
</h2>
|
| 232 |
+
</div>
|
| 233 |
+
<div class="p-4">
|
| 234 |
+
<div class="space-y-4">
|
| 235 |
+
<div>
|
| 236 |
+
<div class="flex justify-between text-sm mb-1">
|
| 237 |
+
<span class="text-gray-600">Accuracy</span>
|
| 238 |
+
<span class="font-medium">94.7%</span>
|
| 239 |
+
</div>
|
| 240 |
+
<div class="w-full bg-gray-200 rounded-full h-2">
|
| 241 |
+
<div class="bg-green-500 h-2 rounded-full" style="width: 94.7%"></div>
|
| 242 |
+
</div>
|
| 243 |
+
</div>
|
| 244 |
+
<div>
|
| 245 |
+
<div class="flex justify-between text-sm mb-1">
|
| 246 |
+
<span class="text-gray-600">Precision</span>
|
| 247 |
+
<span class="font-medium">92.3%</span>
|
| 248 |
+
</div>
|
| 249 |
+
<div class="w-full bg-gray-200 rounded-full h-2">
|
| 250 |
+
<div class="bg-blue-500 h-2 rounded-full" style="width: 92.3%"></div>
|
| 251 |
+
</div>
|
| 252 |
+
</div>
|
| 253 |
+
<div>
|
| 254 |
+
<div class="flex justify-between text-sm mb-1">
|
| 255 |
+
<span class="text-gray-600">Recall</span>
|
| 256 |
+
<span class="font-medium">89.5%</span>
|
| 257 |
+
</div>
|
| 258 |
+
<div class="w-full bg-gray-200 rounded-full h-2">
|
| 259 |
+
<div class="bg-purple-500 h-2 rounded-full" style="width: 89.5%"></div>
|
| 260 |
+
</div>
|
| 261 |
+
</div>
|
| 262 |
+
<div>
|
| 263 |
+
<div class="flex justify-between text-sm mb-1">
|
| 264 |
+
<span class="text-gray-600">F1 Score</span>
|
| 265 |
+
<span class="font-medium">90.8%</span>
|
| 266 |
+
</div>
|
| 267 |
+
<div class="w-full bg-gray-200 rounded-full h-2">
|
| 268 |
+
<div class="bg-yellow-500 h-2 rounded-full" style="width: 90.8%"></div>
|
| 269 |
+
</div>
|
| 270 |
+
</div>
|
| 271 |
+
</div>
|
| 272 |
+
<div class="mt-4 pt-4 border-t border-gray-200 text-center">
|
| 273 |
+
<span class="text-xs text-gray-500 inline-flex items-center">
|
| 274 |
+
<i data-feather="info" class="w-3 h-3 mr-1"></i>
|
| 275 |
+
YOLOv8 Nano | Updated 2 hours ago
|
| 276 |
+
</span>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
</div>
|
| 280 |
+
|
| 281 |
+
<!-- Quick Actions -->
|
| 282 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
| 283 |
+
<div class="p-4 border-b border-gray-200">
|
| 284 |
+
<h2 class="text-lg font-semibold text-gray-800 flex items-center">
|
| 285 |
+
<i data-feather="zap" class="w-5 h-5 mr-2 text-orange-500"></i>
|
| 286 |
+
Quick Actions
|
| 287 |
+
</h2>
|
| 288 |
+
</div>
|
| 289 |
+
<div class="p-4 grid grid-cols-2 gap-3">
|
| 290 |
+
<button class="p-3 bg-red-50 rounded-lg flex flex-col items-center justify-center hover:bg-red-100 transition">
|
| 291 |
+
<div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center mb-2">
|
| 292 |
+
<i data-feather="alert-octagon" class="w-5 h-5 text-red-500"></i>
|
| 293 |
+
</div>
|
| 294 |
+
<span class="text-sm font-medium text-gray-700">Emergency Stop</span>
|
| 295 |
+
</button>
|
| 296 |
+
<button class="p-3 bg-blue-50 rounded-lg flex flex-col items-center justify-center hover:bg-blue-100 transition">
|
| 297 |
+
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mb-2">
|
| 298 |
+
<i data-feather="users" class="w-5 h-5 text-blue-500"></i>
|
| 299 |
+
</div>
|
| 300 |
+
<span class="text-sm font-medium text-gray-700">Notify Team</span>
|
| 301 |
+
</button>
|
| 302 |
+
<button class="p-3 bg-green-50 rounded-lg flex flex-col items-center justify-center hover:bg-green-100 transition">
|
| 303 |
+
<div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mb-2">
|
| 304 |
+
<i data-feather="refresh-cw" class="w-5 h-5 text-green-500"></i>
|
| 305 |
+
</div>
|
| 306 |
+
<span class="text-sm font-medium text-gray-700">System Reset</span>
|
| 307 |
+
</button>
|
| 308 |
+
<button class="p-3 bg-purple-50 rounded-lg flex flex-col items-center justify-center hover:bg-purple-100 transition">
|
| 309 |
+
<div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mb-2">
|
| 310 |
+
<i data-feather="download" class="w-5 h-5 text-purple-500"></i>
|
| 311 |
+
</div>
|
| 312 |
+
<span class="text-sm font-medium text-gray-700">Export Logs</span>
|
| 313 |
+
</button>
|
| 314 |
+
</div>
|
| 315 |
+
</div>
|
| 316 |
+
</div>
|
| 317 |
+
</div>
|
| 318 |
+
</main>
|
| 319 |
+
</div>
|
| 320 |
+
|
| 321 |
+
<script>
|
| 322 |
+
// Initialize Vanta.js background
|
| 323 |
+
VANTA.WAVES({
|
| 324 |
+
el: "#vanta-bg",
|
| 325 |
+
mouseControls: true,
|
| 326 |
+
touchControls: true,
|
| 327 |
+
gyroControls: false,
|
| 328 |
+
minHeight: 200.00,
|
| 329 |
+
minWidth: 200.00,
|
| 330 |
+
scale: 1.00,
|
| 331 |
+
scaleMobile: 1.00,
|
| 332 |
+
color: 0x3a86ff,
|
| 333 |
+
shininess: 35.00,
|
| 334 |
+
waveHeight: 15.00,
|
| 335 |
+
waveSpeed: 0.85,
|
| 336 |
+
zoom: 0.75
|
| 337 |
+
});
|
| 338 |
+
|
| 339 |
+
// Initialize feather icons
|
| 340 |
+
feather.replace();
|
| 341 |
+
|
| 342 |
+
// Simulate alert pulse
|
| 343 |
+
setInterval(() => {
|
| 344 |
+
document.querySelector('.alert-pulse')?.classList.toggle('opacity-90');
|
| 345 |
+
}, 1000);
|
| 346 |
+
</script>
|
| 347 |
+
</body>
|
| 348 |
</html>
|