mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-16 11:49:43 +02:00
Favicon now matches the LokiMark topbar icon instead of an unrelated arrow glyph. New /api/system/stats endpoint (psutil + nvidia-smi) polled every 2s and shown in the topbar next to the Ollama status.
53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
"""Statistiques système temps réel : CPU, RAM, GPU/VRAM (barre supérieure)."""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import shutil
|
|
|
|
import psutil
|
|
from fastapi import APIRouter
|
|
|
|
router = APIRouter(prefix="/api/system", tags=["system"])
|
|
|
|
_NVIDIA_SMI = shutil.which("nvidia-smi")
|
|
|
|
|
|
async def _gpu_stats() -> dict | None:
|
|
"""Utilisation GPU/VRAM via nvidia-smi ; None si absent (pas de GPU NVIDIA)."""
|
|
if not _NVIDIA_SMI:
|
|
return None
|
|
try:
|
|
proc = await asyncio.create_subprocess_exec(
|
|
_NVIDIA_SMI,
|
|
"--query-gpu=utilization.gpu,memory.used,memory.total,name",
|
|
"--format=csv,noheader,nounits",
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
)
|
|
out, _ = await asyncio.wait_for(proc.communicate(), timeout=3)
|
|
line = out.decode().strip().splitlines()[0]
|
|
util, used, total, name = (p.strip() for p in line.split(","))
|
|
return {
|
|
"name": name,
|
|
"util_pct": float(util),
|
|
"vram_used_mb": float(used),
|
|
"vram_total_mb": float(total),
|
|
}
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
@router.get("/stats")
|
|
async def stats() -> dict:
|
|
"""CPU %, RAM et GPU/VRAM courants."""
|
|
cpu_pct = psutil.cpu_percent(interval=None)
|
|
mem = psutil.virtual_memory()
|
|
gpu = await _gpu_stats()
|
|
return {
|
|
"cpu_pct": cpu_pct,
|
|
"ram_used_go": round(mem.used / 1_000_000_000, 1),
|
|
"ram_total_go": round(mem.total / 1_000_000_000, 1),
|
|
"ram_pct": mem.percent,
|
|
"gpu": gpu,
|
|
}
|