掘金 人工智能 07月13日 14:13
【Gradio】初识Gradio
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

Gradio是一个轻量级的Python库,它简化了机器学习模型的交互式Web页面开发流程。通过提供丰富的预构建组件,开发者可以快速搭建AI应用的用户界面,方便用户体验和测试模型。本文介绍了Gradio的基本概念、安装方法,并详细阐述了多个常用组件的使用方法,例如文本框、数字输入、按钮、图片、音频、文件上传等,帮助读者快速上手Gradio,构建自己的AI应用。

💡Gradio 提供了30多个预构建的组件,这些组件可作为演示中的输入或输出,帮助开发者快速构建用户界面。

💡Textbox(文本框)组件,可用于接收用户输入的文本或显示文本输出,支持文本对比功能,并可以监听输入内容的改变。

💡Number(数字)组件,用于创建数值输入字段,可以接收用户输入的数字或显示数值输出,并支持数值的动态更新。

💡Button(按钮)组件,用于触发特定操作,可以自定义按钮的文本和主题,并支持清除按钮功能,用于清除组件或组件列表的值。

💡Image(图片)组件,用于上传图像或显示图像,可以结合滤镜功能,对图像进行编辑处理;ImageEditor(图片编辑)组件,则提供了更丰富的编辑工具。

💡File(文件)组件,支持单文件和多文件上传,可以指定文件类型,并提供文件预览功能;FileExplorer(文件浏览器)组件,允许用户浏览服务器上的文件。

前言

我们经常在网上看到这样

或者这样的界面

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

Gradio简介

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

官网地址:www.gradio.app

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

安装

Gradio 需要 Python 3.10 或更高版本

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

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

预构建组件

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

Textbox(文本框)

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

import gradio as grdef 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还可以监听输入内容改变

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

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

from difflib import Differdef 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(数字)

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

import gradio as grdef update_number(number):    return number * 2with 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

普通按钮

import gradio as grdef 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的主题类型

upload_btn = gr.Button("Upload Results", variant="primary")

ClearButton(清除按钮)

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

import gradio as grdef button_click(name: str|None):    return "Hello " + name + "!!"# clearButtonwith 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(上传|下载按钮)

from pathlib import Pathimport gradio as grdef 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(单选框)

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

import gradio as grdef 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(复选框)

import gradio as grdef 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(图片)

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

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

图片添加滤镜

import numpy as npimport gradio as grdef sepia(input_img):    if input_img is None:        return None    sepia_filter = np.array([        [0.3930.7690.189],        [0.3490.6860.168],        [0.2720.5340.131]    ])    # 确保输入是float类型,避免溢出    img = input_img.astype(np.float32)    # 应用sepia滤镜    sepia_img = img @ sepia_filter.T    # 保证像素值在0-255之间    sepia_img = np.clip(sepia_img, 0255)    sepia_img = sepia_img.astype(np.uint8)    return sepia_imgdemo = gr.Interface(sepia, gr.Image(), "image")if __name__ == "__main__":    demo.launch()

ImageEditor(图片编辑)

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

import gradio as grimport timedef 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(图片滑块)

滑动展示图片模糊对比

import gradio as grfrom PIL import ImageFilterdef 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 imdef 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代码编辑器,用于查看代码(作为输出组件),或用于输入和编辑代码(作为输入组件)。

import gradio as grdef code_demo(code):    return code# 方法1:使用 Interface# demo = gr.Interface(fn=code_demo, inputs="code", outputs="text")# 方法2:使用 Blockswith 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(颜色选择器)

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

import gradio as grimport numpy as npfrom PIL import Image, ImageColorimport redef 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 (25500)    # 如果所有解析都失败,返回默认颜色    return (25500)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_imagedemo = 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 。

import gradio as grdef 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 布局中渲染子组件。

import gradio as grwith gr.Blocks() as demo:    with gr.Sidebar():        gr.Textbox()        gr.Button()    gr.Textbox()if __name__ == "__main__":    demo.launch()

DateTime(时间选择器)

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

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

import gradio as grdef 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(作为输出使用时)

单文件上传

import gradio as grimport osdef 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()

多文件上传

multiple_files = gr.File(label="上传多个文件",file_count="multiple")

指定文件类型上传

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

文件预览

import gradio as grdef preview_and_prepare_download(file):    if file is None:        return None    return filewith 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 应用的机器上的文件。作为输入组件,它还允许用户选择文件用作函数的输入,而作为输出组件,它显示所选文件。

import gradio as grdef 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(音频)

import numpy as npimport gradio as grnotes = ["C""C#""D""D#""E""F""F#""G""G#""A""A#""B"]def generate_tone(note, octave, duration):    sr48000    a4_freq, tones_from_a444012 * (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, audiodemo = 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(画廊)

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

import randomimport gradio as grdef 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 imageswith 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 输出。由于这个组件不接受用户输入,它很少被用作输入组件。

import gradio as grwith 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。由于这个组件不接受用户输入,它很少被用作输入组件。

import gradio as grwith 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 输出。由于该组件不接受用户输入,因此很少用作输入组件。

from zipfile import ZipFileimport gradio as grdef 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 filesdemo = gr.Interface(zip_to_json, "file""json")if __name__ == "__main__":    demo.launch()

Label(分类标签)

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

import gradio as grwith 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(多模态文本框)

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

import gradio as grimport 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 historywith gr.Blocks() as demo:    chatbot = gr.Chatbot(elem_id="chatbot", bubble_full_width=Falsetype="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, NoneNone, like_user_message=True)if __name__ == "__main__":    demo.launch()

DataFrame(表格组件)

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

import gradio as grdef tax_calculator(income, assets):    total_deductible = sum(assets["Cost"])    taxable_income = income - total_deductible    return taxable_incomedemo = 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(参数查看器)

以表格形式展示组件参数

import gradio as grwith 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(状态)

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

import gradio as grdef 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 事件监听器定期触发事件。

import gradio as grimport timewith 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 的数据

import gradio as grimport pandas as pdfrom random import randint, randomfood_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 的数据。

import gradio as grimport pandas as pdfrom random import randinttemp_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(图表)

import pandas as pdimport numpy as npimport gradio as grdef plot(v, a):    g9.81    theta = a / 180 * 3.14    tmax = ((2 * v) * np.sin(theta)) / g    timemat = tmax * np.linspace(0140)    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 dfdemo = 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(13025, label="Speed")        angle = gr.Slider(09045, label="Angle")    output = gr.LinePlot(        x="x",        y="y",        overlay_point=True,        tooltip=["x""y"],        x_lim=[0100],        y_lim=[060],        width=350,        height=300,    )    btn = gr.Button(value="Run")    btn.click(plot, [speed, angle], output)if __name__ == "__main__":    demo.launch()

import matplotlib.pyplot as pltimport numpy as npimport gradio as grdef plot_forecast(final_year, companies, noise, show_legend, point_style):    start_year2020    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 figdemo = 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 的数据。

import pandas as pdfrom random import randint, randomimport gradio as grfood_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()

基本使用

简单示例

import 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

Interface类核心参数解释:

Interface

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

简单使用

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

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

Examples

import gradio as grdef 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(220, 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支持多输入输出,可以构建出更为复杂的界面

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 / 9    return greeting, round(celsius, 2)demo = gr.Interface(    fn=greet,     inputs=["text""checkbox", gr.Slider(0100)],     outputs=["text""number"])demo.launch()

Blocks

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

简单使用

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

import gradio as grwith 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(队列)

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

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(加载)

import gradio as grdef 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(卸载)

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

import gradio as grwith gr.Blocks() as demo:    gr.Markdown("# When you close the tab, hello will be printed to the console")    demo.unload(lambdaprint("hello"))demo.launch()

ChatInterface

简单使用

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

import gradio as grdef echo(message, history):    return messagedemo = gr.ChatInterface(  fn=echo,   type="messages",   examples=["hello""hola""merhaba"],   title="Echo Bot")demo.launch()

自定义机器人

import gradio as grdef 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, NoneNone)    gr.ChatInterface(fn=yes, type="messages", chatbot=chatbot)demo.launch()

TabbedInterface

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

import gradio as grhello_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 应用程序。

 $ gradio app.py

分享示例

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

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

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

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

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

还可以为分享添加授权

import gradio as grdef reverse(text):    return text[::-1]demo = gr.Interface(reverse, "text""text")demo.launch(share=True, auth=("username""password"))

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

生态系统

常见问题

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

 $ chmod +x frpc_darwin_amd64_v0.3

友情提示

见原文:【Gradio】初识Gradio

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

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Gradio 机器学习 Web应用 Python
相关文章