1. 项目概述
最近在折腾一个需要实时语音识别的项目,发现FunASR这个开源工具包确实挺有意思。作为阿里通义实验室出品的工业级语音识别方案,它不仅支持离线文件转写,还能通过WebSocket实现低延迟的流式识别。今天我就来分享一下如何在Linux服务器上部署FunASR的Websocket实时语音识别服务。
这个方案特别适合需要实时字幕、语音助手、直播转写等场景。相比传统的轮询方式,WebSocket协议能建立持久连接,实现服务端主动推送识别结果,延迟可以控制在600ms以内。我实测下来,在4核8G的云服务器上,单个服务实例能稳定处理10路以上的语音流。
2. 环境准备与依赖安装
2.1 服务器基础配置
建议使用Ubuntu 20.04/22.04 LTS系统,这个版本对Python生态支持最友好。我测试过CentOS 7也能跑,但会遇到更多依赖问题。硬件方面:
- 最低配置:2核CPU/4GB内存(仅限测试)
- 生产推荐:4核CPU/8GB内存起步
- GPU加速:如果有NVIDIA显卡(如T4),识别速度能提升5-10倍
先更新系统基础包:
sudo apt update && sudo apt upgrade -y sudo apt install -y python3-pip python3-dev ffmpeg2.2 Python环境配置
建议使用conda创建独立环境,避免污染系统Python:
# 安装miniconda wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda source ~/miniconda/bin/activate # 创建专用环境 conda create -n funasr python=3.10 -y conda activate funasr2.3 FunASR核心安装
基础安装(CPU/GPU通用):
pip install funasr完整安装(推荐生产环境):
pip install funasr vllm fastapi uvicorn python-multipart websockets注意:如果使用GPU加速,需要提前安装CUDA 11.7+和cuDNN。可以通过
nvidia-smi命令确认驱动是否正常。
3. WebSocket服务部署
3.1 服务启动脚本
创建server.py文件:
from funasr import AutoModel from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware import uvicorn import websockets import asyncio app = FastAPI() # 允许跨域(前端调试需要) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) # 加载流式模型 model = AutoModel( model="paraformer-zh-streaming", vad_model="fsmn-vad", device="cuda" # 或"cpu" ) async def handle_ws(websocket): cache = {} chunk_size = [5, 10, 5] # 600ms前瞻 async for audio_data in websocket: try: result = model.generate( input=audio_data, cache=cache, is_final=False, chunk_size=chunk_size ) await websocket.send(result[0]["text"]) except Exception as e: print(f"Error: {e}") async def main(): server = await websockets.serve( handle_ws, "0.0.0.0", 8899, ping_interval=None ) await server.wait_closed() if __name__ == "__main__": asyncio.run(main())3.2 服务管理方案
建议使用systemd管理服务进程,创建/etc/systemd/system/funasr.service:
[Unit] Description=FunASR WebSocket Service After=network.target [Service] User=root WorkingDirectory=/path/to/your/project Environment="PATH=/root/miniconda/envs/funasr/bin" ExecStart=/root/miniconda/envs/funasr/bin/python server.py Restart=always [Install] WantedBy=multi-user.target启用并启动服务:
sudo systemctl daemon-reload sudo systemctl enable funasr sudo systemctl start funasr检查服务状态:
sudo systemctl status funasr4. 客户端实现方案
4.1 Python测试客户端
import websockets import asyncio import soundfile as sf async def send_audio(): async with websockets.connect("ws://your_server_ip:8899") as ws: audio, sr = sf.read("test.wav") chunk_size = 9600 # 每次发送1秒音频 for i in range(0, len(audio), chunk_size): chunk = audio[i:i+chunk_size].tobytes() await ws.send(chunk) result = await ws.recv() print(f"Partial: {result}") asyncio.run(send_audio())4.2 Web前端实现
HTML部分:
<audio id="audioInput" controls></audio> <button id="startBtn">开始识别</button> <div id="result"></div> <script> const resultDiv = document.getElementById('result'); let websocket; document.getElementById('startBtn').addEventListener('click', async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const audioContext = new AudioContext(); const source = audioContext.createMediaStreamSource(stream); const processor = audioContext.createScriptProcessor(4096, 1, 1); websocket = new WebSocket("ws://your_server_ip:8899"); websocket.onmessage = (event) => { resultDiv.textContent += event.data; }; processor.onaudioprocess = (e) => { if (websocket.readyState === WebSocket.OPEN) { const audioData = e.inputBuffer.getChannelData(0); websocket.send(audioData.buffer); } }; source.connect(processor); processor.connect(audioContext.destination); } catch (err) { console.error("Error:", err); } }); </script>5. 性能优化与生产部署
5.1 参数调优建议
在model.generate()中关键参数:
chunk_size=[5,10,5]:控制流式处理的延迟和准确率平衡hotword="阿里巴巴":加入业务关键词提升识别准确率beam_size=10:增大可提升准确率但会增加延迟
5.2 负载均衡方案
当并发量较大时,建议:
- 使用Nginx做WebSocket反向代理:
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name your_domain.com; location / { proxy_pass http://127.0.0.1:8899; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } }- 使用Docker Compose横向扩展:
version: '3' services: funasr1: image: your_funasr_image ports: - "8899:8899" deploy: resources: limits: cpus: '2' memory: 4G funasr2: image: your_funasr_image ports: - "8900:8899" deploy: resources: limits: cpus: '2' memory: 4G5.3 监控与日志
建议集成Prometheus监控:
from prometheus_client import start_http_server, Counter REQUEST_COUNT = Counter('funasr_requests', 'Total request count') async def handle_ws(websocket): REQUEST_COUNT.inc() # ...原有处理逻辑...启动监控端点:
start_http_server(8000)6. 常见问题排查
6.1 连接问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接立即断开 | 端口未开放 | ufw allow 8899 |
| 音频无响应 | 采样率不匹配 | 确保客户端使用16kHz采样率 |
| 识别结果乱码 | 编码问题 | 客户端发送原始PCM数据 |
| 高延迟 | chunk_size设置过大 | 调整为[5,10,5] |
6.2 性能问题优化
CPU占用过高:
- 降低
beam_size参数 - 使用
model.set_device("cpu")明确指定设备
- 降低
内存泄漏:
- 定期重启服务(建议使用supervisor)
- 检查Python版本(3.10+内存管理更好)
识别准确率低:
model = AutoModel( model="paraformer-zh-streaming", vad_model="fsmn-vad", punc_model="ct-punc", # 添加标点模型 hotword="您的业务关键词" )
7. 进阶应用场景
7.1 与LLM集成方案
async def handle_ws(websocket): llm_prompt = "请将以下语音转写内容总结为要点:\n" async for audio_data in websocket: text = model.generate(input=audio_data) summary = await llm_api(llm_prompt + text) await websocket.send(summary)7.2 多语言支持
FunASR支持切换不同语言模型:
# 英语流式模型 en_model = AutoModel(model="paraformer-en-streaming") # 日语模型 jp_model = AutoModel(model="paraformer-jp-streaming")切换时需要注意:
- 不同语言的VAD模型可能不同
- 标点模型需要对应语言
- 采样率要求可能不同(英语常用16kHz)
我在实际部署中发现,WebSocket接口的稳定性很大程度上取决于网络环境。内网环境下延迟可以控制在300ms以内,而公网部署时需要特别注意以下几点:
- 启用WebSocket压缩:
server = await websockets.serve( handle_ws, "0.0.0.0", 8899, compression="deflate" )- 设置合理的心跳间隔:
ping_interval=30, # 30秒心跳 ping_timeout=10- 对于移动端应用,建议实现自动重连机制,并缓存未发送的音频数据。一个实用的技巧是使用指数退避算法来控制重试间隔。