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 允许你通过在
with gradio.Blocks
上下文中实例化 Python 对象来构建结合了 Markdown、HTML、按钮和交互式组件的 Web 应用程序。🙋如果你不熟悉 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()
(当用户在聚焦于文本框时按下回车键时)。更复杂的组件可以有更多事件:例如,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 上。