9-Building_and_sharing_demos-6-Introduction_to_Blocks

中英文对照学习,效果更佳!
原课程链接:https://huggingface.co/course/chapter9/7?fw=pt

Introduction to Gradio Blocks

GRadio积木简介

Ask a Question
Open In Colab
Open In Studio Lab
In the previous sections we have explored and created demos using the Interface class. In this section we will introduce our newly developed low-level API called gradio.Blocks.

在前面的章节中,我们已经使用Interface类探索并创建了演示。在本节中,我们将介绍我们新开发的名为gradio.Blocks的底层接口。

Now, what’s the difference between Interface and Blocks?

那么,InterfaceBlocks有什么区别呢?

  • Interface: a high-level API that allows you to create a full machine learning demo simply by providing a list of inputs and outputs.
  • 🧱 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”).

Interface:高级接口,您只需提供输入和输出列表即可创建完整的机器学习演示。🧱Blocks:低级接口,允许您完全控制应用的数据流和布局。您可以使用Blocks构建非常复杂的多步骤应用程序(如构建块中的应用程序)。

Why Blocks 🧱?

为什么要屏蔽🧱?

As we saw in the previous sections, the Interface class allows you to easily create full-fledged machine learning demos with just a few lines of code. The Interface API is extremely easy to use but lacks the flexibility that the Blocks API provides. For example, you might want to:

正如我们在前面几节中看到的,Interface类允许您只需几行代码就可以轻松创建成熟的机器学习演示。Interface接口使用起来非常简单,但缺乏Blocks接口提供的灵活性。例如,您可能希望:

  • Group together related demos as multiple tabs in one web application
  • Change the layout of your demo, e.g. to specify where the inputs and outputs are located
  • 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 visibility based on user input

We will explore all of these concepts below.

将相关演示组合为一个Web应用程序中的多个选项卡更改演示的布局,例如,指定输入和输出的位置具有多步骤界面,其中一个模型的输出成为下一个模型的输入,或具有更灵活的数据流基于用户输入更改组件的属性(例如,下拉列表中的选项)或其可见性下面我们将探讨所有这些概念。

Creating a simple demo using Blocks

使用块创建简单的演示

After you have installed Gradio, run the code below as a Python script, a Jupyter notebook, or a Colab notebook.

安装GRadio之后,将下面的代码作为一个Python脚本、一个Jupyter笔记本或一个Colab笔记本运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import gradio as gr


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


demo = gr.Blocks()

with demo:
gr.Markdown(
"""
# Flip Text!
Start typing below to see the output.
"""
)
input = gr.Textbox(placeholder="Flip this text")
output = gr.Textbox()

input.change(fn=flip_text, inputs=input, outputs=output)

demo.launch()

This simple example above introduces 4 concepts that underlie Blocks:

上面这个简单的示例介绍了作为块基础的4个概念:

  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.

🙋If you’re not familiar with the with statement in Python, we recommend checking out the excellent tutorial from Real Python. Come back here after reading that 🤗

块允许您通过在一个with gradio.Blocks上下文中实例化PYTHON中的对象来构建结合了markdown、Html、按钮和交互组件的Web应用程序。🙋如果您不熟悉PYTHON语言中的`with‘语句,我们推荐参考来自Real Python语言的优秀教程。读完🤗后回到这里

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 “flips” the input text, but you can write any Python function, from a simple calculation to processing the predictions from a machine learning model.
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.

实例化组件的顺序很重要,因为每个元素都会按照其创建的顺序呈现到Web应用程序中。(下面讨论更复杂的布局)2.您可以在代码中的任何位置定义常规的Python函数,并使用Blocks与用户输入一起运行它们。在我们的示例中,我们有一个简单的函数来“翻转”输入文本,但您可以编写任何Python函数,从简单的计算到处理来自机器学习模型的预测。3.您可以将事件分配给任何Blocks组件。当您分配事件时,传入三个参数:fn:应该调用的函数;inputs:输入组件的(List);outputs:应该调用的输出组件(List)。

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

在上面的示例中,当名为inputTextbox中的值发生变化时,我们运行flip_Text()函数。该事件读取input中的值,将其作为name参数传递给flip_Text(),然后返回一个赋值给我们的第二个名为outputTextbox`。

To see a list of events that each component supports, see the Gradio 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 flip_text() 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 a boolean to the interactive parameter of the component (e.g. gr.Textbox(placeholder="Flip this text", interactive=True)).

