Gradio logo

Using Gradio Blocks Like Functions

Prerequisite: This Guide builds on the Blocks Introduction. Make sure to read that guide first.

Introduction

Did you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?

This means that if you have a gradio Blocks (or Interface) app called demo, you can use demo like you would any python function.

So doing something like output = demo("Hello", "friend") will run the first event defined in demo on the inputs “Hello” and “friend” and store it in the variable output.

If I put you to sleep 🥱, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps. The following section will show how.

Treating Blocks like functions

Let’s say we have the following demo that translates english text to german text.

import gradio as gr

from transformers import pipeline

pipe = pipeline("translation", model="t5-base")


def translate(text):
    return pipe(text)[0]["translation_text"]


with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            english = gr.Textbox(label="English text")
            translate_btn = gr.Button(value="Translate")
        with gr.Column():
            german = gr.Textbox(label="German Text")

    translate_btn.click(translate, inputs=english, outputs=german, api_name="translate-to-german")
    examples = gr.Examples(examples=["I went to the supermarket yesterday.", "Helen is a good swimmer."],
                           inputs=[english])

demo.launch()

I already went ahead and hosted it in Hugging Face spaces at gradio/english_translator.

You can see the demo below as well:

Now, let’s say you have an app that generates english text, but you wanted to additionally generate german text.

You could either:

  1. Copy the source code of my english-to-german translation and paste it in your app.

  2. Load my english-to-german translation in your app and treat it like a normal python function.

Option 1 technically always works, but it often introduces unwanted complexity.

Option 2 lets you borrow the functionality you want without tightly coupling our apps.

All you have to do is call the Blocks.load class method in your source file. After that, you can use my translation app like a regular python function!

The following code snippet and demo shows how to use Blocks.load.

Note that the variable english_translator is my english to german app, but its used in generate_text like a regular function.

import gradio as gr

from transformers import pipeline

english_translator = gr.Blocks.load(name="spaces/gradio/english_translator")
english_generator = pipeline("text-generation", model="distilgpt2")


def generate_text(text):
    english_text = english_generator(text)[0]["generated_text"]
    german_text = english_translator(english_text)
    return english_text, german_text


with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            seed = gr.Text(label="Input Phrase")
        with gr.Column():
            english = gr.Text(label="Generated English Text")
            german = gr.Text(label="Generated German Text")
    btn = gr.Button("Generate")
    btn.click(generate_text, inputs=[seed], outputs=[english, german])
    gr.Examples(["My name is Clara and I am"], inputs=[seed])

demo.launch()

How to control which function in the app to use

If the app you are loading defines more than one function, you can specify which function to use with the fn_index and api_name parameters.

In the code for our english to german demo, you’ll see the following line:

translate_btn.click(translate, inputs=english, outputs=german, api_name="translate-to-german")

The api_name gives this function a unique name in our app. You can use this name to tell gradio which function in the upstream space you want to use:

english_generator(text, api_name="translate-to-german")[0]["generated_text"]

You can also use the fn_index parameter. Imagine my app also defined an english to spanish translation function. In order to use it in our text generation app, we would use the following code:

english_generator(text, fn_index=1)[0]["generated_text"]

Functions in gradio spaces are zero-indexed, so since the spanish translator would be the second function in my space, you would use index 1.

Parting Remarks

We showed how treating a Blocks app like a regular python helps you compose functionality across different apps. Any Blocks app can be treated like a function, but a powerful pattern is to load an app hosted on Hugging Face Spaces prior to treating it like a function in your own app. You can also load models hosted on the Hugging Face Model Hub - see the Using Hugging Face Integrations guide for an example.

Happy building! ⚒️