Files
2026-06-20 23:30:58 +02:00

105 lines
2.9 KiB
Python

"""
System-Router: Liefert Live-Auslastung (CPU, RAM, Disk, GPU, Temp).
Greift lokal auf psutil und sysfs zu.
"""
from pathlib import Path
import asyncio
import psutil
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
from auth import auth
router = APIRouter(prefix="/api/system", dependencies=[Depends(auth)])
def _read_sysfs_int(path: Path) -> int | None:
try:
if path.exists():
return int(path.read_text().strip())
except Exception:
pass
return None
def _get_gpu_mem():
# Suche in /sys/class/drm/ nach card*, die mem_info_* hat
drm_dir = Path("/sys/class/drm")
if not drm_dir.exists():
return None
for card in drm_dir.glob("card*"):
dev_dir = card / "device"
vram_total = _read_sysfs_int(dev_dir / "mem_info_vram_total")
if vram_total is not None:
return {
"vram": {
"used": _read_sysfs_int(dev_dir / "mem_info_vram_used") or 0,
"total": vram_total,
},
"gtt": {
"used": _read_sysfs_int(dev_dir / "mem_info_gtt_used") or 0,
"total": _read_sysfs_int(dev_dir / "mem_info_gtt_total") or 0,
}
}
return None
def _get_temperatures():
temps = {"cpu": None, "gpu": None}
hwmon_dir = Path("/sys/class/hwmon")
if not hwmon_dir.exists():
return temps
for hw in hwmon_dir.glob("hwmon*"):
try:
name = (hw / "name").read_text().strip()
temp_val = _read_sysfs_int(hw / "temp1_input")
if temp_val is not None:
if name == "k10temp":
temps["cpu"] = temp_val / 1000.0
elif name == "amdgpu":
temps["gpu"] = temp_val / 1000.0
except Exception:
continue
return temps
@router.get("/status")
def system_status():
temps = _get_temperatures()
cpu_percent = psutil.cpu_percent(interval=None)
ram = psutil.virtual_memory()
disk = psutil.disk_usage("/")
return {
"cpu": {
"percent": cpu_percent,
"temp": temps["cpu"]
},
"ram": {
"used": ram.used,
"total": ram.total,
"percent": ram.percent
},
"disk": {
"used": disk.used,
"total": disk.total,
"percent": disk.percent
},
"gpu": _get_gpu_mem() or {
"vram": {"used": 0, "total": 0},
"gtt": {"used": 0, "total": 0}
},
"gpu_temp": temps["gpu"]
}
@router.websocket("/stream")
async def system_stream(websocket: WebSocket):
await websocket.accept()
try:
while True:
# Sende Live-Daten alle 500ms
data = system_status()
await websocket.send_json(data)
await asyncio.sleep(0.5)
except WebSocketDisconnect:
pass