Introduction To Blocks

Gradio is a Python library that allows you to quickly build web-based machine learning demos, data science dashboards, or other kinds of web apps, entirely in Python. These web apps can be launched from wherever you use Python (jupyter notebooks, colab notebooks, Python terminal, etc.) and shared with anyone instantly using Gradio's auto-generated share links.

To offer both simplicity and more powerful and flexible control for advanced web apps, Gradio offers two different APIs to users:

  • gradio.Interface: a high-level API that allows you to create a full machine learning demo simply by providing a list of inputs and outputs.

  • 🧱 gradio.Blocks: a low-level API that allows you to have full control over the data flows and layout of your application. You can build very complex, multi-step applications using Blocks (as in "building blocks").

This Guide will teach you the Blocks API and we will create several custom web apps in the process. It will be helpful but not necessary to be familiar with the Interface API before you read this tutorial.

Why Blocks 🧱?

If you have already used gradio.Interface, you know that you can easily create fully-fledged machine learning demos with just a few lines of code. The Interface API is very convenient but in some cases may not be sufficiently flexible for your needs. For example, you might want to:

  • Group together related demos as multiple tabs in one web app
  • Change the layout of your demo instead of just having all of the inputs on the left and outputs on the right
  • Have multi-step interfaces, in which the output of one model becomes the input to the next model, or have more flexible data flows in general
  • Change a component's properties (for example, the choices in a Dropdown) or its visibilty based on user input

These are all use cases where you should use the Blocks API!

"Hello World" with Blocks

After you have installed Gradio, run the code below as a Python script or in a Python notebook (or in a colab notebook)

import gradio as gr

def update(name):
    return f"Welcome to Gradio, {name}!"

demo = gr.Blocks()

with demo:
    gr.Markdown(
    """
    # Hello World!
    Start typing below to see the output.
    """)
    inp = gr.Textbox(placeholder="What is your name?")
    out = gr.Textbox()

    inp.change(fn=update, 
               inputs=inp, 
               outputs=out)

demo.launch()

The interface below will appear automatically within the Python notebook, or pop in a browser on http://localhost:7860 if running from a script.

Understanding this Example

This simple example introduces 5 concepts that underlie Blocks:

  1. Blocks allow you to build web applications that combine markdown, HTML, buttons, and interactive components simply by instantiating objects in Python inside of a "with gradio.Blocks" context. The order in which you instantiate components matters as each element gets rendered into the web app in the order it was created. (More complex layouts are discussed below)

  2. You can define regular Python functions anywhere in your code and run them with user input using BLocks. In our example, we have a simple function that adds a welcome message before a user's name, but you can write any Python function, from a simple calculation to large machine learning model's inference.

  3. You can assign events to any Blocks component. This will run your function when the component is clicked/changed/etc. When you assign an event, you pass in three parameters: fn: the function that should be called, inputs: the (list) of input component(s), and outputs: the (list) of output components that should be called.

    In this example, we run the update() function when the value in the Textbox named inp changes. The event reads the value in inp, passes it as the name parameter to update(), which then returns a value that gets assigned to our second Textbox named out.

    To see a list of events that each component supports, see the documentation.

  4. Blocks automatically figures out whether a component should be interactive (accept user input) or not, based on the event triggers you define. In our example, the first textbox is interactive, since its value is used by the update() function. The second textbox is not interactive, since its value is never used as an input. In some cases, you might want to override this, which you can do by passing the appropriate boolean to interactive, a parameter that every component accepts.

  5. You can write and launch() your Blocks anywhere: jupyter notebooks, colab notebooks, or regular Python IDEs since Gradio uses the standard Python interpreter. You can also share Blocks with other people by setting a single parameter: launch(share=True), which we will discuss towards the end of this guide.

Layouts

By default, Blocks renders the components that you create vertically in one column. You can change that by creating additional columns (with gradio.Column():) or rows (with gradio.Row():) and creating components within those contexts.

Here's what you should keep in mind: any components created under a Column (this is also the default) will be laid out vertically. Any component created under a Row will be laid out horizontally, similar to the flexbox model in web development.

Finally, you can also create a with gradio.Tabs(): and within it create multiple with gradio.TabItem(name_of_tab): children. Any component created inside of a with gradio.TabItem(name_of_tab): context appears in that tab.

Here is a example with tabs, rows, and columns:

import numpy as np
import gradio as gr

demo = gr.Blocks()

def flip_text(x):
    return x[::-1]

def flip_image(x):
    return np.fliplr(x)

with demo:
    gr.Markdown("Flip text or image files using this demo.")
    with gr.Tabs():
        with gr.TabItem("Flip Text"):
            text_input = gr.Textbox()
            text_output = gr.Textbox()
            text_button = gr.Button("Flip")
        with gr.TabItem("Flip Image"):
            with gr.Row():
                image_input = gr.Image()
                image_output = gr.Image()
            image_button = gr.Button("Flip")

    text_button.click(flip_text, inputs=text_input, outputs=text_output)
    image_button.click(flip_image, inputs=image_input, outputs=image_output)

