"""/stats · /stats/history — always live from the database.""" from __future__ import annotations import asyncio from datetime import UTC, datetime from typing import Any from fastapi import APIRouter, Query, Request from aiatlas.api.common import MAIN_ENTITY_TYPES, cached from aiatlas.db import connection from aiatlas.sdk.archive import archive_size from aiatlas.services.stats import history, live_counts router = APIRouter(prefix="/api/v1/stats", tags=["stats"]) @router.get("") @cached(60) async def stats(request: Request) -> dict[str, Any]: async with connection() as conn: counts = await live_counts(conn) counts["entities"] = {**{t: 0 for t in (*MAIN_ENTITY_TYPES, "artifact", "model_family")}, **counts["entities"]} # zero-filled: the homepage never renders a missing key counts["archive"] = await asyncio.to_thread(archive_size) counts["computed_at"] = datetime.now(UTC) return counts @router.get("/history") @cached(300) async def stats_history(request: Request, days: int = Query(90, ge=1, le=730)) -> dict[str, Any]: async with connection() as conn: rows = await history(conn, days) return {"items": [{"day": r["day"].date().isoformat() if hasattr(r["day"], "date") else str(r["day"]), "counts": r["counts"]} for r in rows]}