From b20d50e8d0145eb4d1ecf94e3579d2d108bd80bb Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Mon, 16 Feb 2026 10:29:21 +0000 Subject: [PATCH] feat: add GET /api/system/hardware endpoint for GPU info and package versions --- studio/backend/main.py | 11 +++++ studio/backend/utils/hardware/__init__.py | 4 ++ studio/backend/utils/hardware/hardware.py | 50 +++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/studio/backend/main.py b/studio/backend/main.py index 16f112eeb1..3d9e2a0f9a 100644 --- a/studio/backend/main.py +++ b/studio/backend/main.py @@ -117,6 +117,17 @@ async def get_system_info(): } +@app.get("/api/system/hardware") +async def get_hardware_info(): + """Return GPU name, total VRAM, and key ML package versions.""" + from utils.hardware import get_gpu_summary, get_package_versions + + return { + "gpu": get_gpu_summary(), + "versions": get_package_versions(), + } + + # ============ Serve Frontend (Optional) ============ def setup_frontend(app: FastAPI, build_path: Path): diff --git a/studio/backend/utils/hardware/__init__.py b/studio/backend/utils/hardware/__init__.py index b992fc191d..df6df6d34c 100644 --- a/studio/backend/utils/hardware/__init__.py +++ b/studio/backend/utils/hardware/__init__.py @@ -10,6 +10,8 @@ from .hardware import ( clear_gpu_cache, get_gpu_memory_info, log_gpu_memory, + get_gpu_summary, + get_package_versions, ) __all__ = [ @@ -21,4 +23,6 @@ __all__ = [ 'clear_gpu_cache', 'get_gpu_memory_info', 'log_gpu_memory', + 'get_gpu_summary', + 'get_package_versions', ] diff --git a/studio/backend/utils/hardware/hardware.py b/studio/backend/utils/hardware/hardware.py index 25320a25e1..2effae4814 100644 --- a/studio/backend/utils/hardware/hardware.py +++ b/studio/backend/utils/hardware/hardware.py @@ -206,3 +206,53 @@ def log_gpu_memory(context: str): ) else: logger.info(f"GPU Memory [{context}]: No GPU available (CPU-only)") + + +# ========== GPU Summary & Package Versions ========== + +def get_gpu_summary() -> Dict[str, Any]: + """ + Return a compact summary of the primary GPU. + + Returns dict with keys: + gpu_name – e.g. "NVIDIA L4" (or None) + vram_total_gb – e.g. 22.17 (or None) + """ + mem = get_gpu_memory_info() + if mem.get("available"): + return { + "gpu_name": mem.get("device_name"), + "vram_total_gb": round(mem.get("total_gb", 0), 2), + } + return {"gpu_name": None, "vram_total_gb": None} + + +def get_package_versions() -> Dict[str, Optional[str]]: + """ + Return the installed versions of key ML packages. + + Uses importlib.metadata (stdlib) so no subprocess is needed. + CUDA version comes from torch.version.cuda. + + Returns dict with keys: unsloth, torch, transformers, cuda. + Missing packages yield None. + """ + from importlib.metadata import version as pkg_version, PackageNotFoundError + + packages = ("unsloth", "torch", "transformers") + versions: Dict[str, Optional[str]] = {} + + for name in packages: + try: + versions[name] = pkg_version(name) + except PackageNotFoundError: + versions[name] = None + + # CUDA toolkit version bundled with torch + try: + import torch + versions["cuda"] = getattr(torch.version, "cuda", None) + except Exception: + versions["cuda"] = None + + return versions