Gradio 前端状态追踪组件 @gradio/statustracker 深度解析:StatusTracker、Toast 与 Loader 的完整指南
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
@gradio/statustracker是 Gradio 前端(Svelte 5)中负责「执行状态可视化」的核心 UI 包:它通过StatusTracker展示任务的排队、进度、ETA 与错误,通过Toast弹出全局通知,通过Loader渲染加载动画。本文基于仓库内 js/statustracker/README.md 的组件契约,结合 js/statustracker/static 下的 Svelte 源码与LoadingStatus状态机实现,完整讲解三个组件的全部属性(Props)、底层状态流转逻辑与可验证的测试用例,帮助你在自定义 Gradio 前端组件或二次开发时正确接入这套状态体系。
包定位与基本导入方式
@gradio/statustracker是 Gradio monorepo(使用 pnpm workspace)中的一个前端包,版本见 js/statustracker/package.json(当前为 0.15.3),依赖@gradio/atoms、@gradio/icons、@gradio/sanitize、@gradio/utils等兄弟包,并以svelte: ^5.48.0作为 peer dependency,是一个典型的 Svelte 5 组件库。
包入口 js/statustracker/index.ts 导出了 4 个组件与 1 个状态类:
export { default as StatusTracker } from "./static/index.svelte"; export { default as Toast } from "./static/Toast.svelte"; export { default as Loader } from "./static/Loader.svelte"; export { default as StreamingBar } from "./static/StreamingBar.svelte"; export type * from "./static/types"; export { LoadingStatus } from "./static/state.svelte.js";在 Svelte 组件中的典型导入方式(与 README 一致):
<script> import { StatusTracker, Toast, Loader } from "@gradio/statustracker"; </script>此外还可以额外导入StreamingBar(流式输出倒计时条)和LoadingStatus(状态管理类,供非组件环境维护全局执行状态)。
StatusTracker:任务执行状态指示器
StatusTracker是包内最核心的组件,实现位于 js/statustracker/static/index.svelte。它根据组件 Props 中的status、队列信息、进度数据和 ETA 渲染一个覆盖在输入/输出组件上的状态层,并在满足条件时自动隐藏。
Props 完整清单(继承自 README)
以下属性全部为 Svelte 5 的export let(实现中通过$props()解构并带默认值),可按需传入:
export let i18n: I18nFormatter; // 国际化格式化函数,用于“Clear”“Error”等文案 export let eta: number | null = null; // 剩余预计秒数(服务端估计) export let queue = false; // 本次运行是否经过队列 export let queue_position: number | null; // 当前排队位置(从 0 开始) export let queue_size: number | null; // 队列总长度 export let status: "complete" | "pending" | "error" | "generating"; // 当前执行状态 export let scroll_to_output = false; // 状态变化时是否自动滚动到输出 export let timer = true; // 是否显示已运行计时器 export let show_progress: "full" | "minimal" | "hidden" = "full"; // 进度展示粒度 export let message: string | null = null; // 与状态关联的消息(错误详情等) export let progress: LoadingStatus["progress"] | null | undefined = null; // 进度数组 export let variant: "default" | "center" = "default"; // 覆盖样式变体 export let loading_text = "Loading..."; // 关闭计时器时显示的加载文案 export let absolute = true; // 使用 absolute 定位覆盖组件(false 时转为 static 流式布局) export let translucent = false; // 半透明背景(无背景填充) export let border = false; // 是否显示边框 export let autoscroll: boolean; // 是否允许自动滚动(控制滚动行为开关)状态与自动隐藏逻辑
组件通过一个should_hide派生值决定是否隐藏(.hide类设置为opacity: 0; pointer-events: none):
const should_hide = $derived( !(show_validation_error && validation_error) && (type === "input" || !status || status === "complete" || show_progress === "hidden" || status == "streaming") );从源码结构看,满足以下任一条件时 StatusTracker 自动隐藏:存在输入型事件(type === "input")、状态为空或已complete、show_progress === "hidden",以及streaming状态(流式输出另有专用 UI)。这也解释了 README 中status类型声明为"complete" | "pending" | "error" | "generating"而源码 Props 额外接受"streaming" | null的原因——实现层面需要兼容流式与空状态。
队列、进度与 ETA 的展示细节
在pending状态下,组件按优先级展示三类信息(见 index.svelte 的模板逻辑):
- 进度文本:若存在
progress数组,则显示pretty_si(index)/pretty_si(length) unit形式的进度(pretty_si位于 js/statustracker/static/utils.ts,会将数值格式化为k/M/G等 SI 单位);否则若queue_position >= 0显示queue: {queue_position + 1}/{queue_size};否则显示processing。 - 计时器与 ETA:当
timer为 true 时显示{elapsed}{eta ?/${formatted_eta}: ""}s。计时从time_start(首次进入 pending 时的performance.now())开始,通过requestAnimationFrame循环刷新。 - 进度条:由
progress数组推导每个子任务的进度级别(index / length或progress字段),渲染最细粒度的进度条;若show_progress === "full"且没有任何进度数据,则回退到<Loader />加载动画。当timer为 false 时,改为渲染loading_text文本。
此外组件还支持校验错误展示(validation_error+show_validation_error)、错误态(status === "error"时显示错误徽标与on_clear_status清除按钮),以及缓存命中指示器:当输出来自缓存(used_cache === "full" | "partial")且提供了cache_duration时,会在右下角显示⚡ from cache: Xs(或used cache),并在 1.75 秒后淡出——这是 Gradio 缓存机制在前端的状态反馈。
底层状态机:LoadingStatus 类
StatusTracker只负责渲染,真正的状态流转由 js/statustracker/static/state.svelte.ts 中的LoadingStatus类维护。该类的类型契约定义在 js/statustracker/static/types.ts 的ILoadingStatus接口中,字段包括:
export interface ILoadingStatus { eta: number | null; status: "pending" | "error" | "complete" | "generating" | "streaming"; queue: boolean; queue_position: number | null; queue_size?: number; component_id?: number; fn_index: number; message?: string | null; scroll_to_output?: boolean; show_progress?: "full" | "minimal" | "hidden"; time_limit?: number | null | undefined; time_start?: number | null; // performance.now() 首次进入 pending 的时刻,软重载后保留 eta_total?: number | null; // 最近一次服务端 ETA 更新时的总耗时(已用+剩余) progress?: { progress, index, length, unit, desc }[]; validation_error?: string | null; type: "input" | "output" | "skip"; stream_state: "open" | "closed" | "waiting" | null; used_cache?: "full" | "partial" | null; cache_duration?: number | null; avg_time?: number | null; cache_event_id?: number | null; }核心方法包括:
register(dependency_id, outputs, inputs, show_progress):把某个依赖(事件)与其输入/输出组件 id 绑定,并记录其show_progress粒度。update(args):接收服务端推送的LoadingStatusArgs,为每个相关组件 id 生成新状态。resolve_args(args):核心状态机。它维护pending_outputs计数器,正确处理pending→pending(不变)、非 pending→pending(计数 +1)、pending→非 pending(计数 -1,若还有其它 pending 依赖则保持 pending)的并发切换;同时决定每个组件状态的type:输入组件仅在流式事件(有stream_state)时标记为"input",否则输出组件标记为"output",无关组件标记为"skip"并被过滤。remap_ids(...):在热重载(hot-reload)后 UI 以新组件 id 重新挂载时,把 in-flight 的 loading 状态从旧 id 迁移到新 id,避免刷新后丢失状态。set_status(id, status)/clear(id):直接设置或清空某个组件 id 的状态。
在update中,eta_total的计算也值得注意:每次服务端推送新的eta时,用(performance.now() - time_start) / 1000 + eta累计出总 ETA,从而在多次推送之间保持计时连续性(这正是StatusTracker里eta_from_start与eta_level进度条的数据来源)。
Toast:全局消息通知组件
Toast组件(js/statustracker/static/Toast.svelte)用于在页面右上角弹出消息通知,仅有一个 Props:
export let messages: ToastMessage[] = [];ToastMessage类型同样定义在 types.ts:
export interface ToastMessage { type: "error" | "warning" | "info" | "success"; title: string; message: string; id: number; duration: number | null; // null 表示不自动关闭(常驻) visible: boolean; }从源码看,Toast的实现包含以下值得注意的行为:
- 按类型分组:
group_messages将同类型的消息聚合为一个分组(GroupedToastMessage),点击头部可在展开/收起之间切换,并在标题上显示(N)数量角标。 - 自动关闭:单条消息且
duration非 null 时,ToastContent在duration秒后自动关闭,同时渲染一条底部倒计时进度条(animation-duration由 duration 决定);点击右上角 × 可立即关闭该组全部消息。 - 触控滑动关闭:
ToastContent(js/statustracker/static/ToastContent.svelte)监听touchstart/touchmove/touchend,水平滑动超过 100px 即关闭整组消息,否则回弹复位——这是为移动端设计的交互。 - 内容安全:消息文本通过
@gradio/sanitize的sanitize函数消毒后再以{@html}渲染,避免 XSS。 - 无障碍:容器声明
role="status"与aria-live="polite";标题区支持键盘 Enter/空格切换展开。 - 嵌入模式适配:在 iframe 嵌入场景(存在
parentIFrame)中会根据父页面滚动位置调整 toast 顶部偏移。
Loader:加载动画组件
Loader(js/statustracker/static/Loader.svelte)是纯装饰性加载动画,只有一个 Props:
export let margin = true;margin控制是否保留四周间距(.margin { margin: var(--size-4) })。实现使用 Svelte 5 的spring动画驱动两组渐变橙色四边形 SVG 上下往复运动,构成 Gradio 标志性的加载图标;组件卸载时通过dismounted标志停止动画循环。它通常内嵌于StatusTracker的pending状态中作为无进度数据时的回退展示(见上文),也可单独使用。
补充组件:StreamingBar 与测试验证
StreamingBar
js/statustracker/static/StreamingBar.svelte 是流式输出场景的倒计时条:接收time_limit: number | null,以animation-duration: {time_limit}s的线性动画在 4px 高的进度条上从右向左收缩,用于提示流式事件的服务端时间预算。
测试用例
包内附带 Vitest 测试 js/statustracker/StatusTracker.test.ts,通过mount(StatusTracker, { target, props })真实挂载组件并用within(target)断言。现有测试覆盖了validation_error场景的核心行为:
- 存在
validation_error时data-testid="status-tracker"元素可见; - 校验错误文本被正确渲染(
getByText("Can't be built")可见); - 状态为
null且无校验错误时组件隐藏(对应should_hide逻辑)。
测试中给出的最小 Props 组合{ i18n, autoscroll: false, queue_position: null, queue_size: null }也可作为你在自定义组件中集成StatusTracker时的最小传参参考。
在自定义组件中的接入建议
综合 README 与源码实现,接入@gradio/statustracker的推荐路径如下:
- 引入组件:在 Svelte 组件中
import { StatusTracker } from "@gradio/statustracker";,并按上文 Props 清单传入status、queue_position、queue_size、eta、progress等来自服务端状态的数据。 - 数据源接入:若你的模块需要自行维护多组件执行状态,可实例化
LoadingStatus并调用register+update,将结果映射到各StatusTracker的 Props;利用其pending_outputs计数器与remap_ids处理并发事件与热重载。 - 展示粒度:通过
show_progress(full/minimal/hidden)与variant(default/center)控制覆盖层外观;absolute、translucent、border用于布局微调。 - 全局通知:需要向用户弹窗时,维护
ToastMessage[]数组并传入Toast的messages,设置duration(秒)控制自动关闭。
小结
@gradio/statustracker是 Gradio 前端「状态可视化」的关键基础设施:StatusTracker负责细粒度的执行反馈(队列、进度、ETA、错误、缓存命中),LoadingStatus类在底层保证并发与热重载场景下的状态一致性,Toast提供移动端友好的分组通知,Loader与StreamingBar分别补充加载动画与流式倒计时。开发者既可以直接消费其 Props 做声明式集成,也可以通过LoadingStatus状态机实现更复杂的执行态管理。深入阅读 js/statustracker/static/index.svelte、js/statustracker/static/state.svelte.ts 与 js/statustracker/static/types.ts 三份核心文件,即可完整掌握这套状态体系的设计细节。
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考