【Gradio】初识Gradio

前言

我们经常在网上看到这样

或者这样的界面

可能经常使用AI文生图或者文生视频的小伙伴比较熟悉,不知道有没有人好奇这些都是用什么框架做的,反正我好奇了,经过了解找到了今天的主角Gradio,还有另一个框架下次有时间再学习。

Gradio简介

Gradio提供轻量化的机器学习交互式web页面定制工具,为开发者迅速定制AI应用提供快速上手的脚手架。

官网地址:www.gradio.app

Gradio官方文档:www.gradio.app/guides/quic...

安装

|-----------------------------|
| Gradio 需要 Python 3.10 或更高版本 |

Gradio安装也很简单,只需要一行命令

php 复制代码
$ pip install gradio
#为了更快安装,可以使用清华镜像源
$ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple gradio

预构建组件

Gradio 包括 30 多个预构建的组件(以及许多社区构建的自定义组件 ),这些组件可用作演示中的输入或输出,这里探索一些常用的组件使用及效果,只有了解组件才知道构建边界。

Textbox(文本框)

创建一个文本区域供用户输入字符串或显示字符串输出。

ini 复制代码
import gradio as gr
def textbox_demo(text: str|None):
    return text
# 方法1:默认类型
demo = gr.Interface(
  fn=textbox_demo, 
  inputs="textbox", 
  outputs="textbox",
  title="文本框示例"
)
# 方法2:使用 Interface 上下文
# demo = gr.Interface(
#   fn=textbox_demo, 
#   inputs=gr.Textbox(label="输入"), 
#   outputs=gr.Textbox(label="输出"),
#   title="文本框示例"
# )
demo.launch()

效果如下所示:

|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|
| | |

Textbox还可以监听输入内容改变

ini 复制代码
# 使用 Blocks 上下文
with gr.Blocks() as demo:
    textbox = gr.Textbox(label="输入")
    output_text = gr.Textbox(label="输出")
    textbox.change(textbox_demo, inputs=textbox, outputs=output_text)

甚至还可以实现文本对比功能

ini 复制代码
from difflib import Differ
def diff_texts(text1: str, text2: str):
    d = Differ()
    return [
      (token[2:], token[0] if token[0] != " " else None)
      for token in d.compare(text1, text2)
    ]
demo = gr.Interface(
  fn=diff_texts, 
  inputs=[
    gr.Textbox(label="输入1", info="Initial text", lines=3, value="Text 1"), 
    gr.Textbox(label="输入2", info="Compare text", lines=3, value="Text 2")
  ], 
  outputs=[
    gr.HighlightedText(
      label="Diff", 
      combine_adjacent=True, 
      show_legend=True, 
      color_map={"+" : "red", "-" : "green"}
    )
  ],
  title="文本框示例"
)
demo.launch()

Number(数字)

创建一个数值输入字段,供用户输入数字作为输入或显示数值输出。

typescript 复制代码
import gradio as gr
def update_number(number):
    return number * 2
with gr.Blocks() as demo:
    number = gr.Number(label="Number")
    output = gr.Textbox(label="Output")
    number.change(fn=update_number, inputs=number, outputs=output)
if __name__ == "__main__":
    demo.launch()

Button

普通按钮

python 复制代码
import gradio as gr
def button_click(name: str|None):
    return "Hello " + name + "!!"
# 方法1:使用 Blocks 上下文
with gr.Blocks() as demo:
    name_input = gr.Textbox(label="输入您的姓名")
    output_text = gr.Textbox(label="输出")
    button = gr.Button("点击我")

    button.click(button_click, inputs=name_input, outputs=output_text)
# 方法2:或者直接使用 Interface(注释掉上面的代码,使用下面的)
# demo = gr.Interface(
#     fn=button_click,
#     inputs=gr.Textbox(label="输入您的姓名"),
#     outputs=gr.Textbox(label="输出"),
#     title="按钮点击示例"
# )
if __name__ == "__main__":
    demo.launch()

效果如下所示:

|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|
| | |

按钮默认是灰色的,也可以通过 variant 修改Button的主题类型

ini 复制代码
upload_btn = gr.Button("Upload Results", variant="primary")

ClearButton(清除按钮)

ClearButton可以清除组件或者组建列表的值

ini 复制代码
import gradio as gr
def button_click(name: str|None):
    return "Hello " + name + "!!"
# clearButton
with gr.Blocks() as demo:
    name_input = gr.Textbox(label="输入您的姓名")
    output_text = gr.Textbox(label="输出")

    # 普通按钮用于执行功能
    submit_button = gr.Button("提交", variant="primary")

    # 清除按钮用于清除文本框内容
    clear_button = gr.ClearButton(
        components=[name_input, output_text],
        value="清除"
    )

    submit_button.click(button_click, inputs=name_input, outputs=output_text)
if __name__ == "__main__":
    demo.launch()

UploadButton & DownloadButton(上传|下载按钮)

python 复制代码
from pathlib import Path
import gradio as gr
def upload_file(filepath):
    name = Path(filepath).name
    return [gr.UploadButton(visible=False), gr.DownloadButton(label=f"Download {name}", value=filepath, visible=True)]
def download_file():
    return [gr.UploadButton(visible=True), gr.DownloadButton(visible=False)]
with gr.Blocks() as demo:
    gr.Markdown("First upload a file and and then you'll be able download it (but only once!)")
    with gr.Row():
        u = gr.UploadButton("Upload a file", file_count="single")
        d = gr.DownloadButton("Download the file", visible=False)
    u.upload(upload_file, u, [u, d])
    d.click(download_file, None, [u, d])
