knowledge-work-plugins 中的 Zoom AI Services Scribe 转录实战指南:JWT 认证、Fast/Batch 双模式与浏览器麦克风伪流式架构
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
本篇技术指南以开源仓库 knowledge-work-plugins 中 scribe 技能 及其配套子文档为核心,完整讲解 Zoom AI Services Scribe 文件/存储转录服务的落地方法:从 Build-platform JWT 签发、Fast Mode 同步转录与 Batch 异步批处理两条主链路,到浏览器麦克风伪流式方案、Webhook 驱动的状态通知,以及围绕版本漂移的排障与预检 Runbook。读完本文,你将能独立搭建一条可运行的上传转录代理、批量 S3 转录与 Webhook 回写流水线,并掌握 9 类高频故障的定位方法。
Scribe 是什么:文件/存储转录服务的定位与路由护栏
Scribe 是 Zoom AI Services 家族中面向已上传或已存储媒体的转录服务,核心能力是把音频/视频文件转成带时间戳、声道与说话人信息的文本。它与 Zoom 的实时媒体流服务 RTMS 边界清晰:Scribe 处理「文件」,RTMS 处理「直播流」。
在 scribe 技能入口 中定义了四条路由护栏,用于避免产品选错:
| 用户诉求 | 路由目标 |
|---|---|
| 上传或存储的媒体需要转成文本 | 先路由到scribe |
| 需要实时会议媒体(非文件上传/批处理) | 转 rtms 技能 |
| 需要 Zoom REST API 的 AI Services 路径清单 | 串联 rest-api 技能 |
| 需要 Webhook 签名模式或通用 HMAC 接收加固 | 可选串联 webhooks 技能 |
Scribe 覆盖的能力面包括:
- 同步单文件转录(
POST /aiservices/scribe/transcribe) - 异步批量作业(
/aiservices/scribe/jobs*) - 基于重复短文件上传的浏览器麦克风伪流式转录
- 由 Webhook 驱动的批量状态更新
- Build-platform JWT 签发与凭据处理
认证模型:Build-platform JWT 与凭据命名漂移
HS256 JWT 结构
Scribe 使用Build-platform JWT Bearer Token认证,而非 OAuth。JWT 的三要素:
- 算法:
HS256 - issuer(
iss)声明:Build-platform 凭据标识符,Scribe API 用它识别调用方 - 过期时间(
exp):保持在一小时或更短
认证与处理模式文档 给出了 Node.js 侧的最小签发实现(基于jsrsasign的KJUR):
import { KJUR } from 'jsrsasign'; export function generateJWT(apiKey, apiSecret) { const iat = Math.round(Date.now() / 1000) - 30; const exp = iat + 60 * 60; return KJUR.jws.JWS.sign( 'HS256', JSON.stringify({ alg: 'HS256', typ: 'JWT' }), JSON.stringify({ iss: apiKey, iat, exp }), apiSecret, ); }注意iat回拨了 30 秒,这是为时钟偏差留的缓冲;exp设为iat + 3600(一小时)。
凭据命名漂移:API Key 还是 SDK Key?
Zoom 官方文档在不同页面使用了不一致的命名:
- AI Services 认证页:
API key/API secret - Build-platform 凭据页:
SDK key/SDK secret - Quickstart 示例代码:
ZOOM_API_KEY/ZOOM_API_SECRET
版本漂移文档 明确指出:实现时统一把它们当作 Build-platform 的 JWT issuer/secret 对,但在上线前务必到当前门户 UI 核实确切的字段标签。
环境变量约定
环境变量文档 给出了完整的配置面:
JWT 认证必填:
| 变量 | 必填 | 说明 |
|---|---|---|
ZOOM_API_KEY | 是 | Build-platform issuer key,用于 JWTiss声明 |
ZOOM_API_SECRET | 是 | HS256 签名的 Build-platform secret |
通用应用变量:
| 变量 | 必填 | 说明 |
|---|---|---|
PORT | 否 | 本地服务端口 |
LANGUAGE | 否 | 默认语言代码,如en-US |
Batch / S3 变量:
| 变量 | 必填(batch 场景) | 说明 |
|---|---|---|
S3_INPUT_URI | 通常 | 输入前缀或文件 URI |
S3_OUTPUT_URI | 通常 | 输出转录目的地 |
AWS_ACCESS_KEY_ID | 未使用预签名访问时需要 | AWS 凭据 |
AWS_SECRET_ACCESS_KEY | 未使用预签名访问时需要 | AWS 凭据 |
AWS_SESSION_TOKEN | 常需要 | 临时凭据令牌 |
Webhook 变量:
| 变量 | 必填 | 说明 |
|---|---|---|
WEBHOOK_URL | 可选 | 接收批量通知的公网 HTTPS 回调 |
WEBHOOK_SECRET | 可选但推荐 | 校验 Zoom 回调签名的 HMAC secret |
关键坑:不要把${ZOOM_API_KEY}这类 shell 占位符当作有效配置值。占位符会让健康检查「看起来已配置」,但每次真实调用都会失败——这是文档与 Runbook 反复强调的失败模式。
处理模式:Fast Mode 与 Batch Mode 的选择
认证与处理模式文档 对两种模式做了精确定位:
| 模式 | 适用场景 | 传输方式 | 结果时机 |
|---|---|---|---|
| Fast mode | 单个短文件、交互式 UX | POST /transcribe | 立即返回同步 JSON |
| Batch mode | 归档、长媒体、大量文件 | POST /jobs后查状态/等 Webhook | 异步 |
选择 Fast mode 的条件:
- 用户只上传一个文件
- 延迟比吞吐量更重要
- 文件大小与时长可控
- 在做基于短麦克风分片的浏览器伪流式
选择 Batch mode 的条件:
- 需要处理大量文件
- 转录结果可以稍后到达
- 存储中心化工作流比直传更契合
端点清单与请求/响应形状
端点总览
API 参考文档 基于 AI Services OpenAPI 清单(api-hub/ai-services/methods/endpoints.json),基础 URL 为https://api.zoom.us/v2:
| Method | Endpoint | 说明 | Operation ID |
|---|---|---|---|
| POST | /aiservices/scribe/transcribe | Scribe 同步转录 | createFastAsr |
| POST | /aiservices/scribe/jobs | 提交批量 Scribe 作业 | submitBatchAsr |
| GET | /aiservices/scribe/jobs | 列出批量作业 | listBatchJobs |
| GET | /aiservices/scribe/jobs/{jobId} | 查询批量作业状态 | getBatchJobStatus |
| DELETE | /aiservices/scribe/jobs/{jobId} | 取消排队/处理中的作业 | cancelBatchJob |
| GET | /aiservices/scribe/jobs/{jobId}/files | 查看每个文件的转录结果 | listBatchJobFiles |
Fast Mode 请求形状
必填顶层字段:file、config
常见 config 字段(认证与处理模式文档):
| 字段 | 作用 |
|---|---|
language | 语言代码,如en-US |
word_time_offsets | 是否输出逐词时间偏移 |
channel_separation | 是否按声道分离(立体声通话录音) |
timestamps | 时间戳 |
output_format | 输出格式 |
profanity_filter | 粗话过滤 |
diarization | 说话人分离/区分 |
响应关键键:request_id、duration_sec、model、result
Batch Mode 请求形状
必填顶层字段:input、output、config
input 子字段:
mode:SINGLE/PREFIX/MANIFESTsource:当前 OpenAPI 中为S3uri/manifestfilters.include_globs、filters.exclude_globs(均最多 10 项)auth.aws.access_key_id/secret_access_key/session_token
output 子字段:
destination、urilayout:SINGLE/PREFIX/ADJACENTauth.aws.*
config 子字段:language、word_time_offsets、channel_separation、diarization、profanity_filter、output_format、segmentation_mode
可选字段:reference_id、notifications.webhook_url、notifications.secret
提交响应键:job_id、state、submitted_at
查询与状态端点
GET /jobs:查询参数state、page_size、next_page_token;响应键jobs、next_page_tokenGET /jobs/{jobId}:响应键job_id、state、submitted_at、summaryGET /jobs/{jobId}/files:查询参数page_size、next_page_token;响应键files、next_page_token
当前限制与约束(来自源文档)
- Batch manifest 上限:1000 个文件 URI
include_globs最多10项;exclude_globs最多10项- 文档标注的媒体格式:
WAV、MP3、M4A、MP4 - Fast mode 正式上限:100 MB文件、2 小时时长
- OpenAPI 描述中批量作业的速率限制标签为
LIGHT
实战一:Fast Mode 同步转录(Node/Express 代理)
Fast Mode Node 示例 提供了一个可直接复用的最小后端代理。核心思路:前端上传文件 → 后端签 JWT → 转发 multipart 到 Zoom → 回传转录 JSON。
import express from 'express'; import multer from 'multer'; import { KJUR } from 'jsrsasign'; const app = express(); const upload = multer({ storage: multer.memoryStorage() }); app.use(express.json()); function generateJWT() { const iat = Math.round(Date.now() / 1000) - 30; const exp = iat + 60 * 60; return KJUR.jws.JWS.sign( 'HS256', JSON.stringify({ alg: 'HS256', typ: 'JWT' }), JSON.stringify({ iss: process.env.ZOOM_API_KEY, iat, exp }), process.env.ZOOM_API_SECRET, ); } app.post('/transcribe', upload.single('file'), async (req, res) => { const token = generateJWT(); const config = { language: req.body.language || 'en-US', word_time_offsets: true, channel_separation: false, }; let response; if (req.file) { const form = new FormData(); form.append('file', new Blob([new Uint8Array(req.file.buffer)]), req.file.originalname); form.append('config', JSON.stringify(config)); response = await fetch('https://api.zoom.us/v2/aiservices/scribe/transcribe', { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: form, }); } else { response = await fetch('https://api.zoom.us/v2/aiservices/scribe/transcribe', { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ file: req.body.file, config, }), }); } const text = await response.text(); res.status(response.status).type('application/json').send(text); });该示例同时演示了 fast mode 的两种合法提交形态,务必按服务边界选一种清晰的模型:
| 形态 | 提交方式 | 适用场景 |
|---|---|---|
| 调用方上传文件到你的后端 | 后端以multipart/form-data转发(FormData携带file+config字符串) | 浏览器/客户端直传 |
| 调用方已有 URL 可访问的媒体 | 后端以 JSON body 提交(file字段放 URL) | 服务端已存文件 |
样例验证文档 补充了关键实现细节:multer的 memory storage 对小型 fast mode 演示足够;官方 quickstart 也证明「即使文档展示的是 JSON 示例,fast mode 同样可以在你的服务器上以 multipart 上传处理方式代理」。
实战二:Batch 作业 + Webhook 流水线
端到端流程
Batch 作业 + Webhook 流水线示例 给出的链路为:
submit batch job -> receive job_id -> poll /jobs or wait for webhook -> inspect /jobs/{jobId}/files -> ingest transcript outputs提交示例(curl)
curl -X POST https://api.zoom.us/v2/aiservices/scribe/jobs -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{ "input": { "mode": "PREFIX", "source": "S3", "uri": "s3://example-bucket/audio/", "auth": { "aws": { "access_key_id": "...", "secret_access_key": "...", "session_token": "..." } } }, "output": { "destination": "S3", "uri": "s3://example-bucket/transcripts/", "layout": "PREFIX", "auth": { "aws": { "access_key_id": "...", "secret_access_key": "...", "session_token": "..." } } }, "config": { "language": "en-US", "word_time_offsets": true, "channel_separation": true }, "notifications": { "webhook_url": "https://example.com/webhooks/scribe", "secret": "replace-me" } }'要点:input.mode=PREFIX表示处理uri前缀下的全部匹配文件;output.layout=PREFIX表示转录结果按源前缀镜像落盘;AWS 凭据直接注入请求载荷——样例验证文档 指出这是 quickstart 的常规做法,但生产流水线更建议使用预签名 URL 或短时 STS 临时凭据,不要把长期 AK/SK 写进请求体。
Webhook 签名验证
Zoom 回调用的是x-zm-signature+x-zm-request-timestamp头,HMAC-SHA256 计算后带sha256=前缀。验证实现:
import crypto from 'crypto'; function verifyZoomWebhook(rawBody, timestamp, signature, secret) { const message = `v0:${timestamp}:${rawBody}`; const expected = `sha256=${crypto.createHmac('sha256', secret).update(message).digest('hex')}`; return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); }验证失败时按顺序排查:raw body 是否在 JSON 解析前捕获、时间戳头是否纳入签名串、共享 secret 是否与作业的notifications.secret一致。
浏览器麦克风伪流式模式
Scribe 不暴露文档化的实时流 API,因此浏览器麦克风体验必须建模为重复的短文件上传,而不是一条长连接流。推荐的模式:
- 用
MediaRecorder捕获浏览器麦克风音频 - 按短分片 flush 到你的后端
- 每个分片通过异步 fast mode 包装器提交
- 按请求 ID 轮询完成状态
- 按顺序拼接各分片转录结果
推荐起始节奏:
- 分片大小:
5 秒(可接受范围5-10 秒) - 同时在途分片请求:
2-3个
该模式的适用边界(认证与处理模式文档 的护栏):
- 它本质上是「基于文件上传的伪流式」
- 它不是实时音频捕获的首选生产设计
- 仅当轻量浏览器演示或粗略的增量转录可接受时使用
- 需要稳定低延迟实时转录、更低开销、跨语句强连续性时应避免
- 真正的直播媒体流、低延迟服务端摄入或会议中连续音频,改用 rtms
高等级应用场景
场景文档 给出了六类落地场景,覆盖了从交互式单文件到离线合规处理的全谱系:
场景 1:按需上传转录(Fast mode)浏览器上传 → 后端签发 Build JWT → 调用POST /aiservices/scribe/transcribe→ 返回转录 JSON。下游用途:通话后摘要、工单充实、可检索片段库、内部审阅/交接笔记。
场景 2:批量 S3 归档转录(Batch mode)构建带输入前缀与输出前缀的批量请求 → 提交POST /aiservices/scribe/jobs→ 通过 Webhook 或轮询跟踪状态 → 读/jobs/{jobId}/files获取逐文件成败 → 导入搜索、分析或存储。下游用途:合规与审计日志、可检索的网络研讨会/播客归档、批量转录回填、QA 评分输入。
场景 3:Zoom 录音导出后重新转录技能链:zoom-rest-api拉取/下载录音 +scribe转录导出媒体。典型动机:自建留存/搜索管线、需要不同于 Zoom 托管默认的转录设置、用自建摘要/打标流程增强录音。
场景 4:合规 / QA 处理(Batch mode)离线生成用于审计、QA 评分或归档搜索的转录。优先项:审阅者需要精确摘录时word_time_offsets=true;立体声通话录音用channel_separation=true;大流量下用 Webhook + 队列摄入而非同步轮询。
场景 5:客服语音到洞察流水线录音入库 →scribe转录 → 存储转录文本及说话人/时间元数据 → 下游自建情绪、关键词、升级、QA 逻辑。护栏:Scribe 只做转录,情绪分析、关键词检测、评分全部放到转录生成后的下游服务。
场景 6:浏览器麦克风增量转录浏览器MediaRecorder捕获 → 每5 秒flush 一个分片 → 后端把每个分片当作普通 fast mode 上传经异步包装器提交 → 前端按请求 ID 轮询并按序拼接。护栏:这是重复文件上传的伪流式,最适合轻量演示或受限兜底;真正的实时转录产品优先走rtms。
故障排查与 5 分钟预检 Runbook
九类高频故障速查
常见漂移与故障文档 系统梳理了 9 类问题:
- 凭据看似正确但认证失败:核对
iss值、exp窗口、门户当前凭据标签;确认不是把非 Build 应用凭据混用。若 API 返回{"code":124,"message":"Invalid Access token"},这是真实的上游认证失败,而非传输问题。 - Fast mode 请求形状不匹配:上传文件与 URL 文件是两条独立请求路径,不要强行用单一 JSON 形态承载。症状是浏览器请求长时间挂起、后端最终超时或空响应。
413 Request Entity Too Large:通常是反向代理在请求到达应用前就拒绝了上传。nginx 前置时需把client_max_body_size抬到不低于服务端上传上限。504 Gateway time-out:请求已到后端,但同步处理超过边缘/代理路径时长。部署观测显示:约 17.2 MB MP4 约 26s 完成,约 38.6 MB 约 26-37s,约 59.2 MB 约 32-34s(后端),但部分约 59.2 MB 浏览器请求先以504超时而后端日志显示200。前端 504 + 后端 200 = 浏览器/边缘超时竞态,不是转录失败。建议:为请求级日志记录文件名、大小、mime、上游耗时、响应载荷大小与顶层键;托管 UI 用异步请求/轮询包装器;若 nginx 访问日志出现499而应用日志稍后显示zoom_request_finished status: 200,说明转录已成功、只是浏览器侧请求路径丢失。- 批量作业被接受但输出永不出现:检查 S3 URI/认证不匹配、STS 凭据过期、输出 layout/URI 不匹配、依赖回调时 Webhook 端点不可达;核对
/jobs/{jobId}摘要与/jobs/{jobId}/files及云存储权限。 - Webhook 验证失败:确认 raw body 捕获先于 JSON 解析、时间戳头纳入签名串、共享 secret 与作业通知配置一致。
- 健康检查说凭据存在但 API 调用仍失败:环境文件里多半是
${ZOOM_API_KEY}这类字面占位符。只把真实值视为已配置,并在调用 Zoom 前以明确的凭据错误快速失败。 - 产品选错:文件/存储转录用
scribe,直播会议媒体用rtms。 - 浏览器麦克风第 1 个分片正常、后续分片为空:
MediaRecorder.start(timeslice)长会话的后续 blob 可能是缺少容器头的部分 WebM/Opus 簇。首选修复:按分片轮转录音器——启动录音器 → 记录一个分片窗口 → 停止 → 上传该 blob → 为下一分片重新启动新录音器。这是文件容器边界问题,不是 Scribe 语言模型问题。
5 分钟预检 Runbook 与快速决策树
RUNBOOK.md 提供了深度调试前的预检清单与决策树,浓缩如下:
预检七步:
- 确认产品:文件/存储转录留在
scribe;直播媒体用rtms;需要先入会录音的 bot 链路先走 Meeting SDK Linux。 - 确认凭据:Build-platform issuer 凭据对存在;JWT 用
HS256且过期不超过一小时;secret 只留服务端;拒绝${ZOOM_API_KEY}这类占位符。 - 确认模式:fast mode(单短文件即时 JSON)/ batch mode(多文件/长录音/归档)/ 麦克风伪流式(短分片异步包装器)。托管浏览器 UI 下 fast mode 应包装为「一次上传 → 后端返回
202+ 请求 ID → 前端轮询」,避免边缘超时竞态丢失成功转录。 - 确认存储/Webhook 输入:fast mode 文件 URL 或上传路径可解析;batch 输入输出 URI 有效;S3 模式 AWS 或预签名访问正确;Webhook 地址为公网 HTTPS。
- 确认后处理契约:下游代码期待
text_display、segments 还是逐词时间戳;声道分离与 diarization 是否在发货前确定。 - 快速探针:本地 JWT 生成成功;已知小文件
POST /aiservices/scribe/transcribe成功;浏览器上传经后端以multipart/form-data(而非 JSONdata:URI 包装)转发;batch 提交返回201且带job_id;Webhook 签名验证通过。 - 决策树(见下)。
快速决策树:
401/认证失败 → 凭据对错误或 JWT 过期- fast mode 返回 schema 错误 → 请求体或 config 字段错误
- 应用无日志就返回
413→ 反向代理限制,不是 Scribe - 前端
504而后端日志稍后200→ 浏览器/边缘超时竞态,按请求 ID 轮询而非判定失败 - 麦克风功能需要真正的连续低延迟媒体 → 切换
rtms,不是scribe - 麦克风第 1 分片正常、后续为空 → 录音器/容器边界问题,每个分片重启录音器
- batch 作业排队但永不完成 → 存储认证 / URI / Webhook 问题
- 部分文件缺转录 → 先查
/jobs/{jobId}/files再重提整个 batch
版本漂移:三张易变的面与维护触发点
版本漂移文档 把「文档会变」本身当作必须管理的工程风险,识别出三类漂移:
命名漂移:API key/secret、SDK key/secret、ZOOM_API_KEY/SECRET并存,统一按 Build-platform issuer/secret 对处理,改生产代码前先到 Zoom 开发者 UI 核实标签。
产品定位漂移:Scribe 属于 AI Services,但相关产品可能把用户引向 RTMS(直播流)、Meeting SDK Linux bot(可见的会内捕获)、AI Companion / REST API(Zoom 生成摘要与转录)。守住边界:scribe= 文件/存储转录;rtms= 直播媒体流摄入;Meeting SDK Linux = 参与者 bot 捕获/原始录音。
工作流声明漂移:部分博客材料把 Scribe 包装进「通话后摘要、工单充实、合规日志、可检索归档、客服 QA 管线、情绪/关键词下游分析」等语音洞察工作流。这些是合法的架构用例,但不扩展当前文档化的端点面。实现规则:scribe只负责生成转录,情绪、分类、QA 评分、摘要全部放自己的下游管线;不要仅凭博客措辞推断未文档化的实时或分析端点。
API 表面漂移观察点:关注 S3 之外的新存储提供方、config字段名变更、Webhook 签名头约定、响应 summary/file schema、语言与输出格式支持。
重新审查触发点:api-hub/ai-services/methods/endpoints.json变更、AI Services 文档再次改凭据命名、quickstart 样例改变 Webhook 或上传模式时,需重新校对本文所引用的全部结论。
延伸阅读
- scribe 技能入口与路由护栏
- 认证与处理模式
- 高等级场景
- Fast Mode Node 示例
- Batch 作业 + Webhook 流水线示例
- API 参考
- 环境变量
- 样例验证
- 版本漂移
- 常见漂移与故障
- 5 分钟预检 Runbook
- 相邻技能:rtms(直播流)、rest-api(REST 清单)、webhooks(签名加固)
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考