salvirezwan's picture
End-to-end real-time traffic analytics pipeline β€” YOLOv8s ONNX
5b60216
Raw
History Blame Contribute Delete
2.84 kB
"""REST endpoints for historical analytics queries.
All heavy reads go to SQLite (hourly aggregates).
Recent real-time data comes from the in-memory ring buffer.
"""
from __future__ import annotations
import datetime
from fastapi import APIRouter, HTTPException, Query, status
from api.database import fetch_hourly_range, fetch_summary, ring_recent
from api.schemas import (
AnalyticsSummaryResponse,
HourlyAggregate,
RecentMetricsResponse,
)
router = APIRouter(prefix="/analytics", tags=["analytics"])
# ── Helpers ───────────────────────────────────────────────────────────────────
def _iso_now() -> str:
return datetime.datetime.utcnow().replace(minute=0, second=0, microsecond=0).isoformat()
def _iso_hours_ago(n: int) -> str:
dt = datetime.datetime.utcnow() - datetime.timedelta(hours=n)
return dt.replace(minute=0, second=0, microsecond=0).isoformat()
# ── Endpoints ─────────────────────────────────────────────────────────────────
@router.get("/recent", response_model=RecentMetricsResponse)
async def recent_metrics(
window: int = Query(default=300, ge=10, le=3600, description="Window in seconds"),
) -> RecentMetricsResponse:
"""Return per-frame metrics from the last `window` seconds (ring buffer)."""
frames = ring_recent(window_seconds=float(window))
return RecentMetricsResponse(window_seconds=window, frames=frames)
@router.get("/hourly", response_model=list[HourlyAggregate])
async def hourly_data(
hours: int = Query(default=24, ge=1, le=168, description="How many hours back to fetch"),
) -> list[HourlyAggregate]:
"""Return hourly aggregates for the last N hours."""
end = _iso_now()
start = _iso_hours_ago(hours)
return await fetch_hourly_range(start, end)
@router.get("/summary", response_model=AnalyticsSummaryResponse)
async def summary(
hours: int = Query(default=24, ge=1, le=168, description="Summarise last N hours"),
) -> AnalyticsSummaryResponse:
"""Return a summary of traffic over the last N hours."""
end = _iso_now()
start = _iso_hours_ago(hours)
data = await fetch_summary(start, end)
if not data:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No data found for the requested period.",
)
return AnalyticsSummaryResponse(**data)
@router.delete("/history", status_code=status.HTTP_204_NO_CONTENT)
async def clear_ring_buffer() -> None:
"""Clear the in-memory ring buffer (does not affect SQLite)."""
from api.database import ring_clear
ring_clear()