Build ML Demos with Gradio in Python (2026)
Build ML Demos with Gradio in Python (2026) shows how to wrap any prediction function in a browser UI with a few lines of Python. Gradio’s Interface maps inputs and outputs to widgets, serves a FastAPI app, and exposes a typed API under /gradio_api — ideal for model demos, LLM playgrounds, and shareable prototypes without a JavaScript build.
If you already use Instructor for structured LLM outputs or DSPy to optimize LLM pipelines, Gradio is how you put those functions in front of humans. For Quasar-style dashboards instead of model demos, see our NiceGUI web UI tutorial.
TL;DR
- Gradio turns a Python function into an interactive ML demo UI (
gr.Interface). - Install with
pip install gradio(we tested6.28.0on Python 3.13.5). - Textbox + Slider inputs, Textbox output — Submit calls your
fnover SSE. - Real API:
POST /gradio_api/call/predictthen poll theevent_idfor results. - Prefer Gradio for model/LLM demos; prefer NiceGUI/FastHTML for dashboards and HTML-first pages.
Why Gradio in 2026?
Machine-learning work only sticks when non-engineers can try it. Gradio remains the default for Hugging Face Spaces and local model sandboxes: you keep writing Python, Gradio ships the UI, queue, and client SDK. Version 6.x keeps the familiar Interface / Blocks APIs while tightening the /gradio_api surface.
| Tool | Best for | You write |
|---|---|---|
| Gradio | ML / LLM demos, Spaces | Interface / Blocks around fn |
| NiceGUI | Dashboards, Quasar widgets | Python widgets + events |
| FastAPI + SPA | Product UIs with FE team | API + separate JS/TS app |
Versions tested (2026-09-29)
- Python
3.13.5 gradio6.28.0- fastapi
0.141.1, uvicorn0.54.0 - Demo server:
http://127.0.0.1:7860
python -m venv .venv && source .venv/bin/activate
pip install gradio
python app.py
# Running on http://127.0.0.1:7860
1. Minimal Interface demo
Save this as app.py. A toy “scorer” stands in for a real model: it counts words at least threshold characters long. Swap summarize_scores for your model’s predict later — the UI stays the same.
import gradio as gr
def summarize_scores(text: str, threshold: float) -> str:
words = [w.strip(".,!?;:\"'()[]") for w in text.split() if w.strip()]
if not words:
return "No words to score."
hits = [w for w in words if len(w) >= threshold]
miss = [w for w in words if len(w) < threshold]
pct = 100.0 * len(hits) / len(words)
return (
f"words={len(words)} threshold={int(threshold)}+\n"
f"long_hits={len(hits)} ({pct:.1f}%)\n"
f"short={len(miss)}\n"
f"hits: {', '.join(hits) if hits else '(none)'}"
)
demo = gr.Interface(
fn=summarize_scores,
inputs=[
gr.Textbox(lines=3, label="Input text",
value="Gradio turns any Python function into a shareable ML demo UI."),
gr.Slider(1, 12, value=5, step=1, label="Min word length"),
],
outputs=gr.Textbox(label="Score summary", lines=5),
title="Gradio Word-Length Scorer",
description="Toy ML-demo pattern: wrap a Python function with Interface — no JS.",
flagging_mode="never",
api_name="predict",
)
demo.launch(server_name="127.0.0.1", server_port=7860, share=False)
api_name="predict" publishes /predict on the Gradio API. flagging_mode="never" hides the flag button for demos that should not write flagged CSV rows.
2. Real output from the running app
We launched the app and probed it with curl. Home returned HTTP 200 with Gradio 6.28.0 assets; /config listed our textbox, slider, Submit/Clear buttons, and Score summary; the predict endpoint returned the scored lines:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:7860/
# 200
curl -s http://127.0.0.1:7860/config | python -c \
"import sys,json; d=json.load(sys.stdin); print(d['title'], d['version'])"
# Gradio Word-Length Scorer 6.28.0
# Gradio 6 call + poll pattern:
curl -s -X POST http://127.0.0.1:7860/gradio_api/call/predict \
-H 'Content-Type: application/json' \
-d '{"data":["Gradio turns any Python function into a shareable ML demo UI.", 5]}'
# {"event_id":"..."}
# then GET /gradio_api/call/predict/{event_id} →
# event: complete
# data: ["words=11 threshold=5+\nlong_hits=5 (45.5%)\nshort=6\nhits: Gradio, turns, Python, function, shareable"]
HTTP 200 · title Gradio Word-Length Scorer · gradio 6.28.0
components: textbox, slider, Submit, Clear, Score summary
predict → words=11 long_hits=5 (45.5%)
hits: Gradio, turns, Python, function, shareable
3. Practical tips
- Start with
Interface. UseBlocksonly when you need multi-step layouts, tabs, or custom event wiring. - Keep
fnpure. Side effects belong behind a queue or background worker so the UI stays responsive. - Share carefully.
share=Truecreates a temporary public tunnel — fine for demos, not for secrets or PII. - Client SDK.
gradio_client.Client("http://127.0.0.1:7860").predict(...)mirrors what Spaces and other apps call. - When to prefer Gradio vs NiceGUI. Choose Gradio for model/LLM demos and Spaces. Choose NiceGUI for Quasar dashboards — see the NiceGUI guide.
Common pitfalls
- Blocking the event loop. Heavy inference in
fnfreezes the queue. Offload GPU work or use generators for streaming. - Wrong API path. Gradio 6 uses
/gradio_api/call/{api_name}(not the older/api/predictalone). - Forgetting types. Slider values arrive as
float; cast when your model expectsint. - Opening ports widely. Pin
server_name='127.0.0.1'unless you intend LAN/remote access.
What to do next
- Run the demo:
pip install gradio && python app.py. - Replace
summarize_scoreswith a real model or an Instructor/DSPy pipeline. - Add
examples=[...]so visitors can one-click sample inputs. - Try
gr.ChatInterfacewhen the demo is a chatbot instead of a form. - Deploy to Hugging Face Spaces or keep it local behind your own reverse proxy.
Gradio will not replace every product frontend — and it does not try to. For interactive ML and LLM demos in 2026, wrapping your Python function with gr.Interface is still the shortest path from notebook to clickable UI.