Enterprise DNA

Omni by Enterprise DNA

Enterprise DNA Resources

Step-by-step how-tos. Practical AI operating-system thinking for owners, operators, and teams doing real work.

220k+

Data professionals

Omni

AI agents and apps

Audit

Map the manual work

Guide Intermediate General

Gradio tutorial: build working AI demos step by step

Hands-on Gradio tutorial covering a first working demo, the launch parameters most people ignore, and a realistic team workflow for hosting prototypes.

Sam McKay |
Gradio tutorial: build working AI demos step by step

What Gradio actually is

Gradio is a Python library that wraps a callable function, usually one that runs a machine learning model, inside a web UI without you writing any HTML, CSS, or JavaScript. Under the hood it spins up a FastAPI backend, serves a pre-built Svelte frontend, and uses websockets to stream inputs and outputs back and forth between the browser and your Python process.

It is not a no-code platform. You write Python, you import the library, you define inputs and outputs, you call launch(), and a browser tab opens at http://127.0.0.1:7860. That port, 7860, was picked deliberately because the digits spell “gradi” on a phone keypad, which tells you something about who the original authors had in mind as the typical user. Local server mode is the canonical way most people work with the tool.

When you pass share=True to launch(), Gradio’s CLI provisions a temporary public URL through a reverse tunnel, typically valid for about 72 hours. This is the mechanism behind most of the demo links you see shared on social media or in private messages. It is not a hosting product, it is a sharing affordance.

Two APIs matter in the current version. gr.Interface wraps a single function with a fixed set of inputs and outputs and is enough for roughly 80 percent of demos. gr.Blocks is the lower-level builder for assembling richer layouts with multiple components, persistent state, and chained event handlers. Everything you build starts as a local Python script. Hosting is your problem.

Setup and authentication

The fastest path requires Python 3.10 or later and pip.

Open a terminal, create a fresh virtual environment, and run pip install gradio. The current version pulls in FastAPI, Uvicorn, Starlette, Jinja2, and a bundle of frontend assets. Expect the install to take roughly a minute on a typical laptop. There is no first-run login, no telemetry prompt blocking startup, and no required account.

Authentication is local and optional. If you pass auth=(“username”, “password”) to launch(), Gradio prompts visitors in the browser for credentials before the UI loads. For finer control, auth_dependency lets you plug in a FastAPI dependency that runs on every request, so you can read JWTs, check API keys, or hit an internal identity service.

For Hugging Face hosted Spaces, authentication is handled through the HF Hub token, set with huggingface-cli login. You push a git repo, the platform builds it, and the demo runs inside Hugging Face infrastructure. From inside your code, this looks like any other git remote.

If your function calls external APIs such as OpenAI, Anthropic, or internal models, those credentials live in environment variables. The library does not ship a secrets manager, so you wire that yourself with python-dotenv or os.environ before you import the app module.

First working example

Save the following as app.py and run python app.py.

The script imports gradio, defines a function that takes a string and returns a shorter string, then declares an Interface with one input Textbox and one output Textbox. The launch() call starts the server. When you paste a long paragraph into the left box and click Submit, the right box fills with the summary. The function body can be anything callable, so you can drop in a transformers pipeline, a call to an internal LLM endpoint, or a hand-written heuristic for testing.

Here is a minimal, runnable text summarizer demo:

import gradio as gr

def summarize(text: str) -> str:
    sentences = text.split(". ")
    if len(sentences) <= 3:
        return text
    return ". ".join(sentences[:3]) + "."

demo = gr.Interface(
    fn=summarize,
    inputs=gr.Textbox(lines=10, label="Paste text"),
    outputs=gr.Textbox(lines=5, label="Summary"),
    title="Quick Summarizer",
)

demo.launch()

For something more visual, swap the function for an image classifier using a transformers pipeline. Pass that pipeline object straight into Interface and the library will figure out the component types from the function signature and return annotation. If the function returns a dict of labels and confidences, Gradio automatically renders a bar chart next to the image with no extra work from you.

The Blocks API works differently. You instantiate gr.Blocks(), enter the context with a with block, declare components inside it, wire up event handlers with the .click() method, and launch from inside the context. This is where you build tabs, sidebars, galleries, and chat interfaces. A chat-style demo runs roughly fifty lines of code: a Chatbot component, a Textbox for input, a Button, and a respond function that appends to the message history and returns the updated list.

Key settings that matter

Most people ignore the launch() parameters and end up with a demo that dies the moment they close the terminal. Here are the ones that bite.

server_name defaults to “127.0.0.1”, meaning the server only listens on your loopback interface. Set it to “0.0.0.0” if you want other devices on your LAN to reach the demo, which matters when you test on a phone or hand the laptop to a colleague at the desk next to you. server_port lets you pin a specific port, useful when you run multiple Gradio apps and need predictable URLs across services.

queue() should be called before launch() whenever your function takes more than a couple of seconds. Without it, only one request can be in flight at a time and the UI locks up. With it, requests go through a worker pool and you get the live progress bar component automatically. Concurrency is configurable through the queue() arguments, with sensible defaults for the current version.

show_error=True is the default and prints Python tracebacks in the browser when something blows up. That is invaluable during development and noisy in front of stakeholders. Flip it off before a client demo and keep your errors in the server logs instead.

flagging lets users click a button on any example and save the input plus the output to disk or to a Hugging Face dataset. Disable it when inputs contain anything sensitive, because the default is to write to a flagged folder inside the working directory.

theme and css affect appearance more than people expect. theme=gr.themes.Soft() gives you a clean light-mode UI, gr.themes.Glass() for a darker look. css accepts a chunk of CSS that gets injected into the page, which is how you resize components, hide the footer, or match brand colors. For Blocks, the height and width kwargs on each component are how you stop demos from looking like raw prototypes. The default component heights are tuned for short text, so a long-form document summarizer almost always needs a Textbox(lines=20) override.

Where it shines

Internal stakeholder demos. You can stand up a working prototype of an internal LLM tool in an afternoon, host it on a company-controlled Hugging Face Space, and drop the link in a Slack thread before the next standup. The friction between “I have a Python function” and “someone else can click on it” is the lowest of any tool in this space.

Model evaluation harnesses. Because flagging saves the inputs that produce outputs, data scientists can route real users through a model, collect the hard cases, and add them to a held-out test set. The flagged folder writes a CSV by default and parses cleanly into any dataframe workflow.

Documentation supplements. Gradio apps embedded in docs sites via the embed option in launch, or via Spaces iframes