Skip to content

Commit 31119ec

Browse files
authored
docs: add JavaScript OpenAI API recipes
Document OpenAI JS SDK, Node fetch, TypeScript helper, and Next.js proxy patterns for FunASR OpenAI-compatible API users.
1 parent 0386bff commit 31119ec

11 files changed

Lines changed: 399 additions & 13 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ curl http://localhost:8000/v1/audio/transcriptions \
198198
docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12
199199
```
200200

201-
[OpenAI API example →](./examples/openai_api/) · [Client recipes →](./examples/openai_api/CLIENTS.md) · [Workflow recipes →](./examples/openai_api/WORKFLOWS.md) · [Postman collection →](./examples/openai_api/POSTMAN.md) · [OpenAPI spec →](./examples/openai_api/OPENAPI.md) · [Deployment matrix →](./docs/deployment_matrix.md) · [Deployment docs →](./runtime/readme.md) · [Agent integration →](https://modelscope.github.io/FunASR/agent.html)
201+
[OpenAI API example →](./examples/openai_api/) · [Client recipes →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript recipes →](./examples/openai_api/JAVASCRIPT.md) · [Workflow recipes →](./examples/openai_api/WORKFLOWS.md) · [Postman collection →](./examples/openai_api/POSTMAN.md) · [OpenAPI spec →](./examples/openai_api/OPENAPI.md) · [Deployment matrix →](./docs/deployment_matrix.md) · [Deployment docs →](./runtime/readme.md) · [Agent integration →](https://modelscope.github.io/FunASR/agent.html)
202202

203203
---
204204

README_zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ curl http://localhost:8000/v1/audio/transcriptions \
197197
docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12
198198
```
199199

