import asyncio import socket import time from typing import Any import psutil from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse, JSONResponse from app.collect import net as net_col from app.render import render, uptime_str router = APIRouter(prefix="/api", tags=["overview"]) @router.get("/overview") async def overview(request: Request): store = request.app.state.store s: dict[str, Any] = store.latest() or {} mem_total = s.get("mem_total") or 0 vram_total = s.get("vram_total") or 0 vram_used = s.get("vram_used") c = { "cpu": s.get("cpu"), "cpu_temp": s.get("cpu_temp"), "load1": s.get("load1"), "load5": s.get("load5"), "load15": s.get("load15"), "mem_used": s.get("mem_used"), "mem_total": mem_total, "mem_pct": s.get("mem_pct"), "swap_used": s.get("swap_used"), "swap_total": s.get("swap_total") or 0, "swap_pct": s.get("swap_pct"), "gpu": s.get("gpu"), "gpu_name": s.get("gpu_name"), "gpu_temp": s.get("gpu_temp"), "vram_used": vram_used, "vram_total": vram_total, "vram_pct": s.get("vram_pct") or ((vram_used / vram_total * 100) if (vram_total and vram_used is not None) else None), "battery": s.get("battery"), "battery_status": s.get("battery_status"), "ac_online": s.get("ac_online"), "uptime": uptime_str(time.time() - psutil.boot_time()), "hostname": socket.gethostname(), "cores": psutil.cpu_count(logical=True) or 1, **await asyncio.to_thread(net_col.sample), } return HTMLResponse(render("overview.html", c=c)) @router.get("/history") async def history(request: Request): snap = request.app.state.store.snapshot() ts = [round(t, 1) for t, _ in snap] keys: set[str] = set() for _, sample in snap: for k, v in sample.items(): if isinstance(v, (int, float)) and not isinstance(v, bool): keys.add(k) series: dict[str, list[Any]] = {} for _, sample in snap: for k in keys: v = sample.get(k) if isinstance(v, (int, float)) and not isinstance(v, bool): if isinstance(v, float): v = round(v, 1) else: v = None series.setdefault(k, []).append(v) return JSONResponse({"ts": ts, "series": series})