要查看每个组件支持的事件列表,请参阅GRadio文档。4.BLOCKS根据您定义的事件触发器,自动确定组件是否应该是交互的(接受用户输入)。在我们的示例中,第一个文本框是交互式的,因为它的值由flip_text()函数使用。第二个文本框不是交互式的,因为它的值从不用作输入。在某些情况下,您可能想要覆盖它,您可以通过将布尔值传递给组件的interactive参数(例如gr.Textbox(PLACEHOLDER=“Flip This Text”,Interactive=True))来实现。

Customizing the layout of your demo

自定义演示的布局

How can we use Blocks to customize the layout of our demo? 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.

如何使用分块自定义我们的Demo的布局?默认情况下,Blocks会将您垂直创建的组件呈现在一列中。您可以通过使用gradio.Column():创建额外的列或使用gradio.Row():创建行并在这些上下文中创建组件来改变这一点。

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.

请记住:在Column(这也是默认设置)下创建的任何组件都将垂直布局。任何在Row下创建的组件都将水平布局,类似于Web开发中的FlexBox模型。

Finally, you can also create tabs for your demo by using the with gradio.Tabs() context manager. Within this context, you can create multiple tabs by specifying with gradio.TabItem(name_of_tab): children. Any component created inside of a with gradio.TabItem(name_of_tab): context appears in that tab.

最后,您还可以使用with gradio.Tabs()上下文管理器为您的演示创建标签。在此上下文中,您可以通过指定with gradio.TabItem(Name_Of_Tag):Child来创建多个页签。在with gradio.TabItem(Name_Of_Tag):上下文中创建的任何组件都会出现在该选项卡中。

Now let’s add a flip_image() function to our demo and add a new tab that flips images. Below is an example with 2 tabs and also uses a Row:

现在,让我们在演示中添加一个flip_Image()函数,并添加一个用于翻转图像的新选项卡。下面是一个包含两个选项卡的示例,它还使用了一行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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"):
with gr.Row():
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.

您会注意到,在本例中,我们还在每个选项卡中创建了一个Button组件,并为每个按钮分配了一个Click事件,这是实际运行函数的原因。

Exploring events and state

探索事件和状态

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.

就像你可以控制布局一样,Blocks让你可以细粒度地控制事件触发函数调用的内容。每个组件和许多布局都有它们支持的特定事件。

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.

例如,Textbox组件有两个事件:change()(当TextBox内部的值发生变化时)和Submit()(当用户关注文本框时按Enter键)。更复杂的组件可以有更多的事件:例如,Audio组件也有单独的事件,用于音频文件的播放、清除、暂停等。有关每个组件支持的事件,请参阅文档。

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:

您可以将事件触发器附加到这些事件中的一个或多个。您可以通过将组件实例上的事件名称作为函数调用来创建事件触发器-例如extbox.change(...)btn.ick(...)。如上所述,该函数接受三个参数:

  • 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 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:

`fn:要运行inputs的函数:其值应作为函数的输入参数提供的组件(列表)。每个组件的值按顺序映射到相应的函数参数。如果函数不接受任何参数,则此参数可以为NONE。outputs`:应根据函数返回的值更新其值的组件(列表)。每个返回值按顺序设置相应组件的值。如果函数不返回任何内容,则此参数可以为NONE。您甚至可以使输入和输出组件成为相同的组件,就像我们在使用GPT模型进行文本完成的示例中所做的那样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()

Creating multi-step demos

创建多步骤演示

In some cases, you might 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:

在某些情况下,您可能需要一个多步骤演示,在此演示中,您将一个函数的输出重用为下一个函数的输入。这对于Blocks来说非常简单,因为您可以使用一个组件作为一个事件触发器的输入,但另一个事件触发器的输出。看看下面示例中的文本组件,它的值是语音到文本模型的结果,但也传递到情感分析模型中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 what happens 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.

到目前为止,我们已经了解了如何创建事件来更新另一个组件的值。但是,如果要更改组件的其他属性,如文本框的可见性或单选按钮组中的选项,该怎么办呢?您可以通过返回组件类的update()方法来实现这一点,而不是从您的函数返回常规返回值。

This is most easily illustrated with an example:

这一点最容易用一个例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 block:
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)
block.launch()

We just explored all the core concepts of Blocks! Just like with Interfaces, you can create cool demos that can be shared by using share=True in the launch() method or deployed on Hugging Face Spaces.

我们刚刚探索了Blocks‘的所有核心概念!和Interfaces一样,您也可以创建很酷的demo,可以在unch()方法中使用share=True`进行分享,也可以部署在Hugging Face空间上。