if __name__ == "__main__":
    demo.launch()

DuplicateButton(重复按钮)

DuplicateButton为特定平台兼容组件,当 demo 在 Hugging Face Spaces 上运行时触发 Spaces 复制的按钮,本地不执行任何操作。

Radio(单选框)

创建一组(字符串或数值类型)单选按钮,其中只能选择一个。

python 复制代码
import gradio as gr
def update_location(location):
    return f"You selected {location}"
with gr.Blocks() as demo:
    radio = gr.Radio(["park", "zoo", "road"], label="Location", info="Where did they go?")
    output_text = gr.Textbox(label="Result")
    radio.change(fn=update_location, inputs=radio, outputs=output_text)
if __name__ == "__main__":
    demo.launch()

Checkbox & CheckboxGroup(复选框)

python 复制代码
import gradio as gr
def checkbox_demo(morning, fruits):
    return "Now is " + ("morning" if morning else "afternoon") + " and I like " + (" and ".join(fruits) if fruits else "nothing")
# 方法1:默认类型
# demo = gr.Interface(
#   fn=checkbox_demo, 
#   inputs="checkbox", 
#   outputs="text",
#   title="Checkbox Demo",
# )
# 方法2:指定类型
demo = gr.Interface(
    checkbox_demo, 
    inputs=[
        gr.Checkbox(label="morning"),
        gr.CheckboxGroup(
          choices=["apples", "bananas", "cherries"], 
          label="Fruits", 
          info="Choose your favorite fruit"
        ),
    ],
    outputs="text",
    title="Checkbox Demo",
)
demo.launch()

Image

Image(图片)

图像组件,可用于上传图像(作为输入)或显示图像(作为输出)

ini 复制代码
import gradio as gr
demo = gr.Interface(
    fn=lambda x: x,
    inputs=gr.Image(type="filepath"),
    outputs=gr.Image(type="filepath"),
)
if __name__ == "__main__":
    demo.launch()

图片添加滤镜

ini 复制代码
import numpy as np
import gradio as gr
def sepia(input_img):
    if input_img is None:
        return None
    sepia_filter = np.array([
        [0.393, 0.769, 0.189],
        [0.349, 0.686, 0.168],
        [0.272, 0.534, 0.131]
    ])
    # 确保输入是float类型,避免溢出
    img = input_img.astype(np.float32)
    # 应用sepia滤镜
    sepia_img = img @ sepia_filter.T
    # 保证像素值在0-255之间
    sepia_img = np.clip(sepia_img, 0, 255)
    sepia_img = sepia_img.astype(np.uint8)
    return sepia_img
demo = gr.Interface(sepia, gr.Image(), "image")
if __name__ == "__main__":
    demo.launch()

ImageEditor(图片编辑)

创建一个图像组件,作为输入时,可用于使用简单的编辑工具(如画笔、笔触、裁剪和图层)上传和编辑图像。作为输出时,该组件可用于显示图像。

ini 复制代码
import gradio as gr
import time
def sleep(im):
    time.sleep(5)
    return [im["background"], im["layers"][0], im["layers"][1], im["composite"]]
def predict(im):
    return im["composite"]
with gr.Blocks() as demo:
    with gr.Row():
        im = gr.ImageEditor(
            type="numpy",
            crop_size="1:1",
        )
        im_preview = gr.Image()
    n_upload = gr.Number(0, label="Number of upload events", step=1)
    n_change = gr.Number(0, label="Number of change events", step=1)
    n_input = gr.Number(0, label="Number of input events", step=1)
    im.upload(lambda x: x + 1, outputs=n_upload, inputs=n_upload)
    im.change(lambda x: x + 1, outputs=n_change, inputs=n_change)
    im.input(lambda x: x + 1, outputs=n_input, inputs=n_input)
    im.change(predict, outputs=im_preview, inputs=im, show_progress="hidden")
if __name__ == "__main__":
    demo.launch()

ImageSlider(图片滑块)

滑动展示图片模糊对比

python 复制代码
import gradio as gr
from PIL import ImageFilter
def img_to_slider(im):
    if not im:
        return im
    return (im, im.filter(filter=ImageFilter.GaussianBlur(radius=10)))
def slider_to_self(im):
    if not im or not im[0]:
        return im
    return (im[0], im[0].filter(filter=ImageFilter.GaussianBlur(radius=10)))
def slider_to_self_two(im):
    return im
def position_to_slider(pos):
    return gr.ImageSlider(slider_position=pos)
with gr.Blocks() as demo:
    gr.Markdown("## img to image slider")
    with gr.Row():
        img1 = gr.Image(label="Blur image", type="pil")
        img2 = gr.ImageSlider(label="Blur image", type="pil")
    btn = gr.Button("Blur image")
    btn.click(img_to_slider, inputs=img1, outputs=img2)
    gr.Markdown("## unified image slider")

    with gr.Row():
        img3 = gr.ImageSlider(label="Blur image", type="pil")
        img3.upload(slider_to_self, inputs=img3, outputs=img3)
    pos = gr.Slider(label="Position", value=50, minimum=0, maximum=100, step=0.01)
    pos.change(position_to_slider, inputs=pos, outputs=img3, show_progress="hidden")
if __name__ == "__main__":
    demo.launch()

Code(代码)

Code代码编辑器,用于查看代码(作为输出组件),或用于输入和编辑代码(作为输入组件)。

ini 复制代码
import gradio as gr
def code_demo(code):
    return code
