视频文案提取 API Node.js 教程:提交、轮询和读取文字结果
Videosays API 使用异步任务模型:POST 创建任务,保存 taskId,再通过 GET 查询,直到 completed、failed 或 cancelled。客户端不应把一次 HTTP 请求保持到视频处理完成,也不应在超时后盲目重复创建任务。下面示例只使用公开契约中的 X-API-Key、Idempotency-Key、input 和 duplicatePolicy。
操作步骤
创建并妥善保存 API Key
在开发者控制台创建带标签的 API Key,并通过环境变量 VIDEOSAYS_API_KEY 注入后端进程。密钥只展示一次,可能过期或被撤销;不要写进浏览器代码、仓库、日志或教程截图。
使用幂等键创建任务
向 https://api.videosays.com/api/v1/transcribe 发送 POST,请求头包含 X-API-Key、Content-Type 和一个 UUID 格式的 Idempotency-Key。相同业务请求重试时复用相同键,不同请求必须使用新键。
保存 taskId 并按间隔轮询
接口可能返回 200 或 202。保存 taskId,通过 GET /api/v1/transcribe/{taskId} 查询;优先使用响应中的 retryAfterSeconds,避免高频轮询和 429。
处理完成、失败和复用状态
completed 时读取 result.text 和 result.segments;failed 或 cancelled 时停止轮询并记录 error;awaiting_reuse 时按产品策略处理复用决定。不要将失败响应包装成空白成功结果。
生产环境最小数据记录
创建时保存
业务请求 ID、Idempotency-Key、taskId、输入来源和创建时间;不要保存明文 API Key。
完成时保存
终态、result.text、segments、video 上下文、计费状态、完成时间和安全的错误码。
本地轮询超时应记录为“等待超时”,不能擅自把服务端任务写成 failed。
为什么异步任务更适合视频转写
视频解析、音轨准备、队列和语音识别时间不稳定,单个长 HTTP 请求容易被代理或客户端超时。异步模型让创建请求快速返回,业务系统可以保存 taskId、恢复轮询,并独立处理完成和失败。
Idempotency-Key 与同用户复用不是一回事
幂等键保护同一创建请求的网络重放;duplicatePolicy 控制同一用户是否复用自己已有的转写结果。不要为每次网络重试生成新幂等键,否则可能创建重复资源。Videosays 不跨用户共享转写结果。
常见状态和停止条件
pending、analyzing、submitting、processing 表示仍在运行;awaiting_reuse 需要调用方做复用选择;completed、failed 和 cancelled 是终态。客户端应该为总等待时间设置上限,但本地超时不等于服务端任务失败。
HTTP 错误应如何处理
401 表示鉴权失败;402 可能表示明确的新转写请求额度不足;409 可能是幂等键冲突;422 表示输入不支持;429 表示限流。记录状态码和安全的错误字段,不记录完整密钥。
批量处理使用专门的 batches 接口
需要提交 1–100 个普通视频输入时,使用 POST /api/v1/batches,并通过 GET /api/v1/batches/{batchId}?view=status 轻量轮询。不要在客户端瞬间并发 100 个单条创建请求。
可运行示例
创建并等待一条转写任务
Node.js 22 内置 fetch。示例保留服务端返回的 taskId,并按 retryAfterSeconds 轮询。
const API_BASE = 'https://api.videosays.com';
const apiKey = process.env.VIDEOSAYS_API_KEY;
if (!apiKey) throw new Error('VIDEOSAYS_API_KEY is required');
const createResponse = await fetch(API_BASE + '/api/v1/transcribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey,
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
input: 'https://www.douyin.com/video/REPLACE_WITH_PUBLIC_ID',
options: { language: 'auto', sourceMode: 'auto', duplicatePolicy: 'reuse' },
}),
});
if (![200, 202].includes(createResponse.status)) {
throw new Error('Create failed: ' + createResponse.status);
}
let task = await createResponse.json();
while (!['completed', 'failed', 'cancelled'].includes(task.status)) {
const waitSeconds = task.retryAfterSeconds ?? 5;
await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
const pollResponse = await fetch(
API_BASE + '/api/v1/transcribe/' + task.taskId,
{ headers: { 'X-API-Key': apiKey } },
);
if (!pollResponse.ok) throw new Error('Poll failed: ' + pollResponse.status);
task = await pollResponse.json();
}
if (task.status !== 'completed') {
throw new Error(task.error?.message ?? 'Transcription did not complete');
}
console.log(task.result.text);批量接口的最小请求
批量接口接受 1–100 个输入,并返回可独立轮询的 batchId。
const response = await fetch('https://api.videosays.com/api/v1/batches', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.VIDEOSAYS_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
items: publicVideoLinks,
options: { language: 'auto', sourceMode: 'auto', duplicatePolicy: 'reuse' },
}),
});
if (response.status !== 202) {
throw new Error('Batch create failed: ' + response.status);
}
const batch = await response.json();
console.log(batch.batchId);核对来源
- Videosays OpenAPI 规范 — 当前公开接口、状态码和响应模型。
- Videosays API 与 CLI 文档 — 鉴权、命令行和调用示例。
先完成最小异步闭环
创建 API Key,用一个公开样本跑通创建、轮询、终态和错误处理,再扩展到批量。
常见问题
Node.js 需要安装额外的 HTTP 库吗?
Node.js 22 已内置 fetch 和 crypto.randomUUID,基础示例不需要额外 HTTP 依赖。
为什么创建任务可能返回 200,也可能返回 202?
202 表示新任务已接受;200 可能表示幂等重放或按同用户复用策略返回已有终态任务。客户端应同时接受并读取响应体。
可以每秒轮询一次吗?
不建议。优先读取 retryAfterSeconds,并为 429 和网络错误设置退避。
怎样导出 SRT 或 VTT?
任务响应包含文字和时间轴 segments;网页和 CLI 提供 TXT、SRT、VTT 工作流。具体公开字段与格式应以 OpenAPI 和文档为准。
API Key 可以放在 Next.js 的 NEXT_PUBLIC 变量里吗?
不可以。NEXT_PUBLIC 会进入浏览器公开包。API Key 应只保存在服务端环境变量或安全密钥系统。