Skip to content

zaigie/FunSpeech

Repository files navigation

FunSpeech

开箱即用的本地私有化部署语音服务 — 微服务架构

ASR + TTS API 网关,兼容阿里云语音 API 与 OpenAI TTS API,支持 WebSocket 流式协议。 模型推理由独立子服务承载(每个引擎独立 venv + 容器),通过 docker-compose 编排。


Static Badge Static Badge Static Badge

Important

从单体版升级? 先读 docs/migration_to_latest.md

本分支已重构为微服务架构 (gateway + 4 个 GPU 子服务)。对外 HTTP/WS 协议字节级兼容, 客户端代码不用动; 但部署侧 docker-compose、模型缓存挂载路径、.env 变量都有变化。迁移文档覆盖:数据原地复用、必改的 mount 路径、.env 增删项、零停机切换、回滚步骤。

架构

                       ┌─────────────────────────┐
   外部客户端 ────────► │  gateway (CPU)          │
   (HTTP/WS)           │  - Aliyun/OpenAI 协议   │
                       │  - 句子状态机 + ITN     │
                       │  - 采样率/格式转换      │
                       └────────┬────────────────┘
                                │ HTTP / WS (X-Internal-Token)
                ┌───────────────┼───────────────┬───────────────┐
                ▼               ▼               ▼               ▼
         funasr (GPU)   dolphin (GPU)   qwen3-asr (GPU)   cosyvoice (GPU)
         Paraformer/    DataoceanAI     Qwen3-ASR-1.7B    CosyVoice2/3
         SenseVoice     Dolphin Small   (vLLM 加速)        (in-process)

子服务各自一个 pyproject.toml + uv.lock + Dockerfile,依赖完全隔离。 例如 funasr 用 transformers 4.51.3,qwen3-asr 用 transformers 4.57.1 + vLLM 0.11+, 互不冲突。

快速开始

1. 准备环境

git clone https://cnb.cool/nexa/FunSpeech.git
cd FunSpeech

# 必须: 拉 cosyvoice 上游源码 (git submodule)
# 不做这一步, cosyvoice 镜像启动会 ModuleNotFoundError
git submodule update --init --recursive

cp .env.example .env  # 按需修改

如果机器在国内,把代理放进 .env:

HTTP_PROXY=http://host.docker.internal:7890   # macOS/Windows Docker Desktop
HTTPS_PROXY=http://host.docker.internal:7890
# Linux 服务器: 改成宿主机 LAN IP, 例如 http://192.168.1.10:7890

2. 构建 + 启动

Dockerfile 用了 RUN --mount=type=cache 给 apt / uv 双缓存,需要 BuildKit。Docker 23+ 默认开启;低版本手动启用:

export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
docker compose build                         # 重 build 时 apt/uv 走本机缓存,极快
docker compose up -d                         # 默认: gateway + qwen3-asr + cosyvoice
docker compose --profile funasr up -d        # 加上 funasr (paraformer/sensevoice)
docker compose --profile dolphin up -d       # 加上 dolphin
docker compose --profile funasr --profile dolphin up -d   # 全部 ASR 引擎

服务暴露在 http://localhost:${GATEWAY_PORT:-8000}

3. 验证

# 健康
curl http://localhost:8000/stream/v1/asr/health
curl http://localhost:8000/stream/v1/tts/health

# ASR
curl -X POST "http://localhost:8000/stream/v1/asr?format=wav&sample_rate=16000" \
     -H "Content-Type: application/octet-stream" \
     --data-binary @audio.wav

# TTS
curl -X POST "http://localhost:8000/stream/v1/tts" \
     -H "Content-Type: application/json" \
     -d '{"text":"你好","voice":"中文女"}' \
     --output speech.wav

WebSocket 测试页:

  • ASR: http://localhost:8000/ws/v1/asr/test
  • TTS: http://localhost:8000/ws/v1/tts/test

服务列表

服务 端口 镜像 GPU 默认启动 profile
gateway 8000 funspeech/gateway (默认)
funasr-0 8001 funspeech/funasr funasr
dolphin-0 8002 funspeech/dolphin dolphin
qwen3-asr-0 8003 funspeech/qwen3-asr (默认, 默认 ASR 引擎)
cosyvoice-0 8004 funspeech/cosyvoice (默认)