# 方法1:使用 Interface
# demo = gr.Interface(fn=code_demo, inputs="code", outputs="text")
# 方法2:使用 Blocks
with gr.Blocks() as demo:
    code_input = gr.Code(label="输入您的代码")
    output_text = gr.Textbox(label="输出")
    submit_button = gr.Button("提交")

    submit_button.click(code_demo, inputs=code_input, outputs=output_text)
demo.launch() 

|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|
| | |

ColorPicker(颜色选择器)

颜色选择器让用户选择颜色作为字符串输入。可以用作输入,将颜色值传递给函数,或用作输出,显示颜色值。

python 复制代码
import gradio as gr
import numpy as np
from PIL import Image, ImageColor
import re
def parse_color(color_str):
    """解析颜色字符串,支持 rgba() 和十六进制格式"""
    if color_str.startswith('rgba('):
        # 解析 rgba(r, g, b, a) 格式
        match = re.match(r'rgba\(([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\)', color_str)
        if match:
            r, g, b, a = match.groups()
            return (int(float(r)), int(float(g)), int(float(b)))
    elif color_str.startswith('rgb('):
        # 解析 rgb(r, g, b) 格式
        match = re.match(r'rgb\(([^,]+),\s*([^,]+),\s*([^)]+)\)', color_str)
        if match:
            r, g, b = match.groups()
            return (int(float(r)), int(float(g)), int(float(b)))
    else:
        # 尝试使用 PIL 的标准颜色解析
        try:
            return ImageColor.getcolor(color_str, "RGB")
        except ValueError:
            # 如果解析失败,返回默认颜色(红色)
            return (255, 0, 0)

    # 如果所有解析都失败,返回默认颜色
    return (255, 0, 0)
def change_color(icon, color):
    if icon is None:
        return None

    img = icon.convert("LA")
    img = img.convert("RGBA")
    image_np = np.array(icon)
    _, _, _, alpha = image_np.T
    mask = alpha > 0

    # 使用自定义的颜色解析函数
    rgb_color = parse_color(color)
    image_np[..., :-1][mask.T] = rgb_color

    edited_image = Image.fromarray(image_np)
    return edited_image
demo = gr.Interface(
    fn=change_color,
    inputs=[
        gr.Image(label="icon", type="pil", image_mode="RGBA"),
        gr.ColorPicker(label="color"),
    ],
    outputs=gr.Image(label="colored icon")
)
if __name__ == "__main__":
    demo.launch()

Slider(滑块)

创建一个从 minimum 到 maximum 的滑动条,步长为 step 。

python 复制代码
import gradio as gr
def greet(age: int) -> str:
    return f"你今年{age}岁。"
with gr.Blocks() as demo:
    input = gr.Slider(minimum=0, maximum=100, step=10, value=50, label="Slider")
    output = gr.Textbox(label="Output")
    input.change(greet, [input], output)
if __name__ == "__main__":
    demo.launch()

SideBar(侧边栏)

SideBar是位于屏幕左侧的侧边栏,是一个可折叠的面板,常用于在 Blocks 布局中渲染子组件。

scss 复制代码
import gradio as gr
with gr.Blocks() as demo:
    with gr.Sidebar():
        gr.Textbox()
        gr.Button()
    gr.Textbox()
if __name__ == "__main__":
    demo.launch()

DateTime(时间选择器)

该组件有兼容问题,不兼容Safari内核

DateTime时间选择器用于选择日期(可选)和时间的选择组件。

ini 复制代码
import gradio as gr
def greet(name, datetime):
    return f"{name},你的预约时间是:{datetime}"
demo = gr.Interface(
    fn=greet,
    inputs=[
        gr.Textbox(label="姓名"),
        gr.DateTime(label="预约时间")
    ],
    outputs="text"
)
demo.launch()

File

File(上传)

创建一个文件组件,允许上传一个或多个通用文件(作为输入使用时)或显示通用文件或下载 URL(作为输出使用时)

单文件上传

ini 复制代码
import gradio as gr
import os
def process_single_file(file):
    if file is None:
        return "没有上传文件", None
    file_info = f"""
    文件名: {file.name}
    文件大小: {os.path.getsize(file.name) if os.path.exists(file.name) else "未知"} bytes
    文件路径: {file.name}
    """
    return file_info, file

# 单个文件上传
with gr.Blocks() as demo:
    single_file = gr.File(label="上传文件", file_count="single")
    single_btn = gr.Button("处理文件")
    single_output = gr.Textbox(label="文件信息")
    single_file_output = gr.File(label="处理后的文件")
    single_btn.click(process_single_file, inputs=single_file, outputs=[single_output, single_file_output])
demo.launch()

多文件上传

ini 复制代码
multiple_files = gr.File(label="上传多个文件",file_count="multiple")

指定文件类型上传

ini 复制代码
# pdf
pdf_file = gr.File(label="上传PDF文件",file_types=[".pdf"])
# 图片|视频
media_files = gr.File(label="上传图片或视频文件",file_types=["image", "video"])

文件预览

ini 复制代码
import gradio as gr
def preview_and_prepare_download(file):
    if file is None:
        return None

    return file

with gr.Blocks() as demo:
  with gr.Row():
      with gr.Column():
          preview_file = gr.File(
              label="上传文件进行预览",
              file_count="single"
          )
      with gr.Column():
          file_preview = gr.File(
              label="文件预览",
              interactive=False # 只预览文件
          )
      preview_file.change(
          preview_and_prepare_download,
          inputs=preview_file,
          outputs=[file_preview]
      )
