55
66Supported platforms: Windows, Linux, macOS (Intel + Apple Silicon).
77"""
8+
89from __future__ import annotations
910
1011import ctypes
@@ -30,9 +31,11 @@ class _HardwareCache:
3031
3132# ── System RAM ───────────────────────────────────────────────────────
3233
34+
3335def _get_ram_windows () -> tuple [float , float ] | None :
3436 """Get RAM via Win32 API (ctypes). Returns (total_gb, available_gb)."""
3537 try :
38+
3639 class MEMORYSTATUSEX (ctypes .Structure ):
3740 _fields_ = [
3841 ("dwLength" , ctypes .c_ulong ),
@@ -78,7 +81,10 @@ def _get_ram_macos() -> tuple[float, float] | None:
7881 try :
7982 result = subprocess .run (
8083 ["sysctl" , "-n" , "hw.memsize" ],
81- capture_output = True , text = True , timeout = 5 , check = False ,
84+ capture_output = True ,
85+ text = True ,
86+ timeout = 5 ,
87+ check = False ,
8288 )
8389 if result .returncode != 0 or not result .stdout :
8490 return None
@@ -87,7 +93,11 @@ def _get_ram_macos() -> tuple[float, float] | None:
8793
8894 avail_gb = 0.0
8995 result = subprocess .run (
90- ["vm_stat" ], capture_output = True , text = True , timeout = 5 , check = False ,
96+ ["vm_stat" ],
97+ capture_output = True ,
98+ text = True ,
99+ timeout = 5 ,
100+ check = False ,
91101 )
92102 if result .returncode == 0 and result .stdout :
93103 # Default page size: Apple Silicon = 16384, Intel Mac = 4096
@@ -124,6 +134,7 @@ def _detect_system_ram() -> dict[str, Any]:
124134
125135# ── GPU / VRAM ───────────────────────────────────────────────────────
126136
137+
127138def _detect_gpu_nvidia () -> list [dict [str , Any ]]:
128139 """Detect NVIDIA GPUs via nvidia-smi (works on all platforms)."""
129140 try :
@@ -133,7 +144,10 @@ def _detect_gpu_nvidia() -> list[dict[str, Any]]:
133144 "--query-gpu=name,memory.total,memory.free,driver_version" ,
134145 "--format=csv,noheader,nounits" ,
135146 ],
136- capture_output = True , text = True , timeout = 5 , check = False ,
147+ capture_output = True ,
148+ text = True ,
149+ timeout = 5 ,
150+ check = False ,
137151 )
138152 if result .returncode != 0 or not result .stdout :
139153 return []
@@ -144,14 +158,16 @@ def _detect_gpu_nvidia() -> list[dict[str, Any]]:
144158 if len (parts ) >= 4 :
145159 vram_total = int (parts [1 ])
146160 vram_free = int (parts [2 ])
147- gpus .append ({
148- "name" : parts [0 ],
149- "vram_total_mb" : vram_total ,
150- "vram_free_mb" : vram_free ,
151- "vram_total_gb" : round (vram_total / 1024 , 1 ),
152- "driver_version" : parts [3 ],
153- "vendor" : "nvidia" ,
154- })
161+ gpus .append (
162+ {
163+ "name" : parts [0 ],
164+ "vram_total_mb" : vram_total ,
165+ "vram_free_mb" : vram_free ,
166+ "vram_total_gb" : round (vram_total / 1024 , 1 ),
167+ "driver_version" : parts [3 ],
168+ "vendor" : "nvidia" ,
169+ }
170+ )
155171 return gpus
156172 except (FileNotFoundError , subprocess .TimeoutExpired , ValueError ):
157173 return []
@@ -162,7 +178,10 @@ def _detect_gpu_macos() -> list[dict[str, Any]]:
162178 try :
163179 result = subprocess .run (
164180 ["system_profiler" , "SPDisplaysDataType" , "-json" ],
165- capture_output = True , text = True , timeout = 10 , check = False ,
181+ capture_output = True ,
182+ text = True ,
183+ timeout = 10 ,
184+ check = False ,
166185 )
167186 if result .returncode != 0 or not result .stdout :
168187 return []
@@ -181,13 +200,15 @@ def _detect_gpu_macos() -> list[dict[str, Any]]:
181200 unit = parts [1 ].upper ()
182201 vram_mb = val * 1024 if "GB" in unit else val
183202
184- gpus .append ({
185- "name" : name ,
186- "vram_total_mb" : vram_mb ,
187- "vram_free_mb" : 0 , # Apple Silicon uses unified memory; discrete VRAM is always 0
188- "vram_total_gb" : round (vram_mb / 1024 , 1 ),
189- "vendor" : "apple" ,
190- })
203+ gpus .append (
204+ {
205+ "name" : name ,
206+ "vram_total_mb" : vram_mb ,
207+ "vram_free_mb" : 0 , # Apple Silicon uses unified memory; discrete VRAM is always 0
208+ "vram_total_gb" : round (vram_mb / 1024 , 1 ),
209+ "vendor" : "apple" ,
210+ }
211+ )
191212 return gpus
192213 except (FileNotFoundError , json .JSONDecodeError , subprocess .TimeoutExpired , ValueError ):
193214 return []
@@ -207,6 +228,7 @@ def _detect_gpus() -> list[dict[str, Any]]:
207228
208229# ── Public API ───────────────────────────────────────────────────────
209230
231+
210232def detect_hardware () -> dict [str , Any ]:
211233 """Detect hardware environment. Results are cached for 5 minutes.
212234
0 commit comments