Introducing Gradio Clients
WatchIntroducing Gradio Clients
WatchPrerequisite: This Guide builds on the Blocks Introduction. Make sure to read that guide first.
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.
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:
Copy the source code of my english-to-german translation and paste it in your app.
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.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()
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.
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.