if __name__ == "__main__":
    demo.launch()

FileExplorer(文件浏览器)

创建一个文件浏览器组件,允许用户浏览托管 Gradio 应用的机器上的文件。作为输入组件,它还允许用户选择文件用作函数的输入,而作为输出组件,它显示所选文件。

ini 复制代码
import gradio as gr
def show_selected_files(files):
    if not files:
        return "未选择任何文件"
    info = []
    for f in files:
        # gr.FileExplorer 返回的是文件路径字符串,而不是带有 .name 属性的对象
        info.append(f"文件名: {f.split('/')[-1]}\n路径: {f}\n")
    return "\n".join(info)
with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            file_explorer = gr.FileExplorer(
                label="选择文件或文件夹",
                root_dir=".",  # 可以根据需要设置根目录
                file_count="multiple"
            )
        with gr.Column():
            selected_files_info = gr.Textbox(
                label="选中文件信息",
                lines=8
            )
    file_explorer.change(
        show_selected_files,
        inputs=file_explorer,
        outputs=selected_files_info
    )

demo.launch()

Audio(音频)

ini 复制代码
import numpy as np
import gradio as gr
notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
def generate_tone(note, octave, duration):
    sr = 48000
    a4_freq, tones_from_a4 = 440, 12 * (octave - 4) + (note - 9)
    frequency = a4_freq * 2 ** (tones_from_a4 / 12)
    duration = int(duration)
    audio = np.linspace(0, duration, duration * sr)
    audio = (20000 * np.sin(audio * (2 * np.pi * frequency))).astype(np.int16)
    return sr, audio
demo = gr.Interface(
    generate_tone,
    [
        gr.Dropdown(notes, type="index"),
        gr.Slider(4, 6, step=1),
        gr.Textbox(value="1", label="Duration in seconds"),
    ],
    "audio",
)
if __name__ == "__main__":
    demo.launch()

Gallery(画廊)

画廊组件允许显示图像或视频的网格,如果用作输入,用户可以将图像或视频上传到画廊。如果用作输出,用户可以点击单个图像或视频以查看更高分辨率的版本。

ini 复制代码
import random
import gradio as gr
def fake_gan():
    images = [
        (random.choice(
            [
                "http://www.marketingtool.online/en/face-generator/img/faces/avatar-1151ce9f4b2043de0d2e3b7826127998.jpg",
                "http://www.marketingtool.online/en/face-generator/img/faces/avatar-116b5e92936b766b7fdfc242649337f7.jpg",
                "http://www.marketingtool.online/en/face-generator/img/faces/avatar-1163530ca19b5cebe1b002b8ec67b6fc.jpg",
                "http://www.marketingtool.online/en/face-generator/img/faces/avatar-1116395d6e6a6581eef8b8038f4c8e55.jpg",
                "http://www.marketingtool.online/en/face-generator/img/faces/avatar-11319be65db395d0e8e6855d18ddcef0.jpg",
            ]
        ), f"label {i}")
        for i in range(3)
    ]
    return images
with gr.Blocks() as demo:
    gallery = gr.Gallery(
        label="Generated images", show_label=False, elem_id="gallery"
    , columns=2, object_fit="contain", height="200px")
    btn = gr.Button("Generate images", scale=0)
    btn.click(fake_gan, None, gallery)
if __name__ == "__main__":
    demo.launch()

HTML(展示HTM L)

用来显示任意的 HTML 输出。由于这个组件不接受用户输入,它很少被用作输入组件。

ini 复制代码
import gradio as gr
with gr.Blocks() as demo:
    input_text = gr.Textbox(placeholder="Enter text.")
    scroll_btn = gr.Button("Scroll")
    no_scroll_btn = gr.Button("No Scroll")
    big_block = gr.HTML("""
    <div style='height: 100px; width: 100px; background-color: pink;'></div>
    <div style='height: 100px; width: 100px; background-color: blue;'></div>
    <div style='height: 100px; width: 100px; background-color: green;'></div>
    <div style='height: 100px; width: 100px; background-color: yellow;'></div>
    <div style='height: 100px; width: 100px; background-color: red;'></div>
    """)
    out = gr.Textbox()
    scroll_btn.click(
      lambda x: x,
      inputs=input_text,
      outputs=out,
      scroll_to_output=True
    )
    no_scroll_btn.click(
      lambda x: x,
      inputs=input_text,
      outputs=out,
      scroll_to_output=False
    )
if __name__ == "__main__":
    demo.launch()

Markdown(展示Markdown)

用于渲染任意 Markdown 输出。也可以渲染被美元符号包围的 LaTeX。由于这个组件不接受用户输入,它很少被用作输入组件。

python 复制代码
import gradio as gr
with gr.Blocks() as demo:
    gr.Markdown(
    """
    # Hello World!
    Start typing below to see the output.
    ## 这是一个标题
    ### 这是一个副标题
    #### 这是一个小标题
    """)
    gr.Markdown(
    """
    # 图片
    <img src="http://www.marketingtool.online/en/face-generator/img/faces/avatar-1151ce9f4b2043de0d2e3b7826127998.jpg" alt="alt text" width="200" height="200"/>
    """)
if __name__ == "__main__":
    demo.launch()

JSON(JSON美化)

用于美观地显示任意 JSON 输出。由于该组件不接受用户输入,因此很少用作输入组件。