每个子服务暴露 GET /health + 自有业务端点(详见各 services/*/README.md)。

对外 API(网关)

ASR

端点 方法 说明
/stream/v1/asr POST 一句话语音识别
/stream/v1/asr/models GET 模型列表
/stream/v1/asr/health GET 健康检查
/ws/v1/asr WS 流式识别(Aliyun 协议)

可识别模型(models.json):qwen3-asr-flash(默认)、paraformer-largesensevoice-small(后两者需 --profile funasr)、dolphin-small(需 --profile dolphin)。

TTS

端点 方法 说明
/stream/v1/tts POST 语音合成
/openai/v1/audio/speech POST OpenAI 兼容
/rest/v1/tts/async POST/GET 异步长文本合成
/stream/v1/tts/voices GET 音色列表
/stream/v1/tts/voices/info GET 音色详细信息
/stream/v1/tts/voices/refresh POST 刷新音色
/stream/v1/tts/health GET 健康检查
/ws/v1/tts WS 双向流式合成(Aliyun 协议)

外部协议与之前的进程内版本完全兼容。

配置(网关侧 env)

变量 默认 说明
GATEWAY_PORT 8000 对外暴露端口
APPTOKEN / APPKEY - 外部鉴权(可选)
INTERNAL_SERVICE_TOKEN funspeech-internal 网关→子服务鉴权头(X-Internal-Token)
ASR_MODEL_MODE all all / offline / realtime
TTS_MODEL_MODE all all / sft / clone
ASR_ENABLE_REALTIME_PUNC false 流式中间结果是否带标点
AUTO_LOAD_CUSTOM_ASR_MODELS - 启动时预热的额外 ASR 模型 id
FUNASR_SERVICE_URLS http://funasr-0:8001 子服务 URL,逗号分隔多副本
DOLPHIN_SERVICE_URLS http://dolphin-0:8002
QWEN3_ASR_SERVICE_URLS http://qwen3-asr-0:8003
COSYVOICE_SERVICE_URLS http://cosyvoice-0:8004
SERVICE_REQUEST_TIMEOUT 60 子服务调用超时(秒)
INFERENCE_THREAD_POOL_SIZE max(4, CPU 核数) 网关同步调用线程池大小;高 QPS 调大
HTTPX_MAX_CONNECTIONS 200 网关→子服务 HTTP 连接池上限;>100 req/s 时调到 500+
HTTPX_MAX_KEEPALIVE 50 保活连接数上限

子服务专属 env(模型版本、TRT/FP16/vLLM 等)请见 .env.exampledocs/deployment.md §6 和各 services/*/README.md

关于"GPU 并发数":子服务内部的 GPU 并发已在代码里硬编码 (funasr/dolphin=1, cosyvoice=2, qwen3-asr=Lock+vLLM 内部 batching), 不通过环境变量暴露。横向扩展请用多副本, 见下文。

开发

单独跑某个子服务

cd services/funasr
uv sync
PORT=8001 INTERNAL_SERVICE_TOKEN=test uv run python server.py

网关本地跑(连容器里的子服务)

uv sync
FUNASR_SERVICE_URLS=http://localhost:8001 \
COSYVOICE_SERVICE_URLS=http://localhost:8004 \
INTERNAL_SERVICE_TOKEN=funspeech-internal \
uv run python start.py

性能与副本规划

在 NVIDIA RTX 4090 24G 上的实测单副本容量 (完整数据见 benchmarks/):

子服务 单副本容量 单条延迟 显存
funasr (all) ~12 req/s ~80 ms ~3 GiB
dolphin ~12 req/s ~80 ms ~1 GiB
qwen3-asr ~5 req/s (vLLM 内部 batch 可吃 64 并发) ~190 ms 0.85 × 卡显存 (vLLM KV pool)
cosyvoice (clone) 2 路实时 TTS (RTF ≈ 1.05) ~3.5 s / 句 ~4 GiB

ASR 看 req/s, TTS 看"几路实时" (RTF ≤ 1) — 单副本 sem=2 时同时 2 路 RTF=1.05 刚好实时, 4 路就开始 RTF=1.75 卡顿。想 N 路实时 TTS 需 ceil(N/2) 张卡。

横向扩展 = 多卡多副本, 不是单卡多副本 (同一服务两副本绑同一张卡, 实测总容量不升反降)。

用规划脚本一键算出应该开几副本 / 怎么绑卡, 并在当前目录生成完整 docker-compose.generated.yml:

python3 scripts/plan_deployment.py                  # 交互式
python3 scripts/plan_deployment.py --preset 4090-quad   # 看预设
python3 scripts/plan_deployment.py --list-presets

详细说明见 docs/deployment.md §4.3

模型权重缓存

所有 GPU 子服务通过 bind mount 共享 MODELSCOPE_CACHE(默认 ~/.cache/modelscope/hub/models, mount 到容器 /root/.cache/modelscope/hub), 因此即便 funasr / cosyvoice 各自的 transformers 版本不同,权重文件可以复用。

提前下载:

pip install modelscope
modelscope download --model iic/CosyVoice-300M-SFT
modelscope download --model FunAudioLLM/Fun-CosyVoice3-0.5B-2512
modelscope download --model iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch
modelscope download --model iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online
modelscope download --model iic/punc_ct-transformer_zh-cn-common-vocab272727-pytorch
modelscope download --model iic/speech_fsmn_vad_zh-cn-16k-common-pytorch
# 按需:
modelscope download --model DataoceanAI/dolphin-small
modelscope download --model Qwen/Qwen3-ASR-1.7B

音色管理(克隆)

零样本克隆音色由 cosyvoice 子服务托管。把 张三.wav + 张三.txt 放到 ./voices/ 卷,然后:

curl -X POST http://localhost:8000/stream/v1/tts/voices/refresh

或通过 API 上传(需要外部 multipart 接入,见 docs/)。所有音色状态(spk2info.pt + voice_registry.json) 持久化到 ./voices/ 卷。

已知设计取舍

  • vLLM 加速 CosyVoice 默认关闭:vLLM 0.11+ 要求 transformers ≥4.55, 与 CosyVoice 主代码所需的 4.51.3 冲突。如果性能瓶颈明显,可拆出 services/cosyvoice_vllm/ 独立 venv 启用,见 services/cosyvoice/README.md 的多副本注释。
  • Qwen3-ASR 流式不走 vLLM 通用 /v1/realtime:vLLM 通用 realtime 端点对 Qwen3-ASR 质量明显劣化(无跨段上下文、无 token 修订,见 vllm Issue #35767)。 我们用官方 qwen_asr.Qwen3ASRModel.streaming_transcribe + init_streaming_state, 在子服务进程内跑,具备 unfixed_chunk / unfixed_token 修订能力。
  • Qwen3-ASR 子服务进程内 GPU 串行: vLLM 的 Python LLM(...) 入口 非线程安全, 子服务用 asyncio.Lock 保证只有一个调用进 vLLM。这不影响 vLLM 自身的 continuous batching (batching 在 engine 内部), 但要靠多副本扩吞吐。
  • 音色 CRUD 多副本同步 (commit 299075b): URL 列表第一个 = 写副本 (primary)。 所有 POST/DELETE /voices 自动路由到 primary, 写后网关广播 POST /voices/reload 让其它副本从磁盘热重载 spk2info.pt。详见 docs/deployment.md §5.2

目录结构

.
├── app/                       # 网关代码
│   ├── api/v1/                # FastAPI 路由 (Aliyun + OpenAI)
│   ├── services/asr/          # ASR 引擎抽象 + HTTP 客户端
│   ├── services/tts/          # TTS 引擎抽象 + HTTP 客户端 (含 voice_manager)
│   ├── services/websocket_*.py
│   ├── core/config.py         # 网关 env
│   └── utils/audio.py         # 重采样、PCM/WAV 转码、ITN
├── services/                  # 各子服务(独立 venv + Dockerfile)
│   ├── funasr/
│   ├── dolphin/
│   ├── qwen3_asr_vllm/
│   └── cosyvoice/             # third_party/CosyVoice 是官方 submodule
├── scripts/
│   ├── plan_deployment.py     # 副本规划 (零依赖)
│   └── analyze_audio_rms.py   # 远场过滤阈值分析
├── benchmarks/                # 4090 实测数据 + 测试脚本 (git-lfs)
│   ├── README.md
│   ├── scripts/               # bench_tts.py / bench_asr.py / ...
│   ├── audio/                 # TTS 生成的测试样本
│   └── results/               # 结果 (json + log)
├── docker-compose.yml
├── .env.example
└── pyproject.toml             # 网关 deps (CPU only, ~57 包)

相关链接

许可证

MIT — 见 LICENSE

About

开箱即用的本地私有化部署语音服务,快速搭建Qwen3ASR/FunASR与CosyVoice2/3后端

Topics

Resources

License

Stars

Watchers

Forks

Contributors