Gradio 模块简介
在前面的章节中,我们已经探索并创建了使用 Interface
类的演示。在本节中,我们将介绍我们**新开发的**低级 API,称为 gradio.Blocks
。
那么,Interface
和 Blocks
之间有什么区别呢?
⚡
Interface
:一个高级 API,允许您只需提供输入和输出列表即可创建完整的机器学习演示。🧱
Blocks
:一个低级 API,允许您完全控制应用程序的数据流和布局。您可以使用Blocks
(如“构建块”)构建非常复杂的多步骤应用程序。
为什么选择 Blocks 🧱?
正如我们在前面的章节中看到的,Interface
类允许您只需几行代码即可轻松创建功能齐全的机器学习演示。Interface
API 非常易于使用,但缺乏 Blocks
API 提供的灵活性。例如,您可能希望
- 将相关的演示组合为一个 Web 应用程序中的多个选项卡
- 更改演示的布局,例如指定输入和输出的位置
- 具有多步骤界面,其中一个模型的输出成为下一个模型的输入,或者具有更灵活的数据流
- 根据用户输入更改组件的属性(例如,下拉列表中的选项)或其可见性
我们将在下面探讨所有这些概念。
使用 Blocks 创建简单的演示
安装 Gradio 后,将以下代码作为 Python 脚本、Jupyter Notebook 或 Colab Notebook 运行。
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()
以上这个简单的示例介绍了 Blocks 的 4 个核心概念
Blocks 允许您构建 Web 应用程序,这些应用程序可以结合 Markdown、HTML、按钮和交互式组件,只需在
with gradio.Blocks
上下文中实例化 Python 对象即可。🙋如果您不熟悉 Python 中的 `with` 语句,我们建议您查看 Real Python 提供的优秀的[教程](https://realpython.com/python-with-statement/)。阅读完后请回到这里 🤗实例化组件的顺序很重要,因为每个元素都按照创建的顺序渲染到 Web 应用程序中。(更复杂的布局将在下面讨论)您可以在代码中的任何位置定义常规 Python 函数,并使用
Blocks
通过用户输入运行它们。在我们的示例中,我们有一个简单的函数来“翻转”输入文本,但您可以编写任何 Python 函数,从简单的计算到处理机器学习模型的预测。您可以为任何
Blocks
组件分配事件。这将在单击、更改等组件时运行您的函数。当您分配事件时,您会传递三个参数:fn
:应调用的函数,inputs
:输入组件的(列表),以及outputs
:应调用的输出组件的(列表)。在上面的示例中,当名为输入
input
的Textbox
中的值发生更改时,我们运行flip_text()
函数。该事件读取input
中的值,将其作为名称参数传递给flip_text()
,然后该函数返回一个值,该值被分配给名为output
的第二个Textbox
。要查看每个组件支持的事件列表,请参阅 Gradio 的文档。
Blocks 会根据您定义的事件触发器自动确定组件是否应该具有交互性(接受用户输入)。在我们的示例中,第一个文本框是交互式的,因为它的值被
flip_text()
函数使用。第二个文本框不是交互式的,因为它的值从未用作输入。在某些情况下,您可能希望覆盖此行为,您可以通过将布尔值传递给组件的interactive
参数来实现(例如gr.Textbox(placeholder="Flip this text", interactive=True)
)。
自定义演示的布局
我们如何使用 Blocks
来自定义演示的布局?默认情况下,Blocks
会在一列中垂直渲染您创建的组件。您可以通过创建额外的列 with gradio.Column():
或行 with gradio.Row():
并在这些上下文中创建组件来更改这一点。
您需要注意以下几点:在 Column
下创建的任何组件(这也是默认设置)都将垂直布局。在 Row
下创建的任何组件都将水平布局,类似于Web 开发中的 flexbox 模型。
最后,您还可以使用 with gradio.Tabs()
上下文管理器为您的演示创建选项卡。在此上下文中,您可以通过指定 with gradio.TabItem(name_of_tab):
子项来创建多个选项卡。在 with gradio.TabItem(name_of_tab):
上下文中创建的任何组件都将显示在该选项卡中。
现在让我们向演示中添加一个 flip_image()
函数,并添加一个翻转图像的新选项卡。下面是一个包含 2 个选项卡并使用 Row 的示例
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()
您会注意到,在这个示例中,我们还在每个选项卡中创建了一个 Button
组件,并为每个按钮分配了一个单击事件,这实际上是运行函数的操作。
探索事件和状态
就像您可以控制布局一样,Blocks
使您可以对触发函数调用的事件进行细粒度的控制。每个组件和许多布局都支持特定的事件。
例如,Textbox
组件有两个事件:change()
(当文本框内的值发生变化时)和 submit()
(当用户在聚焦于文本框时按下 Enter 键时)。更复杂的组件可以有更多的事件:例如,Audio
组件还分别具有音频文件播放、清除、暂停等的事件。请参阅每个组件支持的事件的文档。
您可以将事件触发器附加到这些事件中的零个、一个或多个事件。您可以通过将组件实例上的事件名称作为函数调用来创建事件触发器,例如 textbox.change(...)
或 btn.click(...)
。该函数接收三个参数,如上所述
fn
:要运行的函数inputs
:一个(或多个)组件,其值应作为输入参数提供给函数。每个组件的值按顺序映射到相应的函数参数。如果函数不接受任何参数,则此参数可以为 None。outputs
:一个(或多个)组件,其值应根据函数返回的值进行更新。每个返回值按顺序设置相应组件的值。如果函数不返回任何内容,则此参数可以为 None。
您甚至可以使输入和输出组件成为同一个组件,就像我们在使用 GPT 模型进行文本补全的示例中所做的那样
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()
创建多步骤演示
在某些情况下,您可能希望使用一个多步骤演示,其中您将一个函数的输出重新用作下一个函数的输入。使用 Blocks
执行此操作非常简单,因为您可以将一个组件用作一个事件触发器的输入,但用作另一个事件触发器的输出。请查看下面示例中的文本组件,其值是语音到文本模型的结果,但也传递给情感分析模型
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()
更新组件属性
到目前为止,我们已经了解了如何创建事件来更新另一个组件的值。但是,如果您想更改组件的其他属性,例如文本框的可见性或单选按钮组中的选项,该怎么办?您可以通过从函数返回组件类的 update()
方法而不是常规返回值来实现此目的。
这用一个例子最容易说明
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()
我们刚刚探索了 Blocks
的所有核心概念!就像使用 Interfaces
一样,您可以通过在 launch()
方法中使用 share=True
或部署在 Hugging Face Spaces 上来创建可以共享的酷炫演示。