python 复制代码
from zipfile import ZipFile
import gradio as gr
def zip_to_json(file_obj):
    files = []
    with ZipFile(file_obj.name) as zfile:
        for zinfo in zfile.infolist():
            files.append(
                {
                    "name": zinfo.filename,
                    "file_size": zinfo.file_size,
                    "compressed_size": zinfo.compress_size,
                }
            )
    return files
demo = gr.Interface(zip_to_json, "file", "json")
if __name__ == "__main__":
    demo.launch()

Label(分类标签)

显示分类标签以及提供的顶级类别的置信度分数。由于此组件不接受用户输入,因此很少用作输入组件。

ini 复制代码
import gradio as gr
with gr.Blocks() as demo:
    label1 = gr.Label(
        value={"A类": 0.8, "B类": 0.15, "C类": 0.05},
        label="分类结果"
    )
    label2 = gr.Label(
        value={"A类": 0.8, "B类": 0.15, "C类": 0.05},
        label="分类结果",
        num_top_classes=2 # 只显示前2个
    )
if __name__ == "__main__":
    demo.launch()

MultimodalTextbox(多模态文本框)

创建一个文本区域供用户输入字符串或显示字符串输出,并允许上传多媒体文件。

python 复制代码
import gradio as gr
import time
# Chatbot demo with multimodal input (text, markdown, LaTeX, code blocks, image, audio, & video). Plus shows support for streaming text.
def print_like_dislike(x: gr.LikeData):
    print(x.index, x.value, x.liked)
def add_message(history, message):
    for x in message["files"]:
        history.append({"role": "user", "content": {"path": x}})
    if message["text"] is not None:
        history.append({"role": "user", "content": message["text"]})
    return history, gr.MultimodalTextbox(value=None, interactive=False)
def bot(history: list):
    response = "**That's cool!**"
    history.append({"role": "assistant", "content": ""})
    for character in response:
        history[-1]["content"] += character
        time.sleep(0.05)
        yield history
with gr.Blocks() as demo:
    chatbot = gr.Chatbot(elem_id="chatbot", bubble_full_width=False, type="messages")
    chat_input = gr.MultimodalTextbox(
        interactive=True,
        file_count="multiple",
        placeholder="Enter message or upload file...",
        show_label=False,
        sources=["microphone", "upload"],
    )
    chat_msg = chat_input.submit(
        add_message, 
        [chatbot, chat_input], 
        [chatbot, chat_input]
    )
    bot_msg = chat_msg.then(bot, chatbot, chatbot, api_name="bot_response")
    bot_msg.then(lambda: gr.MultimodalTextbox(interactive=True), None, [chat_input])
    chatbot.like(print_like_dislike, None, None, like_user_message=True)
if __name__ == "__main__":
    demo.launch()

DataFrame(表格组件)

显示一个表格组件,可以用作输出组件来显示数据,或作为输入组件来收集用户数据。

ini 复制代码
import gradio as gr
def tax_calculator(income, assets):
    total_deductible = sum(assets["Cost"])
    taxable_income = income - total_deductible
    return taxable_income
demo = gr.Interface(
    fn=tax_calculator,
    inputs=[
      gr.Number(label="Income"),
      gr.Dataframe(
        headers=["Item", "Cost"],
        datatype=["str", "number"],
        label="Assets Purchased this Year",
      )  
    ],
    outputs="text",
    examples=[
        [100000, [["Suit", 5000], ["Laptop", 800], ["Car", 1800]]],
        [100000, [["Suit", 5000], ["Watch", 500], ["Car", 1800]]],
    ],
)
if __name__ == "__main__":
    demo.launch()

ParamViewer(参数查看器)

以表格形式展示组件参数

python 复制代码
import gradio as gr
with gr.Blocks() as demo:
    gr.ParamViewer(
        {
            "iterable": {
                "type": "Iterable",
                "description": "可迭代对象,如列表、元组等",
                "default": None
            },
            "key": {
                "type": "function | None",
                "description": "用于比较的函数",
                "default": "None"
            },
            "default": {
                "type": "Any",
                "description": "当可迭代对象为空时返回的默认值",
                "default": "None"
            }
        }
    )

if __name__ == "__main__":
    demo.launch()

State(状态)

用于表单中存储任意类型的值,避免破坏分组结构

ini 复制代码
import gradio as gr
def add_message(message, history):
    """添加消息到历史记录"""
    if not history:
        history = []
    history.append(message)
    return history, ""  # 返回更新的历史和清空的输入框
def clear_history():
    """清空消息历史"""
    return []

with gr.Blocks() as demo:
    # 消息历史状态
    message_history_state = gr.State(value=[])

    with gr.Row():
        message_input = gr.Textbox(
            label="输入消息",
            placeholder="输入您的消息...",
            scale=3
        )
        history_display = gr.JSON(label="消息历史", value=[])

    with gr.Row():
        add_msg_btn = gr.Button("📤 发送", scale=1, variant="primary")
        clear_history_btn = gr.Button("🗑️ 清空历史", variant="stop")

    # 绑定消息相关事件
    add_msg_btn.click(
        fn=add_message,
        inputs=[message_input, message_history_state],
        outputs=[message_history_state, message_input]
    ).then(
        fn=lambda x: x,
        inputs=message_history_state,
        outputs=history_display
    )

    # 支持回车发送
    message_input.submit(
        fn=add_message,
        inputs=[message_input, message_history_state],
        outputs=[message_history_state, message_input]
    ).then(
        fn=lambda x: x,
        inputs=message_history_state,
        outputs=history_display
    )

    clear_history_btn.click(
        fn=clear_history,
        outputs=message_history_state
    ).then(
        fn=lambda x: x,
        inputs=message_history_state,
        outputs=history_display
    )
