基于 sherpa-onnx 和 SenseVoice 的 C++ WebSocket 流式语音识别服务器。
/sttRealtime(流式) + /oneshot(一句话)# 克隆项目并进入目录
git clone <your-repository-url>
cd stt
本地构建运行:
./build.sh
./build/websocket_asr_server --models-root ./assets --port 8000
Docker构建运行(推荐):
./docker_build.sh
docker run -d --name asr-server -p 8000:8000 websocket-asr-server:latest
确保在 assets 目录下有以下模型文件:
assets/
├── sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
│ ├── model.onnx
│ └── tokens.txt
└── silero_vad/
└── silero_vad.onnx
# SenseVoice 模型 - 支持中英日韩粤语识别
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
mv sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17 assets/
# VAD 模型 - 语音活动检测
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
mkdir -p assets/silero_vad
mv silero_vad.onnx assets/silero_vad/
模型说明: SenseVoice 模型来自 FunAudioLLM/SenseVoice 项目,已转换为 ONNX 格式用于 sherpa-onnx。
# 给构建脚本执行权限
chmod +x build.sh
# 编译项目(会自动检测 sherpa-onnx 安装位置)
./build.sh
# 基本启动
./build/websocket_asr_server
# 自定义参数
./build/websocket_asr_server \
--models-root ./assets \
--port 8000 \
--threads 4
# 查看所有参数
./build/websocket_asr_server --help
--port PORT: 服务器端口(默认:8000)--models-root PATH: 模型文件目录(默认:./assets)--threads NUM: 推理线程数(默认:2)--help: 显示帮助信息# 方法一:使用构建脚本
./docker_build.sh
docker run -d --name asr-server -p 8000:8000 websocket-asr-server:latest
# 方法二:直接构建
docker build -t websocket-asr-server .
docker run -p 8000:8000 websocket-asr-server:latest
# 方法三:使用 Docker Compose(推荐)
docker compose up -d
# 检查容器状态
docker ps --format "table {{.Names}}\t{{.Status}}"
# 手动健康检查
curl http://localhost:8000/health
# 查看日志
docker logs -f websocket-asr-server
流式识别: ws://localhost:8000/sttRealtime?samplerate=16000
OneShot一句话识别: ws://localhost:8000/oneshot
# 流式识别 - 音频文件
python websocket_client.py --mode streaming --file examples/test.mp3
# 流式识别 - 麦克风(持续录音)
python websocket_client.py --mode streaming --mic
# OneShot识别 - 音频文件(一次性处理)
python websocket_client.py --mode oneshot --file examples/test.mp3
# OneShot识别 - 麦克风(录音5秒后识别)
python websocket_client.py --mode oneshot --mic --duration 5
# 交互式测试(对比两种模式)
python oneshot_examples.py
--mode: 识别模式 (streaming|oneshot)--file: 音频文件路径--mic: 使用麦克风输入--duration: 录音时长(秒)--sample-rate: 音频采样率(默认16000)连接: ws://localhost:8000/sttRealtime?samplerate=16000
发送: 二进制音频数据(16-bit PCM)
接收: JSON格式结果
{
"text": "识别的文本",
"finished": false, // true=最终结果,false=部分结果
"idx": 0, // 语音段索引
"lang": "zh" // 语言代码
}
连接: ws://localhost:8000/oneshot
发送控制消息:
{"command": "start"} // 开始录音
{"command": "stop"} // 停止录音并处理
发送音频: 二进制音频数据(16-bit PCM)
接收消息:
// 状态消息
{
"type": "status",
"status": "ready" // ready|recording|processing|finished
}
// 识别结果(包含更多元数据)
{
"type": "result",
"text": "识别的文本",
"finished": true,
"idx": 0,
"lang": "zh", // 检测到的语言
"emotion": "neutral", // 情感信息
"event": "", // 事件信息
"timestamps": [...] // 时间戳数组
}
// 错误消息
{
"type": "error",
"message": "错误描述"
}
import asyncio
import websockets
import wave
import json
async def test_asr():
uri = "ws://localhost:8000/sttRealtime?samplerate=16000"
async with websockets.connect(uri) as websocket:
# 发送音频文件
with wave.open("test.wav", "rb") as wav_file:
data = wav_file.readframes(1024)
while data:
await websocket.send(data)
data = wav_file.readframes(1024)
# 接收结果
async for message in websocket:
result = json.loads(message)
print(f"识别结果: {result['text']}")
if result['finished']:
break
# 运行测试
asyncio.run(test_asr())
const socket = new WebSocket('ws://localhost:8000/sttRealtime?samplerate=16000');
socket.onopen = function(event) {
console.log('连接已建立');
// 发送音频数据...
};
socket.onmessage = function(event) {
const result = JSON.parse(event.data);
console.log('识别结果:', result.text);
if (result.finished) {
console.log('识别完成');
}
};
# 启用高级优化
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -march=native"
make -j$(nproc)
# 增加处理线程数
./build/websocket_asr_server --threads 8
# 使用快速存储设备存放模型
# 建议将 assets 目录放在 SSD 上
# 调整系统参数
echo 'net.core.somaxconn = 1024' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 1024' >> /etc/sysctl.conf
sysctl -p
# 增加文件描述符限制
ulimit -n 65536
./install_sherpa_onnx.sh
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y libwebsocketpp-dev libjsoncpp-dev libasio-dev
# CentOS/RHEL
没试过
# 检查模型文件
ls -la assets/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
ls -la assets/silero_vad/
# 如果不存在,参考sherpa-onnx,下载需要的两个模型
# 检查端口占用
netstat -tlnp | grep :8000
lsof -i :8000
# 使用不同端口
./build/websocket_asr_server --port 8001
# 检查防火墙
sudo ufw status
sudo iptables -L
# 检查服务状态
curl http://localhost:8000/health
# 清理 Docker 缓存
docker system prune -a
# 无缓存重新构建
docker build --no-cache -t websocket-asr-server .
# 查看详细日志
docker logs --details websocket-asr-server
# 进入容器调试
docker exec -it websocket-asr-server /bin/bash
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
libsherpa-onnx.so: not found | 库路径未设置 | 运行 source setup_env.sh |
Model file not found | 模型路径错误 | 检查 --models-root 参数 |
Address already in use | 端口被占用 | 更换端口或终止占用进程 |
Connection refused | 防火墙阻止 | 检查防火墙设置 |
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ WebSocket │ │ WebSocket ASR │ │ sherpa-onnx │
│ Client │◄──►│ Server │◄──►│ Engine │
│ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ Connection │ │ Model Files │
│ Manager │ │ • SenseVoice │
│ │ │ • Silero VAD │
└──────────────────┘ └─────────────────┘
src/asr_engine.cpp, include/asr_engine.hsrc/asr_session.cpp, include/asr_session.hsrc/websocket_server.cpp, include/websocket_server.hsrc/logger.cpp, include/logger.h1. 客户端连接 WebSocket
↓
2. 创建 ASRSession 实例
↓
3. 接收 PCM 音频数据
↓
4. VAD 检测语音活动
↓
5. 流式推理生成部分结果
↓
6. VAD 检测语音结束
↓
7. 生成最终结果
↓
8. 通过 WebSocket 发送 JSON 结果
├── CMakeLists.txt # CMake 配置(已优化)
├── build.sh # 构建脚本
├── install_sherpa_onnx.sh # sherpa-onnx 安装脚本(优化版)
├── install_sherpa_onnx_simple.sh # 简化安装脚本
├── setup_env.sh # 环境设置脚本
├── sherpa_config.sh # 统一配置管理
├── docker_build.sh # Docker 构建脚本
├── Dockerfile # Docker 配置
├── docker-compose.yml # Docker Compose 配置
├── main.cpp # 程序入口
├── include/ # 头文件目录
│ ├── asr_engine.h # ASR 引擎接口
│ ├── asr_session.h # ASR 会话管理
│ ├── websocket_server.h # WebSocket 服务器
│ ├── logger.h # 日志系统
│ └── common.h # 公共定义
├── src/ # 源文件目录
│ ├── asr_engine.cpp # ASR 引擎实现
│ ├── asr_session.cpp # ASR 会话实现
│ ├── websocket_server.cpp # WebSocket 服务器实现
│ └── logger.cpp # 日志实现
├── assets/ # 模型文件目录
│ ├── sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
│ └── silero_vad/
./install_sherpa_onnx.sh source ./setup_env.sh
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)
PascalCase (如 ASREngine)camelCase (如 processAudio)snake_case (如 sample_rate)UPPER_CASE (如 MAX_BUFFER_SIZE)// 在 ASREngine::initialize() 中
if (model_type == "new-model") {
auto config = sherpa_onnx::OfflineRecognizerConfig{};
config.model_config.model = model_path;
// ... 配置新模型参数
}
// 在 ASREngine::initialize() 中
vad_config.silero_vad.threshold = 0.5f; // 检测阈值
vad_config.silero_vad.min_silence_duration = 0.25f; // 最小静音时长
vad_config.silero_vad.min_speech_duration = 0.25f; // 最小语音时长
// 在 WebSocket 连接处理中
bool authenticate(const std::string& token) {
// 实现认证逻辑
return validate_token(token);
}
# 使用 Valgrind
valgrind --leak-check=full ./build/websocket_asr_server
# 使用 AddressSanitizer
cmake .. -DCMAKE_CXX_FLAGS="-fsanitize=address"
// 设置日志级别
Logger::getInstance().setLevel(LogLevel::DEBUG);
// 添加调试信息
LOG_DEBUG("Processing audio chunk: {} bytes", chunk_size);
LOG_INFO("VAD detected speech: {:.2f}s", speech_duration);
# 编译调试版本
cmake .. -DCMAKE_BUILD_TYPE=Debug
make
# 启动 GDB
gdb ./build/websocket_asr_server
(gdb) run --port 8000
(gdb) bt # 查看堆栈
# 使用 perf
perf record ./build/websocket_asr_server
perf report
# 使用 gperftools
cmake .. -DENABLE_PROFILING=ON
make
type(scope): description
[optional body]
[optional footer]
类型:
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式refactor: 重构test: 测试相关chore: 构建、工具等示例:
feat(asr): add support for new SenseVoice model
- Add model configuration parsing
- Update inference pipeline
- Add corresponding unit tests
Closes #123
C++
54.8%
Python
17.3%
Shell
17.0%
CMake
5.4%
Dockerfile
2.9%
Makefile
2.7%
基于 sherpa-onnx 和 SenseVoice 的 C++ WebSocket 流式语音识别服务器。
/sttRealtime(流式) + /oneshot(一句话)# 克隆项目并进入目录
git clone <your-repository-url>
cd stt
本地构建运行:
./build.sh
./build/websocket_asr_server --models-root ./assets --port 8000
Docker构建运行(推荐):
./docker_build.sh
docker run -d --name asr-server -p 8000:8000 websocket-asr-server:latest
确保在 assets 目录下有以下模型文件:
assets/
├── sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
│ ├── model.onnx
│ └── tokens.txt
└── silero_vad/
└── silero_vad.onnx
# SenseVoice 模型 - 支持中英日韩粤语识别
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
mv sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17 assets/
# VAD 模型 - 语音活动检测
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
mkdir -p assets/silero_vad
mv silero_vad.onnx assets/silero_vad/
模型说明: SenseVoice 模型来自 FunAudioLLM/SenseVoice 项目,已转换为 ONNX 格式用于 sherpa-onnx。
# 给构建脚本执行权限
chmod +x build.sh
# 编译项目(会自动检测 sherpa-onnx 安装位置)
./build.sh
# 基本启动
./build/websocket_asr_server
# 自定义参数
./build/websocket_asr_server \
--models-root ./assets \
--port 8000 \
--threads 4
# 查看所有参数
./build/websocket_asr_server --help
--port PORT: 服务器端口(默认:8000)--models-root PATH: 模型文件目录(默认:./assets)--threads NUM: 推理线程数(默认:2)--help: 显示帮助信息# 方法一:使用构建脚本
./docker_build.sh
docker run -d --name asr-server -p 8000:8000 websocket-asr-server:latest
# 方法二:直接构建
docker build -t websocket-asr-server .
docker run -p 8000:8000 websocket-asr-server:latest
# 方法三:使用 Docker Compose(推荐)
docker compose up -d
# 检查容器状态
docker ps --format "table {{.Names}}\t{{.Status}}"
# 手动健康检查
curl http://localhost:8000/health
# 查看日志
docker logs -f websocket-asr-server
流式识别: ws://localhost:8000/sttRealtime?samplerate=16000
OneShot一句话识别: ws://localhost:8000/oneshot
# 流式识别 - 音频文件
python websocket_client.py --mode streaming --file examples/test.mp3
# 流式识别 - 麦克风(持续录音)
python websocket_client.py --mode streaming --mic
# OneShot识别 - 音频文件(一次性处理)
python websocket_client.py --mode oneshot --file examples/test.mp3
# OneShot识别 - 麦克风(录音5秒后识别)
python websocket_client.py --mode oneshot --mic --duration 5
# 交互式测试(对比两种模式)
python oneshot_examples.py
--mode: 识别模式 (streaming|oneshot)--file: 音频文件路径--mic: 使用麦克风输入--duration: 录音时长(秒)--sample-rate: 音频采样率(默认16000)连接: ws://localhost:8000/sttRealtime?samplerate=16000
发送: 二进制音频数据(16-bit PCM)
接收: JSON格式结果
{
"text": "识别的文本",
"finished": false, // true=最终结果,false=部分结果
"idx": 0, // 语音段索引
"lang": "zh" // 语言代码
}
连接: ws://localhost:8000/oneshot
发送控制消息:
{"command": "start"} // 开始录音
{"command": "stop"} // 停止录音并处理
发送音频: 二进制音频数据(16-bit PCM)
接收消息:
// 状态消息
{
"type": "status",
"status": "ready" // ready|recording|processing|finished
}
// 识别结果(包含更多元数据)
{
"type": "result",
"text": "识别的文本",
"finished": true,
"idx": 0,
"lang": "zh", // 检测到的语言
"emotion": "neutral", // 情感信息
"event": "", // 事件信息
"timestamps": [...] // 时间戳数组
}
// 错误消息
{
"type": "error",
"message": "错误描述"
}
import asyncio
import websockets
import wave
import json
async def test_asr():
uri = "ws://localhost:8000/sttRealtime?samplerate=16000"
async with websockets.connect(uri) as websocket:
# 发送音频文件
with wave.open("test.wav", "rb") as wav_file:
data = wav_file.readframes(1024)
while data:
await websocket.send(data)
data = wav_file.readframes(1024)
# 接收结果
async for message in websocket:
result = json.loads(message)
print(f"识别结果: {result['text']}")
if result['finished']:
break
# 运行测试
asyncio.run(test_asr())
const socket = new WebSocket('ws://localhost:8000/sttRealtime?samplerate=16000');
socket.onopen = function(event) {
console.log('连接已建立');
// 发送音频数据...
};
socket.onmessage = function(event) {
const result = JSON.parse(event.data);
console.log('识别结果:', result.text);
if (result.finished) {
console.log('识别完成');
}
};
# 启用高级优化
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -march=native"
make -j$(nproc)
# 增加处理线程数
./build/websocket_asr_server --threads 8
# 使用快速存储设备存放模型
# 建议将 assets 目录放在 SSD 上
# 调整系统参数
echo 'net.core.somaxconn = 1024' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 1024' >> /etc/sysctl.conf
sysctl -p
# 增加文件描述符限制
ulimit -n 65536
./install_sherpa_onnx.sh
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y libwebsocketpp-dev libjsoncpp-dev libasio-dev
# CentOS/RHEL
没试过
# 检查模型文件
ls -la assets/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
ls -la assets/silero_vad/
# 如果不存在,参考sherpa-onnx,下载需要的两个模型
# 检查端口占用
netstat -tlnp | grep :8000
lsof -i :8000
# 使用不同端口
./build/websocket_asr_server --port 8001
# 检查防火墙
sudo ufw status
sudo iptables -L
# 检查服务状态
curl http://localhost:8000/health
# 清理 Docker 缓存
docker system prune -a
# 无缓存重新构建
docker build --no-cache -t websocket-asr-server .
# 查看详细日志
docker logs --details websocket-asr-server
# 进入容器调试
docker exec -it websocket-asr-server /bin/bash
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
libsherpa-onnx.so: not found | 库路径未设置 | 运行 source setup_env.sh |
Model file not found | 模型路径错误 | 检查 --models-root 参数 |
Address already in use | 端口被占用 | 更换端口或终止占用进程 |
Connection refused | 防火墙阻止 | 检查防火墙设置 |
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ WebSocket │ │ WebSocket ASR │ │ sherpa-onnx │
│ Client │◄──►│ Server │◄──►│ Engine │
│ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ Connection │ │ Model Files │
│ Manager │ │ • SenseVoice │
│ │ │ • Silero VAD │
└──────────────────┘ └─────────────────┘
src/asr_engine.cpp, include/asr_engine.hsrc/asr_session.cpp, include/asr_session.hsrc/websocket_server.cpp, include/websocket_server.hsrc/logger.cpp, include/logger.h1. 客户端连接 WebSocket
↓
2. 创建 ASRSession 实例
↓
3. 接收 PCM 音频数据
↓
4. VAD 检测语音活动
↓
5. 流式推理生成部分结果
↓
6. VAD 检测语音结束
↓
7. 生成最终结果
↓
8. 通过 WebSocket 发送 JSON 结果
├── CMakeLists.txt # CMake 配置(已优化)
├── build.sh # 构建脚本
├── install_sherpa_onnx.sh # sherpa-onnx 安装脚本(优化版)
├── install_sherpa_onnx_simple.sh # 简化安装脚本
├── setup_env.sh # 环境设置脚本
├── sherpa_config.sh # 统一配置管理
├── docker_build.sh # Docker 构建脚本
├── Dockerfile # Docker 配置
├── docker-compose.yml # Docker Compose 配置
├── main.cpp # 程序入口
├── include/ # 头文件目录
│ ├── asr_engine.h # ASR 引擎接口
│ ├── asr_session.h # ASR 会话管理
│ ├── websocket_server.h # WebSocket 服务器
│ ├── logger.h # 日志系统
│ └── common.h # 公共定义
├── src/ # 源文件目录
│ ├── asr_engine.cpp # ASR 引擎实现
│ ├── asr_session.cpp # ASR 会话实现
│ ├── websocket_server.cpp # WebSocket 服务器实现
│ └── logger.cpp # 日志实现
├── assets/ # 模型文件目录
│ ├── sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/
│ └── silero_vad/
./install_sherpa_onnx.sh source ./setup_env.sh
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)
PascalCase (如 ASREngine)camelCase (如 processAudio)snake_case (如 sample_rate)UPPER_CASE (如 MAX_BUFFER_SIZE)// 在 ASREngine::initialize() 中
if (model_type == "new-model") {
auto config = sherpa_onnx::OfflineRecognizerConfig{};
config.model_config.model = model_path;
// ... 配置新模型参数
}
// 在 ASREngine::initialize() 中
vad_config.silero_vad.threshold = 0.5f; // 检测阈值
vad_config.silero_vad.min_silence_duration = 0.25f; // 最小静音时长
vad_config.silero_vad.min_speech_duration = 0.25f; // 最小语音时长
// 在 WebSocket 连接处理中
bool authenticate(const std::string& token) {
// 实现认证逻辑
return validate_token(token);
}
# 使用 Valgrind
valgrind --leak-check=full ./build/websocket_asr_server
# 使用 AddressSanitizer
cmake .. -DCMAKE_CXX_FLAGS="-fsanitize=address"
// 设置日志级别
Logger::getInstance().setLevel(LogLevel::DEBUG);
// 添加调试信息
LOG_DEBUG("Processing audio chunk: {} bytes", chunk_size);
LOG_INFO("VAD detected speech: {:.2f}s", speech_duration);
# 编译调试版本
cmake .. -DCMAKE_BUILD_TYPE=Debug
make
# 启动 GDB
gdb ./build/websocket_asr_server
(gdb) run --port 8000
(gdb) bt # 查看堆栈
# 使用 perf
perf record ./build/websocket_asr_server
perf report
# 使用 gperftools
cmake .. -DENABLE_PROFILING=ON
make
type(scope): description
[optional body]
[optional footer]
类型:
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式refactor: 重构test: 测试相关chore: 构建、工具等示例:
feat(asr): add support for new SenseVoice model
- Add model configuration parsing
- Update inference pipeline
- Add corresponding unit tests
Closes #123
C++
54.8%
Python
17.3%
Shell
17.0%
CMake
5.4%
Dockerfile
2.9%
Makefile
2.7%