200-
[OpenAI API 示例 →](./examples/openai_api/README_zh.md) · [客户端配方 →](./examples/openai_api/CLIENTS.md) · [工作流配方 →](./examples/openai_api/WORKFLOWS_zh.md) · [Postman 集合 →](./examples/openai_api/POSTMAN_zh.md) · [OpenAPI 规范 →](./examples/openai_api/OPENAPI_zh.md) · [部署选型 →](./docs/deployment_matrix_zh.md) · [部署文档 →](./runtime/readme_cn.md) · [Agent 集成 →](https://modelscope.github.io/FunASR/agent.html)
200+
[OpenAI API 示例 →](./examples/openai_api/README_zh.md) · [客户端配方 →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript 配方 →](./examples/openai_api/JAVASCRIPT_zh.md) · [工作流配方 →](./examples/openai_api/WORKFLOWS_zh.md) · [Postman 集合 →](./examples/openai_api/POSTMAN_zh.md) · [OpenAPI 规范 →](./examples/openai_api/OPENAPI_zh.md) · [部署选型 →](./docs/deployment_matrix_zh.md) · [部署文档 →](./runtime/readme_cn.md) · [Agent 集成 →](https://modelscope.github.io/FunASR/agent.html)
201201

202202
---
203203

docs/deployment_matrix.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Use the Python API from the README. It is the shortest route for validating inst
2424

2525
### I want a local replacement for cloud transcription
2626

27-
Use the OpenAI-compatible API. It exposes `/v1/audio/transcriptions`, `/v1/models`, `/health`, and Swagger docs. Start with `sensevoice`, run `examples/openai_api/smoke_test.sh` or `examples/openai_api/smoke_test.py`, then connect existing SDK or HTTP clients using [client recipes](../examples/openai_api/CLIENTS.md). For Dify, n8n, HTTP nodes, or webhook workers, follow the [workflow recipes](../examples/openai_api/WORKFLOWS.md). For API gateways, developer portals, and schema-driven imports, use the [OpenAPI spec](../examples/openai_api/OPENAPI.md).
27+
Use the OpenAI-compatible API. It exposes `/v1/audio/transcriptions`, `/v1/models`, `/health`, and Swagger docs. Start with `sensevoice`, run `examples/openai_api/smoke_test.sh` or `examples/openai_api/smoke_test.py`, then connect existing SDK or HTTP clients using [client recipes](../examples/openai_api/CLIENTS.md) and [JavaScript/TypeScript recipes](../examples/openai_api/JAVASCRIPT.md). For Dify, n8n, HTTP nodes, or webhook workers, follow the [workflow recipes](../examples/openai_api/WORKFLOWS.md). For API gateways, developer portals, and schema-driven imports, use the [OpenAPI spec](../examples/openai_api/OPENAPI.md).
2828

2929
### I want a repeatable container demo
3030

docs/deployment_matrix_zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
### 我想替代云端转写服务
2626

27-
使用 OpenAI 兼容 API。它提供 `/v1/audio/transcriptions``/v1/models``/health` 和 Swagger docs。先用 `sensevoice` 跑通 `examples/openai_api/smoke_test.sh``examples/openai_api/smoke_test.py`,再根据 [客户端配方](../examples/openai_api/CLIENTS.md) 接入 SDK 或 HTTP 客户端。Dify、n8n、HTTP 节点或 webhook worker 可参考 [工作流配方](../examples/openai_api/WORKFLOWS_zh.md)。API 网关、开发者门户或按 schema 导入时可使用 [OpenAPI 规范](../examples/openai_api/OPENAPI_zh.md)
27+
使用 OpenAI 兼容 API。它提供 `/v1/audio/transcriptions``/v1/models``/health` 和 Swagger docs。先用 `sensevoice` 跑通 `examples/openai_api/smoke_test.sh``examples/openai_api/smoke_test.py`,再根据 [客户端配方](../examples/openai_api/CLIENTS.md) [JavaScript/TypeScript 配方](../examples/openai_api/JAVASCRIPT_zh.md) 接入 SDK 或 HTTP 客户端。Dify、n8n、HTTP 节点或 webhook worker 可参考 [工作流配方](../examples/openai_api/WORKFLOWS_zh.md)。API 网关、开发者门户或按 schema 导入时可使用 [OpenAPI 规范](../examples/openai_api/OPENAPI_zh.md)
2828

2929
### 我想要可复现的容器 demo
3030

docs/use_case_showcase.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ FunASR is useful far beyond a single offline transcription command. This page co
99
| Transcribe one file locally | [README quick start](../README.md#quick-start) | Verify install and model download in minutes. |
1010
| Compare accuracy and speed | [Benchmark report](https://modelscope.github.io/FunASR/benchmark.html) | Reproduce the 184-file long-audio benchmark before choosing a model. |
1111
| Migrate from Whisper/cloud ASR | [Migration guide](./migration_from_whisper.md) | Map existing pipelines to FunASR, benchmark representative audio, and plan a safe rollout. |
12-
| Build a private speech API | [OpenAI-compatible API example](../examples/openai_api/), [client recipes](../examples/openai_api/CLIENTS.md), and [workflow recipes](../examples/openai_api/WORKFLOWS.md) | Reuse LangChain, Dify, n8n, AutoGen, and other OpenAI-style clients without sending audio to a cloud ASR provider. |
12+
| Build a private speech API | [OpenAI-compatible API example](../examples/openai_api/), [client recipes](../examples/openai_api/CLIENTS.md), [JavaScript/TypeScript recipes](../examples/openai_api/JAVASCRIPT.md), and [workflow recipes](../examples/openai_api/WORKFLOWS.md) | Reuse LangChain, Dify, n8n, AutoGen, and other OpenAI-style clients without sending audio to a cloud ASR provider. |
1313
| Add speech input to agents | [MCP server](../examples/mcp_server/) and [voice input](../examples/voice_input/) | Connect local ASR to Claude, Cursor, and desktop agent workflows. |
1414
| Choose a deployment path | [Deployment matrix](./deployment_matrix.md) | Compare Python API, OpenAI API, Docker Compose, WebSocket, vLLM, MCP, batch, subtitles, and Triton. |
1515
| Serve streaming ASR | [Runtime service docs](../runtime/readme.md) | Run WebSocket or service-mode ASR for live captioning and call-center style workloads. |
@@ -37,7 +37,8 @@ curl http://localhost:8000/v1/audio/transcriptions \
3737

3838
Recommended next steps:
3939

40-
- Run the [OpenAI-compatible API smoke test](../examples/openai_api/smoke_test.sh).
40+
- Run the [OpenAI-compatible API smoke test](../examples/openai_api/smoke_test.sh) or the cross-platform [Python smoke test](../examples/openai_api/smoke_test.py).
41+
- For Node.js or Next.js services, start from the [JavaScript/TypeScript recipes](../examples/openai_api/JAVASCRIPT.md).
4142
- Add authentication and network controls at your service boundary.
4243
- Record model name, device, driver, and audio duration in bug reports and benchmarks.
4344

docs/use_case_showcase_zh.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ FunASR 不只是一个离线转写命令。这个页面把常见的评测、部
99
| 本地转写一个文件 | [README 快速开始](../README_zh.md#快速开始) | 几分钟内验证安装、模型下载和首次推理。 |
1010
| 对比准确率和速度 | [性能评测报告](https://modelscope.github.io/FunASR/zh/benchmark.html) | 选型前先查看 184 条长音频评测结果。 |
1111
| 从 Whisper/云端 ASR 迁移 | [迁移指南](./migration_from_whisper_zh.md) | 将现有流水线映射到 FunASR,用代表性音频评测并规划安全上线。 |
12-
| 搭建私有语音 API | [OpenAI 兼容 API 示例](../examples/openai_api/README_zh.md)[客户端配方](../examples/openai_api/CLIENTS.md)[工作流配方](../examples/openai_api/WORKFLOWS_zh.md) | 复用 LangChain、Dify、n8n、AutoGen 等 OpenAI 风格客户端,音频不出内网。 |
12+
| 搭建私有语音 API | [OpenAI 兼容 API 示例](../examples/openai_api/README_zh.md)[客户端配方](../examples/openai_api/CLIENTS.md)[JavaScript/TypeScript 配方](../examples/openai_api/JAVASCRIPT_zh.md)[工作流配方](../examples/openai_api/WORKFLOWS_zh.md) | 复用 LangChain、Dify、n8n、AutoGen 等 OpenAI 风格客户端,音频不出内网。 |
1313
| 给 Agent 增加语音输入 | [MCP 服务](../examples/mcp_server/)[语音输入示例](../examples/voice_input/) | 将本地 ASR 接入 Claude、Cursor 和桌面 Agent 工作流。 |
1414
| 选择部署路径 | [部署选型表](./deployment_matrix_zh.md) | 对比 Python API、OpenAI API、Docker Compose、WebSocket、vLLM、MCP、批处理、字幕和 Triton。 |
1515
| 部署流式 ASR | [Runtime 服务文档](../runtime/readme_cn.md) | 面向实时字幕、客服、会议等低延迟场景。 |
@@ -37,7 +37,8 @@ curl http://localhost:8000/v1/audio/transcriptions \
3737

3838
建议下一步:
3939

40-
- 运行 [OpenAI 兼容 API smoke test](../examples/openai_api/smoke_test.sh)
40+
- 运行 [OpenAI 兼容 API smoke test](../examples/openai_api/smoke_test.sh) 或跨平台 [Python smoke test](../examples/openai_api/smoke_test.py)
41+
- Node.js 或 Next.js 服务可从 [JavaScript/TypeScript 配方](../examples/openai_api/JAVASCRIPT_zh.md) 开始。
4142
- 在服务边界增加鉴权、限流和网络访问控制。
4243
- 记录模型、设备、驱动、音频时长和处理耗时,便于复现问题和 benchmark。
4344

examples/openai_api/CLIENTS.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Client Recipes for the FunASR OpenAI-Compatible API
22

3-
Use this page when `funasr-server` is already running and you want to connect an existing application, agent tool, or workflow engine to local speech recognition. For Dify, n8n, HTTP nodes, and webhook workers, see the [workflow recipes](WORKFLOWS.md) or [Chinese workflow recipes](WORKFLOWS_zh.md). For no-code API smoke tests, import the [Postman collection](POSTMAN.md). For schema-driven imports or client generation, use the [OpenAPI spec](OPENAPI.md).
3+
Use this page when `funasr-server` is already running and you want to connect an existing application, agent tool, or workflow engine to local speech recognition. For JavaScript, TypeScript, and Next.js examples, see the [JavaScript/TypeScript recipes](JAVASCRIPT.md) or [Chinese JavaScript/TypeScript recipes](JAVASCRIPT_zh.md). For Dify, n8n, HTTP nodes, and webhook workers, see the [workflow recipes](WORKFLOWS.md) or [Chinese workflow recipes](WORKFLOWS_zh.md). For no-code API smoke tests, import the [Postman collection](POSTMAN.md). For schema-driven imports or client generation, use the [OpenAPI spec](OPENAPI.md).
44

55
## Preflight
66

@@ -42,6 +42,30 @@ for segment in getattr(result, "segments", []):
4242

4343
Most OpenAI SDKs require an API key value even when the local FunASR server does not check it. Use any placeholder for local development, then add real authentication at your gateway if the service is shared.
4444

45+
## JavaScript and TypeScript
46+
47+
Use the [JavaScript/TypeScript recipes](JAVASCRIPT.md) for OpenAI JS SDK, built-in `fetch`, TypeScript helper functions, and Next.js route handlers. Minimal OpenAI SDK shape:
48+
49+
```javascript
50+
import OpenAI from "openai";
51+
import { createReadStream } from "node:fs";
52+
53+
const client = new OpenAI({
54+
baseURL: "http://localhost:8000/v1",
55+
apiKey: "local-development",
56+
});
57+
58+
const result = await client.audio.transcriptions.create({
59+
model: "sensevoice",
60+
file: createReadStream("meeting.wav"),
61+
response_format: "verbose_json",
62+
});
63+
64+
console.log(result.text);
65+
```
66+
67+
For browser uploads, send audio to your backend first, then proxy to FunASR with authentication and upload limits. See the [Chinese JavaScript/TypeScript recipes](JAVASCRIPT_zh.md) for localized guidance.
68+
4569
## Plain Python requests
4670

4771
```python

examples/openai_api/JAVASCRIPT.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# JavaScript and TypeScript Recipes for the FunASR OpenAI-Compatible API
2+
3+
Use this guide when `funasr-server` is already running and you want to connect Node.js, TypeScript services, Next.js route handlers, or other JavaScript agent workflows to local speech recognition.
4+
5+
## Preflight
6+
7+
Start the API server first:
8+
9+
```bash
10+
cd examples/openai_api
11+
python server.py --model sensevoice --device cuda --port 8000
12+
```
13+
14+
Then verify the service from another terminal:
15+
16+
```bash
17+
python smoke_test.py --base-url http://localhost:8000
18+
```
19+
20+
SDK base URLs include `/v1`; direct health checks do not:
21+
22+
```text
23+
OpenAI SDK baseURL: http://localhost:8000/v1
24+
Health endpoint: http://localhost:8000/health
25+
Transcription URL: http://localhost:8000/v1/audio/transcriptions
26+
```
27+
28+
## OpenAI JavaScript SDK
29+
30+
Install the official JavaScript SDK:
31+
32+
```bash
33+
npm install openai
34+
```
35+
36+
Create `transcribe.mjs`:
37+
38+
```javascript
39+
import OpenAI from "openai";
40+
import { createReadStream } from "node:fs";
41+
42+
const audioPath = process.argv[2] ?? "sample.wav";
43+
44+
const client = new OpenAI({
45+
baseURL: process.env.FUNASR_OPENAI_BASE_URL ?? "http://localhost:8000/v1",
46+
apiKey: process.env.OPENAI_API_KEY ?? "local-development",
47+
});
48+
49+
const result = await client.audio.transcriptions.create({
50+
model: process.env.FUNASR_MODEL ?? "sensevoice",
51+
file: createReadStream(audioPath),
52+
response_format: "verbose_json",
53+
});
54+
55+
console.log(result.text);
56+
for (const segment of result.segments ?? []) {
57+
console.log(`${segment.start}s-${segment.end}s`, segment.text);
58+
}
59+
```
60+
61+
Run it:
62+
63+
```bash
64+
node transcribe.mjs meeting.wav
65+
```
66+
67+
Most OpenAI-compatible SDKs require an API key value even when the local FunASR server does not check it. Use any placeholder for local development, then add real authentication at your gateway if the service is shared.
68+
69+
## Built-in fetch without an SDK
70+
71+
Node.js 18+ includes `fetch`, `FormData`, and `Blob`, so you can call the API without third-party dependencies:
72+
73+
```javascript
74+
import { readFile } from "node:fs/promises";
75+
import { basename } from "node:path";
76+
77+
const baseUrl = process.env.FUNASR_BASE_URL ?? "http://localhost:8000";
78+
const audioPath = process.argv[2] ?? "sample.wav";
79+
const audio = await readFile(audioPath);
80+
81+
const form = new FormData();
82+
form.append("file", new Blob([audio], { type: "audio/wav" }), basename(audioPath));
83+
form.append("model", process.env.FUNASR_MODEL ?? "sensevoice");
84+
form.append("response_format", "verbose_json");
85+
86+
const response = await fetch(`${baseUrl}/v1/audio/transcriptions`, {
87+
method: "POST",
88+
body: form,
89+
});
90+
91+
if (!response.ok) {
92+
throw new Error(`FunASR request failed: ${response.status} ${await response.text()}`);
93+
}
94+
95+
const result = await response.json();
96+
console.log(result.text);
97+
```
98+
99+
Use this pattern for queue workers, webhook workers, scheduled jobs, and small internal services.
100+
101+
## TypeScript helper
102+
103+
```typescript
104+
import OpenAI from "openai";
105+
import { createReadStream } from "node:fs";
106+
107+
export interface FunASRTranscript {
108+
text: string;
109+
segments?: Array<{ start: number; end: number; text: string; speaker?: number }>;
110+
language?: string;
111+
duration?: number;
112+
model?: string;
113+
}
114+
115+
const client = new OpenAI({
116+
baseURL: process.env.FUNASR_OPENAI_BASE_URL ?? "http://localhost:8000/v1",
117+
apiKey: process.env.OPENAI_API_KEY ?? "local-development",
118+
});
119+
120+
export async function transcribeWithFunASR(audioPath: string): Promise<FunASRTranscript> {
121+
const result = await client.audio.transcriptions.create({
122+
model: process.env.FUNASR_MODEL ?? "sensevoice",
123+
file: createReadStream(audioPath),
124+
response_format: "verbose_json",
125+
});
126+
127+
return result as FunASRTranscript;
128+
}
129+
```
130+
131+
Keep the return type small and application-owned. FunASR can return richer metadata over time, and your application can opt into only the fields it needs.
132+
133+
## Next.js route handler
134+
135+
Proxy browser uploads through your backend so you can enforce authentication, file-size limits, and audit logs before audio reaches FunASR.
136+
137+
```typescript
138+
export async function POST(request: Request) {
139+
const incoming = await request.formData();
140+
const file = incoming.get("file");
141+
142+
if (!(file instanceof File)) {
143+
return Response.json({ error: "missing file" }, { status: 400 });
144+
}
145+
146+
const upstream = new FormData();
147+
upstream.append("file", file, file.name || "audio.wav");
148+
upstream.append("model", "sensevoice");
149+
upstream.append("response_format", "verbose_json");
150+
151+
const response = await fetch("http://funasr-api:8000/v1/audio/transcriptions", {
152+
method: "POST",
153+
body: upstream,
154+
});
155+
156+
const body = await response.json();
157+
return Response.json(body, { status: response.status });
158+
}
159+
```
160+
161+
In Docker Compose or Kubernetes, replace `funasr-api` with the service name reachable from your web backend. Avoid sending browser traffic directly to an unauthenticated FunASR endpoint on a public network.
162+
163+
## Production checklist
164+
165+
- Put TLS, authentication, upload-size limits, and rate limits in front of the API.
166+
- Set request timeouts based on maximum audio duration; long recordings need longer HTTP timeouts.
167+
- Log audio duration, model alias, response format, latency, and upstream error text.
168+
- Run `GET /health` and `GET /v1/models` during readiness checks before accepting user uploads.
169+
- Keep audio upload handling on the server side for browser applications.
170+
- Pin `openai` package versions in production services and retest after SDK upgrades.
171+
172+
## Troubleshooting
173+
174+
| Symptom | Fix |
175+
|---|---|
176+
| SDK reports a missing API key | Pass any placeholder `apiKey` for local development. |
177+
| 404 from SDK calls | Use `baseURL=http://localhost:8000/v1`; direct endpoint calls use `http://localhost:8000`. |
178+
| `unknown model` | Call `/v1/models` and use one of the returned aliases. |
179+
| Browser upload fails with CORS or auth errors | Send uploads to your backend first, then proxy to FunASR. |
180+
| Request times out | Increase SDK or fetch timeouts, or split very long audio. |

0 commit comments

Comments
 (0)