FunASR OpenAI 兼容 API JavaScript/TypeScript 接入配方
May 25, 2026 · View on GitHub
当 funasr-server 已经启动,而你希望把 Node.js、TypeScript 服务、Next.js route handler 或 JavaScript Agent 工作流接入本地语音识别时,可以按这份指南复制代码。
预检查
先启动 API 服务:
cd examples/openai_api
python server.py --model sensevoice --device cuda --port 8000
在另一个终端验证服务:
python smoke_test.py --base-url http://localhost:8000
SDK base URL 需要包含 /v1,直接健康检查不需要:
OpenAI SDK baseURL: http://localhost:8000/v1
健康检查: http://localhost:8000/health
转写接口: http://localhost:8000/v1/audio/transcriptions
OpenAI JavaScript SDK
安装官方 JavaScript SDK:
npm install openai
创建 transcribe.mjs:
import OpenAI from "openai";
import { createReadStream } from "node:fs";
const audioPath = process.argv[2] ?? "sample.wav";
const client = new OpenAI({
baseURL: process.env.FUNASR_OPENAI_BASE_URL ?? "http://localhost:8000/v1",
apiKey: process.env.OPENAI_API_KEY ?? "local-development",
});
const result = await client.audio.transcriptions.create({
model: process.env.FUNASR_MODEL ?? "sensevoice",
file: createReadStream(audioPath),
response_format: "verbose_json",
});
console.log(result.text);
for (const segment of result.segments ?? []) {
console.log(`${segment.start}s-${segment.end}s`, segment.text);
}
运行:
node transcribe.mjs meeting.wav
多数 OpenAI 兼容 SDK 即使在本地服务不校验密钥时,也要求传入一个 API key。开发环境可以使用任意占位值;如果服务被多人共享,请在网关层增加真实鉴权。
不依赖 SDK 的内置 fetch 写法
Node.js 18+ 内置 fetch、FormData 和 Blob,可以不安装第三方依赖直接调用接口:
import { readFile } from "node:fs/promises";
import { basename } from "node:path";
const baseUrl = process.env.FUNASR_BASE_URL ?? "http://localhost:8000";
const audioPath = process.argv[2] ?? "sample.wav";
const audio = await readFile(audioPath);
const form = new FormData();
form.append("file", new Blob([audio], { type: "audio/wav" }), basename(audioPath));
form.append("model", process.env.FUNASR_MODEL ?? "sensevoice");
form.append("response_format", "verbose_json");
const response = await fetch(`${baseUrl}/v1/audio/transcriptions`, {
method: "POST",
body: form,
});
if (!response.ok) {
throw new Error(`FunASR request failed: ${response.status} ${await response.text()}`);
}
const result = await response.json();
console.log(result.text);
这个模式适合队列 worker、webhook worker、定时任务和小型内部服务。
TypeScript helper
import OpenAI from "openai";
import { createReadStream } from "node:fs";
export interface FunASRTranscript {
text: string;
segments?: Array<{ start: number; end: number; text: string; speaker?: number }>;
language?: string;
duration?: number;
model?: string;
}
const client = new OpenAI({
baseURL: process.env.FUNASR_OPENAI_BASE_URL ?? "http://localhost:8000/v1",
apiKey: process.env.OPENAI_API_KEY ?? "local-development",
});
export async function transcribeWithFunASR(audioPath: string): Promise<FunASRTranscript> {
const result = await client.audio.transcriptions.create({
model: process.env.FUNASR_MODEL ?? "sensevoice",
file: createReadStream(audioPath),
response_format: "verbose_json",
});
return result as FunASRTranscript;
}
建议在应用侧维护一个小而稳定的返回类型。FunASR 后续可能返回更丰富的元数据,业务代码只需要消费自己关心的字段。
Next.js route handler
浏览器上传建议先进入自己的后端,再由后端转发到 FunASR,这样可以统一做鉴权、文件大小限制和审计日志。
export async function POST(request: Request) {
const incoming = await request.formData();
const file = incoming.get("file");
if (!(file instanceof File)) {
return Response.json({ error: "missing file" }, { status: 400 });
}
const upstream = new FormData();
upstream.append("file", file, file.name || "audio.wav");
upstream.append("model", "sensevoice");
upstream.append("response_format", "verbose_json");
const response = await fetch("http://funasr-api:8000/v1/audio/transcriptions", {
method: "POST",
body: upstream,
});
const body = await response.json();
return Response.json(body, { status: response.status });
}
在 Docker Compose 或 Kubernetes 中,把 funasr-api 换成 Web 后端能访问到的 service name。不要把未鉴权的 FunASR 接口直接暴露给公网浏览器。
生产检查清单
- 在 API 前增加 TLS、鉴权、上传大小限制和限流。
- 根据最大音频时长设置请求超时;长录音需要更长的 HTTP timeout。
- 记录音频时长、模型别名、响应格式、延迟和上游错误文本。
- 接收用户上传前,先用
GET /health和GET /v1/models做就绪检查。 - 浏览器应用应把音频上传处理留在服务端。
- 生产服务固定
openai包版本,并在 SDK 升级后重新测试。
故障排查
| 现象 | 处理方式 |
|---|---|
| SDK 提示缺少 API key | 本地开发传入任意占位 apiKey。 |
| SDK 调用返回 404 | SDK 使用 baseURL=http://localhost:8000/v1;直接端点调用使用 http://localhost:8000。 |
unknown model | 调用 /v1/models,使用返回的模型别名。 |
| 浏览器上传遇到 CORS 或鉴权错误 | 先上传到自己的后端,再由后端代理到 FunASR。 |
| 请求超时 | 增加 SDK 或 fetch 超时,或切分超长音频。 |