Download app.py from morriszjm/anyjev: direct link, hf CLI and curl.
- Browser
- Download file 5.37 kB
-
https://huggingface.co/spaces/morriszjm/anyjev/resolve/main/app.py
- Command line
-
hf download hf://spaces/morriszjm/anyjev/app.py
-
curl -L -o app.py https://huggingface.co/spaces/morriszjm/anyjev/resolve/main/app.py
5.37 kB
| """Hugging Face Space entry point. Reorder the options, watch raw readout flip and AnyJev hold still. | |
| pip install gradio | |
| python space/app.py --model Qwen/Qwen3-8B | |
| One model, one state, one choice question. Left: raw next-token readout with | |
| the options in the order you typed them and in reverse. Right: AnyJev L0 on | |
| the same two orders. The bars that move are the bug; the bars that do not | |
| are the fix. | |
| The model default follows the hardware. L0 runs one prefill per cyclic shift, | |
| so a four-option question costs four prefills per order and the page renders | |
| two orders. On a CPU Space that is eight prefills per click, which is why the | |
| CPU default is the 0.6B model that the maze benchmark already reports. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import os | |
| from anyjev import Decider | |
| from anyjev.question import Question | |
| # ZeroGPU attaches a GPU only while a decorated function runs, so the decorator | |
| # has to wrap the inference call. The environment variable is the reliable | |
| # signal: torch sees no CUDA device at startup on ZeroGPU, so probing for one | |
| # would pick the CPU path and load the small model on an A10G. The import is | |
| # guarded broadly because a failure here must not take the Space down, and | |
| # without it the decorator becomes a no-op on ordinary hardware. | |
| ZERO_GPU = os.environ.get("SPACES_ZERO_GPU", "").lower() in ("1", "true", "yes") | |
| try: # pragma: no cover - depends on the hosting environment | |
| import spaces | |
| def on_gpu(fn): | |
| return spaces.GPU(duration=120)(fn) | |
| except Exception as exc: # pragma: no cover | |
| if ZERO_GPU: | |
| print(f"[anyjev] ZeroGPU requested but 'spaces' is unusable: {exc!r}") | |
| ZERO_GPU = False | |
| def on_gpu(fn): | |
| return fn | |
| GPU_MODEL = "Qwen/Qwen3-8B" | |
| CPU_MODEL = "Qwen/Qwen3-0.6B" | |
| DEFAULT_STATE = ( | |
| "Customer message: Hi, I was charged twice for order #4471 last Tuesday. " | |
| "The app also crashes every time I open the receipts page. Can someone help?" | |
| ) | |
| DEFAULT_OPTIONS = "billing\ntechnical\nsales\nother" | |
| DEFAULT_QUESTION = "Which team should handle this message?" | |
| def build(decider: Decider, model_name: str, device: str): | |
| import gradio as gr | |
| def run(state, question, options_text): | |
| opts = [o.strip() for o in options_text.splitlines() if o.strip()] | |
| if len(opts) < 2: | |
| return {}, {}, {}, {}, "need at least two options" | |
| q = Question.choice(question, opts, name="q") | |
| qr = Question(q.kind, q.text, tuple(reversed(opts)), "q", q.scale, q.ordered) | |
| a = decider.decide(state, [q])["q"] | |
| b = decider.decide(state, [qr])["q"] | |
| raw_a = dict(zip(opts, map(float, a.diagnostics["raw_probs"]))) | |
| raw_b = dict(zip(reversed(opts), map(float, b.diagnostics["raw_probs"]))) | |
| l0_a = a.distribution | |
| l0_b = b.distribution | |
| flip_raw = max(raw_a, key=raw_a.get) != max(raw_b, key=raw_b.get) | |
| flip_l0 = max(l0_a, key=l0_a.get) != max(l0_b, key=l0_b.get) | |
| msg = (f"raw: {'FLIPPED' if flip_raw else 'same answer'} when options reversed | " | |
| f"AnyJev L0: {'flipped' if flip_l0 else 'same answer'} | " | |
| f"label-token mass {a.diagnostics['answer_mass']:.3f} | level {a.level}") | |
| return raw_a, raw_b, l0_a, l0_b, msg | |
| with gr.Blocks(title="AnyJev: reorder the options") as demo: | |
| gr.Markdown("# Reorder the options. Watch raw logit readout flip. Watch AnyJev not.") | |
| gr.Markdown( | |
| f"Running `{model_name}` on {device}. Reverse the option list and click again. " | |
| "The raw readout is what every logit-reading clone does. " | |
| "[Library and benchmark](https://github.com/MorrisZJ/AnyJev)." | |
| ) | |
| with gr.Row(): | |
| state = gr.Textbox(DEFAULT_STATE, label="state", lines=4) | |
| with gr.Column(): | |
| question = gr.Textbox(DEFAULT_QUESTION, label="question") | |
| options = gr.Textbox(DEFAULT_OPTIONS, label="options, one per line", lines=4) | |
| btn = gr.Button("decide (original order and reversed order)") | |
| with gr.Row(): | |
| r1 = gr.Label(label="raw, options as typed") | |
| r2 = gr.Label(label="raw, options reversed") | |
| with gr.Row(): | |
| l1 = gr.Label(label="AnyJev L0, options as typed") | |
| l2 = gr.Label(label="AnyJev L0, options reversed") | |
| msg = gr.Markdown() | |
| btn.click(run, [state, question, options], [r1, r2, l1, l2, msg]) | |
| return demo | |
| def main(): | |
| import torch | |
| from anyjev.backends.hf import HFBackend | |
| # On ZeroGPU the GPU is present for decorated calls even though the process | |
| # starts without one, so trust the package rather than probing for CUDA. | |
| if ZERO_GPU: | |
| device = "cuda" | |
| else: | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--model", default=os.environ.get( | |
| "MODEL", GPU_MODEL if device == "cuda" else CPU_MODEL)) | |
| ap.add_argument("--port", type=int, default=int(os.environ.get("PORT", "7860"))) | |
| args = ap.parse_args() | |
| dtype = "bfloat16" if device == "cuda" else "float32" | |
| decider = Decider(HFBackend(args.model, device=device, dtype=dtype, batch_size=8)) | |
| build(decider, args.model, device).launch(server_name="0.0.0.0", server_port=args.port) | |
| if __name__ == "__main__": | |
| main() | |