文章目录
- 一、快速开始
- 1.1 创建第一个demo
- 1.2 分享demo
- 1.3 Interface Class
- 1.4 Core Gradio Classes
- 1.5 Gradio生态系统
- 二、Gradio的主要特点
- 2.1 组件(Components)
- 2.1.1 组件属性
- 2.1.2 静态与交互式组件
- 2.1.3 预处理和后处理
- 2.2 并发(Queuing)
- 2.3 流式输出(Streaming outputs)
- 2.4 流式输入(Streaming inputs)
- 2.5 警告模式(Alert modals)
- 2.6 样式设置(Styling)
- 2.7 进度条(Progress bars)
- 2.8 批处理函数(Batch functions)
- 2.8.1 定义批处理函数
- 2.8.2 使用 Interface 类启用批处理和队列
- 2.8.3 使用 Blocks 类启用批处理和排队
- 三、Interface class
- 3.1 常用参数
- 3.2 多输入、多输出组件
- 3.3 图像示例
- 3.4 示例输入
- 3.4.1 添加示例数据
- 3.4.2 从目录加载示例数据
- 3.4.3 缓存示例数据
- 3.5 描述性内容
- 3.6 折叠面板
- 3.7 标记(Flagging)
- 3.7.1 Flag 功能的概述
- 3.7.2 添加标记原因
- 3.8 接口状态(Interface State)
- 3.8.1 全局状态(Global State)
- 3.8.2 会话状态(Session State)
- 3.9 四种Gradio Interfaces
- 3.9.1 Standard demos(略)
- 3.9.2 Output-only demos
- 3.9.3 Input-only demos
- 3.9.4 Unified demos
- 3.10 反应式接口(Reactive Interfaces)
- 3.10.1 实时界面(Live Interfaces)
- 3.10.2 流式组件(Streaming Components)
- 3.10.2.1 流式输入
- 3.10.2.2 流式输出
gradio(GitHub)、gradio官方教程、gradio官方文档
一、快速开始
1.1 创建第一个demo
Gradio 是一个用于快速构建机器学习模型界面的 Python 库,使用 Gradio 内置的共享功能,您可以在几秒钟内分享您的演示或网络应用程序链接,无需任何 JavaScript、CSS 或网页托管经验!下面进行演示,让我们编写第一个 Gradio 应用程序:
# pip install gradioimport gradio as grdef greet(name, intensity):return "Hello, " + name + "!" * int(intensity)demo = gr.Interface(fn=greet,inputs=["text", "slider"],outputs=["text"],
)demo.launch()
你可以将上述代码放入以文件运行( python app.py ),下面的演示将在 http://localhost:7860 上的浏览器中打开。如果您在笔记本中运行,则演示将嵌入在笔记本中。在左侧的文本框中键入您的姓名,拖动滑块,然后按“提交”按钮,就会在右侧看到问候语。
另外,在本地开发时,您可以在在命令行中输入gradio app.py
来启动热重载模式( hot reload mode
)以运行 Gradio 应用程序。这意味着当你在本地编辑app.py
文件时,Gradio会自动重新加载修改后的应用程序,而不需要手动停止和启动它,这一便利特性,可以让开发者更快地迭代和测试他们的应用。更多内容,详见《Hot Reloading Guide》。
1.2 分享demo
只需在 launch()
中 设置 share=True
,即可为您的演示创建一个可公开访问的 URL,让您轻松共享机器学习演示,而不必担心在 Web 服务器上托管的麻烦。
import gradio as grdef greet(name):return "Hello " + name + "!"demo = gr.Interface(fn=greet, inputs="textbox", outputs="textbox")demo.launch(share=True) # Share your demo with just 1 extra parameter 🚀
当您运行此代码时,将在几秒钟内为您的演示生成一个公共 URL:
https://a23dsf231adb.gradio.live
有关共享演示的更多信息,详见《sharing your Gradio application》。
1.3 Interface Class
gr.Interface
类是 Gradio 中的高级抽象,只需指定输入类型和输出类型,即可快速为任何 Python 函数创建用户界面(UI)。Interface类有三个核心参数:
fn
:需要包裹UI的函数。fn
参数非常灵活,可以是任何你想要包裹UI的Python函数,例如音乐生成器、税务计算器,或者是预训练机器学习模型的预测函数。- 函数的每个参数对应于一个输入组件,并且函数应返回单个值或值的元组,元组中的每个元素对应于一个输出组件。
inputs
:输入的Gradio组件或组件列表。
组件可以作为实例化对象传递,也可以通过其字符串快捷方式引用。组件的数量与函数参数的数量相匹配。outputs
:输出的Gradio组件或组件列表。组件的数量与函数返回值的数量相匹配。
Gradio提供了超过30个内置组件,比如gr.Textbox()
、gr.Image()
和gr.HTML()
,这些都是为机器学习应用设计的。如果函数接受的参数或返回的值超过一个,可以在inputs或outputs中传递一个组件列表,每个组件对应函数的一个参数或返回值,按照参数或返回值的顺序排列。
1.4 Core Gradio Classes
Gradio不仅提供了方便高效的 Interface类来快速构建演示,还有其他一些非常实用的工具和库。
- Chatbots with gr.ChatInterface:这是一个高级类,专门用于创建聊天机器人UI。它和gr.Interface非常相似,我们只需要提供一个函数,Gradio就能迅速创建出一个完整的聊天机器人界面,更多内容详见《How to Create a Chatbot with Gradio》。
- Custom Demos with gr.Blocks: 这是Gradio提供的一个底层API,它允许设计具有更灵活布局和数据流的Web应用程序。使用
gr.Blocks
,我们可以控制组件在页面上的位置,处理复杂的数据流(例如,输出可以作为其他函数的输入),以及根据用户互动更新组件的属性和可见性。所有这些都在Python环境中完成。例如,Automatic1111
的stable diffusion Web UI就是用Gradio的Blocks构建的。
1.5 Gradio生态系统
以上是Gradio核心Python库的简要介绍,但实际上,Gradio是一个更广泛的生态系统,包括Python和JavaScript库,使我们能够在Python或JavaScript中构建机器学习应用程序,或者以编程方式查询它们。Gradio生态系统还包括:
- Gradio Python Client(gradio_client):以编程方式在Python中查询任何Gradio应用程序。
- Gradio JavaScript Client(@gradio/client):以编程方式在JavaScript中查询任何Gradio应用程序。
- Gradio-Lite(@gradio/lite):使用Pyodide在浏览器中编写Gradio应用程序,无需服务器。
- Hugging Face Spaces:最流行的Gradio应用程序托管平台,且免费使用!
二、Gradio的主要特点
让我们来看看 Gradio 的一些主要功能。
2.1 组件(Components)
内置组件详见文档:gradio Components
Gradio提供了超过30个内置组件,以及许多用户自定义的组件(详见gradio Components)。这些组件涵盖了机器学习和数据科学中常见的数据类型,例如,gr.Image
组件用于处理输入或输出图像,gr.Label
组件用于显示分类标签和概率,gr.Plot
组件用于显示各种类型的图表等。
2.1.1 组件属性
在我们创建的第一个demo中,我们使用了默认版的 gr.Textbox
和 gr.Slider
组件。但如果我们要更改 UI 组件的外观或行为,该怎么办?
Gradio中,每个组件类都有一系列属性。例如,使用gr.Textbox
和gr.Slider
这两个类的实例,而不是使用它们的简写形式(例如"text"
和gr.Slider()
),那么可以通过设置其属性来自定义组件的外观和行为。
import gradio as grdef greet(name, intensity):return "Hello, " + name + "!" * intensitydemo = gr.Interface(fn=greet,inputs=["text", gr.Slider(value=2, minimum=1, maximum=10, step=1)],outputs=[gr.Textbox(label="greeting", lines=3)],
)demo.launch()
上述代码中,我们定义滑块的值介于 1 到 10 之间,且默认值为 2;自定义输出文本字框标签为greeting
,文本框显示最多3行的文本。
又比如 gr.Image
组件有一个 sources
参数,这个参数接受一个列表,比如 ["webcam", "upload"]
,用来指定用户提供图像的方式。在这里,webcam
表示用户可以通过摄像头实时捕捉图像,而 upload
表示用户可以从本地上传图像。
2.1.2 静态与交互式组件
每个组件都有一个静态版本,用于显示数据,并且大多数组件还有一个交互式版本,用于让用户输入或修改数据。通常,在构建Gradio演示时,Gradio会自动判断组件应该是静态还是交互式。但是,你也可以通过interactive
参数手动设置这个属性。
2.1.3 预处理和后处理
当组件用作输入时,Gradio会自动进行预处理,将用户浏览器发送的数据转换为可以被你的函数接受的形式,例如,将用户上传的图像转换为numpy数组。当组件用作输出时,Gradio也会自动进行后处理,将你的函数返回的数据转换为可以在用户浏览器中显示的形式,例如,将函数返回的图像路径列表( image paths)转换为可以在浏览器中显示的图片画廊(a gallery of images)。
考虑一个Gradio demo,用作图像到图像生成模型的UI。此demo其具有三个输入组件——gr.Textbox、gr.Number和gr.Image和两个输出组件——gr.Number和gr.Gallery。下图显示了其预处理和后处理的过程:
- 文本框中的文本将转换为 Python中的 str格式
- 输入中的数字转换为 Python中的 float 格式
- 用户提供的图像被转换为numpy.array 表示的RGB值
在构造组件时,你也可以使用组件的参数来控制此预处理过程。例如,使用以下参数实例化 Image 组件时,图像将被预处理为 PIL 格式
img = gr.Image(type="pil")
后处理则更简单,Gradio 组件会自动将模型返回的数据转换为可以在浏览器中显示的形式。例如,如果返回的是一个浮点数,Gradio会直接将这个数字显示给用户;如果返回的是一个字符串文件路径列表,Gradio会将这个列表解释为一组图像文件路径,并在浏览器中以画廊的形式显示这些图像。
总的来说,Gradio通过其丰富的预建组件和自动的预处理和后处理功能,使得构建机器学习和数据科学的Web UI变得简单和高效。
2.2 并发(Queuing)
每个 Gradio 应用程序都带有一个内置的排队系统,可以通过使用queue()
方法来进行配置,以支持数千个并发用户。gr.Interface
、gr.Blocks
和gr.ChatInterface
类都支持queue()
方法。
具体来说,可以通过设置queue()
方法的default_concurrency_limit
参数来控制同时处理请求的数量。默认情况下,default_concurrency_limit
被设置为1,这意味着当多个用户同时使用应用时,只有一位用户的请求会被处理。更多内容,详见queue。
# 设置同一时间内处理的请求数量为5。
demo = gr.Interface(...).queue(default_concurrency_limit=5)
demo.launch()
2.3 流式输出(Streaming outputs)
有时候,我们希望展示一系列连续的输出,而不是一次性显示单个结果。这种功能在某些场景下非常有用,比如:
- 图像生成模型:可以展示每一步生成的中间图像,直到最终图像完成。
- 聊天机器人:可以一个词一个词地流式输出回复,而不是等待整个回答生成完毕才显示。
在Gradio中,可以使用Python的生成器函数(generator)来实现流式输出。生成器函数的特点是:使用yield
语句而不是return
语句;yield
语句通常会放在循环中,以产生一系列的值。例如,下面的生成器函数会依次生成从0到x-1的数字::
def my_generator(x):for i in range(x):yield i
在Gradio中使用生成器的方式与使用普通函数相同,下面是一个图像生成模型的例子。
import gradio as gr
import numpy as np
import timedef fake_diffusion(steps):rng = np.random.default_rng()for i in range(steps):time.sleep(1) # 创建人工停顿,便于观察image = rng.random(size=(600, 600, 3))yield imageimage = np.ones((1000,1000,3), np.uint8)image[:] = [255, 124, 0]yield imagedemo = gr.Interface(fake_diffusion,inputs=gr.Slider(1, 10, 3, step=1),outputs="image")demo.launch()
上述代码中的模型会生成几步随机噪声图像,最后输出一个橙色的图像。界面会有一个滑动条,用于控制步数。
fake_diffusion
函数:- 这是一个生成器函数,接受步数作为参数
- 循环指定的步数,每步生成一个随机噪声图像并yield
- 最后生成一个橙色图像并yield
- 创建Gradio界面:
- 使用
gr.Interface
- 输入是一个范围为1-10的滑动条
- 输出是图像
- 使用
这个例子展示了如何在Gradio中使用生成器函数来实现流式输出,特别适用于需要展示中间过程或逐步生成结果的场景。
2.4 流式输入(Streaming inputs)
Gradio不仅可以处理流式输出,还能处理流式输入。这意味着Gradio可以实时处理持续变化的输入数据。例如:
- 实时音频转录:可以处理实时的音频流,将音频实时转换为文字
- 实时图像生成:每当用户输入一个字母,模型就会重新运行生成新的图像
在《Reactive Interfaces》中,有更详细的介绍。
2.5 警告模式(Alert modals)
Alert modals允许开发者向用户显示各种类型的警告或信息,提供更好的用户体验和更清晰的错误处理机制。Alert modals一共有三种,需要启用队列(queueing)功能才能使用这些警告:
- Error:错误,使用
gr.Error("custom message")
来显示 - Warning:警告,使用 gr.Warning(“message”)来显示;
- Info:信息,使用
gr.Info("message")
来显示。
def start_process(name):gr.Info("Starting process")if name is None:gr.Warning("Name is empty")...if success == False:raise gr.Error("Process failed")
gr.Error
需要通过 raise
语句来触发,会中断函数执行。gr.Warning
和 gr.Info
可以作为函数中的独立语句使用,会立即显示警告模态框,但不会中断函数执行。
2.6 样式设置(Styling)
Gradio 提供了一种简单的方法来自定义应用程序的外观和感觉,可以选择各种预定义的主题,或者创建自己的主题。例如,你可以通过 theme
参数来设置应用程序的主题:
demo = gr.Interface(..., theme=gr.themes.Monochrome())
Gradio 还附带了一组预构建的主题,可以通过 gr.themes.*
来加载这些主题。你还可以扩展这些预构建的主题,或者从头开始创建自己的主题,详见 Gradio 的主题指南《Theming》。
除了使用主题之外,还可以向 Gradio 应用程序传递任何 CSS(以及自定义 JavaScript),以进一步定制样式。有关详细信息,请参阅自定义指南《Customizing your demo with CSS and Javascript》。
2.7 进度条(Progress bars)
Gradio支持创建自定义进度条,以向用户展示进度更新。
- 启用自定义进度条
只需在你的方法中添加一个默认值为 gr.Progress 实例的参数,即可 启用自定义进度条。例如:
def your_method(progress=gr.Progress()):# Your code here
- 更新进度条
通过直接调用这个 Progress 实例,并传递一个介于 0 和 1 之间的浮点数,来更新进度条的进度。你也可以使用 Progress 实例的tqdm()
方法,来跟踪一个可迭代对象的进度。例如:
import gradio as gr
import timedef slowly_reverse(word, progress=gr.Progress()):progress(0, desc="Starting") # 将进度条初始化为 0,并显示描述“Starting”。time.sleep(1)progress(0.05) # 将进度条更新为 5%。new_string = "" # 初始化一个空字符串for letter in progress.tqdm(word, desc="Reversing"):time.sleep(0.25)new_string = letter + new_stringreturn new_stringdemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())demo.launch()
-
slowly_reverse
:遍历输入单词的每个字母,每次循环等待 0.25 秒,缓慢地将其反转,同时更新进度条。 -
gr.Interface(slowly_reverse, gr.Text(), gr.Text())
:创建一个 Gradio 接口demo
,它将函数slowly_reverse
连接到一个文本输入和一个文本输出。
如果函数中已经存在 tqdm.tqdm 进度条,可以通过设置默认参数 gr.Progress(track_tqdm=True)
来自动报告进度更新,效果和上面是一样的。
import gradio as gr
import time
import tqdmdef slowly_reverse(word, progress=gr.Progress(track_tqdm=True)):progress(0, desc="Starting")time.sleep(1)progress(0.05)new_string = ""for letter in tqdm.tqdm(word, desc="Reversing"):time.sleep(0.25)new_string = letter + new_stringreturn new_stringdemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())demo.launch()
2.8 批处理函数(Batch functions)
2.8.1 定义批处理函数
批处理函数是接收一组输入并返回一组预测的函数。通过使用批处理函数,Gradio 服务器可以自动将多个传入请求批量处理,从而提高处理效率和速度。下面是一个简单的示例,
import timedef trim_words(words, lens):trimmed_words = []time.sleep(5)for w, l in zip(words, lens):trimmed_words.append(w[:int(l)])return [trimmed_words]
我们定义了一个批处理函数 trim_words
,该函数接收两个列表(单词列表和整数列表),并返回一个修剪后的单词列表trimmed_words
(将每个单词修剪为长度为5的单词)。
2.8.2 使用 Interface 类启用批处理和队列
demo = gr.Interface(fn=trim_words, inputs=["textbox", "number"], outputs=["output"],batch=True, max_batch_size=16
)demo.launch()
在上面的示例中,可以并行处理 16 个请求,总推理时间为 5 秒;如果单独处理每个请求,总推理时间为 80 秒。许多 Hugging Face transformers 和 diffusers 模型能够自然地与 Gradio 的批处理模式一起工作。
2.8.3 使用 Blocks 类启用批处理和排队
使用 Gradio 的 Blocks 类也实现相同的功能,在这种情况下,通过点击按钮触发批处理函数。
import gradio as grwith gr.Blocks() as demo:with gr.Row():word = gr.Textbox(label="word")leng = gr.Number(label="leng")output = gr.Textbox(label="Output")with gr.Row():run = gr.Button()event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)demo.launch()
三、Interface class
3.1 常用参数
live
:布尔类型。如果任何输入发生变化,界面是否应自动重新运行。title
:界面的标题;如果提供,将以大字体显示在输入和输出组件上方。在浏览器窗口中打开时也用作选项卡标题。description
:接口的描述;如果提供,则以常规字体显示在输入和输出组件上方以及标题下方。接受 Markdown 和 HTML 内容。article
:解释界面的扩展文章;如果提供,将以常规字体显示在输入和输出组件下方。接受 Markdown 和 HTML 内容。如果它是指向可下载远程文件的 HTTP(S) 链接,则会显示该文件的内容。theme
:主题对象或表示主题的字符串。如果是字符串,将查找具有该名称的内置主题(例如“soft”或“default”),或者尝试从 Hugging Face Hub 加载主题(例如“gradio/monochrome”)。默认为None,表示使用默认主题。css
:自定义 css 作为字符串或 css 文件的路径。此 CSS 将包含在演示网页中。- allow_flagging:用于控制是否启用标记功能。标记功能允许用户将特定的输入输出对标记为需要注意或进一步处理的内容。这对于收集用户反馈、识别问题或改进模型非常有用。一共有三个选项:
never
:禁用标记功能。auto
:用户界面上不会显示标记按钮,每个输入输出对都会被自动标记manual
:用户界面显示标记按钮,允许用户手动标记输入输出对
flagging_options
:如果提供,则允许用户在标记时从选项列表中进行选择。仅当allow_flagging
为manual
时才适用。flagging_options有两种形式:- 字符串列表:每个字符串代表一个标记选项。用户界面上将显示按钮,标签为 “Flag as X”, “Flag as Y” 等,而存储的值为相应的字符串 “X”, “Y”。例如:
flagging_options = ["Spam", "Offensive", "Other"]
- 元组列表:每个元组的形式为 (label, value),其中 label 是显示在按钮上的字符串,value 是存储在标记 CSV 中的字符串。例如:
flagging_options = [("Spam", "spam"), ("Offensive", "offensive"), ("Other", "other")]
- 字符串列表:每个字符串代表一个标记选项。用户界面上将显示按钮,标签为 “Flag as X”, “Flag as Y” 等,而存储的值为相应的字符串 “X”, “Y”。例如:
flagging_dir
:存储标记数据的目录的名称batch
:是否进行批处理max_batch_size
:批处理的最大sizeconcurrency_limit
:函数调用的并发执行数量None
:不限制并发数量,允许任意数量的此事件同时运行default
:使用默认并发限制。默认并发限制由 .queue() 方法中的 default_concurrency_limit 参数定义,默认值是 1。- 整数值:自定义并发限制,指定同时运行此事件的最大实例数
submit_btn,stop_btn,clear_btn
:提交输入按钮、停止界面按钮、清除输入按钮。可以设置为字符串(按钮标签)或gr.Button
对象(允许更多自定义)。
3.2 多输入、多输出组件
假设你有一个更复杂的函数,具有多个输入和多个输出,比如下面这个函数,接受字符串、布尔值和数字,并返回字符串和数字。
import gradio as grdef greet(name, is_morning, temperature):salutation = "Good morning" if is_morning else "Good evening"greeting = f"{salutation} {name}. It is {temperature} degrees today"celsius = (temperature - 32) * 5 / 9return greeting, round(celsius, 2)demo = gr.Interface(fn=greet,inputs=["text", "checkbox", gr.Slider(0, 100)],outputs=["text", "number"],
)
demo.launch()
3.3 图像示例
Gradio 支持多种类型的组件,例如 Image 、 DataFrame 、 Video 或 Label 。让我们尝试一个图像到图像的功能来感受一下!
import numpy as np
import gradio as grdef sepia(input_img):sepia_filter = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]])sepia_img = input_img.dot(sepia_filter.T)sepia_img /= sepia_img.max()return sepia_imgdemo = gr.Interface(sepia, gr.Image(), "image")
demo.launch()
使用 Image 组件作为输入时,函数将收到一个形状为 (height, width, 3) 的 NumPy 数组,其中最后一个维度表示 RGB 值,我们还将以 NumPy 数组的形式返回图像。你也可以使用 type关键字来控制预处理过程。例如,如果希望函数采用图像的文件路径而不是 NumPy 数组来进行预处理,则输入 Image 组件可以编写为:
gr.Image(type="filepath", shape=...)
有关Gradio内置组件的更多信息,请查阅gradio Components。
3.4 示例输入
3.4.1 添加示例数据
通过examples
参数,可以方便地加载示例数据。这样做可以展示模型期望的输入类型。如果提供,则显示在 UI 组件下方,并且可以单击以填充界面。
如果界面只有一个输入组件,示例数据可以是一个普通列表。如果是多输入组件,示例输入应该是一个嵌套列表,这个列表中的每个子列表代表一个数据样本,而每个子列表中的元素则代表每个输入组件的输入。每个组件所需的示例数据格式在《Example Usage文档》中有详细说明。
import gradio as gr
#from foo import BARdef calculator(num1, operation, num2):if operation == "add":return num1 + num2elif operation == "subtract":return num1 - num2elif operation == "multiply":return num1 * num2elif operation == "divide":if num2 == 0:raise gr.Error("Cannot divide by zero!")return num1 / num2demo = gr.Interface(calculator,["number", gr.Radio(["add", "subtract", "multiply", "divide"]),"number"],"number",examples=[[45, "add", 3],[3.14, "divide", 2],[144, "multiply", 2.5],[0, "subtract", 1.2],],title="Toy Calculator",description="Here's a sample toy calculator. Allows you to calculate things like $2+2=4$",
)demo.launch()
通过这种方式,您可以将大型数据集加载到示例中,以便通过 Gradio 浏览数据集并与之交互。这些示例将自动分页(通过 examples_per_page
参数进行配置)。另外,对于有多个输入组件的应用,你也可以仅为部分组件提供示例数据,只需要使用 None 排除不需要的组件。
3.4.2 从目录加载示例数据
- 单一文件类型输入
如果你的接口只接受单一文件类型的输入(例如图像分类器),你可以将示例文件存放在一个目录中,然后将该目录的路径传递给 examples 参数。Gradio界面会自动加载目录中的文件作为示例。 - 多输入情况
如果你的接口有多个输入,目录中必须包含一个 log.csv 文件,列出每个示例数据的值。例如,在上一节计算器应用中,假设设置examples='/demo/calculator/examples'
,那么在该目录下需要有一个log.csv
文件,其内容如下:
num,operation,num2
45,"add",3
3.14,"divide",2
144,"multiply",2.5
0,"subtract",1.2
3.4.3 缓存示例数据
如果你的模型运行时间较长,可以提供一些缓存示例,提高Gradio应用的响应速度,改善用户体验,尤其是在处理复杂或耗时任务时。具体来说,有两种方式:
cache_examples=True
:预先缓存- 此时,Gradio应用会在调用
launch()
方法时,预先运行所有示例,并将输出结果保存到缓存目录中。当用户在应用界面中点击一个示例时,应用会自动使用缓存目录中的数据来填充输出,而不是重新运行预测函数。这样用户可以立即看到结果,而不需要等待模型运行,提高用户体验。 - 优点是所有示例都即时响应,缺点是启动时间较长(因为需要预先运行所有示例)
- 此时,Gradio应用会在调用
cache_examples="lazy"
:按需缓存- 每个示例只有在用户第一次使用时才会被缓存。一旦某个示例被缓存,后续所有用户点击该示例时,都会直接使用缓存结果,响应速度会很快。
- 因为不需要预先运行所有示例,所以启动时间会更快
默认情况下,缓存数据存储在 gradio_cached_examples
文件夹中,可以通过 GRADIO_EXAMPLES_CACHE
环境变量自定义缓存目录路径。另外,缓存生成后,在后续的应用启动中不会自动更新。如果示例数据或函数逻辑发生变化,需要手动删除缓存文件夹,以清除缓存并在下一次启动时重新生成。
3.5 描述性内容
Interface构造函数中有三个参数可以用来指定描述性内容:
title
:接受文本格式,可以在接口的最顶部显示它,同时它也成为了页面标题。description
:接受文本、Markdown 或 HTML,并将其放置在标题下方。article
:接受文本、Markdown 或 HTML,并将其放置在接口下方。
如果你使用的是 Blocks
类,你可以使用 gr.Markdown(…)
或 gr.HTML(…)
组件,在应用程序中的任何位置插入文本、Markdown 或 HTML。
另一个有用的关键字参数是 label=
,它存在于每个组件中。这会修改每个组件顶部标签的文本。你还可以向表单元素(如 Textbox 或 Radio )添加 info=
关键字参数,以提供进一步的描述信息,例如:
gr.Number(label='Age', info='In years, must be greater than 0')
3.6 折叠面板
当你的预测函数(prediction function)有很多种输入时,为了防止界面杂乱,你可以在一个折叠面板(Accordion)内隐藏一些输入。Interface类有一个additional_inputs
参数,它类似于inputs,但包含在这里的输入组件默认是不可见的。用户需要点击折叠面板才能显示这些组件。Additional Inputs
在standard inputs
之后按顺序传递给预测函数。
你还可以通过可选参数additional_inputs_accordion来自定义折叠面板的外观。这个参数可以接受一个字符串(此时它成为折叠面板的标签),或者一个gr.Accordion()
类的实例(例如,这让你可以控制折叠面板默认是展开还是折叠)。下面是一个简单的示例:
import gradio as grdef generate_fake_image(prompt, seed, initial_image=None):return f"Used seed: {seed}", "https://dummyimage.com/300/09f.png"demo = gr.Interface(generate_fake_image,inputs=["textbox"],outputs=["textbox", "image"],additional_inputs=[gr.Slider(0, 1000),"image"]
)demo.launch()
3.7 标记(Flagging)
3.7.1 Flag 功能的概述
在Gradio界面中,默认会显示一个“Flag”按钮。当用户在使用演示时看到有趣的输出,例如错误或意外的模型行为,可以点击这个按钮来标记输入,供开发者审查。
标记的输入会记录在一个CSV文件中,存储在由 flagging_dir
参数指定的目录中。如果界面涉及文件数据(如图像和音频组件),还会创建文件夹来存储这些标记的数据。
示例一:计算器接口
- 目录结构
+-- calculator.py
+-- flagged/
| +-- logs.csv
logs.csv
文件内容:
#flagged/logs.csv
num1,operation,num2,Output
5,add,7,12
6,subtract,1.5,4.5
这个文件记录了标记的输入参数(num1, operation, num2)及其输出结果(Output)
示例二:图像处理接口(例如sepia)
- 目录结构:
+-- sepia.py
+-- flagged/
| +-- logs.csv
| +-- im/
| | +-- 0.png
| | +-- 1.png
| +-- Output/
| | +-- 0.png
| | +-- 1.png
logs.csv
文件内容:
#flagged/logs.csv
im,Output
im/0.png,Output/0.png
im/1.png,Output/1.png
这个文件记录了标记的输入图像文件路径(im)及其输出结果文件路径(Output)。同时,图像数据保存在相应的文件夹中。
3.7.2 添加标记原因
如果希望用户在标记时提供标记原因,可以将一个字符串列表传递给 flagging_options
参数,这样用户在标记时需要选择一个原因,这个原因会作为附加列保存到CSV文件中。例如:
flagging_options=["Incorrect Output", "Unexpected Behavior", "Other"]
3.8 接口状态(Interface State)
到目前为止,我们创建的的演示都是无状态的,即每次函数调用后不保存任何信息。如果你希望根据之前的交互修改演示的行为,就需要在Gradio中引入状态管理。
3.8.1 全局状态(Global State)
全局状态是所有函数调用和所有用户都可以访问的状态变量,使用方法是在函数调用之外创建一个变量,并在函数内部访问它。比如,您可以在函数外部加载一个大型模型并在函数内部使用它,这样每次函数调用都不需要重新加载模型。
import gradio as grscores = []def track_score(score):scores.append(score)top_scores = sorted(scores, reverse=True)[:3]return top_scoresdemo = gr.Interface(track_score, gr.Number(label="Score"), gr.JSON(label="Top Scores")
)
demo.launch()
上述代码中,scores
数组是全局共享的。如果有多个用户访问这个演示,他们的分数都会添加到同一个列表中,返回的前三名分数也是从这个共享列表中获取的。
3.8.2 会话状态(Session State)
会话状态是指数据在同一个页面会话的多次提交之间保持,但不在不同用户之间共享。实现步骤:
- 在函数中传入一个额外的参数,表示界面的状态。
- 在函数末尾返回更新后的状态值,作为额外的返回值。
- 在创建 Interface 时,添加 ‘state’ 输入和 ‘state’ 输出组件。
下面的示例演示了如何使用会话状态存储用户的消息历史:
import gradio as grdef store_message(message: str, history: list[str]):output = {"Current messages": message,"Previous messages": history[::-1]}history.append(message)return output, historydemo = gr.Interface(fn=store_message, inputs=["textbox", gr.State(value=[])], outputs=["json", gr.State()])demo.launch()
在这个代码中,history
是一个会话状态变量,存储用户的消息历史。每次提交消息时,历史消息都会更新并显示给用户。同一个页面会话中的多次提交可以共享这个状态,但不同用户之间不会共享。
注意事项:
- 初始值:
State
的初始值默认为None
,可以通过传递参数给gr.State(value=[])
来设置默认值。 - 限制:
Interface
类仅支持单个会话状态变量(但可以是包含多个元素的列表)。对于更复杂的用例,可以使用Blocks
,它支持多个状态变量。或者,如果你在构建一个维护用户状态的聊天机器人,可以使用ChatInterface
抽象,它会自动管理状态。
3.9 四种Gradio Interfaces
目前为止,我们构建的Gradio 演示都有要输入和输出,但机器学习演示的情况并非总是如此,比如无条件图像生成模型不接受任何输入,而是生成图像作为输出。实际上,gradio.Interface 类实际上可以处理 4 种不同类型的演示:
Standard demos
:具有单独的输入和输出Output-only demos
:不接受任何输入,只有输出Input-only demos
:产生任何输出,但接受某种输入。例如,将图像上传到外部数据库进行保存的演示。Unified demos
:输入和输出组件相同,这意味着产生的输出会覆盖输入,例如文本自动完成模型。
3.9.1 Standard demos(略)
3.9.2 Output-only demos
只需将 Interface() 中的 inputs 参数的值设置为 None,即可构建Output-only demos。
import time
import gradio as grdef fake_gan():time.sleep(1)images = ["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80","https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=386&q=80","https://images.unsplash.com/photo-1542909168-82c3e7fdca5c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8aHVtYW4lMjBmYWNlfGVufDB8fDB8fA%3D%3D&w=1000&q=80",]return imagesdemo = gr.Interface(fn=fake_gan,inputs=None,outputs=gr.Gallery(label="Generated Images", columns=[2]),title="FD-GAN",description="This is a fake demo of a GAN. In reality, the images are randomly chosen from Unsplash.",
)demo.launch()
3.9.3 Input-only demos
以下是将任何上传的图像保存到磁盘的示例演示:
import random
import string
import gradio as gr def save_image_random_name(image):random_string = ''.join(random.choices(string.ascii_letters, k=20)) + '.png'image.save(random_string)print(f"Saved image to {random_string}!")demo = gr.Interface(fn=save_image_random_name, inputs=gr.Image(type="pil"), outputs=None,
)
demo.launch()
3.9.4 Unified demos
只需将 inputs 和 outputs 参数的值设置为同一组件即可创建Unified demos,下面是文本生成模型的示例演示:
import gradio as gr
from transformers import pipelinegenerator = pipeline('text-generation', model = 'gpt2')def generate_text(text_prompt):response = generator(text_prompt, max_length = 30, num_return_sequences=5)return response[0]['generated_text']textbox = gr.Textbox()demo = gr.Interface(generate_text, textbox, textbox)demo.launch()
3.10 反应式接口(Reactive Interfaces)
最后,介绍一下如何让 Gradio 演示自动刷新或连续流数据。
3.10.1 实时界面(Live Interfaces)
您可以通过在界面中设置 live=True 来使界面自动刷新。现在,一旦用户输入发生变化,界面就会重新计算,output窗口也会马上刷新。
import gradio as grdef calculator(num1, operation, num2):if operation == "add":return num1 + num2elif operation == "subtract":return num1 - num2elif operation == "multiply":return num1 * num2elif operation == "divide":return num1 / num2demo = gr.Interface(calculator,["number",gr.Radio(["add", "subtract", "multiply", "divide"]),"number"],"number",live=True,
)
demo.launch()
3.10.2 流式组件(Streaming Components)
在Gradio中,某些组件(如音频和图像组件)可以以“streaming”(流式)模式运行。这意味着数据会被连续不断地发送到后端,并且接口函数会被持续不断地重新运行。例如麦克风模式下的 Audio 组件,或网络摄像头模式下的 Image 组件。
gr.Audio(source='microphone'),live=True
:默认模式,用户录音结束后,数据会自动提交并运行接口函数。也就是说,接口函数是在用户完成录音并停止后才被调用一次。gr.Audio(source='microphone', streaming=True),live=True
:录音过程中,数据会被连续发送,接口函数也会在录音过程中不断被调用。这意味着每当有新的音频数据,接口函数就会立即处理。
3.10.2.1 流式输入
下面是网络摄像头的流式图像处理示例:
import gradio as gr
import numpy as npdef flip(im):return np.flipud(im)demo = gr.Interface(flip, gr.Image(sources=["webcam"], streaming=True), "image",live=True
)
demo.launch()
这段代码创建了一个接口,将每帧图像(通过gr.Image
组件从网络摄像头获取,并启用了streaming=True
)传递给 flip
函数进行处理,然后显示翻转后的图像。live=True
表示接口在实时运行。
3.10.2.2 流式输出
Gradio不仅支持流式输入组件,还支持流式输出组件。比如,gr.Audio(streaming=True) 输出组件可以接收由生成器函数逐片段生成的音频数据流,并将这些片段组合成一个完整的音频文件。这种机制允许将输入数据流和输出数据流结合起来,实现复杂的实时处理任务。
import gradio as gr
from pydub import AudioSegment
from time import sleepwith gr.Blocks() as demo:input_audio = gr.Audio(label="Input Audio", type="filepath", format="mp3")with gr.Row():with gr.Column():stream_as_file_btn = gr.Button("Stream as File")format = gr.Radio(["wav", "mp3"], value="wav", label="Format")stream_as_file_output = gr.Audio(streaming=True)def stream_file(audio_file, format):audio = AudioSegment.from_file(audio_file)i = 0chunk_size = 1000while chunk_size * i < len(audio):chunk = audio[chunk_size * i : chunk_size * (i + 1)]i += 1if chunk:file = f"/tmp/{i}.{format}"chunk.export(file, format=format)yield filesleep(0.5)stream_as_file_btn.click(stream_file, [input_audio, format], stream_as_file_output)gr.Examples([["audio/cantina.wav", "wav"], ["audio/cantina.wav", "mp3"]],[input_audio, format],fn=stream_file,outputs=stream_as_file_output,)with gr.Column():stream_as_bytes_btn = gr.Button("Stream as Bytes")stream_as_bytes_output = gr.Audio(format="bytes", streaming=True)def stream_bytes(audio_file):chunk_size = 20_000with open(audio_file, "rb") as f:while True:chunk = f.read(chunk_size)if chunk:yield chunksleep(1)else:breakstream_as_bytes_btn.click(stream_bytes, input_audio, stream_as_bytes_output)if __name__ == "__main__":demo.queue().launch()
更多示例,详见 Gradio 自动语音识别指南《Real Time Speech Recognition》。