Gradio JavaScript Client 入门:用 @gradio/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/client是 Gradio 官方提供的 TypeScript/JavaScript 客户端(仓库内实现位于 client/js),它让你无需手动拼 HTTP 请求,就能把任何运行中的 Gradio 应用——语音转写、图像生成、文本翻译、带状态的聊天机器人、计算器等——当作标准的远程 API 来调用。读完本指南,你将掌握从安装、连接(含 Hugging Face Space、私有 Space、鉴权应用)到查看端点、发起预测、监听流式事件与任务状态、取消任务的完整链路,可直接把任意 Gradio App 集成进你自己的 Node.js 服务或前端页面。
快速上手:一段代码调用一个 Gradio App
本指南以一个「音频转写」类应用(Hugging Face Spaceabidlabs/whisper,可将麦克风录制的音频转成文字)为例。使用@gradio/client,仅需几行代码即可完成从拉取音频到拿到转写结果的完整流程:
import { Client, handle_file } from "@gradio/client"; const response = await fetch( "https://example.com/sample-1.wav" // 换成任何可访问的音频文件 URL ); const audio_file = await response.blob(); const app = await Client.connect("abidlabs/whisper"); const transcription = await app.predict("/predict", [handle_file(audio_file)]); console.log(transcription.data); // [ "I said the same phrase 30 times." ]这条链路背后实际发生了三件事:Client.connect拉取应用的运行时配置与 API 元数据,handle_file把浏览器端拿到的Blob标记为待上传的文件对象,predict完成上传与排队请求并等待最终结果。客户端并不限定只能连接 Hugging Face Space——任何部署在你自己服务器上的 Gradio 应用,只要给出完整 URL 都能连接。
前置知识:使用 JS Client 不需要深入掌握
gradio库本身,但了解 Gradio 的「输入/输出组件」这一基本概念会很有帮助——API 的参数与返回值正是按照这些组件的类型来描述的。
安装 @gradio/client
方式一:通过 npm 安装
在 Node.js 或前端工程中,使用 npm 或其他兼容包管理器即可安装:
npm i @gradio/client从仓库中的 client/js/package.json 可以看到该包的关键信息:当前版本为2.5.1,声明"engines": { "node": ">=18.0.0" },因此要求 Node.js 版本 ≥ 18.0.0;包以"type": "module"方式发布,同时提供 ESM(dist/index.js)、CommonJS(dist/index.cjs)与浏览器构建(dist/browser.js、dist/index.min.js)等入口,可被 Node 项目、打包工具及纯<script>场景分别消费。包的全部公开导出见 client/js/src/index.ts:核心是Client类,其余为predict、submit、upload_files、handle_file、upload以及SpaceStatus、Status、Config等类型。
方式二:通过 CDN 引入
若只是想在网页里快速实验,可以把最新版直接以 ES Module 形式引入:
<!DOCTYPE html> <html lang="en"> <head> <script type="module"> import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; const client = await Client.connect("abidlabs/en2fr"); const result = await client.predict("/predict", { text: "My name is Hannah" }); console.log(result); </script> </head> </html>注意:上面的import必须放在<head>的<script type="module">中;CDN 默认加载最新版本,生产环境建议将 URL 中的版本号硬编码固定(package.json 的exports字段中即暴露了./dist/index.min.js这一浏览器构建产物,见 client/js/package.json)。这种方式适合原型验证,但存在版本漂移等局限。
连接到正在运行的 Gradio 应用
核心入口是Client类。连接的本质是两步:先根据应用引用(Space 名或完整 URL)解析出应用配置(config,包括输入输出组件、依赖关系、协议版本等),再通过配置中暴露的依赖信息建立可调用的 API 映射。这一初始化逻辑可在 client/js/src/client.ts 的init()/_resolve_config()中看到:客户端解析端点、拉取 config、自动调用view_api()获取 API 信息并建立「端点名 → fn_index」映射。
连接 Hugging Face Space
传入 Space 名称即可(abidlabs/en2fr是一个英译法翻译应用):
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/en2fr");Client.connect是静态方法,返回解析完成的Client实例(源码见 client/js/src/client.ts)。每个实例会自动生成一个session_hash,用于区分会话、串联有状态应用的多轮交互。
连接私有 Space
如果 Space 是私有的,需要在 options 中传入你的 Hugging Face 访问令牌(Token 可在 Hugging Face 网站的Settings → Access Tokens页面创建):
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/my-private-space", { token: "hf_..." })在 client/js/src/types.ts 的ClientOptions中可以看到,token的类型被限定为`hf_${string}`形式,说明它专用于 Hugging Face 鉴权。除token外,ClientOptions还支持:
| 选项 | 类型 | 作用 |
|---|---|---|
auth | [string, string] \| null | 以用户名/密码元组方式登录启用账号鉴权的 Gradio 应用 |
events | EventType[] | 订阅的事件类型("data" \| "status" \| "log" \| "render"),默认["data"] |
status_callback | SpaceStatusCallback | 连接 Space 过程中的状态回调(如 sleeping/running/error 等加载进度) |
headers | Record<string, string> \| Headers | 附加到每次 HTTP 请求的请求头 |
query_params | Record<string, string> | 附加的查询参数 |
session_hash | string | 手动指定会话哈希(默认随机生成) |
cookies | string | 手动提供 Cookie |
credentials | RequestCredentials | fetch 的 credentials 策略(默认"same-origin") |
with_null_state | boolean | 是否把 State 组件的null一并返回 |
hf_token | hf_${string} | 旧版token别名(标记为 deprecated,仅为兼容保留) |
oauth_token | string | 透传给应用的 OAuth 令牌,仅发送给声明需要它的端点 |
复制(Duplicate)一个 Space 供私人使用
公共 Space 作为 API 高频调用时可能触发 Hugging Face 的频率限制。若需要不限量调用,可以Client.duplicate把 Space 复制成你自己的私有 Space:
import { Client, handle_file } from "@gradio/client"; const response = await fetch("https://example.com/sample-0.mp3"); const audio_file = await response.blob(); const app = await Client.duplicate("abidlabs/whisper", { token: "hf_..." }); const transcription = await app.predict("/predict", [handle_file(audio_file)]);Client.duplicate与Client.connect对外几乎一致,唯一区别在于底层行为:前者会通过 Hugging Face 的副本接口帮你创建一个 Space 并连接它。重复对同一个 Space 调用duplicate不会反复新建副本,而是自动挂载到已创建的 Space 上,因此多次调用是安全的。
计费与硬件说明:如果原 Space 使用了 GPU,副本同样会使用 GPU 并按你的 Hugging Face 账户计费。为控制成本,Space 闲置约 5 分钟后会自动休眠。你也可以在 options 中指定硬件规格与休眠超时:
import { Client } from "@gradio/client"; const app = await Client.duplicate("abidlabs/whisper", { token: "hf_...", timeout: 60, // 空闲 60 分钟后休眠 hardware: "a10g-small" });DuplicateOptions(见 client/js/src/types.ts)在ClientOptions基础上增加了private、hardware、timeout。合法的hardware取值在 client/js/src/helpers/spaces.ts 中定义,且duplicate在运行时会对传入值做白名单校验(非法值会直接报错,见 client/js/src/utils/duplicate.ts):
| 类别 | 取值 |
|---|---|
| CPU | cpu-basic、cpu-upgrade、cpu-xl |
| 入门 GPU | t4-small、t4-medium |
| A10G 系列 | a10g-small、a10g-large、a10g-largex2、a10g-largex4 |
| 高级 GPU | a100-large、h100、h100x8 |
| 其他 | zero-a10g |
连接任意位置的 Gradio 应用
如果应用运行在 Hugging Face 之外(例如自己的服务器、内网或 gradio.live 共享链接),直接传入包含协议前缀的完整 URL 即可:
import { Client } from "@gradio/client"; const app = Client.connect("https://bec81a83-5b5c-471e.gradio.live");从源码看(client/js/src/helpers/api_info.ts 的process_endpoint),客户端会把传入引用解析为http_protocol + host,进而请求config与 API 信息;Space 名与完整 URL 都走这条统一逻辑。
连接带账号鉴权的 Gradio 应用
如果目标应用在启动时启用了账号密码鉴权(即服务端launch(auth=...),原理可参考 sharing-your-app 指南中的 Authentication 部分),把用户名和密码以元组形式传给auth选项即可:
import { Client } from "@gradio/client"; Client.connect( space_name, { auth: [username, password] } )客户端在初始化时(见 client/js/src/client.ts)会先解析 Cookie 完成登录,再把 Cookie 附加到后续所有请求(Client.fetch/Client.stream会自动携带已保存的 Cookie 与 options 中的 headers,源码见 client/js/src/client.ts)。
查看 API 端点
连接成功后,调用view_api()即可查看该应用对外暴露的全部 API:
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/whisper"); const app_info = await app.view_api(); console.log(app_info);上述 whisper Space 返回的结构类似:
{ "named_endpoints": { "/predict": { "parameters": [ { "label": "text", "component": "Textbox", "type": "string" } ], "returns": [ { "label": "output", "component": "Textbox", "type": "string" } ] } }, "unnamed_endpoints": {} }这告诉我们该应用只有 1 个命名端点/predict,以及它的入参、出参各自的组件类型与类型定义。返回结构ApiInfo分为named_endpoints与unnamed_endpoints两组(类型定义见 client/js/src/types.ts),每个端点的EndpointInfo含parameters、returns等描述。客户端在init()阶段也会自动拉取一次 API 信息,用于把/predict这类端点名映射到底层的fn_index(依赖编号),这一映射api_map的建立见 client/js/src/client.ts。
实践中可以这样理解上面的信息:调用时应使用.predict()方法(下文详解),其参数为类型string的输入;显式传入api_name='/predict'并非必须(应用只有单个命名端点时可省略),但当一个应用暴露多个命名端点时,这能让你精确指定调用哪一个。若应用存在未命名端点,可以调用.view_api(all_endpoints=True)把它们一并展示出来。
备选:「View API」页面与 API Recorder
除了调用view_api(),也可以在应用页脚点击"Use via API"链接打开可视化页面,页面展示同样的端点信息并附有示例代码。该页面还内置了API Recorder(录制器):你可以照常操作 Gradio 界面,录制器会把你的每次交互实时翻译成对应的 JS Client 代码片段,是快速获取「正确参数格式」的捷径。相关内容可进一步阅读 view-api-page。
发起一次预测:.predict()
基本调用
最简单的方式是向.predict()传入端点名与参数数组:
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/en2fr"); const result = await app.predict("/predict", ["Hello"]);predict的参数顺序与view_api()展示的parameters数组一一对应。当端点有多个入参时,把它们按顺序放进数组即可,例如gradio/calculator这个计算器应用(接收两个数与一个运算符):
import { Client } from "@gradio/client"; const app = await Client.connect("gradio/calculator"); const result = await app.predict("/predict", [4, "add", 5]);传入文件:handle_file
对图像、音频等文件类输入,需要传入Buffer、Blob或File,具体取决于运行环境:Node.js 中用Buffer或Blob,浏览器中用Blob或File。统一的推荐姿势是借助handle_file函数包装:
import { Client, handle_file } from "@gradio/client"; const response = await fetch("https://example.com/sample-0.mp3"); const audio_file = await response.blob(); const app = await Client.connect("abidlabs/whisper"); const result = await app.predict("/predict", [handle_file(audio_file)]);handle_file的实现位于 client/js/src/helpers/data.ts,其接受File | string | Blob | Buffer并按类型分流:
- HTTP(S) URL 字符串:直接构造为带
path/url/orig_name的FileData,客户端将告知服务端从该 URL 拉取,无需本地上传; - 本地路径字符串(Node.js):包装为一个
Command("upload_file", ...)上传命令,客户端会读取本地文件并上传; File:原样返回,从而保留原始文件名与 MIME 类型;Buffer:在 Node 中包装成Blob后走上传流程;Blob:直接返回;- 其他类型会抛出
"Invalid input: must be a URL, File, Blob, or Buffer object."。
从源码看,predict本质上是「完整跑完一次任务直到结束」的高层封装(见 client/js/src/utils/predict.ts):它调用submit(..., all_events=true)建立异步迭代器,随后在循环里等待data消息拿到结果、以status.complete判断收尾,任何error阶段都会转换为携带完整状态字段的真实Error抛出,方便调用方捕获与排查。
进阶:用事件接口实时消费消息
当端点本身支持排队、生成中阶段,或你希望拿到任务状态、过程性结果时,.predict()的「等全部完成」语义就不够用了。此时使用submit()返回的**异步可迭代对象(iterable interface)**更灵活——它特别适合会随时间产生一系列离散结果的迭代(generator)端点。
import { Client } from "@gradio/client"; function log_result(payload) { const { data: [translation] } = payload; console.log(`The translated result is: ${translation}`); } const app = await Client.connect("abidlabs/en2fr"); const job = app.submit("/predict", ["Hello"]); for await (const message of job) { log_result(message); }submit返回的SubmitIterable(类型见 client/js/src/types.ts)是一个 AsyncIterable,额外带有cancel()、event_id()、wait_for_id()等方法。其底层消息处理逻辑(client/js/src/utils/submit.ts)会根据应用 config 中声明的protocol选择传输方式:若该端点不经过队列,直接向/run或/run/{api_name}POST;若启用队列,则通过 SSE(/queue/data或流式协议)持续接收服务端推送的status/data/log/generating等事件并逐个转发给迭代器。
订阅任务状态:events: ["status", "data"]
要拿到运行中的状态消息,需要在连接时把events选项设为包含status:
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/en2fr", { events: ["status", "data"] });这样服务端的状态消息也会被推送给客户端。每个status对象包含下列属性:
| 属性 | 说明 |
|---|---|
status | 人类可读的任务阶段:"pending" | "generating" | "complete" | "error" |
code | 任务对应的详细 Gradio 状态码 |
position | 该任务在当前队列中的位置 |
queue_size | 当前队列总长度 |
eta | 预计完成时间 |
success | 布尔值,任务是否成功完成 |
time | Date对象,状态生成的时间戳 |
Status类型在源码 client/js/src/types.ts 中也有完整定义(含queue、stage、duration、progress_data、used_cache、cache_duration等字段),可对照使用。在事件循环中按消息类型过滤即可:
import { Client } from "@gradio/client"; function log_status(status) { console.log( `The current status for this job is: ${JSON.stringify(status, null, 2)}.` ); } const app = await Client.connect("abidlabs/en2fr", { events: ["status", "data"] }); const job = app.submit("/predict", ["Hello"]); for await (const message of job) { if (message.type === "status") { log_status(message); } }取消任务:.cancel()
Job 实例提供.cancel()方法,用于取消「已排队但尚未开始」的任务:
import { Client } from "@gradio/client"; const app = await Client.connect("abidlabs/en2fr"); const job_one = app.submit("/predict", ["Hello"]); const job_two = app.submit("/predict", ["Friends"]); job_one.cancel(); job_two.cancel();取消的语义区分两种情况:如果第一个任务已开始处理,服务端不会真正中断它,但客户端会停止监听(相当于丢弃该任务的后续消息);如果第二个任务尚未开始,则会被成功取消并移出队列。底层实现会向/cancel与/reset端点分别发送请求(见 client/js/src/utils/submit.ts),其中/reset用于清理当前会话的排队状态。
生成器端点:实时接收一系列输出
某些 Gradio 端点不返回单个值,而是按时间依次产生一串值。以计数生成器gradio/count_generator为例,可用异步迭代实时读取每个输出:
import { Client } from "@gradio/client"; const app = await Client.connect("gradio/count_generator"); const job = app.submit(0, [9]); for await (const message of job) { console.log(message.data); }注意这里的第一个参数传的是 **0(fn_index / 依赖编号)**而非"/predict"。在 client/js/src/utils/submit.ts 的get_endpoint_info中可以看到:端点参数允许是字符串(命名端点)或数字(依赖索引)。未命名端点没有/predict这类名称,只能(或恰好只能)用数字索引调用;源码中也提示,命名端点列表会在错误信息中列出,便于排查。
迭代输出的任务同样可以取消——取消后该任务会立即结束:
import { Client } from "@gradio/client"; const app = await Client.connect("gradio/count_generator"); const job = app.submit(0, [9]); for await (const message of job) { console.log(message.data); } setTimeout(() => { job.cancel(); }, 3000);小结:从源码理解完整调用链
把上文各环节串起来,一次完整调用的链路是:
- 连接:
Client.connect(space|url, options)解析端点、拉取 config 与 API 信息,建立api_map(端点名 → fn_index),并处理鉴权(token/Cookie/auth)与 Space 唤醒(client/js/src/client.ts); - 构造请求:
submit/predict根据端点在 API 信息中定位参数结构,handle_file把文件类入参解析为FileData/上传命令并先行走上传; - 传输与事件:依据 config 声明的协议(非队列直连
/run/{api_name},队列任务走 SSE),接收服务端推送,客户端把原始消息标准化为type: "data" | "status" | "log" | "render"的事件流供for await消费;所有请求默认携带x-gradio-user: api请求头以标记 API 调用来源(见 client/js/src/utils/submit.ts); - 收尾:收到
complete状态后关闭事件流;predict自动完成这一等待逻辑,submit则把主动权交给调用方(可中途取消)。
这套机制与仓库中的测试覆盖相互印证——客户端的浏览器/Node 双端测试位于 client/js/src/test,前端各组件消费同一Client能力的代码在 js/core 目录中,可作为深入理解事件协议细节的参考。
延伸阅读
- 如需了解 Python 版客户端的使用方式,参见 getting-started-with-the-python-client;
- 想不依赖 SDK、直接以 HTTP/curl 调用 Gradio App,参见 querying-gradio-apps-with-curl;
- 应用端的鉴权与分享配置,参见 sharing-your-app;
- 「View API」页面的完整功能介绍,参见 view-api-page。
【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. 🌟 Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考