if __name__ == "__main__":
    demo.launch()

Timer(计时器)

一个特殊的组件,在激活时按固定间隔触发。不可见,仅用于通过 tick 事件监听器定期触发事件。

ini 复制代码
import gradio as gr
import time
with gr.Blocks() as demo:
    with gr.Row():
        timestamp = gr.Textbox(label="计时器")

    with gr.Row():
        start_manual_btn = gr.Button("开始计时")
        stop_manual_btn = gr.Button("停止计时")

    # 创建另一个定时器用于手动控制
    manual_timer = gr.Timer(1, active=False)  # 初始状态为非活动
    manual_timer.tick(lambda: round(time.time()), outputs=timestamp)

    start_manual_btn.click(lambda: gr.Timer(active=True), None, manual_timer)
    stop_manual_btn.click(lambda: gr.Timer(active=False), None, manual_timer)
if __name__ == "__main__":
    demo.launch()

图表

BarPlot(条形图)

创建一个条形图组件来显示来自 pandas DataFrame 的数据

ini 复制代码
import gradio as gr
import pandas as pd
from random import randint, random
food_rating_data = pd.DataFrame(
    {
        "cuisine": [["Italian", "Mexican", "Chinese"][i % 3] for i in range(100)],
        "rating": [random() * 4 + 0.5 * (i % 3) for i in range(100)],
        "price": [randint(10, 50) + 4 * (i % 3) for i in range(100)],
    }
)
with gr.Blocks() as demo:
    price_by_rating = gr.BarPlot(
        food_rating_data,
        x="rating",
        y="price",
        x_bin=1,
    )
    price_by_rating_color = gr.BarPlot(
        food_rating_data,
        x="rating",
        y="price",
        color="cuisine",
        x_bin=1,
        color_map={"Italian": "red", "Mexican": "green", "Chinese": "blue"},
    )
if __name__ == "__main__":
    demo.launch()

LinePlot(折线图)

创建一个线形图组件,用于显示来自 pandas DataFrame 的数据。

ini 复制代码
import gradio as gr
import pandas as pd
from random import randint
temp_sensor_data = pd.DataFrame(
    {
        "time": pd.date_range("2021-01-01", end="2021-01-05", periods=200),
        "temperature": [randint(50 + 10 * (i % 2), 65 + 15 * (i % 2)) for i in range(200)],
        "humidity": [randint(50 + 10 * (i % 2), 65 + 15 * (i % 2)) for i in range(200)],
        "location": ["indoor", "outdoor"] * 100,
    }
)
with gr.Blocks() as demo:
    temp_by_time = gr.LinePlot(
        temp_sensor_data,
        x="time",
        y="temperature",
    )
    temp_by_time_location = gr.LinePlot(
        temp_sensor_data,
        x="time",
        y="temperature",
        color="location",
    )

if __name__ == "__main__":
    demo.launch()

Plot(图表)

ini 复制代码
import pandas as pd
import numpy as np
import gradio as gr
def plot(v, a):
    g = 9.81
    theta = a / 180 * 3.14
    tmax = ((2 * v) * np.sin(theta)) / g
    timemat = tmax * np.linspace(0, 1, 40)
    x = (v * timemat) * np.cos(theta)
    y = ((v * timemat) * np.sin(theta)) - ((0.5 * g) * (timemat**2))
    df = pd.DataFrame({"x": x, "y": y})
    return df
demo = gr.Blocks()
with demo:
    gr.Markdown(
        r"Let's do some kinematics! Choose the speed and angle to see the trajectory. Remember that the range $R = v_0^2 \cdot \frac{\sin(2\theta)}{g}$"
    )
    with gr.Row():
        speed = gr.Slider(1, 30, 25, label="Speed")
        angle = gr.Slider(0, 90, 45, label="Angle")
    output = gr.LinePlot(
        x="x",
        y="y",
        overlay_point=True,
        tooltip=["x", "y"],
        x_lim=[0, 100],
        y_lim=[0, 60],
        width=350,
        height=300,
    )
    btn = gr.Button(value="Run")
    btn.click(plot, [speed, angle], output)
if __name__ == "__main__":
    demo.launch()
ini 复制代码
import matplotlib.pyplot as plt
import numpy as np
import gradio as gr
def plot_forecast(final_year, companies, noise, show_legend, point_style):
    start_year = 2020
    x = np.arange(start_year, final_year + 1)
    year_count = x.shape[0]
    plt_format = ({"cross": "X", "line": "-", "circle": "o--"})[point_style]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    for i, company in enumerate(companies):
        series = np.arange(0, year_count, dtype=float)
        series = series**2 * (i + 1)
        series += np.random.rand(year_count) * noise
        ax.plot(x, series, plt_format)
    if show_legend:
        plt.legend(companies)
    return fig
demo = gr.Interface(
    plot_forecast,
    [
        gr.Radio([2025, 2030, 2035, 2040], label="Project to:"),
        gr.CheckboxGroup(["Google", "Microsoft", "Gradio"], label="Company Selection"),
        gr.Slider(1, 100, label="Noise Level"),
        gr.Checkbox(label="Show Legend"),
        gr.Dropdown(["cross", "line", "circle"], label="Style"),
    ],
    gr.Plot(label="forecast", format="png"),
)
if __name__ == "__main__":
    demo.launch()

ScatterPlot(散点图)

创建一个散点图组件来显示来自 pandas DataFrame 的数据。

