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+ 内置 fetchFormDataBlob,可以不安装第三方依赖直接调用接口:

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 /healthGET /v1/models 做就绪检查。
  • 浏览器应用应把音频上传处理留在服务端。
  • 生产服务固定 openai 包版本,并在 SDK 升级后重新测试。

故障排查

现象处理方式
SDK 提示缺少 API key本地开发传入任意占位 apiKey
SDK 调用返回 404SDK 使用 baseURL=http://localhost:8000/v1;直接端点调用使用 http://localhost:8000
unknown model调用 /v1/models,使用返回的模型别名。
浏览器上传遇到 CORS 或鉴权错误先上传到自己的后端,再由后端代理到 FunASR。
请求超时增加 SDK 或 fetch 超时,或切分超长音频。