demo.launch()

You'll notice that in this example, we've also created a Button component in each tab, and we've assigned a click event to each button, which is what actually runs the function. So let's talk more about events...

Events

Just as you can control the layout, Blocks gives you fine-grained control over what events trigger function calls. Each component and many layouts have specific events that they support.

For example, the Textbox component has 2 events: change() (when the value inside of the textbox changes), and submit() (when a user presses the enter key while focused on the textbox). More complex components can have even more events: for example, the Audio component also has separate events for when the audio file is played, cleared, paused, etc. See the documentation for the events each component supports.

You can attach event trigger to none, one, or more of these events. You create an event trigger by calling the name of the event on the component instance as a function -- e.g. textbox.change(...) or btn.click(...). The function takes in three parameters, as discussed above:

  • fn: the function to run
  • inputs: a (list of) component(s) whose values should supplied as the input parameters to the function. Each component's value gets mapped to the corresponding function parameter, in order. This parameter can be None if the function does not take any parameters.
  • outputs: a (list of) component(s) whose values should be updated based on the values returned by the function. Each return value gets sets the corresponding component's value, in order. This parameter can be None if the function does not return anything.

You can even make the input and output component be the same component, as we do in this example that uses a GPT model to do text completion:

import gradio as gr

api = gr.Interface.load("huggingface/EleutherAI/gpt-j-6B")

def complete_with_gpt(text):
    # Use the last 50 characters of the text as context
    return text[:-50] + api(text[-50:])

with gr.Blocks() as demo:
    textbox = gr.Textbox(placeholder="Type here and press enter...", lines=4)
    btn = gr.Button("Generate")

    btn.click(complete_with_gpt, textbox, textbox)

demo.launch()

Multistep Demos

In some cases, you might want want a "multi-step" demo, in which you reuse the output of one function as the input to the next. This is really easy to do with Blocks, as you can use a component for the input of one event trigger but the output of another. Take a look at the text component in the example below, its value is the result of a speech-to-text model, but also gets passed into a sentiment analysis model:

from transformers import pipeline

import gradio as gr

asr = pipeline("automatic-speech-recognition", "facebook/wav2vec2-base-960h")
classifier = pipeline("text-classification")

def speech_to_text(speech):
    text = asr(speech)["text"]
    return text

def text_to_sentiment(text):
    return classifier(text)[0]["label"]

demo = gr.Blocks()

with demo:
    audio_file = gr.Audio(type="filepath")
    text = gr.Textbox()
    label = gr.Label()

    b1 = gr.Button("Recognize Speech")
    b2 = gr.Button("Classify Sentiment")

    b1.click(speech_to_text, inputs=audio_file, outputs=text)
    b2.click(text_to_sentiment, inputs=text, outputs=label)

demo.launch()

Updating Component Properties

So far, we have seen how to create events to update the value of another component. But if you want to change other properties of a component (like the visibility of a textbox or the choices in a radio button group)? You can do this by returning a component class's update() method instead of a regular return value from your function.

This is perhaps most easily illustrated with an example:

import gradio as gr

def change_textbox(choice):
    if choice == "short":
        return gr.Textbox.update(lines=2, visible=True)
    elif choice == "long":
        return gr.Textbox.update(lines=8, visible=True)
    else:
        return gr.Textbox.update(visible=False)

with gr.Blocks() as demo:
    radio = gr.Radio(
        ["short", "long", "none"], label="What kind of essay would you like to write?"
    )
    text = gr.Textbox(lines=2, interactive=True)

    radio.change(fn=change_textbox, inputs=radio, outputs=text)

demo.launch()

Sharing Blocks Publicly

Blocks can be easily shared publicly by setting share=True in the launch() method. Like this:

demo = gr.Blocks()

with demo:
    ...  # define components & events here

demo.launch(share=True)

This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the demo in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. If you're working out of colab notebook, a share link is always automatically created. It usually looks something like this: XXXXX.gradio.app. Although the link is served through a gradio link, we are only a proxy for your local server, and do not store any data sent through the demo.

Keep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False (the default), only a local link is created, which can be shared by port-forwarding with specific users.

Share links expire after 72 hours. For permanent hosting, see Hosting Gradio Blocks on Spaces below.

Sharing diagram

Hosting Gradio Blocks on Spaces

Huggingface provides the infrastructure to permanently host your Gradio demo on the internet, for free! You can either drag and drop a folder containing your Gradio model and all related files, or you can point HF Spaces to your Git repository and HF Spaces will pull the Gradio interface from there. It's just as easy to share a Blocks demo as it is a regular Gradio Interface.

See Huggingface Spaces for more information.

Hosting Demo