pliny-the-prompter commited on
Commit
2478e2f
Β·
verified Β·
1 Parent(s): 41ed5bc

Upload 128 files

Browse files
Files changed (6) hide show
  1. README.md +20 -7
  2. app.py +45 -2
  3. obliteratus/cli.py +41 -0
  4. obliteratus/local_ui.py +313 -0
  5. obliteratus/presets.py +33 -0
  6. spaces/README.md +7 -2
README.md CHANGED
@@ -100,18 +100,28 @@ OBLITERATUS implements several techniques that go beyond prior work:
100
 
101
  ## Quickstart
102
 
103
- ### Option A: Browser (no install, free GPU, chat playground)
104
 
105
- The fastest path β€” obliterate a model and chat with it, all in your browser:
106
 
107
  ```bash
108
- # Run locally
109
  pip install -e ".[spaces]"
110
- python app.py
111
- # β†’ open http://localhost:7860
 
 
 
 
 
 
 
 
 
112
  ```
113
 
114
- Or deploy on [HuggingFace Spaces](https://huggingface.co/spaces) with a free T4 GPU β€” pick a model, click OBLITERATE, then chat with the modified model in the built-in playground. See [spaces/README.md](spaces/README.md) for setup.
 
 
115
 
116
  ### Option B: Colab
117
 
@@ -119,7 +129,7 @@ Or deploy on [HuggingFace Spaces](https://huggingface.co/spaces) with a free T4
119
 
120
  Pick a model from the dropdown, pick a method, hit Run All. Download the result or push straight to HuggingFace Hub.
121
 
122
- ### Option C: Local install
123
 
124
  ```bash
125
  pip install -e .
@@ -132,6 +142,9 @@ obliteratus obliterate meta-llama/Llama-3.1-8B-Instruct --method advanced
132
 
133
  # Run a full ablation study from config
134
  obliteratus run examples/gpt2_layer_ablation.yaml
 
 
 
135
  ```
136
 
137
  ### Option D: Python API
 
100
 
101
  ## Quickstart
102
 
103
+ ### Option A: Browser (local GPU, full UI, chat playground)
104
 
105
+ The best local experience β€” the same beautiful UI as the HuggingFace Space, running on your own hardware:
106
 
107
  ```bash
 
108
  pip install -e ".[spaces]"
109
+
110
+ # Launch with GPU auto-detection, system info, and model recommendations
111
+ obliteratus ui
112
+
113
+ # Or with options:
114
+ obliteratus ui --port 8080 # custom port
115
+ obliteratus ui --share # generate a public share link
116
+ obliteratus ui --no-browser # don't auto-open browser
117
+ obliteratus ui --auth user:pass # add basic auth
118
+
119
+ # β†’ opens http://localhost:7860 automatically
120
  ```
121
 
122
+ You can also run directly with `python app.py` (used by HF Spaces). The `obliteratus ui` command adds a beautiful Rich terminal startup with GPU detection, hardware-appropriate model recommendations, and auto-browser-open.
123
+
124
+ Deploy on [HuggingFace Spaces](https://huggingface.co/spaces) with a free T4 GPU for cloud access β€” see [spaces/README.md](spaces/README.md) for setup.
125
 
126
  ### Option B: Colab
127
 
 
129
 
130
  Pick a model from the dropdown, pick a method, hit Run All. Download the result or push straight to HuggingFace Hub.
131
 
132
+ ### Option C: Local CLI (headless)
133
 
134
  ```bash
135
  pip install -e .
 
142
 
143
  # Run a full ablation study from config
144
  obliteratus run examples/gpt2_layer_ablation.yaml
145
+
146
+ # Launch the web UI from the CLI
147
+ obliteratus ui
148
  ```
149
 
150
  ### Option D: Python API
app.py CHANGED
@@ -2,7 +2,9 @@
2
 
3
  Deploy on HuggingFace Spaces (free T4 GPU) or run locally:
4
  pip install -e ".[spaces]"
5
- python app.py
 
 
6
  """
7
 
8
  from __future__ import annotations
@@ -3733,5 +3735,46 @@ Built on the shoulders of:
3733
  # Launch
3734
  # ---------------------------------------------------------------------------
3735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3736
  if __name__ == "__main__":
3737
- demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  Deploy on HuggingFace Spaces (free T4 GPU) or run locally:
4
  pip install -e ".[spaces]"
5
+ obliteratus ui # beautiful launcher with GPU detection
6
+ python app.py # direct launch (used by HF Spaces)
7
+ python app.py --share # with public share link
8
  """
9
 
10
  from __future__ import annotations
 
3735
  # Launch
3736
  # ---------------------------------------------------------------------------
3737
 
3738
+
3739
+ def launch(
3740
+ server_name: str = "0.0.0.0",
3741
+ server_port: int = 7860,
3742
+ share: bool = False,
3743
+ inbrowser: bool = False,
3744
+ auth: tuple[str, str] | None = None,
3745
+ max_threads: int = 40,
3746
+ quiet: bool = False,
3747
+ ):
3748
+ """Launch the Gradio UI with configurable options.
3749
+
3750
+ Called by ``python app.py`` (HF Spaces) or ``obliteratus ui`` (local).
3751
+ """
3752
+ demo.launch(
3753
+ server_name=server_name,
3754
+ server_port=server_port,
3755
+ share=share,
3756
+ inbrowser=inbrowser,
3757
+ auth=auth,
3758
+ max_threads=max_threads,
3759
+ quiet=quiet,
3760
+ )
3761
+
3762
+
3763
  if __name__ == "__main__":
3764
+ import argparse as _ap
3765
+
3766
+ _parser = _ap.ArgumentParser(description="OBLITERATUS β€” Gradio UI")
3767
+ _parser.add_argument("--port", type=int, default=7860, help="Server port (default: 7860)")
3768
+ _parser.add_argument("--host", type=str, default="0.0.0.0", help="Server host (default: 0.0.0.0)")
3769
+ _parser.add_argument("--share", action="store_true", help="Create a public Gradio share link")
3770
+ _parser.add_argument("--open", action="store_true", help="Auto-open browser on launch")
3771
+ _parser.add_argument("--auth", type=str, default=None, help="Basic auth as user:pass")
3772
+ _args = _parser.parse_args()
3773
+ _auth = tuple(_args.auth.split(":", 1)) if _args.auth else None
3774
+ launch(
3775
+ server_name=_args.host,
3776
+ server_port=_args.port,
3777
+ share=_args.share,
3778
+ inbrowser=_args.open,
3779
+ auth=_auth,
3780
+ )
obliteratus/cli.py CHANGED
@@ -58,6 +58,31 @@ def main(argv: list[str] | None = None):
58
  # --- strategies ---
59
  subparsers.add_parser("strategies", help="List available ablation strategies")
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  # --- obliterate (primary) + abliterate (backward-compat alias) ---
62
  def _add_obliterate_args(p):
63
  p.add_argument("model", type=str, help="HuggingFace model name/path")
@@ -128,10 +153,26 @@ def main(argv: list[str] | None = None):
128
  _cmd_report(args)
129
  elif args.command == "aggregate":
130
  _cmd_aggregate(args)
 
 
131
  elif args.command in ("obliterate", "abliterate"):
132
  _cmd_abliterate(args)
133
 
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  def _cmd_interactive():
136
  from obliteratus.interactive import run_interactive
137
  run_interactive()
 
58
  # --- strategies ---
59
  subparsers.add_parser("strategies", help="List available ablation strategies")
60
 
61
+ # --- ui ---
62
+ ui_parser = subparsers.add_parser(
63
+ "ui",
64
+ help="Launch the Gradio web UI locally (same UI as the HuggingFace Space)",
65
+ )
66
+ ui_parser.add_argument(
67
+ "--port", type=int, default=7860, help="Server port (default: 7860)",
68
+ )
69
+ ui_parser.add_argument(
70
+ "--host", type=str, default="0.0.0.0", help="Server host (default: 0.0.0.0)",
71
+ )
72
+ ui_parser.add_argument(
73
+ "--share", action="store_true", help="Create a public Gradio share link",
74
+ )
75
+ ui_parser.add_argument(
76
+ "--no-browser", action="store_true", help="Don't auto-open browser on launch",
77
+ )
78
+ ui_parser.add_argument(
79
+ "--auth", type=str, default=None,
80
+ help="Basic auth as user:pass",
81
+ )
82
+ ui_parser.add_argument(
83
+ "--quiet", action="store_true", help="Suppress the startup banner",
84
+ )
85
+
86
  # --- obliterate (primary) + abliterate (backward-compat alias) ---
87
  def _add_obliterate_args(p):
88
  p.add_argument("model", type=str, help="HuggingFace model name/path")
 
153
  _cmd_report(args)
154
  elif args.command == "aggregate":
155
  _cmd_aggregate(args)
156
+ elif args.command == "ui":
157
+ _cmd_ui(args)
158
  elif args.command in ("obliterate", "abliterate"):
159
  _cmd_abliterate(args)
160
 
161
 
162
+ def _cmd_ui(args):
163
+ from obliteratus.local_ui import launch_local_ui
164
+
165
+ auth = tuple(args.auth.split(":", 1)) if args.auth else None
166
+ launch_local_ui(
167
+ host=args.host,
168
+ port=args.port,
169
+ share=args.share,
170
+ open_browser=not args.no_browser,
171
+ auth=auth,
172
+ quiet=args.quiet,
173
+ )
174
+
175
+
176
  def _cmd_interactive():
177
  from obliteratus.interactive import run_interactive
178
  run_interactive()
obliteratus/local_ui.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Local UI launcher for OBLITERATUS β€” beautiful terminal experience + Gradio web UI.
2
+
3
+ Usage:
4
+ obliteratus ui # launch with defaults
5
+ obliteratus ui --port 8080 --share # public link on custom port
6
+ obliteratus ui --no-browser # don't auto-open browser
7
+ obliteratus ui --auth user:pass # basic auth
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import os
13
+ import platform
14
+ import shutil
15
+ import sys
16
+ import time
17
+
18
+ from rich.console import Console
19
+ from rich.panel import Panel
20
+ from rich.table import Table
21
+ from rich.text import Text
22
+
23
+ console = Console()
24
+
25
+ # ── ASCII banner ────────────────────────────────────────────────────────────
26
+
27
+ _BANNER = r"""
28
+ [bold green]
29
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
30
+ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ
31
+ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
32
+ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ
33
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
34
+ [/bold green]
35
+ [dim] ╔══════════════════════════════════════════╗
36
+ β•‘ MASTER ABLATION SUITE β€” LOCAL EDITION β•‘
37
+ β•‘ Break the chains. Free the mind. β•‘
38
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•[/dim]
39
+ """
40
+
41
+
42
+ def _detect_gpu() -> list[dict]:
43
+ """Detect available GPUs and return info dicts."""
44
+ gpus = []
45
+ try:
46
+ import torch
47
+
48
+ if torch.cuda.is_available():
49
+ for i in range(torch.cuda.device_count()):
50
+ props = torch.cuda.get_device_properties(i)
51
+ gpus.append(
52
+ {
53
+ "index": i,
54
+ "name": props.name,
55
+ "vram_gb": round(props.total_mem / 1024**3, 1),
56
+ "compute": f"{props.major}.{props.minor}",
57
+ }
58
+ )
59
+ elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
60
+ gpus.append(
61
+ {
62
+ "index": 0,
63
+ "name": "Apple Silicon (MPS)",
64
+ "vram_gb": 0, # shared memory
65
+ "compute": "mps",
66
+ }
67
+ )
68
+ except ImportError:
69
+ pass
70
+ return gpus
71
+
72
+
73
+ def _get_disk_free_gb(path: str = "/") -> float:
74
+ """Return free disk space in GB."""
75
+ try:
76
+ usage = shutil.disk_usage(path)
77
+ return round(usage.free / 1024**3, 1)
78
+ except Exception:
79
+ return 0.0
80
+
81
+
82
+ def _get_ram_gb() -> float:
83
+ """Return total system RAM in GB."""
84
+ try:
85
+ import psutil
86
+
87
+ return round(psutil.virtual_memory().total / 1024**3, 1)
88
+ except ImportError:
89
+ # Fallback: read from /proc/meminfo on Linux
90
+ try:
91
+ with open("/proc/meminfo") as f:
92
+ for line in f:
93
+ if line.startswith("MemTotal:"):
94
+ kb = int(line.split()[1])
95
+ return round(kb / 1024**2, 1)
96
+ except Exception:
97
+ pass
98
+ return 0.0
99
+
100
+
101
+ def _print_system_info(gpus: list[dict]) -> None:
102
+ """Print a beautiful system info panel."""
103
+ table = Table(show_header=False, border_style="green", expand=True, padding=(0, 2))
104
+ table.add_column("Key", style="dim", width=18)
105
+ table.add_column("Value", style="cyan")
106
+
107
+ table.add_row("Platform", f"{platform.system()} {platform.release()}")
108
+ table.add_row("Python", f"{platform.python_version()}")
109
+
110
+ ram = _get_ram_gb()
111
+ if ram > 0:
112
+ table.add_row("System RAM", f"{ram} GB")
113
+
114
+ disk = _get_disk_free_gb("/tmp")
115
+ if disk > 0:
116
+ table.add_row("Disk Free (/tmp)", f"{disk} GB")
117
+
118
+ # PyTorch version
119
+ try:
120
+ import torch
121
+
122
+ table.add_row("PyTorch", torch.__version__)
123
+ except ImportError:
124
+ table.add_row("PyTorch", "[red]NOT INSTALLED[/red]")
125
+
126
+ # Transformers version
127
+ try:
128
+ import transformers
129
+
130
+ table.add_row("Transformers", transformers.__version__)
131
+ except ImportError:
132
+ table.add_row("Transformers", "[red]NOT INSTALLED[/red]")
133
+
134
+ # Gradio version
135
+ try:
136
+ import gradio
137
+
138
+ table.add_row("Gradio", gradio.__version__)
139
+ except ImportError:
140
+ table.add_row("Gradio", "[red]NOT INSTALLED[/red]")
141
+
142
+ # GPU info
143
+ if gpus:
144
+ for gpu in gpus:
145
+ vram = f"{gpu['vram_gb']} GB" if gpu["vram_gb"] > 0 else "shared"
146
+ table.add_row(
147
+ f"GPU {gpu['index']}",
148
+ f"[bold green]{gpu['name']}[/bold green] ({vram}, compute {gpu['compute']})",
149
+ )
150
+ else:
151
+ table.add_row("GPU", "[yellow]None detected β€” CPU mode[/yellow]")
152
+
153
+ # HF Token
154
+ hf_token = os.environ.get("HF_TOKEN", "")
155
+ if hf_token:
156
+ table.add_row("HF Token", f"[green]set[/green] ({hf_token[:8]}...)")
157
+ else:
158
+ table.add_row("HF Token", "[dim]not set (gated models won't work)[/dim]")
159
+
160
+ console.print(Panel(table, title="[bold green]System Info[/bold green]", border_style="green"))
161
+
162
+
163
+ def _compute_tier(gpus: list[dict]) -> str:
164
+ """Determine the compute tier based on available hardware."""
165
+ if not gpus:
166
+ return "cpu"
167
+ max_vram = max(g["vram_gb"] for g in gpus)
168
+ if max_vram >= 80:
169
+ return "frontier"
170
+ elif max_vram >= 24:
171
+ return "large"
172
+ elif max_vram >= 8:
173
+ return "medium"
174
+ elif max_vram > 0:
175
+ return "small"
176
+ else:
177
+ return "mps" # Apple Silicon
178
+
179
+
180
+ def _print_recommendations(tier: str) -> None:
181
+ """Print model recommendations based on detected hardware."""
182
+ recs = {
183
+ "cpu": [
184
+ ("distilbert/distilgpt2", "Tiny β€” 82M params, runs on anything"),
185
+ ("TinyLlama/TinyLlama-1.1B-Chat-v1.0", "Small β€” 1.1B params, workable on CPU"),
186
+ ],
187
+ "small": [
188
+ ("TinyLlama/TinyLlama-1.1B-Chat-v1.0", "1.1B β€” fits in 4GB"),
189
+ ("Qwen/Qwen2.5-0.5B-Instruct", "0.5B β€” very fast on small GPUs"),
190
+ ("Qwen/Qwen2.5-3B-Instruct", "3B β€” good quality, ~6GB VRAM"),
191
+ ],
192
+ "mps": [
193
+ ("TinyLlama/TinyLlama-1.1B-Chat-v1.0", "1.1B β€” fast on Apple Silicon"),
194
+ ("Qwen/Qwen2.5-3B-Instruct", "3B β€” good with shared memory"),
195
+ ("meta-llama/Llama-3.2-3B-Instruct", "3B β€” great quality on MPS"),
196
+ ],
197
+ "medium": [
198
+ ("Qwen/Qwen2.5-7B-Instruct", "7B β€” excellent quality at 16GB"),
199
+ ("meta-llama/Llama-3.1-8B-Instruct", "8B β€” the standard benchmark"),
200
+ ("mistralai/Mistral-7B-Instruct-v0.3", "7B β€” fast and capable"),
201
+ ],
202
+ "large": [
203
+ ("openai/gpt-oss-20b", "20B MoE β€” flagship, try surgical/nuclear"),
204
+ ("meta-llama/Llama-3.1-70B-Instruct", "70B β€” with 4bit quant"),
205
+ ("Qwen/Qwen3-30B-A3B", "30B MoE β€” only 3B active"),
206
+ ],
207
+ "frontier": [
208
+ ("deepseek-ai/DeepSeek-V3", "671B MoE β€” the frontier"),
209
+ ("meta-llama/Llama-3.1-70B-Instruct", "70B β€” full precision"),
210
+ ("Qwen/Qwen3.5-397B-A17B", "397B MoE β€” massive"),
211
+ ],
212
+ }
213
+
214
+ tier_recs = recs.get(tier, recs["cpu"])
215
+
216
+ table = Table(
217
+ title=f"Recommended Models for Your Hardware ({tier.upper()})",
218
+ border_style="green",
219
+ )
220
+ table.add_column("Model", style="cyan", min_width=40)
221
+ table.add_column("Notes", style="dim")
222
+
223
+ for model, notes in tier_recs:
224
+ table.add_row(model, notes)
225
+
226
+ console.print(table)
227
+
228
+
229
+ def _print_launch_info(
230
+ host: str,
231
+ port: int,
232
+ share: bool,
233
+ auth: tuple[str, str] | None,
234
+ ) -> None:
235
+ """Print launch configuration."""
236
+ parts = []
237
+ url = f"http://{'localhost' if host == '0.0.0.0' else host}:{port}"
238
+ parts.append(f"[bold green]Local URL:[/bold green] {url}")
239
+ if host == "0.0.0.0":
240
+ parts.append(f"[bold green]Network URL:[/bold green] http://<your-ip>:{port}")
241
+ if share:
242
+ parts.append("[bold green]Share link:[/bold green] [yellow]generating...[/yellow]")
243
+ if auth:
244
+ parts.append(f"[bold green]Auth:[/bold green] {auth[0]}:{'*' * len(auth[1])}")
245
+ parts.append("")
246
+ parts.append("[dim]Press Ctrl+C to stop the server[/dim]")
247
+
248
+ console.print(
249
+ Panel(
250
+ "\n".join(parts),
251
+ title="[bold green]Launching OBLITERATUS UI[/bold green]",
252
+ border_style="green",
253
+ )
254
+ )
255
+
256
+
257
+ def launch_local_ui(
258
+ host: str = "0.0.0.0",
259
+ port: int = 7860,
260
+ share: bool = False,
261
+ open_browser: bool = True,
262
+ auth: tuple[str, str] | None = None,
263
+ quiet: bool = False,
264
+ ) -> None:
265
+ """Launch the OBLITERATUS Gradio UI with a beautiful local experience.
266
+
267
+ This is the main entry point for ``obliteratus ui``.
268
+ """
269
+ # ── Beautiful startup ──────────────────────────────────────────────
270
+ if not quiet:
271
+ console.print(_BANNER)
272
+
273
+ gpus = _detect_gpu()
274
+ _print_system_info(gpus)
275
+ console.print()
276
+
277
+ tier = _compute_tier(gpus)
278
+ _print_recommendations(tier)
279
+ console.print()
280
+
281
+ _print_launch_info(host, port, share, auth)
282
+ console.print()
283
+
284
+ # ── Check dependencies ─────────────────────────────────────────────
285
+ try:
286
+ import gradio # noqa: F401
287
+ except ImportError:
288
+ console.print(
289
+ "[bold red]Error:[/bold red] Gradio is not installed.\n"
290
+ "Install it with: [cyan]pip install -e '.[spaces]'[/cyan]\n"
291
+ "Or: [cyan]pip install gradio>=5.0[/cyan]"
292
+ )
293
+ sys.exit(1)
294
+
295
+ # ── Import and launch the app ──────────────────────────────────────
296
+ console.print("[dim]Loading OBLITERATUS UI (this may take a moment on first run)...[/dim]")
297
+ start = time.time()
298
+
299
+ from app import demo, launch as app_launch
300
+
301
+ elapsed = time.time() - start
302
+ if not quiet:
303
+ console.print(f"[green]UI loaded in {elapsed:.1f}s[/green]")
304
+ console.print()
305
+
306
+ app_launch(
307
+ server_name=host,
308
+ server_port=port,
309
+ share=share,
310
+ inbrowser=open_browser,
311
+ auth=auth,
312
+ quiet=quiet,
313
+ )
obliteratus/presets.py CHANGED
@@ -208,6 +208,39 @@ _PRESETS_LIST = [
208
  recommended_dtype="bfloat16",
209
  recommended_quantization="4bit",
210
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  ModelPreset(
212
  name="Qwen3.5 397B-A17B",
213
  hf_id="Qwen/Qwen3.5-397B-A17B",
 
208
  recommended_dtype="bfloat16",
209
  recommended_quantization="4bit",
210
  ),
211
+ ModelPreset(
212
+ name="Qwen3.5-0.8B",
213
+ hf_id="Qwen/Qwen3.5-0.8B",
214
+ description="Qwen3.5 0.8B β€” Gated DeltaNet hybrid attention, 262K ctx. Non-thinking mode. Apache 2.0.",
215
+ tier="tiny",
216
+ params="0.8B",
217
+ recommended_dtype="float16",
218
+ ),
219
+ ModelPreset(
220
+ name="Qwen3.5-2B",
221
+ hf_id="Qwen/Qwen3.5-2B",
222
+ description="Qwen3.5 2B β€” Gated DeltaNet hybrid attention, 262K ctx, think/non-think modes. Apache 2.0.",
223
+ tier="small",
224
+ params="2B",
225
+ recommended_dtype="float16",
226
+ ),
227
+ ModelPreset(
228
+ name="Qwen3.5-4B",
229
+ hf_id="Qwen/Qwen3.5-4B",
230
+ description="Qwen3.5 4B β€” natively multimodal, 262K ctx, think/non-think modes. Apache 2.0.",
231
+ tier="small",
232
+ params="4B",
233
+ recommended_dtype="float16",
234
+ ),
235
+ ModelPreset(
236
+ name="Qwen3.5-9B",
237
+ hf_id="Qwen/Qwen3.5-9B",
238
+ description="Qwen3.5 9B β€” natively multimodal, 262K ctx (1M extended), think/non-think modes. Apache 2.0.",
239
+ tier="medium",
240
+ params="9B",
241
+ recommended_dtype="float16",
242
+ recommended_quantization="4bit",
243
+ ),
244
  ModelPreset(
245
  name="Qwen3.5 397B-A17B",
246
  hf_id="Qwen/Qwen3.5-397B-A17B",
spaces/README.md CHANGED
@@ -33,16 +33,21 @@ One-click cognitive liberation for language models, with a built-in chat playgro
33
  7. **Leaderboard tab**: Community benchmark rankings
34
  8. **About tab**: Methods, novel techniques, and references
35
 
36
- ## Deploy your own
37
 
38
  ```bash
39
  git clone https://github.com/obliteratus-project/OBLITERATUS
40
  cd OBLITERATUS
41
  pip install -e ".[spaces]"
 
 
 
 
 
42
  python app.py
43
  ```
44
 
45
- Then open http://localhost:7860
46
 
47
  ## Or deploy on HuggingFace Spaces
48
 
 
33
  7. **Leaderboard tab**: Community benchmark rankings
34
  8. **About tab**: Methods, novel techniques, and references
35
 
36
+ ## Run locally (same UI, your own GPU)
37
 
38
  ```bash
39
  git clone https://github.com/obliteratus-project/OBLITERATUS
40
  cd OBLITERATUS
41
  pip install -e ".[spaces]"
42
+
43
+ # Beautiful launcher with GPU detection + model recommendations
44
+ obliteratus ui
45
+
46
+ # Or run directly
47
  python app.py
48
  ```
49
 
50
+ The `obliteratus ui` command auto-detects your GPU, prints hardware-specific model recommendations, and opens the browser automatically. Supports `--share` for public links, `--port` for custom ports, and `--auth user:pass` for access control.
51
 
52
  ## Or deploy on HuggingFace Spaces
53