diff --git a/README.md b/README.md index 514bc9b9e..55c4a201e 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ curl http://localhost:8000/v1/audio/transcriptions \ docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12 ``` -[OpenAI API example →](./examples/openai_api/) · [Gradio demo →](./examples/openai_api/GRADIO.md) · [Client recipes →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript recipes →](./examples/openai_api/JAVASCRIPT.md) · [Kubernetes template →](./examples/openai_api/kubernetes/) · [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) +[OpenAI API example →](./examples/openai_api/) · [Gradio demo →](./examples/openai_api/GRADIO.md) · [Client recipes →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript recipes →](./examples/openai_api/JAVASCRIPT.md) · [Kubernetes template →](./examples/openai_api/kubernetes/) · [Workflow recipes →](./examples/openai_api/WORKFLOWS.md) · [Postman collection →](./examples/openai_api/POSTMAN.md) · [OpenAPI spec →](./examples/openai_api/OPENAPI.md) · [Security guide →](./examples/openai_api/SECURITY.md) · [Deployment matrix →](./docs/deployment_matrix.md) · [Deployment docs →](./runtime/readme.md) · [Agent integration →](https://modelscope.github.io/FunASR/agent.html) --- diff --git a/README_ja.md b/README_ja.md index a3234ebbb..a6cb2127c 100644 --- a/README_ja.md +++ b/README_ja.md @@ -132,7 +132,7 @@ funasr-server --device cuda docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12 ``` -[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) · [デプロイドキュメント →](./runtime/readme.md) · [Agent連携 →](https://modelscope.github.io/FunASR/agent.html) +[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) · [Security guide →](./examples/openai_api/SECURITY.md) · [Deployment matrix →](./docs/deployment_matrix.md) · [デプロイドキュメント →](./runtime/readme.md) · [Agent連携 →](https://modelscope.github.io/FunASR/agent.html) --- diff --git a/README_ko.md b/README_ko.md index 611fd782e..ed08aadf0 100644 --- a/README_ko.md +++ b/README_ko.md @@ -132,7 +132,7 @@ funasr-server --device cuda docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12 ``` -[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) · [배포 문서 →](./runtime/readme.md) · [Agent 연동 →](https://modelscope.github.io/FunASR/agent.html) +[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) · [Security guide →](./examples/openai_api/SECURITY.md) · [Deployment matrix →](./docs/deployment_matrix.md) · [배포 문서 →](./runtime/readme.md) · [Agent 연동 →](https://modelscope.github.io/FunASR/agent.html) --- diff --git a/README_zh.md b/README_zh.md index 14e91c0a7..3405f5985 100644 --- a/README_zh.md +++ b/README_zh.md @@ -197,7 +197,7 @@ curl http://localhost:8000/v1/audio/transcriptions \ docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.12 ``` -[OpenAI API 示例 →](./examples/openai_api/README_zh.md) · [Gradio Demo →](./examples/openai_api/GRADIO_zh.md) · [客户端配方 →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript 配方 →](./examples/openai_api/JAVASCRIPT_zh.md) · [Kubernetes 模板 →](./examples/openai_api/kubernetes/README_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) +[OpenAI API 示例 →](./examples/openai_api/README_zh.md) · [Gradio Demo →](./examples/openai_api/GRADIO_zh.md) · [客户端配方 →](./examples/openai_api/CLIENTS.md) · [JavaScript/TypeScript 配方 →](./examples/openai_api/JAVASCRIPT_zh.md) · [Kubernetes 模板 →](./examples/openai_api/kubernetes/README_zh.md) · [工作流配方 →](./examples/openai_api/WORKFLOWS_zh.md) · [Postman 集合 →](./examples/openai_api/POSTMAN_zh.md) · [OpenAPI 规范 →](./examples/openai_api/OPENAPI_zh.md) · [安全指南 →](./examples/openai_api/SECURITY_zh.md) · [部署选型 →](./docs/deployment_matrix_zh.md) · [部署文档 →](./runtime/readme_cn.md) · [Agent 集成 →](https://modelscope.github.io/FunASR/agent.html) --- diff --git a/docs/deployment_matrix.md b/docs/deployment_matrix.md index 39039371d..2889937e4 100644 --- a/docs/deployment_matrix.md +++ b/docs/deployment_matrix.md @@ -25,7 +25,7 @@ Use the Python API from the README. It is the shortest route for validating inst ### I want a local replacement for cloud transcription -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 browser upload or microphone demos, use the [Gradio browser demo](../examples/openai_api/GRADIO.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). +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 browser upload or microphone demos, use the [Gradio browser demo](../examples/openai_api/GRADIO.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). Before sharing the service, review the [security and gateway guide](../examples/openai_api/SECURITY.md). ### I want a repeatable container demo @@ -57,7 +57,7 @@ Use the vLLM path for Fun-ASR-Nano. Benchmark with your own audio distribution a - Record FunASR version, model version, device, CUDA/PyTorch version, Docker image tag, and command line. - Run a short public smoke sample and at least one realistic private sample. - Log audio duration, model, device, latency, response format, and error type for every request. -- Add upload-size limits, authentication, TLS, and rate limits before exposing an API outside a trusted network. +- Add upload-size limits, authentication, TLS, and rate limits before exposing an API outside a trusted network; use the [security and gateway guide](../examples/openai_api/SECURITY.md) to plan the boundary. - For streaming, test silence, noise, overlapping speakers, long sessions, reconnects, and slow clients. - For benchmark claims, include input duration, hardware, batch size, model, runtime path, and whether model download/warmup time is excluded. diff --git a/docs/deployment_matrix_zh.md b/docs/deployment_matrix_zh.md index 0d68678b2..a12191c01 100644 --- a/docs/deployment_matrix_zh.md +++ b/docs/deployment_matrix_zh.md @@ -25,7 +25,7 @@ ### 我想替代云端转写服务 -使用 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 客户端。浏览器上传或麦克风 demo 可使用 [Gradio 浏览器 Demo](../examples/openai_api/GRADIO_zh.md)。Dify、n8n、HTTP 节点或 webhook worker 可参考 [工作流配方](../examples/openai_api/WORKFLOWS_zh.md)。API 网关、开发者门户或按 schema 导入时可使用 [OpenAPI 规范](../examples/openai_api/OPENAPI_zh.md)。 +使用 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 客户端。浏览器上传或麦克风 demo 可使用 [Gradio 浏览器 Demo](../examples/openai_api/GRADIO_zh.md)。Dify、n8n、HTTP 节点或 webhook worker 可参考 [工作流配方](../examples/openai_api/WORKFLOWS_zh.md)。API 网关、开发者门户或按 schema 导入时可使用 [OpenAPI 规范](../examples/openai_api/OPENAPI_zh.md)。跨团队共享服务前,请先阅读 [安全与网关指南](../examples/openai_api/SECURITY_zh.md)。 ### 我想要可复现的容器 demo @@ -57,7 +57,7 @@ Fun-ASR-Nano 走 vLLM 路径。请用自己的音频分布做 benchmark,并关 - 记录 FunASR 版本、模型版本、设备、CUDA/PyTorch 版本、Docker 镜像 tag 和启动命令。 - 跑一个公开短音频 smoke sample,再跑至少一个真实私有样本。 - 每次请求记录音频时长、模型、设备、延迟、响应格式和错误类型。 -- API 暴露到可信网络外之前,增加上传大小限制、鉴权、TLS 和限流。 +- API 暴露到可信网络外之前,增加上传大小限制、鉴权、TLS 和限流;可用 [安全与网关指南](../examples/openai_api/SECURITY_zh.md) 规划边界。 - 流式场景需要测试静音、噪声、多人重叠、长连接、重连和慢客户端。 - 发布 benchmark 结论时,说明输入时长、硬件、batch size、模型、运行路径,以及是否排除模型下载和 warmup 时间。 diff --git a/docs/use_case_showcase.md b/docs/use_case_showcase.md index 8d75baf51..22a288f88 100644 --- a/docs/use_case_showcase.md +++ b/docs/use_case_showcase.md @@ -41,7 +41,7 @@ Recommended next steps: - For browser upload or microphone demos, start from the [Gradio browser demo](../examples/openai_api/GRADIO.md). - For Node.js or Next.js services, start from the [JavaScript/TypeScript recipes](../examples/openai_api/JAVASCRIPT.md). - For cluster services, start from the [Kubernetes deployment template](../examples/openai_api/kubernetes/). -- Add authentication and network controls at your service boundary. +- Add authentication and network controls at your service boundary; start from the [security and gateway guide](../examples/openai_api/SECURITY.md). - Record model name, device, driver, and audio duration in bug reports and benchmarks. ### Agent speech input diff --git a/docs/use_case_showcase_zh.md b/docs/use_case_showcase_zh.md index d060c507d..1e99328bf 100644 --- a/docs/use_case_showcase_zh.md +++ b/docs/use_case_showcase_zh.md @@ -41,7 +41,7 @@ curl http://localhost:8000/v1/audio/transcriptions \ - 浏览器上传或麦克风 demo 可从 [Gradio 浏览器 Demo](../examples/openai_api/GRADIO_zh.md) 开始。 - Node.js 或 Next.js 服务可从 [JavaScript/TypeScript 配方](../examples/openai_api/JAVASCRIPT_zh.md) 开始。 - 集群内服务可从 [Kubernetes 部署模板](../examples/openai_api/kubernetes/README_zh.md) 开始。 -- 在服务边界增加鉴权、限流和网络访问控制。 +- 在服务边界增加鉴权、限流和网络访问控制;可从 [安全与网关指南](../examples/openai_api/SECURITY_zh.md) 开始。 - 记录模型、设备、驱动、音频时长和处理耗时,便于复现问题和 benchmark。 ### Agent 语音输入 diff --git a/examples/openai_api/CLIENTS.md b/examples/openai_api/CLIENTS.md index ef6ba295b..9e405c418 100644 --- a/examples/openai_api/CLIENTS.md +++ b/examples/openai_api/CLIENTS.md @@ -1,6 +1,6 @@ # Client Recipes for the FunASR OpenAI-Compatible API -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 browser upload or microphone demos, use the [Gradio browser demo](GRADIO.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). +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 browser upload or microphone demos, use the [Gradio browser demo](GRADIO.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). Before sharing the service, review the [security and gateway guide](SECURITY.md). ## Preflight @@ -146,7 +146,7 @@ When the workflow system cannot send files directly, upload audio to an internal ## Production checklist -- Put TLS, authentication, rate limits, and upload-size limits in front of the service before exposing it outside a trusted network. +- Put TLS, authentication, rate limits, and upload-size limits in front of the service before exposing it outside a trusted network; use the [security and gateway guide](SECURITY.md) as the rollout checklist. - Preload the default model at startup and use `/health` for readiness checks. - Set client timeouts based on maximum audio duration; long recordings need longer HTTP timeouts. - Log audio duration, model alias, device, latency, response format, and error type for every request. diff --git a/examples/openai_api/GRADIO.md b/examples/openai_api/GRADIO.md index f8146398b..d3c6cb14d 100644 --- a/examples/openai_api/GRADIO.md +++ b/examples/openai_api/GRADIO.md @@ -57,6 +57,6 @@ See the [model selection guide](../../docs/model_selection.md) for a deeper comp ## Production notes - Treat the Gradio app as a demo or internal operator UI, not a public production frontend. -- Add authentication, TLS, upload-size limits, and rate limits before exposing any audio upload UI outside a trusted network. +- Add authentication, TLS, upload-size limits, and rate limits before exposing any audio upload UI outside a trusted network; see the [security and gateway guide](SECURITY.md). - Keep browser uploads close to your backend; do not send private audio to an unauthenticated public endpoint. - Log model alias, audio duration, latency, response format, and error text when debugging. diff --git a/examples/openai_api/GRADIO_zh.md b/examples/openai_api/GRADIO_zh.md index 6d8040ada..7250dade7 100644 --- a/examples/openai_api/GRADIO_zh.md +++ b/examples/openai_api/GRADIO_zh.md @@ -57,6 +57,6 @@ OpenAI SDK 的 base URL 需要包含 `/v1`;这个 Gradio demo 使用的是不 ## 生产注意事项 - Gradio app 适合作为 demo 或内部操作界面,不建议直接作为公网生产前端。 -- 任何音频上传 UI 对可信网络外开放前,都需要先增加鉴权、TLS、上传大小限制和限流。 +- 任何音频上传 UI 对可信网络外开放前,都需要先增加鉴权、TLS、上传大小限制和限流;见 [安全与网关指南](SECURITY_zh.md)。 - 浏览器上传应尽量靠近你的后端服务,不要把私有音频发送到未鉴权的公网端点。 - 排查问题时记录模型 alias、音频时长、延迟、响应格式和错误文本。 diff --git a/examples/openai_api/README.md b/examples/openai_api/README.md index ed9207237..fd58bdbf0 100644 --- a/examples/openai_api/README.md +++ b/examples/openai_api/README.md @@ -13,7 +13,7 @@ python server.py --model sensevoice --device cuda --port 8000 Server starts in ~20s (model loading). Health check: `GET /health` -Need copy-paste integration snippets for Python SDK, JavaScript/TypeScript, HTTP clients, agent tools, a browser demo, Postman, OpenAPI imports, Kubernetes deployment, or Dify/n8n-style workflows? See [Client recipes](CLIENTS.md), [JavaScript/TypeScript recipes](JAVASCRIPT.md), [Gradio browser demo](GRADIO.md), [workflow recipes](WORKFLOWS.md), the [Chinese workflow recipes](WORKFLOWS_zh.md), the [Postman collection](POSTMAN.md), the [OpenAPI spec](OPENAPI.md), and the [Kubernetes deployment template](kubernetes/README.md). +Need copy-paste integration snippets for Python SDK, JavaScript/TypeScript, HTTP clients, agent tools, a browser demo, Postman, OpenAPI imports, Kubernetes deployment, or Dify/n8n-style workflows? See [Client recipes](CLIENTS.md), [JavaScript/TypeScript recipes](JAVASCRIPT.md), [Gradio browser demo](GRADIO.md), [workflow recipes](WORKFLOWS.md), the [Chinese workflow recipes](WORKFLOWS_zh.md), the [Postman collection](POSTMAN.md), the [OpenAPI spec](OPENAPI.md), the [security and gateway guide](SECURITY.md), and the [Kubernetes deployment template](kubernetes/README.md). ### End-to-end smoke test @@ -162,6 +162,8 @@ python smoke_test.py --base-url http://localhost:8000 ## Kubernetes Deployment +Before sharing the service across a team or exposing it through a gateway, review the [security and gateway guide](SECURITY.md) for TLS, authentication, upload limits, rate limits, and logging. + For an internal cluster service with persistent model cache, health probes, and a private `ClusterIP`, start from the [Kubernetes deployment template](kubernetes/README.md). Build and push the example image, apply the manifests, then verify through `kubectl port-forward` with `python smoke_test.py --base-url http://localhost:8000`. Keep the default CPU mode until you have built a CUDA-capable image and configured GPU scheduling for your cluster. diff --git a/examples/openai_api/README_zh.md b/examples/openai_api/README_zh.md index f19c8fbb9..247874112 100644 --- a/examples/openai_api/README_zh.md +++ b/examples/openai_api/README_zh.md @@ -13,7 +13,7 @@ python server.py --model sensevoice --device cuda --port 8000 服务通常会在模型加载后启动。健康检查:`GET /health`。 -需要直接复制的接入示例?可以继续查看 [客户端配方](CLIENTS.md)、[JavaScript/TypeScript 配方](JAVASCRIPT_zh.md)、[Gradio 浏览器 Demo](GRADIO_zh.md)、[工作流配方](WORKFLOWS_zh.md)、[Postman 集合](POSTMAN_zh.md)、[OpenAPI 规范](OPENAPI_zh.md) 和 [Kubernetes 部署模板](kubernetes/README_zh.md)。 +需要直接复制的接入示例?可以继续查看 [客户端配方](CLIENTS.md)、[JavaScript/TypeScript 配方](JAVASCRIPT_zh.md)、[Gradio 浏览器 Demo](GRADIO_zh.md)、[工作流配方](WORKFLOWS_zh.md)、[Postman 集合](POSTMAN_zh.md)、[OpenAPI 规范](OPENAPI_zh.md)、[安全与网关指南](SECURITY_zh.md) 和 [Kubernetes 部署模板](kubernetes/README_zh.md)。 ### 端到端 smoke test @@ -150,6 +150,8 @@ python smoke_test.py --base-url http://localhost:8000 ## Kubernetes 部署 +在跨团队共享服务或通过网关暴露服务前,请先阅读 [安全与网关指南](SECURITY_zh.md),补齐 TLS、鉴权、上传限制、限流和日志策略。 + 如果需要在集群内部提供带持久化模型缓存、健康检查和私有 `ClusterIP` 的语音 API,可以从 [Kubernetes 部署模板](kubernetes/README_zh.md) 开始。先构建并推送示例镜像,应用 manifests,再通过 `kubectl port-forward` 和 `python smoke_test.py --base-url http://localhost:8000` 验证。 在没有 CUDA-capable 镜像和 GPU 调度配置前,请保持默认 CPU 模式。 diff --git a/examples/openai_api/SECURITY.md b/examples/openai_api/SECURITY.md new file mode 100644 index 000000000..c8a30eb36 --- /dev/null +++ b/examples/openai_api/SECURITY.md @@ -0,0 +1,132 @@ +# Security and Gateway Guide for the FunASR OpenAI-Compatible API + +Use this guide before sharing the example OpenAI-compatible API with a team, workflow engine, browser UI, or service outside your laptop. The example server is intentionally small: it focuses on `/v1/audio/transcriptions` compatibility and does not enforce authentication by itself. + +## Recommended topology + +```text +OpenAI SDK / Dify / n8n / browser UI + | + v +TLS + auth + upload limits + logs +(reverse proxy, API gateway, ingress, or service mesh) + | + v +FunASR OpenAI-compatible API +(private host, VM, container, or Kubernetes ClusterIP) +``` + +Keep FunASR on a private network whenever possible. Put public TLS, identity, request limits, and audit logging at the boundary that your team already operates. + +## Minimum controls before sharing + +| Control | Why it matters | Where to enforce it | +|---|---|---| +| TLS | Audio often contains private data. | Reverse proxy, API gateway, or ingress. | +| Authentication | The local example accepts any SDK `api_key` placeholder. | Gateway bearer token, basic auth, OAuth/OIDC, or internal SSO. | +| Upload-size limits | Prevent accidental multi-GB uploads and memory pressure. | Gateway request-body limit and app-level checks. | +| Timeouts | Long recordings need longer HTTP timeouts, but stuck clients should not hang forever. | Client, proxy, and server process manager. | +| Rate limits | Protect GPU/CPU capacity from bursts. | Gateway, ingress controller, or queue worker. | +| Private `/health` | Health output is useful operational data, not a public product endpoint. | Network allowlist or private monitoring path. | +| Logs and retention | Request metadata is useful; raw audio may be sensitive. | Central logging policy and storage lifecycle. | + +## NGINX reverse proxy sketch + +This is a starting point, not a complete production policy. Add your own certificates, identity provider, and secret management. + +```nginx +server { + listen 443 ssl http2; + server_name funasr.example.com; + + client_max_body_size 200m; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + + location / { + # Add auth_request, basic auth, mTLS, or an API gateway policy here. + proxy_pass http://127.0.0.1:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Authorization $http_authorization; + } + + location = /health { + allow 10.0.0.0/8; + deny all; + proxy_pass http://127.0.0.1:8000/health; + } +} +``` + +## Caddy reverse proxy sketch + +Generate the password hash with `caddy hash-password` and store the real credential outside the repository. + +```caddyfile +funasr.example.com { + request_body { + max_size 200MB + } + + basicauth /* { + team_user + } + + reverse_proxy 127.0.0.1:8000 { + transport http { + read_timeout 600s + write_timeout 600s + } + } +} +``` + +For production teams, prefer your standard SSO/OIDC gateway over shared passwords. + +## Kubernetes notes + +The Kubernetes template keeps the service private with `ClusterIP`. Before adding an ingress or load balancer: + +- Add an ingress controller or API gateway that enforces TLS, authentication, upload-size limits, and rate limits. +- Keep model cache volumes private to the namespace or node pool that owns the service. +- Use `NetworkPolicy` to restrict which namespaces can call the service. +- Use `kubectl port-forward` plus `smoke_test.py` for first validation before exposing a route. +- If you add GPUs, pin scheduling rules and record the image tag, CUDA runtime, and model alias in deployment notes. + +## Client configuration + +OpenAI SDKs usually require an API key string even when FunASR does not check it locally. After you add a gateway, use the gateway-issued token as the SDK key: + +```python +import os +from openai import OpenAI + +client = OpenAI( + base_url="https://funasr.example.com/v1", + api_key=os.environ["FUNASR_API_KEY"], +) +``` + +For internal HTTP workers, read tokens from environment variables or your secret manager. Do not commit tokens to workflow definitions, notebooks, screenshots, or Postman exports. + +## Data handling checklist + +- Decide whether raw audio can be stored, for how long, and who can access it. +- Log request IDs, duration, model alias, status, latency, and error class; avoid logging raw transcript text unless your policy allows it. +- If transcripts may contain personal data, document retention and deletion rules before onboarding users. +- Keep public samples separate from private customer or employee audio when writing benchmark reports. +- Redact headers, tokens, file names, and speaker names before opening GitHub issues. + +## Rollout checklist + +1. Start locally and run `bash smoke_test.sh` or `python smoke_test.py`. +2. Add the gateway and verify `/health`, `/v1/models`, and `/v1/audio/transcriptions` through the gateway URL. +3. Test a small file, a large allowed file, and a file above the upload limit. +4. Confirm unauthorized requests fail before reaching FunASR. +5. Confirm timeout behavior for long audio and slow clients. +6. Record the model alias, device, image tag, FunASR version, and gateway policy. + +Related guides: [OpenAI API README](README.md), [client recipes](CLIENTS.md), [workflow recipes](WORKFLOWS.md), [Gradio browser demo](GRADIO.md), [Kubernetes template](kubernetes/README.md), and the repository [security policy](../../SECURITY.md). diff --git a/examples/openai_api/SECURITY_zh.md b/examples/openai_api/SECURITY_zh.md new file mode 100644 index 000000000..c3a7d4656 --- /dev/null +++ b/examples/openai_api/SECURITY_zh.md @@ -0,0 +1,132 @@ +# FunASR OpenAI 兼容 API 安全与网关指南 + +当你准备把示例 OpenAI 兼容 API 提供给团队、工作流引擎、浏览器 UI 或笔记本之外的服务时,请先看这份指南。示例服务刻意保持轻量,主要关注 `/v1/audio/transcriptions` 兼容性,本身不内置鉴权策略。 + +## 推荐拓扑 + +```text +OpenAI SDK / Dify / n8n / 浏览器 UI + | + v +TLS + 鉴权 + 上传限制 + 日志 +(反向代理、API 网关、Ingress 或 Service Mesh) + | + v +FunASR OpenAI 兼容 API +(私有主机、虚机、容器或 Kubernetes ClusterIP) +``` + +只要条件允许,就让 FunASR 保持在私有网络中。公网 TLS、身份认证、请求限制和审计日志应放在团队已有的边界组件上。 + +## 对团队开放前的最低控制项 + +| 控制项 | 为什么重要 | 建议在哪里实现 | +|---|---|---| +| TLS | 音频通常包含隐私信息。 | 反向代理、API 网关或 Ingress。 | +| 鉴权 | 本地示例会接受任意 SDK `api_key` 占位符。 | 网关 Bearer token、Basic auth、OAuth/OIDC 或内部 SSO。 | +| 上传大小限制 | 避免误传超大文件导致内存和磁盘压力。 | 网关 request body limit 和应用侧检查。 | +| 超时 | 长音频需要更长 HTTP timeout,但异常客户端不能无限挂住。 | 客户端、代理和服务进程管理器。 | +| 限流 | 防止突发请求打满 GPU/CPU。 | 网关、Ingress controller 或队列 worker。 | +| 私有 `/health` | 健康信息是运维数据,不应作为公开产品端点。 | 网络 allowlist 或私有监控路径。 | +| 日志与留存 | 请求元数据有价值,但原始音频可能敏感。 | 集中日志策略和存储生命周期。 | + +## NGINX 反向代理示例 + +下面只是起点,不是完整生产策略。证书、身份系统和密钥管理需要按你的环境补齐。 + +```nginx +server { + listen 443 ssl http2; + server_name funasr.example.com; + + client_max_body_size 200m; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + + location / { + # 在这里增加 auth_request、Basic auth、mTLS 或 API 网关策略。 + proxy_pass http://127.0.0.1:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Authorization $http_authorization; + } + + location = /health { + allow 10.0.0.0/8; + deny all; + proxy_pass http://127.0.0.1:8000/health; + } +} +``` + +## Caddy 反向代理示例 + +使用 `caddy hash-password` 生成密码 hash,真实凭据不要写入仓库。 + +```caddyfile +funasr.example.com { + request_body { + max_size 200MB + } + + basicauth /* { + team_user + } + + reverse_proxy 127.0.0.1:8000 { + transport http { + read_timeout 600s + write_timeout 600s + } + } +} +``` + +生产团队优先使用已有 SSO/OIDC 网关,而不是共享密码。 + +## Kubernetes 注意事项 + +Kubernetes 模板默认使用私有 `ClusterIP`。在增加 Ingress 或 LoadBalancer 前,请先完成: + +- 使用 Ingress controller 或 API 网关强制 TLS、鉴权、上传大小限制和限流。 +- 模型缓存卷只暴露给拥有该服务的 namespace 或 node pool。 +- 使用 `NetworkPolicy` 限制可调用服务的 namespace。 +- 第一次验证先用 `kubectl port-forward` 加 `smoke_test.py`,再开放路由。 +- 如果增加 GPU,固定调度规则,并在部署说明中记录镜像 tag、CUDA runtime 和模型 alias。 + +## 客户端配置 + +OpenAI SDK 通常要求传入 API key 字符串,即使本地 FunASR 不检查它。加上网关后,请使用网关发放的 token 作为 SDK key: + +```python +import os +from openai import OpenAI + +client = OpenAI( + base_url="https://funasr.example.com/v1", + api_key=os.environ["FUNASR_API_KEY"], +) +``` + +内部 HTTP worker 应从环境变量或密钥系统读取 token。不要把 token 提交到工作流定义、notebook、截图或 Postman 导出文件里。 + +## 数据处理清单 + +- 先决定原始音频是否允许存储、保存多久、谁可以访问。 +- 日志建议记录 request ID、音频时长、模型 alias、状态、延迟和错误类型;除非策略允许,不要记录原始转写文本。 +- 如果转写文本可能包含个人信息,请在接入用户前写清留存和删除规则。 +- 写 benchmark 报告时,把公开样例和客户/员工私有音频分开。 +- 打开 GitHub issue 前,先脱敏 header、token、文件名和说话人姓名。 + +## 上线检查清单 + +1. 先在本地启动,并运行 `bash smoke_test.sh` 或 `python smoke_test.py`。 +2. 增加网关后,通过网关 URL 验证 `/health`、`/v1/models` 和 `/v1/audio/transcriptions`。 +3. 分别测试小文件、允许范围内的大文件,以及超过上传限制的文件。 +4. 确认未授权请求会在到达 FunASR 前失败。 +5. 确认长音频和慢客户端的 timeout 行为。 +6. 记录模型 alias、设备、镜像 tag、FunASR 版本和网关策略。 + +相关文档:[OpenAI API README](README_zh.md)、[客户端配方](CLIENTS.md)、[工作流配方](WORKFLOWS_zh.md)、[Gradio 浏览器 Demo](GRADIO_zh.md)、[Kubernetes 模板](kubernetes/README_zh.md) 和仓库 [安全策略](../../SECURITY.md)。 diff --git a/examples/openai_api/WORKFLOWS.md b/examples/openai_api/WORKFLOWS.md index f50283a77..b9375c474 100644 --- a/examples/openai_api/WORKFLOWS.md +++ b/examples/openai_api/WORKFLOWS.md @@ -147,7 +147,7 @@ This worker is also the right place to add audio conversion, file-size checks, r ## Production guardrails -- Put authentication, TLS, upload-size limits, and rate limits in front of FunASR before sharing it across teams. +- Put authentication, TLS, upload-size limits, and rate limits in front of FunASR before sharing it across teams; use the [security and gateway guide](SECURITY.md) for proxy and gateway patterns. - Use `/health` for workflow readiness checks and `/v1/models` to validate model aliases. - Log request id, audio duration, model alias, response format, device, latency, and error type. - Set workflow timeouts according to maximum audio duration; split very long recordings before sending them through low-code tools. diff --git a/examples/openai_api/WORKFLOWS_zh.md b/examples/openai_api/WORKFLOWS_zh.md index a3267c0b0..b24fb9556 100644 --- a/examples/openai_api/WORKFLOWS_zh.md +++ b/examples/openai_api/WORKFLOWS_zh.md @@ -147,7 +147,7 @@ def transcribe_bytes(filename: str, payload: bytes, content_type: str = "audio/w ## 生产环境护栏 -- 在跨团队共享 FunASR 服务前,先加好鉴权、TLS、上传大小限制和限流。 +- 在跨团队共享 FunASR 服务前,先加好鉴权、TLS、上传大小限制和限流;代理和网关模式见 [安全与网关指南](SECURITY_zh.md)。 - 使用 `/health` 做工作流 readiness check,使用 `/v1/models` 校验模型别名。 - 记录 request id、音频时长、模型别名、响应格式、设备、延迟和错误类型。 - 按最长音频时长设置工作流超时;超长录音建议先切分,再交给低代码工具处理。