""" System/OS-Metriken für die Box (Bosgame / Strix Halo). CPU/RAM/Disk via psutil (plattformübergreifend). GPU-Auslastung/VRAM/Temperatur via sysfs (amdgpu) — nur Linux; auf anderen Plattformen None (amd-smi fehlt auf der Box, daher sysfs). Verschachtelte Struktur wie v1 (cpu.percent, ram.used Bytes). """ import glob import os import psutil from config import MODELS_DIR def _read_int(path: str) -> int | None: try: with open(path) as f: return int(f.read().strip()) except Exception: return None def _gpu_sysfs() -> dict | None: """AMD-GPU-Auslastung + VRAM via sysfs (Linux). None, wenn nicht vorhanden.""" base = "/sys/class/drm/card0/device" if not os.path.isdir(base): return None busy = _read_int(f"{base}/gpu_busy_percent") vram_used = _read_int(f"{base}/mem_info_vram_used") vram_total = _read_int(f"{base}/mem_info_vram_total") if busy is None and vram_used is None: return None return {"busy_percent": busy, "vram_used": vram_used, "vram_total": vram_total} def _temps() -> dict | None: """CPU/GPU-Temperatur via hwmon (Linux). None bei Fehlen.""" out: dict = {} for hw in glob.glob("/sys/class/hwmon/hwmon*"): name = "" try: with open(f"{hw}/name") as f: name = f.read().strip() except Exception: continue t = _read_int(f"{hw}/temp1_input") if t is None: continue c = round(t / 1000.0, 1) if name in ("k10temp", "zenpower", "coretemp"): out["cpu"] = c elif name in ("amdgpu", "edge"): out["gpu"] = c return out or None def system_status() -> dict: vm = psutil.virtual_memory() try: du = psutil.disk_usage(str(MODELS_DIR) if MODELS_DIR.exists() else os.getcwd()) disk = {"total": du.total, "used": du.used, "percent": du.percent} except Exception: disk = None return { "cpu": {"percent": psutil.cpu_percent(interval=0.1), "cores": psutil.cpu_count()}, "ram": {"total": vm.total, "used": vm.used, "percent": vm.percent}, "gpu": _gpu_sysfs(), "temp": _temps(), "disk": disk, }