Build ML Demos with Gradio in Python (2026)

Llm And Generative Ai Sep 29, 2026

Watch on YouTube

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 tested 6.28.0 on Python 3.13.5).
  • Textbox + Slider inputs, Textbox output — Submit calls your fn over SSE.
  • Real API: POST /gradio_api/call/predict then poll the event_id for 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.

ToolBest forYou write
GradioML / LLM demos, SpacesInterface / Blocks around fn
NiceGUIDashboards, Quasar widgetsPython widgets + events
FastAPI + SPAProduct UIs with FE teamAPI + separate JS/TS app

Versions tested (2026-09-29)

  • Python 3.13.5
  • gradio 6.28.0
  • fastapi 0.141.1, uvicorn 0.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. Use Blocks only when you need multi-step layouts, tabs, or custom event wiring.
  • Keep fn pure. Side effects belong behind a queue or background worker so the UI stays responsive.
  • Share carefully. share=True creates 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 fn freezes 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/predict alone).
  • Forgetting types. Slider values arrive as float; cast when your model expects int.
  • Opening ports widely. Pin server_name='127.0.0.1' unless you intend LAN/remote access.

What to do next

  1. Run the demo: pip install gradio && python app.py.
  2. Replace summarize_scores with a real model or an Instructor/DSPy pipeline.
  3. Add examples=[...] so visitors can one-click sample inputs.
  4. Try gr.ChatInterface when the demo is a chatbot instead of a form.
  5. 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.

Share:
Last updated: September 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices