news 2026/9/10 14:52:31

Gradio 自定义进度条实战:gr.Progress 与 tqdm 全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gradio 自定义进度条实战:gr.Progress 与 tqdm 全攻略

Gradio 自定义进度条实战:gr.Progress 与 tqdm 全攻略

【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio

本指南基于 Gradio 仓库官方进阶文档《Progress Bars》(guides/04_additional-features/05_progress-bars.md)编写,围绕"如何给耗时函数显示实时进度"这一主题展开。文中将以 demo/progress_simple/run.py 等真实可运行示例为主线,并结合 gradio/helpers.py 中gr.Progress的实现源码,系统讲解手动更新进度、基于可迭代对象的进度追踪,以及自动接管tqdm.tqdm进度条的三种用法。读完本文,你将能在自己的gr.Interfacegr.Blocks应用中精确控制并向用户展示每一个处理阶段的进展。

核心机制:为函数注入gr.Progress参数

Gradio 之所以能显示自定义进度条,靠的是一种非常轻量的"注入"约定:只要在你的函数里新增一个以gr.Progress()实例为默认值的参数,Gradio 就会自动识别它,并把当前事件对应的进度通道绑定到该实例上。你不需要显式创建任何客户端代码或前端组件——绑定、消息推送与界面渲染全部由框架完成。

注意参数位置的约定:Progress参数应紧跟在常规输入参数之后。从源码看,gradio/helpers.py 中的special_args()通过isinstance(param.default, Progress)判断特殊参数(见L979),并把传入的gr.Progress()实例自动插入输入列表对应下标;因此在函数签名中放错位置或写成关键字参数都可能不被识别。

这个默认值参数被识别后,接下来你有两条更新进度的途径,它们可以混合使用:

  1. 直接调用progress实例,传入一个0 ~ 1之间的小数表示完成比例;
  2. 使用progress.tqdm(...)方法包装任意可迭代对象,让进度随迭代自动推进。

Progress类的官方 docstring(见 gradio/helpers.pyL673-L689)给出了最小用法示例,下文将逐一展开。

快速上手:一个最简单的自定义进度条

仓库中与本文档配套的最小可运行示例位于 demo/progress_simple/run.py,完整代码只有 17 行:

import gradio as gr import time def slowly_reverse(word, progress=gr.Progress()): progress(0, desc="Starting") time.sleep(1) progress(0.05) new_string = "" for letter in progress.tqdm(word, desc="Reversing"): time.sleep(0.25) new_string = letter + new_string # type: ignore return new_string demo = gr.Interface(slowly_reverse, gr.Text(), gr.Text(), api_name="predict") if __name__ == "__main__": demo.launch()

运行该文件后,在输入框中输入一个单词并提交,你会依次看到:

  • 阶段一:进度条停驻在0(0%)并显示描述文本"Starting"
  • 阶段二:进度条跳到0.05(5%);
  • 阶段三:进度条随word中每个字符的逐个处理平滑推进,描述变为"Reversing"

这个例子同时示范了两种更新方式,下面分别深入讲解其参数细节与底层行为。

方式一:手动更新进度

Progress.__call__(见 gradio/helpers.pyL736-L764)支持三种形态的入参,签名如下:

progress( progress: float | tuple[int, int | None] | None, desc: str | None = None, total: int | float | None = None, unit: str = "steps", )

各参数的语义(与源码 docstring 一致):

参数类型含义
progressfloat表示整体完成比例的小数,取值应落在01之间,如progress(0.5)表示 50%;
progresstuple[int, int \| None]传入元组时,第一个数代表"已完成步数"index,第二个数代表"总步数"total(未知则传None),由index / total换算成比例;
progressNone隐藏进度条。当阶段划分不明确、或函数即将进入无法量化的环节时,可调用progress(None)让进度条消失;
descstr进度条上显示的描述文字,例如"Cleaning Images"
totalint \| float预估总步数(使用元组形式时同样可传);
unitstr迭代单位名称,默认是"steps",用于展示如3/10 steps

一个典型的多阶段手动更新示例(取自 demo/progress/run.py 的clean_imgs函数):

def clean_imgs(text, progress=gr.Progress()): progress(0.2, desc="Collecting Images") time.sleep(1) progress(0.5, desc="Cleaning Images") time.sleep(1.5) progress(0.8, desc="Sending Images") time.sleep(1.5) return "done"

可以据此把一项长任务拆成若干可命名的工序,每道工序开始前调用一次progress,让用户始终清楚当前处于哪个阶段。

方式二:用progress.tqdm()追踪迭代

Progress.tqdm()(见 gradio/helpers.pyL766-L796)提供与tqdm库类似的迭代式进度追踪。当Progress处于有效绑定状态时,它并不会真的逐项 yield,而是把一个"可追踪迭代器"(TrackedIterable)压入内部栈,并把进度计算委托给底层队列:

for item in progress.tqdm(iterable, desc="Reversing"): ...

其可选参数desctotalunit与手动更新的语义完全一致:

  • 当传入的iterable实现了__len__(如listrange)时,total会取len(iterable),进度精确;
  • 当迭代对象长度未知时(如生成器),可通过total显式给出预估总步数,否则进度条按不确定模式展示。

嵌套进度:外层 + 内层双层循环

tqdm一样,Progress.tqdm天然支持嵌套。例如 demo/progress/run.py 中的load_nested_set演示了"外层列表 + 内层列表"的嵌套追踪:

def load_nested_set(text, text2, progress=gr.Progress()): imgs = [[None] * 8] * 3 for img_set in progress.tqdm(imgs, desc="Nested list"): time.sleep(2) for img in progress.tqdm(img_set, desc="inner list"): time.sleep(0.1) return "done"

从前端表现看,内层循环推进时会显示"细分进度",内层结束后外层条继续推进。这一行为由源码中的"迭代器栈"实现:每次调用tqdm()append一个TrackedIterable,每次迭代耗尽后pop出栈(见 gradio/helpers.pyL784-L793),从而支持任意层级的递归跟踪。

追踪未知长度的生成器

load_random函数展示了传入生成器、长度完全未知的场景:

def load_random(data, progress=gr.Progress()): def yielder(): for i in range(0, random.randint(15, 20)): time.sleep(0.1) yield None for img in progress.tqdm(yielder()): pass return "done"

生成器没有__len__且未传total时,进度条会以不确定状态展示,但仍能实时刷新"已完成 X 项"。

方式三:track_tqdm=True自动追踪已有 tqdm

如果你(或你调用的第三方库)的代码里已经写了原生的tqdm.tqdm,并不想改造它,只要把默认参数改成:

def fn(..., progress=gr.Progress(track_tqdm=True)): for i in tqdm.tqdm(range(100)): ...

此时函数体内所有tqdm.tqdm的进度都会被自动转发到 Gradio 进度条上,无需任何手工同步。

该特性的背后是patch_tqdm()tqdm类的一次全局"猴子补丁"(见 gradio/helpers.pyL837-L902):

  1. tqdm未安装时直接return(不会报错);
  2. tqdm.tqdm__init__updateclose__exit____iter__五个方法做包装,保存原方法为*_orig
  3. 每个方法在执行真实逻辑前,先从LocalContext取出当前线程/上下文中的Progress实例,若存在则调用其tqdm()/update()/close()把进度同步出去;
  4. create_tracker()(见L905-L915)会再用function_wrapper在函数执行前把Progress实例写入LocalContext.progress,结束后清除,避免跨请求串扰。

仓库用两个按钮演示了它的两种典型场景(见 demo/progress/run.py):

def track_tqdm(data, progress=gr.Progress(track_tqdm=True)): for i in tqdm.tqdm(range(5), desc="outer"): for j in tqdm.tqdm(range(4), desc="inner"): time.sleep(1) return "done"

你自己代码里的嵌套原生 tqdm;而bind_internal_tqdm函数则调用datasets.load_dataset(...),演示了第三方库内部使用的 tqdm同样会被自动接管(该 demo 的 requirements.txt 声明了tqdmdatasets两个依赖)。这是模型下载、数据集加载类场景下非常实用的能力——你一行进度代码都不用写。

进度数据的底层流转链路

把进度从 Python 函数一路送到浏览器,涉及如下调用链,理解它有助于排查"进度不显示"的问题:

  1. 函数内调用progress(0.5, desc=...)或迭代progress.tqdm(...)
  2. Progress._progress_callback()(见 gradio/helpers.pyL828-L834)从LocalContext中读取当前blocksevent_id,拿到blocks._queue.set_progress的绑定方法;若当前并不处于 Gradio 事件上下文(如纯本地脚本直接调用函数),回调为None,此时__call__直接原样返回传入值、tqdm()退化为普通迭代器——这就是为什么带gr.Progress参数的处理函数也能在单元测试或本地脚本中被安全调用;
  3. 队列系统在set_progress(见 gradio/queueing.pyL603-L626)中把每个TrackedIterable转成结构化的ProgressUnit(含indexlengthunitprogressdesc字段,定义见 gradio/server_messages.pyL12),组装为ProgressMessageL20)并通过 SSE 推送给前端;
  4. 前端消息循环收到ProgressMessage后渲染进度条。值得注意:多条消息推送之间做了合并去抖,避免高频更新淹没网络通道。

Blocks 场景下的完整进阶示例

gr.Interface外,gr.Blocks中同样可以使用进度条。仓库中的 demo/progress/run.py 是更完整的综合演示,覆盖了上文提到的全部用法,其核心布局包括:

  • Load Set:对定长list使用progress.tqdm(imgs, desc="Loading from list")
  • Load Nested Set:嵌套双层progress.tqdm
  • Load Random:追踪长度未知的生成器;
  • Clean Images:多阶段手动progress(...)调用;
  • Bind TQDM/Bind Internal TQDMgr.Progress(track_tqdm=True)接管自身与库内部的原生tqdm
  • Do All在多个函数之间共享同一个Progress实例并串联执行,其中使用progress(None)在阶段间隙隐藏进度条(见L72-L78):
def do_all(data, progress=gr.Progress()): load_set(data[text], data[textb], progress) load_random(data, progress) clean_imgs(data[text], progress) progress(None) # 隐藏进度条 wait(text) # 进入无法量化、无需展示进度的环节 return "done"

共享同一实例的方式表明:只要把Progress作为参数向下传递,多步骤流水线就能维持一条连续、统一的进度展示。值得注意的是这些函数还演示了把dict{text, textb})直接传给按钮的click作为输入集合,属于 Blocks 中多输入组件的常规写法。

常见问题与注意事项小结

  1. 进度条不出现:确认参数为位置参数、紧跟普通输入之后,且默认值确为gr.Progress()实例;special_args()依赖默认值类型识别该参数。
  2. 函数内已有 tqdm 但没生效:确认函数签名使用的是gr.Progress(track_tqdm=True)而非默认实例;同时确认环境已安装tqdmpatch_tqdm在缺包时会静默跳过)。
  3. 调用progressIndexError: Index not set.:通常在手动调用update()而内部没有已注册迭代器时发生;请优先使用__call__tqdm()这两种公开方式。
  4. 进度停留在 0%:为长度未知的生成器补充total=...参数,可让前端按比例渲染。
  5. 隐藏而非清零:若某个阶段不想展示进度条,用progress(None),而不是传0

上述机制对应的官方源码入口集中在 gradio/helpers.py(Progress类、patch_tqdmcreate_tracker)与 gradio/queueing.py(set_progress),如需深入调试,可沿这两处继续阅读。

【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:50:56

楼宇微网虚拟储能系统优化与PSO算法实现

1. 项目概述:楼宇微网与虚拟储能系统的融合优化在能源管理领域,楼宇微网作为分布式能源系统的重要载体,正面临如何高效整合需求侧资源的挑战。传统物理储能设备存在投资成本高、占地面积大等痛点,而虚拟储能系统(Virtu…

作者头像 李华
网站建设 2026/9/10 14:50:51

商超蔬菜价格弹性与补货策略:Python数据清洗到报童模型实战

简介:针对某商超蔬菜价格与补货策略的建模分析压缩包,适合数学建模参赛者、数据分析师及商超运营人员,可用于赛题复现、业务复盘或教学参考。资源围绕数据采集清洗、时间序列预测、回归定价、库存优化等展开,内含源码、数据集、可…

作者头像 李华
网站建设 2026/9/10 14:49:42

《智能系统》第1章 绪论 读书笔记

目录 1.1 智能系统的前世今生 1.1.1 智能系统概述1.1.2 智能系统的前世1.1.3 智能系统的今生1.1.4 智能系统的主要特征 1.2 概念模型和类谱表1.3 主要特征和类型1.4 智能系统发展前景 1.4.1 专家系统1.4.2 智能机器1.4.3 智能社会1.4.4 智能产业 本节核心总结(必看…

作者头像 李华
网站建设 2026/9/10 14:48:31

Diffusers 中的 Kandinsky 3 文生图与图生图流水线实战指南

Diffusers 中的 Kandinsky 3 文生图与图生图流水线实战指南 【免费下载链接】diffusers 🤗 Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch. 项目地址: https://gitcode.com/GitHub_Trending/di/diffusers …

作者头像 李华
网站建设 2026/9/10 14:48:27

降AI率解读:降AI率工具处理后文本自然度如何判断2026实用指南

降AI率解读:降AI率工具处理后文本自然度如何判断2026实用指南 关于降AI率文本自然度判断,我系统研究过一段时间,也实际验证过各种降AI率说法。 这篇文章把降AI率关键逻辑理清楚——知道了原理,遇到降AI率问题就知道该怎么处理了…

作者头像 李华
网站建设 2026/9/10 14:48:24

DBeaver 单 bundle 构建或测试执行失败怎么排查

DBeaver 单 bundle 构建或测试执行失败怎么排查 【免费下载链接】dbeaver Free universal database tool and SQL client 项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver 在 DBeaver Community Edition 仓库里做二次开发时,最容易卡住的一步是&a…

作者头像 李华