Gradio Python Client 实战指南:用几行代码把任意 Gradio 应用变成可编程 API
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
本指南是 Gradio 官方文档系列 "Gradio Clients and Lite"(位于 guides/09_gradio-clients-and-lite/01_getting-started-with-the-python-client.md)的核心入门篇。你将学会安装独立的
gradio_client轻量包,用它连接托管在 Hugging Face Spaces、Share 链接或自建服务器上的任何 Gradio 应用,完成文件上传、同步/异步预测、任务状态跟踪与取消、生成式端点的流式消费等真实开发场景。读完本文,你可以完全不打开浏览器,用 Python 把任何 Gradio 应用当作标准 REST/流式 API 调用。
Gradio Python Client 是什么
Gradio 生态通常被理解为一个“用 Python 构建机器学习演示界面”的前端框架,而gradio_client则是同一生态的另一半:它把任何正在运行的 Gradio 应用暴露成可编程的 API,让你在脚本、批处理任务、Agent 或 Web 服务中远程调用它的功能。
用 client/python/gradio_client/init.py 中的定义来看,这个独立包向用户暴露的接口非常收敛,只有几个核心对象:
from gradio_client.client import Client from gradio_client.data_classes import FileData from gradio_client.utils import __version__, file, handle_file也就是说,绝大多数使用场景只涉及Client、handle_file、FileData三个名字。官方文档用一个经典示例说明其威力——连接一个“将麦克风录音转成文字”的 Whisper Space,全部代码只有五行:
from gradio_client import Client, handle_file client = Client("abidlabs/whisper") client.predict( audio=handle_file("audio_sample.wav") ) >> "This is a test of the whisper speech recognition model."这里的handle_file("audio_sample.wav")负责把本地文件上传到远端 Gradio 服务器,Client.predict()则把上传结果作为参数送入远端函数。注意这里甚至不需要显式指定api_name,因为该 Space 只有一个命名端点,客户端会自动推断。
需要强调的是:
- 客户端不受托管位置限制。Hugging Face Spaces、临时
*.gradio.live共享链接、你自己的公网/内网服务器,只要是标准 Gradio 应用都能连接。 - 前置知识门槛很低:你不必精通
gradio库本身,只需大致理解 Gradio 的“输入组件 / 输出组件”概念即可,因为客户端的参数结构正是由这些组件推导出来的。
安装与版本前提
gradio_client是一个独立、轻量、与前端解耦的包,仅需网络库(httpx、huggingface_hub 等)就能工作,无需安装完整版gradio。官方文档声明其测试支持的 Python 版本为3.10 及以上。
pip install --upgrade gradio_client如果你已经安装了较新版本的gradio,那么gradio_client会作为依赖自动带上。但需要注意:文档与 API 永远以最新版gradio_client为准,所以如果环境里的版本较老,建议先执行上面的升级命令再继续。
连接一个运行中的应用:四种接入方式
1. 连接 Hugging Face 上的 Space
连接运行在 HF Spaces 上的应用,src直接传 Space 的命名空间路径即可:
from gradio_client import Client client = Client("abidlabs/en2fr") # 一个英译法的 Spacesrc支持两种取值(见 client.py 中 Client.init的文档):
- HF Space 名称,如
"abidlabs/whisper-large-v2",客户端会解析为对应 Space 的公开地址; - 完整 URL(含
http://或https://),指向任何自托管 Gradio 应用。
2. 带鉴权连接:token 与 auth
面向 HF 私有 Space 的 token 鉴权:私有 Space 需要传 HF Token:
from gradio_client import Client client = Client("abidlabs/my-private-space", token="...")在源码里,这个 token 会通过huggingface_hub的build_hf_headers(...)生成请求头(见 client.py 第 113-120 行),其中既有标准authorization头,也会额外复制一份为x-hf-authorization头供 Gradio 应用校验。
面向应用自身的用户名/密码鉴权:如果应用部署时配置了 Basic Auth(即 Gradio 应用的“用户名 + 密码”登录),则把凭据以元组形式传给auth参数:
from gradio_client import Client Client( space_name, auth=[username, password] )注意:token与auth是两类不同的鉴权——前者是 HF 平台凭据,用于拉取/访问私有 Space;后者是应用自身登录凭据,会在首次连接时先调用/login端点换取会话 cookie。
3. 连接自托管或 Share 链接
只要 URL 可达,直接传完整地址,无需任何中间件或代理:
from gradio_client import Client client = Client("https://bec81a83-5b5c-471e.gradio.live")4. 更多底层可调参数
从 client.py 的构造函数签名 可以看到Client.__init__还暴露了若干实用选项,用于把客户端调整到符合你的网络与运行环境:
| 参数 | 默认值 | 作用 |
|---|---|---|
max_workers | 40 | 可同时向远端发起请求的工作线程上限 |
verbose | True | 是否在控制台打印客户端信息 |
httpx_kwargs | None | 透传给底层 httpx 的关键字(timeout、proxy 等) |
download_files | 临时目录(受GRADIO_TEMP_DIR影响) | 远端输出文件下载到本地的目录;传False则不下载、直接返回带远端路径的FileData |
ssl_verify | True | 设为False可连接使用自签名证书的 Gradio 应用 |
oauth_token | None | 供应用代码以你的身份调用需要gr.OAuthToken的端点 |
用 duplicate 复制一个 Space,绕开限流
任何公开 Space 都可以直接当 API 用,但高频请求可能触发 HF 平台的频率限制。官方推荐的做法是:用Client.duplicate()把 Space 复制一份到自己的命名空间下,成为私有 Space,随后对它不限量发起请求。
import os from gradio_client import Client, handle_file HF_TOKEN = os.environ.get("HF_TOKEN") client = Client.duplicate("abidlabs/whisper", token=HF_TOKEN) client.predict(handle_file("audio_sample.wav")) >> "This is a test of the whisper speech recognition model."从 client.py 中 duplicate 的类方法签名 可以确认其完整参数:
Client.duplicate( from_id: str, # 要复制的原 Space to_id: str | None, # 新 Space 名称,默认自动生成 token: str | None, # HF Token private: bool = True, # 默认复制为私有 Space hardware: ..., # 可选:cpu-basic / cpu-upgrade / t4-small / t4-medium / # a10g-small / a10g-large / a100-large 等 GPU 规格 secrets: dict | None, # 需要注入的环境变量密钥 sleep_timeout: int = 5, # 轮询等待 Space 就绪的间隔 max_workers: int = 40, verbose: bool = True, )几个实用要点:
- 重复调用是幂等的。如果已经复制过某个 Space,再次执行
duplicate()不会新建实例,而是复用先前创建好的那一个,可以放心在脚本/CI 中反复调用。 - GPU 成本提示:若原 Space 使用 GPU,你的私有副本同样会占用 GPU,并依据 GPU 规格向你的 HF 账户计费。为控制成本,副本会在闲置 1 小时后自动休眠(这也是平台默认行为);你也可以通过
hardware参数显式选择更便宜的硬件规格,或用sleep_timeout等参数微调。 - 该功能在库内的实现会先经
huggingface_hub创建 Space,随后通过轮询等待其进入运行状态,因此需要传入有效 token(或已通过 HF CLI 登录)。
查看可用端点:Client.view_api()
连接建立后,第一件事通常是弄清楚“这个应用到底能调什么”。调用Client.view_api()即可打印该应用所有命名的 API 端点及其参数结构。对 Whisper Space 输出大致如下:
Client.predict() Usage Info --------------------------- Named API endpoints: 1 - predict(audio, api_name="/predict") -> output Parameters: - [Audio] audio: filepath (required) Returns: - [Textbox] output: str这里揭示了客户端方法论的关键:远端 Gradio 组件(Audio、Textbox……)会被映射成 Python 侧的参数类型。比如[Audio] audio: filepath表示你要传一个本地文件路径或网络文件 URL(经handle_file包装),[Textbox] output: str表示返回的是字符串。
在源码层面,这一能力的支撑是 client.py 中的view_api方法与内部的_get_api_info,它请求远端的config与info?all_endpoints=True接口(对应 utils.py 中定义的 CONFIG_URL / API_INFO_URL),把 Gradio 的组件定义解析成人类可读的参数清单。view_api还支持:
all_endpoints:是否同时展示匿名(无api_name)端点;print_info=False/return_format="dict":将结构以字典返回,便于在程序里进一步处理。
什么时候需要传api_name?当应用只有一个命名端点时可以不传(客户端自动选默认端点);但当应用定义了多个命名端点(如/predict、/count、/chat),就必须通过api_name="/xxx"指定要调用哪一个。
同步预测:Client.predict()
最简单也最常见的调用方式就是同步.predict():传入与端点参数对应的值,等待计算完成并一次性返回结果。
from gradio_client import Client client = Client("abidlabs/en2fr") client.predict("Hello", api_name="/predict") >> Bonjour多参数应用依次传参即可(以gradio/calculator为例,它接收“两个数字 + 一个运算符”):
from gradio_client import Client client = Client("gradio/calculator") client.predict(4, "add", 5) >> 9.0为什么推荐关键字参数
官方文档明确建议:用关键字参数而不是位置参数。这不仅让调用意图一目了然,还能利用 Gradio 组件的默认值机制——端点上凡是“组件有初始值”或“函数参数默认值为 None”的参数,在客户端侧都可以省略。
from gradio_client import Client client = Client("gradio/calculator") client.predict(num1=4, operation="add", num2=5)例如某图像生成 Space 的steps参数底层对应一个带默认值的 Slider 组件,那么你只需要提供必填的text:
from gradio_client import Client client = Client("abidlabs/image_generator") client.predict(text="an astronaut riding a camel")想覆盖默认值就把它一并写上:
client.predict(text="an astronaut riding a camel", steps=25)在实现上,Client.predict会把你的*args/**kwargs交给construct_args()(见 utils.py)与远端 API 描述中记录的ParameterInfo(含parameter_has_default、parameter_default字段,定义在 data_classes.py)进行对齐,缺省参数自动填充,这正是“默认值自动生效”的底层原因。
传文件与传 URL:必须用 handle_file()
当某个参数是 Audio、Image、Video、File 等“文件型组件”时,必须把本地路径或网络 URL 用handle_file()包起来。它负责:把文件上传到 Gradio 服务器的/upload端点,并生成一个标准的 FileData 结构,确保远端能正确预处理。
from gradio_client import Client, handle_file client = Client("abidlabs/whisper") client.predict( audio=handle_file("https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3") ) >> "My thought I have nobody by a beauty and will as you poured. ..."从 utils.py 中 handle_file 的实现 可以看到它的判定逻辑:
def handle_file(filepath_or_url: str | Path): s = str(filepath_or_url) data = {"path": s, "meta": {"_type": "gradio.FileData"}} if is_http_url_like(s): return {**data, "orig_name": s.rsplit("/", maxsplit=1)[-1], "url": s} elif Path(s).exists(): return {**data, "orig_name": Path(s).name} else: raise ValueError( f"File {s} does not exist on local filesystem and is not a valid URL." )即:合法输入只可能是「HTTP(S) 形式的 URL」或「本地确实存在的文件路径」,二者都会携带orig_name与meta._type == "gradio.FileData"标记;两者都不匹配则直接抛ValueError。返回值本质上就是一个结构化的FileData字典——该 TypedDict 的完整字段(name、data、size、orig_name、mime_type等)定义在 data_classes.py。这也解释了为什么文档提示“输入输出数据事实上以 FileData 形式在网络间传输”。
兼容性提醒:旧版接口
gradio_client.file()仍可用,但已标记 deprecated,会在未来版本移除;新代码一律使用handle_file()(utils.py 第 1357-1361 行)。
异步提交与结果回调
.predict()是阻塞调用——它会一直等到远端算完才返回。当一次推理耗时很长(大模型、视频处理等),更合理的做法是先把任务交出去,后台运行,等你需要结果时再取回。这时使用.submit(),它会立刻返回一个Job对象:
from gradio_client import Client client = Client(space="abidlabs/en2fr") job = client.submit("Hello", api_name="/predict") # 非阻塞 # 在这里可以做任何其他事情…… job.result() # 阻塞,直到任务完成并返回结果 >> Bonjour为任务挂上回调
如果你希望在任务完成后自动执行某个动作,而不是手动轮询,可以给submit()传入一个或多个result_callbacks。每个回调接收该次任务的输出作为参数:
from gradio_client import Client def print_result(x): print(f"The translated result is: {x}") client = Client(space="abidlabs/en2fr") job = client.submit("Hello", api_name="/predict", result_callbacks=[print_result]) # 继续做别的事…… >> The translated result is: Bonjour在实现上,submit()会创建后台 Future 并把回调包装成线程安全的完成钩子(见 client.py 的create_fn/fn),回调列表也支持传单个可调用对象或多个可调用对象的列表。
跟踪任务状态:job.status()
通过Job.status()可以随时读取任务在服务端队列/执行器中的状态。它返回一个StatusUpdate对象。根据 utils.py 中 StatusUpdate 数据类定义,其主要属性为:
code:状态码,取自Status枚举(见下);rank:该任务在队列中的当前位置;queue_size:当前队列总长度;eta:预计完成时间;success:任务是否成功;time:该状态生成的时间戳;- 另外还有
progress_data(进度条明细)与log(日志)。
code可取的具体值定义在 utils.py 的 Status 枚举:STARTING、JOINING_QUEUE、QUEUE_FULL、IN_QUEUE、SENDING_DATA、PROCESSING、PROGRESS、ITERATING、FINISHED、CANCELLED。这些状态由后台线程把服务端 SSE 协议消息(send_hash、estimation、process_starts、process_completed……)逐条映射而来(Status.msg_to_status())。
from gradio_client import Client client = Client(src="gradio/calculator") job = client.submit(5, "add", 4, api_name="/predict") job.status() >> <Status.STARTING: 'STARTING'>如果只想判断任务是否已经跑完,可以用Job.done(),它返回布尔值。
取消排队中的任务
Job.cancel()用于取消那些还在排队、尚未开始处理的任务:
client = Client("abidlabs/whisper") job1 = client.submit(handle_file("audio_sample1.wav")) job2 = client.submit(handle_file("audio_sample2.wav")) job1.cancel() # 若已开始处理,返回 False(无法取消) job2.cancel() # 若仍在队列中,返回 True(成功取消并移出队列)其语义清晰地区分两种情况:已经开始被服务端处理的任务不可取消(返回False);尚未开始、仍在排队中的任务会被取消并从队列移除(返回True)。取消动作在底层通过向服务端的/cancel端点发送取消请求实现。
处理 Generator 端点:流式输出
某些 Gradio 端点的函数是 Python 生成器,会连续产出多个值而不是只返回一个值。Job对象针对这类端点提供了三种使用方式。
方式一:job.outputs() 取当前累计结果
from gradio_client import Client client = Client(src="gradio/count_generator") job = client.submit(3, api_name="/count") while not job.done(): time.sleep(0.1) job.outputs() >> ['0', '1', '2']需要留意:对生成器端点执行job.result()只会返回第一个产出值(这里是'0'),要拿全量结果必须用job.outputs()。
方式二:把 Job 当迭代器逐条消费
Job对象实现了__iter__/__next__,可以像生成器一样边产出边处理:
from gradio_client import Client client = Client(src="gradio/count_generator") job = client.submit(3, api_name="/count") for o in job: print(o) >> 0 >> 1 >> 2方式三:取消迭代式任务
对仍在产出中间结果的任务执行cancel(),任务会在当前这一轮迭代完成后优雅结束,而不是立刻中断服务端:
from gradio_client import Client import time client = Client("abidlabs/test-yield") job = client.submit("abcdef") time.sleep(3) job.cancel() # 任务在若干轮迭代后停止仓库自带的本地演示 demo/count_generator/run.py 就是上述count_generatorSpace 的等价实现,可以作为本地复现流式端点的参考。
Session State:客户端自动帮你“记住状态”
Gradio 应用可以用gr.State组件在页面会话内持久化数据(例如累积用户提交过的词列表)。下面这段gr.Blocks演示维护一个“已见过哪些词”的列表:用户每提交一个新词,它返回该词的历史出现次数,并把新词追加进状态:
import gradio as gr def count(word, list_of_words): return list_of_words.count(word), list_of_words + [word] with gr.Blocks() as demo: words = gr.State([]) textbox = gr.Textbox() number = gr.Number() textbox.submit(count, inputs=[textbox, words], outputs=[number, words]) demo.launch()有趣的是,当你用 Python Client 连接这样的应用时,view_api()显示的 API 结构里根本看不到 state 输入/输出,只有一对“词 → 次数”:
- predict(word, api_name="/count") -> value_31 Parameters: - [Textbox] word: str (required) Returns: - [Number] value_31: float原因在源码中有直接体现:utils.py 的SKIP_COMPONENTS集合把"state"列入了“不向用户暴露”的组件类型。也就是说,Python Client 会自动替你管理会话状态:连续多次请求时,上一次请求返回的 state 会被内部保存,并自动作为下一次请求的输入送回去,整个过程对调用方透明。
如果你想强制让应用“回到初始状态”,例如开启一段全新的独立会话,调用Client.reset_session()即可(对应源码中向RESET_URL = "reset"端点发起重置请求,见 utils.py)。
进阶阅读
- 本系列其余篇幅:查询 Gradio 应用的其他方式(curl)、JavaScript Client 入门、在 FastAPI 应用内嵌 Gradio 客户端;
- 若想本地查看客户端实现细节,核心代码集中在 client/python/gradio_client/client.py(Client、Job、Communicator 等)与 client/python/gradio_client/utils.py(网络协议、状态枚举、handle_file 等);
- 需要理解“Gradio 应用端如何定义这些端点”,可结合 gradio/events.py、gradio/blocks.py 中关于事件与端点的实现,以及 guides/04_additional-features 下关于应用共享与鉴权的说明。
把 Python Client 与 Gradio 服务端配合起来看:服务端把任意 Python 函数(含生成器、带状态、带队列)标准化为 HTTP + SSE 端点,客户端则负责上传文件、维护会话、翻译参数、消费流式输出。理解这层抽象后,你会发现“把 Gradio 应用变成 API”与“把 API 交给 Agent / LLM 工具调用”之间只有一步之遥。
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考