Article
官方文档:https://www.gradio.app/guides/quickstart 框架版本:5.38.0
简介
Gradio 是一个基于 Python 的库,用于创建 Web 应用,特别适合机器学习模型的演示和交互。
Demo 样例
app.py:
import gradio as gr
def greet(name, intensity):
return "Hello, " + name + "!" * int(intensity)
demo = gr.Interface(
# 处理逻辑
fn=greet,
# 从控件获取输入,作为参数传递给 fn,text 表示文本框,slider 表示滑动条
inputs=['text', 'slider'],
# 输出控件,获取 fn 输出,作为参数传递给控件
outputs=['text'],
)
# 指定 share=True 可以生成一个公开可访问的 URL
demo.launch(share=True)
# 一次性加载
python app.py
# 支持热重载,每次修改都会重新加载页面
gradio app.py
# 打开 http://localhost:7860 可以浏览页面
Interface 类核心参数
| 参数 | 说明 |
|---|---|
fn | 用于围绕用户界面 (UI) 包装的函数 |
inputs | 用于输入的 Gradio 组件。组件的数量应与函数中的参数数量相匹配 |
outputs | 用于输出的 Gradio 组件。组件的数量应与函数的返回值数量相匹配 |
Interface 支持的输入和输出控件一览表
| 序号 | 名称 | Shortcut 字符串 | 类名 | 示例代码 | 主要参数 |
|---|---|---|---|---|---|
| 1 | 文本框 | "textbox" | gr.Textbox | gr.Textbox(lines=2, placeholder="说点什么…", label="输入") | lines, placeholder, label, value, interactive |
| 2 | 数字输入 | "number" | gr.Number | gr.Number(value=0, label="数字") | value, label, interactive, precision |
| 3 | 滑块 | "slider" | gr.Slider | gr.Slider(minimum=0, maximum=10, step=1, value=5, label="选择") | minimum, maximum, step, value, label |
| 4 | 多选框 | "checkbox" | gr.Checkbox | gr.Checkbox(label="同意条款", value=False) | label, value, interactive |
| 5 | 选项组 | "checkboxgroup" | gr.CheckboxGroup | gr.CheckboxGroup(choices=["A","B"], label="多选") | choices, label, value |
| 6 | 单选按钮 | "radio" | gr.Radio | gr.Radio(choices=["A","B"], label="单选", value="A") | choices, label, value |
| 7 | 下拉菜单 | "dropdown" | gr.Dropdown | gr.Dropdown(choices=["X","Y"], label="下拉") | choices, label, value, multiselect |
| 8 | 按钮 | "button" | gr.Button | gr.Button("提交") | value, variant |
| 9 | 清除按钮 | "clearbutton" | gr.ClearButton | gr.ClearButton(component_id="textbox") | component_id, value, variant |
| 10 | 上传按钮 | "file" | gr.File | gr.File(file_count="single", label="上传文件") | file_count, label, type |
| 11 | 另存按钮 | "downloadbutton" | gr.DownloadButton | gr.DownloadButton("下载TXT", file_name="a.txt") | file_name, label |
| 12 | 复制按钮 | "duplicatebutton" | gr.DuplicateButton | gr.DuplicateButton(component_id="textbox") | component_id |
| 13 | 图像 | "image" | gr.Image | gr.Image(type="numpy", shape=(224,224), label="图片") | type, shape, label, tool, interactive |
| 14 | 注释图像 | "annotatedimage" | gr.AnnotatedImage | gr.AnnotatedImage(label="标注") | label |
| 15 | 图像编辑器 | "imageeditor" | gr.ImageEditor | gr.ImageEditor(label="编辑图") | label, tool, shape |
| 16 | 图像滑块 | "imageslider" | gr.ImageSlider | gr.ImageSlider(images=['a.png','b.png'], label="滑动浏览") | images, label, step |
| 17 | 画廊 | "gallery" | gr.Gallery | gr.Gallery(label="图集", columns=2, rows=2) | columns, rows, label |
| 18 | 音频 | "audio" | gr.Audio | gr.Audio(type="filepath", label="音频") | type, label, source |
| 19 | 视频 | "video" | gr.Video | gr.Video(type="filepath", label="视频") | type, label |
| 20 | HTML | "html" | gr.HTML | gr.HTML("<h3>标题</h3>") | value |
| 21 | Markdown | "markdown" | gr.Markdown | gr.Markdown("**加粗** 文本") | value |
| 22 | JSON | "json" | gr.JSON | gr.JSON({"a":1}, label="JSON显示") | value, label |
| 23 | 数据框 | "dataframe" | gr.Dataframe | gr.Dataframe(headers=["A","B"], datatype=["number","text"], label="表格") | headers, datatype, value, label |
| 24 | 数据集组件 | "dataset" | gr.Dataset | gr.Dataset(select='single', label="数据集") | select, label |
| 25 | 日期时间 | "datetime" | gr.DateTime | gr.DateTime(label="时间选择") | label, value, interactive |
| 26 | 代码编辑区 | "code" | gr.Code | gr.Code(language="python", label="代码") | language, label, value |
| 27 | 线图 | "lineplot" | gr.LinePlot | gr.LinePlot(value={"x":[1,2],"y":[3,4]}, label="折线图") | value, label |
| 28 | 散点图 | "scatterplot" | gr.ScatterPlot | gr.ScatterPlot(value={"x":[1],"y":[2]}, label="散点图") | value, label |
| 29 | 条形图 | "barplot" | gr.BarPlot | gr.BarPlot(value={"x":["A"],"y":[5]}, label="条形图") | value, label |
| 30 | 仪表盘 | "paramviewer" | gr.ParamViewer | gr.ParamViewer(params={"a":1, "b":"x"}) | params, label |
| 31 | 登录按钮 | "loginbutton" | gr.LoginButton | gr.LoginButton("登录", log_in=lambda: None) | value, variant, log_in |
| 32 | 模型 3D 显示 | "model3d" | gr.Model3D | gr.Model3D(value="model.glb", label="3D 模型") | value, label |
| 33 | 计时器 | "timer" | gr.Timer | gr.Timer(interval=1.0, start=True, label="计时") | interval, start |
| 34 | 状态文本 | "state" | gr.State | gr.State(value={"msg":"ok"}) | value |
| 35 | 浏览器状态 | "browserstate" | gr.BrowserState | gr.BrowserState() | — |
使用 gr.Interface 调用控件
方式 1:使用字符串调用控件
import gradio as gr
def greet(name):
return "Hello " + name
gr.Interface(fn=greet, inputs="text", outputs="text").launch()
方式 2:使用类名调用控件
import gradio as gr
def greet(name):
return "Hello " + name
gr.Interface(fn=greet, inputs=gr.Textbox(label="Your Name"), outputs=gr.Textbox(label="Greeting")).launch()
使用 gr.Blocks 调用控件
方式 1:使用类名调用控件
import gradio as gr
def greet(name):
return "Hello " + name + "!"
# with gr.Blocks() as demo 子句,将应用的代码包含在子句中
with gr.Blocks() as demo:
name = gr.Textbox(label="Name")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")
# greet_btn.click 是事件监听器,这里监听器将两个文本框关联在一起
greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
demo.launch()
方式 2:使用装饰器函数调用控件
import gradio as gr
with gr.Blocks() as demo:
name = gr.Textbox(label="Name")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")
# 使用装饰器函数,跳过 fn,支持分配 inputs 和 outputs
@greet_btn.click(inputs=name, outputs=output)
def greet(name):
return "Hello " + name + "!"
demo.launch()
inputs 参数的两种形式
import gradio as gr
with gr.Blocks() as demo:
a = gr.Number(label="a")
b = gr.Number(label="b")
with gr.Row():
add_btn = gr.Button("Add")
sub_btn = gr.Button("Subtract")
c = gr.Number(label="sum")
def add(num1, num2):
return num1 + num2
add_btn.click(add, inputs=[a, b], outputs=c)
def sub(data):
return data[a] - data[b]
sub_btn.click(sub, inputs={a, b}, outputs=c)
demo.launch()
形式 1:参数以列表形式传递给 inputs
add_btn.click(add, inputs=[a, b], outputs=c)
此时,参数 a 传递给 num1,参数 b 传递给 num2。
形式 2:参数以集合形式传递给 inputs
sub_btn.click(sub, inputs={a, b}, outputs=c)
此时,inputs 使用集合的形式传入 a、b,inputs 传递给 sub 函数处理时会转换为一个字典,字典的键是 inputs 中的组件,字典的值是 inputs 中组件对应的值。
outputs 参数的两种形式
形式 1:函数以列表形式将结果传递给 outputs
with gr.Blocks() as demo:
food_box = gr.Number(value=10, label="Food Count")
status_box = gr.Textbox()
def eat(food):
if food > 0:
return food - 1, "full"
else:
return 0, "hungry"
gr.Button("Eat").click(
fn=eat,
inputs=food_box,
outputs=[food_box, status_box]
)
形式 2:函数以字典形式将结果传递给 outputs
with gr.Blocks() as demo:
food_box = gr.Number(value=10, label="Food Count")
status_box = gr.Textbox()
def eat(food):
if food > 0:
return {food_box: food - 1, status_box: "full"}
else:
return {status_box: "hungry"}
gr.Button("Eat").click(
fn=eat,
inputs=food_box,
outputs=[food_box, status_box]
)
注意:由于返回值中只有
status_box,因此只更新了status_box,没有更新food_box。
控制布局
gr.Row() — 水平布局
with gr.Row() 子句内的元素全部水平显示,主要参数如下:
| 参数 | 说明 |
|---|---|
equal_height | 每个元素设置为相同的高度 |
scale | 整数,定义元素在行中占据的空间,同一行内存在多个元素时,会根据各自的 scale 按比例扩展 |
min_width | 设置元素的最小宽度,如果 min_width 超出行的宽度,则换行 |
with gr.Blocks() as demo:
with gr.Row(equal_height=True):
textbox = gr.Textbox()
btn0 = gr.Button("Button 0", scale=0)
btn1 = gr.Button("Button 1", scale=1)
btn2 = gr.Button("Button 2", scale=2)
gr.Column() — 垂直布局
with gr.Column() 子句内的元素垂直显示,主要参数如下:
| 参数 | 说明 |
|---|---|
equal_height | 每个元素设置为相同的高度 |
scale | 整数,定义元素在列中占据的空间,同一列内存在多个元素时,会根据各自的 scale 按比例扩展 |
min_width | 设置元素的最小宽度,如果 min_width 超出行的宽度,则换行 |
import gradio as gr
with gr.Blocks() as demo:
with gr.Row():
text1 = gr.Textbox(label="t1")
slider2 = gr.Textbox(label="s2")
drop3 = gr.Dropdown(["a", "b", "c"], label="d3")
with gr.Row():
with gr.Column(scale=1, min_width=300):
text1 = gr.Textbox(label="prompt 1")
text2 = gr.Textbox(label="prompt 2")
inbtw = gr.Button("Between")
text4 = gr.Textbox(label="prompt 1")
text5 = gr.Textbox(label="prompt 2")
with gr.Column(scale=2, min_width=300):
img1 = gr.Image("images/cheetah.jpg")
btn = gr.Button("Go")
demo.launch()
fill_height 缩放
通过 fill_height 对扩展的组件应用缩放:
with gr.Blocks(fill_height=True) as demo:
...
gr.Tab() — 标签页
with gr.Tab("TabName") 子句创建标签页,上下文中创建的任何组件都会出现在该标签页中,连续的 gr.Tab() 子句会被组合在一起。
import numpy as np
import gradio as gr
def flip_text(x):
return x[::-1]
def flip_image(x):
return np.fliplr(x)
with gr.Blocks() as demo:
gr.Markdown("Flip text or image files using this demo.")
with gr.Tab("Flip Text"):
text_input = gr.Textbox()
text_output = gr.Textbox()
text_button = gr.Button("Flip")
with gr.Tab("Flip Image"):
with gr.Row():
image_input = gr.Image()
image_output = gr.Image()
image_button = gr.Button("Flip")
with gr.Accordion("Open for More!", open=False):
gr.Markdown("Look at me...")
temp_slider = gr.Slider(
0, 1,
value=0.1,
step=0.1,
interactive=True,
label="Slide me",
)
text_button.click(flip_text, inputs=text_input, outputs=text_output)
image_button.click(flip_image, inputs=image_input, outputs=image_output)
demo.launch()
gr.Sidebar() — 侧边栏
with gr.Sidebar(position='left') 子句提供侧边栏。
import gradio as gr
import random
def generate_pet_name(animal_type, personality):
cute_prefixes = ["Fluffy", "Ziggy", "Bubbles", "Pickle", "Waffle", "Mochi", "Cookie", "Pepper"]
animal_suffixes = {
"Cat": ["Whiskers", "Paws", "Mittens", "Purrington"],
"Dog": ["Woofles", "Barkington", "Waggins", "Pawsome"],
"Bird": ["Feathers", "Wings", "Chirpy", "Tweets"],
"Rabbit": ["Hops", "Cottontail", "Bouncy", "Fluff"]
}
prefix = random.choice(cute_prefixes)
suffix = random.choice(animal_suffixes[animal_type])
if personality == "Silly":
prefix = random.choice(["Sir", "Lady", "Captain", "Professor"]) + " " + prefix
elif personality == "Royal":
suffix += " the " + random.choice(["Great", "Magnificent", "Wise", "Brave"])
return f"{prefix} {suffix}"
with gr.Blocks(theme=gr.themes.Soft()) as demo:
with gr.Sidebar(position="left"):
gr.Markdown("# 🐾 Pet Name Generator")
gr.Markdown("Use the options below to generate a unique pet name!")
animal_type = gr.Dropdown(
choices=["Cat", "Dog", "Bird", "Rabbit"],
label="Choose your pet type",
value="Cat"
)
personality = gr.Radio(
choices=["Normal", "Silly", "Royal"],
label="Personality type",
value="Normal"
)
name_output = gr.Textbox(label="Your pet's fancy name:", lines=2)
generate_btn = gr.Button("Generate Name! 🎲", variant="primary")
generate_btn.click(
fn=generate_pet_name,
inputs=[animal_type, personality],
outputs=name_output
)
demo.launch()
visible — 可见性控制
组件和布局元素都有一个 visible 参数,可以设置初始值,并且也可以更新。在 Column 上设置 gr.Column(visible=...) 可以用来显示或隐藏一组组件。
动态渲染
使用装饰器函数 @gr.render() 可以动态渲染页面,根据输入和行为生成页面上的控件。
示例 1:根据输入,生成多个控件
import gradio as gr
with gr.Blocks() as demo:
input_text = gr.Textbox(label="input")
# 注意:被修饰的函数,没有 return
@gr.render(inputs=input_text)
def show_split(text):
if len(text) == 0:
gr.Markdown("## No Input Provided")
else:
for letter in text:
gr.Textbox(letter)
demo.launch()
示例 2:根据触发器,生成多个控件
import gradio as gr
with gr.Blocks() as demo:
input_text = gr.Textbox(label="input")
mode = gr.Radio(["textbox", "button"], value="textbox")
# input_text.submit 对应了"回车"或"点击 submit"
@gr.render(inputs=[input_text, mode], triggers=[input_text.submit])
def show_split(text, mode):
if len(text) == 0:
gr.Markdown("## No Input Provided")
else:
for letter in text:
if mode == "textbox":
gr.Textbox(letter)
else:
gr.Button(letter)
demo.launch()
可视化
gr.LinePlot() — 折线图
import gradio as gr
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
'height': np.random.randint(50, 70, 25),
'weight': np.random.randint(120, 320, 25),
'age': np.random.randint(18, 65, 25),
'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
})
with gr.Blocks() as demo:
gr.LinePlot(df, x="weight", y="height")
demo.launch()
gr.ScatterPlot() — 散点图
基础用法:
import gradio as gr
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
'height': np.random.randint(50, 70, 25),
'weight': np.random.randint(120, 320, 25),
'age': np.random.randint(18, 65, 25),
'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
})
with gr.Blocks() as demo:
gr.ScatterPlot(df, x="weight", y="height")
demo.launch()
x 可以是多个系列,y 必须是数值类型:
with gr.Blocks() as demo:
gr.ScatterPlot(df, x="ethnicity", y="height")
demo.launch()
color 参数可以是数值类型:
with gr.Blocks() as demo:
gr.ScatterPlot(df, x="weight", y="height", color="age")
demo.launch()
gr.BarPlot() — 直方图
import gradio as gr
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
'height': np.random.randint(50, 70, 25),
'weight': np.random.randint(120, 320, 25),
'age': np.random.randint(18, 65, 25),
'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
})
with gr.Blocks() as demo:
gr.BarPlot(df, x="weight", y="height", x_bin=10, y_aggregate="sum")
demo.launch()
当 x 轴是字符串类型,将按照 x 的字符串值进行自动分箱:
with gr.Blocks() as demo:
gr.BarPlot(df, x="ethnicity", y="height", y_aggregate="mean")
demo.launch()
gr.SelectData — 图表区域选择监听器
用于选择图表的区域:
import gradio as gr
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
'height': np.random.randint(50, 70, 25),
'weight': np.random.randint(120, 320, 25),
'age': np.random.randint(18, 65, 25),
'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
})
with gr.Blocks() as demo:
plt = gr.LinePlot(df, x="weight", y="height")
selection_total = gr.Number(label="Total Weight of Selection")
def select_region(selection: gr.SelectData):
min_w, max_w = selection.index
return df[(df["weight"] >= min_w) & (df["weight"] <= max_w)]["weight"].sum()
plt.select(select_region, None, selection_total)
demo.launch()
创建仪表盘
绘制多个图表:
import gradio as gr
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
'height': np.random.randint(50, 70, 25),
'weight': np.random.randint(120, 320, 25),
'age': np.random.randint(18, 65, 25),
'ethnicity': [random.choice(["white", "black", "asian"]) for _ in range(25)]
})
with gr.Blocks() as demo:
with gr.Row():
ethnicity = gr.Dropdown(["all", "white", "black", "asian"], value="all")
max_age = gr.Slider(18, 65, value=65)
def filtered_df(ethnic, age):
_df = df if ethnic == "all" else df[df["ethnicity"] == ethnic]
_df = _df[_df["age"] < age]
return _df
gr.ScatterPlot(filtered_df, inputs=[ethnicity, max_age], x="weight", y="height", title="Weight x Height")
gr.LinePlot(filtered_df, inputs=[ethnicity, max_age], x="age", y="height", title="Age x Height")
demo.launch()