Spaces:
Running on Zero
Running on Zero
| """ | |
| Describing a machine in terms the maths cares about. | |
| The whole job here is to turn "I have a Windows laptop with an RTX 3060 and | |
| 16 GB of RAM" into two numbers the advisor can reason about: | |
| - fast_budget_gb : memory the model can use *on the fast path* (the GPU, or | |
| on Apple Silicon, the shared memory the GPU can borrow) | |
| - total_budget_gb: the absolute most a model can use if we let it spill onto | |
| ordinary RAM (slower, but it runs) | |
| Everything is deliberately conservative. We'd rather say "this might be tight" | |
| and be wrong than promise something that then fails to load. | |
| """ | |
| from dataclasses import dataclass | |
| # -------------------------------------------------------------------------- | |
| # Common consumer GPUs -> VRAM (GB). So people pick a name, not a number. | |
| # VRAM is baked into the label too, because some cards ship in two sizes. | |
| # -------------------------------------------------------------------------- | |
| GPU_PRESETS: dict[str, float] = { | |
| # NVIDIA RTX 50-series | |
| "NVIDIA RTX 5090 (32 GB)": 32, | |
| "NVIDIA RTX 5080 (16 GB)": 16, | |
| "NVIDIA RTX 5070 Ti (16 GB)": 16, | |
| "NVIDIA RTX 5070 (12 GB)": 12, | |
| "NVIDIA RTX 5060 Ti (16 GB)": 16, | |
| "NVIDIA RTX 5060 (8 GB)": 8, | |
| # NVIDIA RTX 40-series | |
| "NVIDIA RTX 4090 (24 GB)": 24, | |
| "NVIDIA RTX 4080 (16 GB)": 16, | |
| "NVIDIA RTX 4070 Ti (12 GB)": 12, | |
| "NVIDIA RTX 4070 (12 GB)": 12, | |
| "NVIDIA RTX 4060 Ti (16 GB)": 16, | |
| "NVIDIA RTX 4060 (8 GB)": 8, | |
| # NVIDIA RTX 30-series | |
| "NVIDIA RTX 3090 (24 GB)": 24, | |
| "NVIDIA RTX 3080 (10 GB)": 10, | |
| "NVIDIA RTX 3070 (8 GB)": 8, | |
| "NVIDIA RTX 3060 (12 GB)": 12, | |
| "NVIDIA RTX 3050 (8 GB)": 8, | |
| # Older / budget NVIDIA | |
| "NVIDIA GTX 1660 (6 GB)": 6, | |
| "NVIDIA GTX 1650 (4 GB)": 4, | |
| # AMD | |
| "AMD RX 7900 XTX (24 GB)": 24, | |
| "AMD RX 7800 XT (16 GB)": 16, | |
| "AMD RX 7600 (8 GB)": 8, | |
| "AMD RX 6700 XT (12 GB)": 12, | |
| # Laptop integrated (no real VRAM — uses shared system RAM) | |
| "Intel built-in graphics (no separate card)": 0, | |
| "AMD built-in graphics (no separate card)": 0, | |
| } | |
| # Apple Silicon: there's no separate VRAM. The GPU shares system memory, and | |
| # macOS lets it borrow a large slice. We treat it specially below. | |
| APPLE_CHIPS: dict[str, int] = { | |
| "Apple M1 / M2 / M3 / M4 (base)": 8, # default RAM if they don't know | |
| "Apple M-series Pro": 16, | |
| "Apple M-series Max": 32, | |
| "Apple M-series Ultra": 64, | |
| } | |
| class HardwareSpec: | |
| """A machine, described just enough to reason about it.""" | |
| os: str = "windows" # windows | macos | linux | |
| ram_gb: float = 16.0 # system RAM | |
| gpu_vendor: str = "none" # nvidia | amd | apple | intel | none | |
| vram_gb: float = 0.0 # dedicated GPU memory (0 if shared/none) | |
| is_apple_silicon: bool = False | |
| gpu_label: str = "No dedicated graphics card" | |
| form_factor: str = "laptop" # laptop | desktop | mac | sbc | |
| # -- derived memory budgets ------------------------------------------- | |
| def fast_budget_gb(self) -> float: | |
| """Memory available on the *fast* path (GPU / Apple shared memory).""" | |
| if self.is_apple_silicon: | |
| # macOS lets the GPU use a large fraction of unified memory. | |
| # ~70% is a safe, widely-quoted working figure. | |
| return round(self.ram_gb * 0.70, 1) | |
| if self.gpu_vendor in ("nvidia", "amd") and self.vram_gb > 0: | |
| # Leave headroom for the display, driver, and other apps. | |
| return round(self.vram_gb * 0.85, 1) | |
| # Integrated graphics / CPU-only: no meaningful fast path. | |
| return 0.0 | |
| def os_reserve_gb(self) -> float: | |
| """RAM we set aside for the operating system + other open programs. | |
| Windows idles heavy; a headless Raspberry Pi barely uses anything. | |
| Being honest here matters: too small a reserve over-promises. | |
| """ | |
| return { | |
| "sbc": 1.0, | |
| "mac": 3.0, | |
| "desktop": 3.0, | |
| "laptop": 3.5, | |
| }.get(self.form_factor, 3.0) if self.os != "linux" else { | |
| "sbc": 1.0, | |
| }.get(self.form_factor, 2.0) | |
| def total_budget_gb(self) -> float: | |
| """The most a model can use if it spills onto ordinary RAM (slower).""" | |
| if self.is_apple_silicon: | |
| return self.fast_budget_gb # unified memory — same pool | |
| # Dedicated VRAM (fully usable on the fast path) PLUS a conservative | |
| # slice of system RAM for CPU offload, after reserving room for the OS. | |
| ram_for_model = max(0.0, self.ram_gb - self.os_reserve_gb) * 0.9 | |
| return round(self.vram_gb + ram_for_model, 1) | |
| def has_fast_path(self) -> bool: | |
| return self.fast_budget_gb >= 1.0 | |
| def build_spec( | |
| *, | |
| computer_kind: str, | |
| ram_gb: float, | |
| gpu_choice: str, | |
| apple_chip: str | None = None, | |
| ) -> HardwareSpec: | |
| """Turn friendly UI selections into a HardwareSpec. | |
| computer_kind: "Windows laptop/desktop", "Mac", "Linux PC", | |
| "Raspberry Pi / mini PC" | |
| gpu_choice: a key from GPU_PRESETS, or one of the "don't know" options. | |
| """ | |
| kind = computer_kind.lower() | |
| # ---- Mac / Apple Silicon ------------------------------------------- | |
| if "mac" in kind: | |
| chip = apple_chip or "Apple M1 / M2 / M3 / M4 (base)" | |
| return HardwareSpec( | |
| os="macos", | |
| ram_gb=ram_gb, | |
| gpu_vendor="apple", | |
| vram_gb=0.0, | |
| is_apple_silicon=True, | |
| gpu_label=f"{chip} (shares your {ram_gb:g} GB of memory)", | |
| form_factor="mac", | |
| ) | |
| # ---- Raspberry Pi / tiny single-board ------------------------------ | |
| if "raspberry" in kind or "mini" in kind or "sbc" in kind: | |
| return HardwareSpec( | |
| os="linux", | |
| ram_gb=ram_gb, | |
| gpu_vendor="none", | |
| vram_gb=0.0, | |
| gpu_label="No dedicated graphics card (tiny computer)", | |
| form_factor="sbc", | |
| ) | |
| # ---- Windows / Linux PC with a possible discrete GPU --------------- | |
| os_name = "linux" if "linux" in kind else "windows" | |
| form = "desktop" if "desktop" in kind else "laptop" | |
| vram = GPU_PRESETS.get(gpu_choice, 0.0) | |
| if "nvidia" in gpu_choice.lower(): | |
| vendor = "nvidia" | |
| elif "amd" in gpu_choice.lower() and "built-in" not in gpu_choice.lower(): | |
| vendor = "amd" | |
| elif "built-in" in gpu_choice.lower(): | |
| vendor = "intel" if "intel" in gpu_choice.lower() else "amd" | |
| else: | |
| vendor = "none" | |
| label = gpu_choice if vram > 0 else "No dedicated graphics card (built-in graphics only)" | |
| return HardwareSpec( | |
| os=os_name, | |
| ram_gb=ram_gb, | |
| gpu_vendor=vendor, | |
| vram_gb=vram, | |
| is_apple_silicon=False, | |
| gpu_label=label, | |
| form_factor=form, | |
| ) | |