ini 复制代码
import pandas as pd
from random import randint, random
import gradio as gr
food_rating_data = pd.DataFrame(
    {
        "cuisine": [["Italian", "Mexican", "Chinese"][i % 3] for i in range(100)],
        "rating": [random() * 4 + 0.5 * (i % 3) for i in range(100)],
        "price": [randint(10, 50) + 4 * (i % 3) for i in range(100)],
        "wait": [random() for i in range(100)],
    }
)
with gr.Blocks() as demo:
    price_by_rating = gr.ScatterPlot(
        food_rating_data,
        x="rating",
        y="price",
        color="wait",
        show_actions_button=True,
    )
    price_by_rating_color = gr.ScatterPlot(
        food_rating_data,
        x="rating",
        y="price",
        color="cuisine",
    )
if __name__ == "__main__":
    demo.launch()

基本使用

简单示例

ini 复制代码
import gradio as gr
def 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

Interface类核心参数解释:

  • fn : 用于包装用户界面(UI)的函数
  • inputs : 用于输入的 Gradio 组件。组件的数量应与你的函数参数数量相匹配。
  • outputs : 用于输出的 Gradio 组件。组件的数量应与函数返回值的数量相匹配。

Interface

Interface是 Gradio 的主要高级类,它允许您用几行代码围绕机器学习模型(或任何 Python 函数)创建基于网络的GUI演示。Interface初始化必须指定三个参数:事件处理函数、输入组件、输出组件。

简单使用

我们可以使用如下方式快速构建一个表单界面,默认会自带提交按钮

python 复制代码
import gradio as gr
def image_classifier(inp):
    return {'cat': 0.3, 'dog': 0.7}
demo = gr.Interface(fn=image_classifier, inputs="image", outputs="label")
demo.launch()

Examples

python 复制代码
import gradio as gr
def sentence_builder(quantity, animal, countries, place, activity_list, morning):
    return f"""The {quantity} {animal}s from {" and ".join(countries)} went to the {place} where they {" and ".join(activity_list)} until the {"morning" if morning else "night"}"""
demo = gr.Interface(
    sentence_builder,
    [
        gr.Slider(2, 20, value=4, label="Count", info="Choose between 2 and 20"),
        gr.Dropdown(
            ["cat", "dog", "bird"], label="Animal", info="Will add more animals later!"
        ),
        gr.CheckboxGroup(["USA", "Japan", "Pakistan"], label="Countries", info="Where are they from?"),
        gr.Radio(["park", "zoo", "road"], label="Location", info="Where did they go?"),
        gr.Checkbox(label="Morning", info="Did they do it in the morning?"),
    ],
    "text",
    examples=[
        [2, "cat", ["Japan", "Pakistan"], "park", True],
        [4, "dog", ["Japan"], "zoo", False],
        [10, "bird", ["USA", "Pakistan"], "road", False],
        [8, "cat", ["Pakistan"], "zoo", True],
    ]
)
if __name__ == "__main__":
    demo.launch()

examples会为组件提供初始化示例,用户点击示例即可快速填充示例值进行初始化体验

多输入输出

gr.Interface支持多输入输出,可以构建出更为复杂的界面

ini 复制代码
import gradio as gr
def 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 / 9
    return greeting, round(celsius, 2)
demo = gr.Interface(
    fn=greet, 
    inputs=["text", "checkbox", gr.Slider(0, 100)], 
    outputs=["text", "number"])
demo.launch()

Blocks

Blocks 是 Gradio 的底层 API,它允许你创建比 Interfaces 更自定义的 Web 应用程序和演示,与 Interface 类相比,Blocks 提供了更多关于以下方面的灵活性和控制权。

简单使用

Blocks提供更灵活的界面构建方式,使用如下方式即可快速构建一个简单界面

scss 复制代码
import gradio as gr
with gr.Blocks(title="测试") as demo:
    gr.Markdown("# 🗂️ 示例")
    gr.Markdown("这个示例展示了Gradio Blocks的基本用法")

    with gr.Row():
      button = gr.Button("确定", variant="primary")
      cancel = gr.Button("取消")

demo.launch()

Blocks的灵活也意味着很多事件需要我们自己定义,Blocks构建的页面不会默认带提交按钮

Queue(队列)

通过启用队列,可以控制在队列中的位置,并设置允许的最大事件数量限制。

ini 复制代码
with gr.Blocks() as demo:
    button = gr.Button(label="Generate Image")
    button.click(fn=image_generator, inputs=gr.Textbox(), outputs=gr.Image())
# 设置队列上限
demo.queue(max_size=10)
demo.launch()

load(加载)

python 复制代码
import gradio as gr
def on_page_load():
    """页面加载时执行的函数"""
    return "✅ 页面加载完成,欢迎使用!"
with gr.Blocks(title="简单的页面加载示例") as demo:
    # 用于显示加载消息的组件
    status_box = gr.Textbox(
        label="状态", 
        placeholder="等待页面加载...",
        interactive=False
    )

    # 页面加载事件 - 无输入,只有输出
    demo.load(
        fn=on_page_load,
        outputs=status_box
    )

if __name__ == "__main__":
    print("启动简单的页面加载示例...")
    demo.launch() 

unload(卸载)

当用户关闭或刷新标签页时,此监听器会被触发,结束用户会话。在应用关闭时清理资源时,它很有用。

python 复制代码
import gradio as gr
with gr.Blocks() as demo:
    gr.Markdown("# When you close the tab, hello will be printed to the console")
    demo.unload(lambda: print("hello"))
