Spaces:
Paused
Paused
Upload 128 files
Browse files- README.md +20 -7
- app.py +45 -2
- obliteratus/cli.py +41 -0
- obliteratus/local_ui.py +313 -0
- obliteratus/presets.py +33 -0
- 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 (
|
| 104 |
|
| 105 |
-
The
|
| 106 |
|
| 107 |
```bash
|
| 108 |
-
# Run locally
|
| 109 |
pip install -e ".[spaces]"
|
| 110 |
-
|
| 111 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
```
|
| 113 |
|
| 114 |
-
|
|
|
|
|
|
|
| 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
|
| 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 |
-
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
##
|
| 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 |
-
|
| 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 |
|