"""Gradio demo for the simplifier. Loads the base model plus the published LoRA adapter from the Hub. Set MODEL_ID in the Space settings to point at a different adapter. """ import difflib import html import os import gradio as gr import spaces import torch from peft import PeftModel from transformers import AutoModelForCausalLM, AutoTokenizer BASE_ID = os.environ.get("BASE_ID", "Qwen/Qwen3-8B") MODEL_ID = os.environ.get("MODEL_ID", "NikhilVerma/qwen3-8b-simplifier") SYSTEM = open(os.path.join(os.path.dirname(__file__), "system.md")).read().strip() # ZeroGPU: weights must load on CPU at import; .to("cuda") is intercepted by `spaces`. tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) model = AutoModelForCausalLM.from_pretrained(BASE_ID, torch_dtype=torch.bfloat16) model = PeftModel.from_pretrained(model, MODEL_ID, torch_device="cpu") model.to("cuda") EXAMPLE = """Vexwright 3.0 — Reimagining How Developers Orchestrate Their Workflows We're thrilled to announce the release of Vexwright 3.0, a truly game-changing update that will elevate your development workflow to entirely new heights. This isn't just an incremental update — it's a complete reimagining of what task orchestration can be. First up, our brand-new parallel execution engine. Significant improvements have been made to the scheduler, delivering pipelines that are 2x faster than before. It's not just faster, it's smarter, it's more reliable, and it's incredibly efficient. Additionally, we've introduced seamless cloud sync, letting you leverage remote runners without a single line of configuration. The result? Pure productivity. Furthermore, Vexwright 3.0 unlocks a robust new plugin API that supercharges extensibility. While the surface area is small, it's also absolutely powerful — developers everywhere agree this is the most flexible plugin system ever built for a task runner. We invite you to delve into the documentation and discover what's possible. **Migration note:** Configuration has been migrated to the new `vexwright.config.mjs` format. Legacy `.vexwrightrc` files are still supported, they will be removed in 4.0. Run `vexwright migrate` to upgrade automatically. Ready to unlock a faster, smarter, and more delightful workflow? Download Vexwright 3.0 today at vexwright.example.dev, and join us on this incredible journey.""" def degenerate(source: str, text: str) -> str | None: """The failure modes worth catching before a visitor sees them: empty output, a repetition loop, or a rewrite that ballooned.""" if not text: return "The model returned nothing. Try again, or lower the temperature." words = text.split() if len(words) >= 40: grams = [" ".join(words[i:i + 6]) for i in range(len(words) - 5)] top = max(grams.count(g) for g in set(grams)) if top >= 4: return "The model got stuck repeating itself. Run it again." if len(words) > 2 * max(1, len(source.split())): return "The rewrite came back much longer than the input, which usually means it went off track. Run it again." return None @spaces.GPU(duration=120) def simplify(document: str, temperature: float) -> tuple[str, str]: document = document.strip() if not document: return "", "" doc_tokens = len(tokenizer(document)["input_ids"]) if doc_tokens > 3000: return "", ( "
This input is too long for the demo. The model was " "trained on documents of 120\u2013900 words; please paste a section at a time.
" ) # An edit keeps roughly the source length, so budget the output from the # input instead of a flat cap that silently cuts long documents mid-sentence. max_new = min(4096, int(doc_tokens * 1.5) + 256) prompt = tokenizer.apply_chat_template( [ {"role": "system", "content": SYSTEM}, {"role": "user", "content": f"Simplify this:\n\n{document}"}, ], tokenize=False, add_generation_prompt=True, enable_thinking=False, ) inputs = tokenizer(prompt, return_tensors="pt").to(model.device) with torch.no_grad(): out = model.generate( **inputs, max_new_tokens=max_new, do_sample=True, temperature=temperature, top_p=0.8, top_k=20, pad_token_id=tokenizer.eos_token_id, ) new_tokens = out[0][inputs["input_ids"].shape[1]:] text = tokenizer.decode(new_tokens, skip_special_tokens=True).strip() if len(new_tokens) >= max_new: return text, ( "The rewrite hit the output limit and is cut off at the end. " "Paste a shorter section, or split the document.
" ) problem = degenerate(document, text) if problem: return "", f"{problem}
" return text, report(document, text) def report(source: str, rewrite: str) -> str: """Word counts plus an inline diff: what was cut, what replaced it. The point of the tool is that meaning survives, so show exactly what moved.""" src_words, out_words = len(source.split()), len(rewrite.split()) delta = (out_words - src_words) / max(1, src_words) sm = difflib.SequenceMatcher(None, source.split(), rewrite.split()) parts = [] for op, i1, i2, j1, j2 in sm.get_opcodes(): a = html.escape(" ".join(source.split()[i1:i2])) b = html.escape(" ".join(rewrite.split()[j1:j2])) if op == "equal": parts.append(a) else: if a: parts.append( f'{src_words} words in, {out_words} out ({delta:+.0%})
" f'{" ".join(parts)}
' ) with gr.Blocks(title="Simplifier") as demo: gr.Markdown( "# Simplifier\n" "Paste a pull-request description, a release note, or a README section. " "It comes back said plainly, with every fact, number, and code span intact." ) with gr.Row(): source = gr.Textbox(label="Your text", lines=18, value=EXAMPLE) output = gr.Textbox(label="Simplified", lines=18, show_copy_button=True) temperature = gr.Slider(0.1, 1.0, value=0.7, step=0.05, label="Temperature") run = gr.Button("Simplify", variant="primary") detail = gr.HTML() run.click(simplify, inputs=[source, temperature], outputs=[output, detail]) demo.queue().launch()