demo.launch()

ChatInterface

简单使用

ChatInterface 是 Gradio 用于创建聊天机器人 UI 的高级抽象,允许你用几行代码围绕聊天机器人模型创建一个基于网络的演示。

ini 复制代码
import gradio as gr
def echo(message, history):
    return message
demo = gr.ChatInterface(
  fn=echo, 
  type="messages", 
  examples=["hello", "hola", "merhaba"], 
  title="Echo Bot"
)
demo.launch()

自定义机器人

python 复制代码
import gradio as gr
def yes(message, history):
    return "yes"
def vote(data: gr.LikeData):
    if data.liked:
        print("You upvoted this response: " + str(data.value))
    else:
        print("You downvoted this response: " + str(data.value))
with gr.Blocks() as demo:
    chatbot = gr.Chatbot(placeholder="<strong>Your Personal Yes-Man</strong><br>Ask Me Anything")
    chatbot.like(vote, None, None)
    gr.ChatInterface(fn=yes, type="messages", chatbot=chatbot)

demo.launch()

TabbedInterface

一个 TabbedInterface 是通过提供一系列 Interface 或 Blocks 创建的,每个 Interface 或 Block 都会在单独的标签页中渲染。只有 Interface/Blocks 中的组件会在标签页中渲染。Blocks 的某些高级属性(例如自定义的 css 、 js 和 head 属性)不会被加载。

ini 复制代码
import gradio as gr
hello_world = gr.Interface(lambda name: "Hello " + name, "text", "text")
bye_world = gr.Interface(lambda name: "Bye " + name, "text", "text")
chat = gr.ChatInterface(lambda *args: "Hello " + args[0])
demo = gr.TabbedInterface([hello_world, bye_world, chat], ["Hello World", "Bye World", "Chat"])
if __name__ == "__main__":
    demo.launch()

Gradio Sketch

只需在终端中键入 gradio sketch 即可打开一个编辑器(相当于一个低代码平台),该编辑器可让您定义和修改 Gradio 组件、调整其布局、添加事件,所有这些都通过 Web 编辑器完成。或者使用这个托管版本的 Gradio Sketch,在 Hugging Face Spaces 上运行 :huggingface.co/spaces/alia...

热重载

Gradio支持热重载,本地开发时只需要在热重载模式下运行 Gradio 应用程序,只要更改文件,该模式就会自动重新加载 Gradio 应用程序。

php 复制代码
 $ gradio app.py

分享示例

python 复制代码
import gradio as gr
def greet(name):
    return "Hello " + name + "!"
# 创建一个简单的接口
demo = gr.Interface(fn=greet, inputs="textbox", outputs="textbox")
# 启动服务
demo.launch(share=True)

按照提示下载依赖文件、重命名、移动位置,最后为依赖文件添加权限

shell 复制代码
# 进入/Users/username/.cache/huggingface/gradio/frpc目录下为依赖文件添加权限
$ chmod +x frpc_darwin_amd64_v0.3

最新运行代码,可以看到生成的分享链接(链接有效期为1周)

在浏览器中打开,效果如下:

还可以为分享添加授权

ini 复制代码
import gradio as gr
def reverse(text):
    return text[::-1]
demo = gr.Interface(reverse, "text", "text")
demo.launch(share=True, auth=("username", "password"))

输入预置的用户名和密码登录成功后方可进入

生态系统

  • Gradio Python 客户端 (gradio_client):在 Python 中以编程方式查询任何 Gradio 应用程序。
  • Gradio JavaScript 客户端 (@gradio/client):在 JavaScript 中以编程方式查询任何 Gradio 应用程序。
  • Gradio-Lite (@gradio/lite):感谢 Pyodide,用 Python 编写完全在浏览器中运行的 Gradio 应用程序(不需要服务器!)
  • Hugging Face Spaces:最受欢迎的托管 Gradio 应用程序的地方 - 免费!

常见问题

进入 /Users/username/.cache/huggingface/gradio/frpc 目录下为依赖文件添加权限

shell 复制代码
 $ chmod +x frpc_darwin_amd64_v0.3

友情提示

见原文:【Gradio】初识Gradio

本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。

相关推荐
小和尚同志1 小时前
使用 Dify 工作流实现每日热点简报
人工智能·aigc
墨风如雪3 小时前
PPT 我自己就能做!智谱新模型“玩转”工作汇报,简直是打工人福音!
aigc
堆栈future10 小时前
大模型时代的三巨头—Grok、ChatGPT与Gemini深度解析
llm·aigc·openai
redreamSo11 小时前
AI Daily | AI日报:斯坦福:AI当第一作者的学术会议来了; Chai-2:重构药物设计逻辑的「药界ChatGPT」; 实测:AI让顶尖程序员写代码慢19%
程序员·aigc·资讯
软件测试君12 小时前
向量数据库 Chroma 和 Milvus的使用
langchain·aigc·openai
欧雷殿12 小时前
超越 Vibe Coding 的智能研发
低代码·aigc·ai编程
产品经理独孤虾1 天前
如何利用AI大模型对已有创意进行评估,打造杀手级的广告创意
人工智能·大模型·aigc·产品经理·数字营销·智能营销·智能创意生成
墨风如雪1 天前
你的笔记本也能跑“AI大神”!微软Phi-4-mini-flash-reasoning震撼登场
aigc
堆栈future1 天前
深度剖析Manus:如何打造低幻觉、高效率、安全可靠的Agentic AI系统
llm·aigc·mcp