""" Endpoints pour les métriques du dashboard """ from fastapi import APIRouter, HTTPException from ..database import db from ..models import MetricsResponse, MetricsSummary, TimeSeriesPoint router = APIRouter(prefix="/api/metrics", tags=["metrics"]) @router.get("", response_model=MetricsResponse) async def get_metrics(): """ Récupère les métriques globales du dashboard """ try: # Résumé des métriques summary_query = """ SELECT count() AS total_detections, countIf(threat_level = 'CRITICAL') AS critical_count, countIf(threat_level = 'HIGH') AS high_count, countIf(threat_level = 'MEDIUM') AS medium_count, countIf(threat_level = 'LOW') AS low_count, countIf(bot_name != '') AS known_bots_count, countIf(bot_name = '') AS anomalies_count, uniq(src_ip) AS unique_ips FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR """ summary_result = db.query(summary_query) summary_row = summary_result.result_rows[0] if summary_result.result_rows else None if not summary_row: raise HTTPException(status_code=404, detail="Aucune donnée disponible") summary = MetricsSummary( total_detections=summary_row[0], critical_count=summary_row[1], high_count=summary_row[2], medium_count=summary_row[3], low_count=summary_row[4], known_bots_count=summary_row[5], anomalies_count=summary_row[6], unique_ips=summary_row[7] ) # Série temporelle (par heure) timeseries_query = """ SELECT toStartOfHour(detected_at) AS hour, count() AS total, countIf(threat_level = 'CRITICAL') AS critical, countIf(threat_level = 'HIGH') AS high, countIf(threat_level = 'MEDIUM') AS medium, countIf(threat_level = 'LOW') AS low FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR GROUP BY hour ORDER BY hour """ timeseries_result = db.query(timeseries_query) timeseries = [ TimeSeriesPoint( hour=row[0], total=row[1], critical=row[2], high=row[3], medium=row[4], low=row[5] ) for row in timeseries_result.result_rows ] # Distribution par menace threat_distribution = { "CRITICAL": summary.critical_count, "HIGH": summary.high_count, "MEDIUM": summary.medium_count, "LOW": summary.low_count } return MetricsResponse( summary=summary, timeseries=timeseries, threat_distribution=threat_distribution ) except Exception as e: raise HTTPException(status_code=500, detail=f"Erreur lors de la récupération des métriques: {str(e)}") @router.get("/threats") async def get_threat_distribution(): """ Récupère la répartition par niveau de menace """ try: query = """ SELECT threat_level, count() AS count, round(count() * 100.0 / sum(count()) OVER (), 2) AS percentage FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR GROUP BY threat_level ORDER BY count DESC """ result = db.query(query) return { "items": [ {"threat_level": row[0], "count": row[1], "percentage": row[2]} for row in result.result_rows ] } except Exception as e: raise HTTPException(status_code=500, detail=f"Erreur: {str(e)}")