Vosk-api学习路径:从入门到专家的完整指南
1. 什么是Vosk-api?
Vosk-api是一个开源离线语音识别工具包,支持20多种语言和方言,适用于各种编程语言。它可以在本地设备上实现高效的语音识别,无需云端连接,保护用户隐私的同时保证识别速度。
1.1 Vosk-api核心优势
特性 | Vosk-api | 云端API | 其他离线方案 |
---|---|---|---|
延迟 | 低(毫秒级) | 高(网络延迟) | 中 |
隐私 | 完全本地处理 | 数据上传云端 | 完全本地处理 |
网络 | 无需网络 | 必须联网 | 无需网络 |
模型大小 | 50-200MB | 不适用 | 通常>1GB |
内存占用 | 低(<500MB) | 不适用 | 高(>2GB) |
识别速度 | 实时(甚至更快) | 受网络影响 | 接近实时 |
自定义能力 | 高 | 低 | 中 |
多语言支持 | 20+种 | 通常10+种 | 有限 |
1.2 Vosk-api架构概览
2. 快速入门
2.1 环境准备
2.1.1 安装Vosk-api
Python:
pip install vosk
Java:
<dependency>
<groupId>org.vosk</groupId>
<artifactId>vosk</artifactId>
<version>0.3.45</version>
</dependency>
Node.js:
npm install vosk
C#:
Install-Package Vosk
Go:
go get github.com/alphacep/vosk-api/go
2.1.2 获取模型
# 中文模型
wget https://alphacephei.com/vosk/models/vosk-model-cn-0.22.zip
unzip vosk-model-cn-0.22.zip -d model
# 英文模型
wget https://alphacephei.com/vosk/models/vosk-model-en-us-0.22.zip
unzip vosk-model-en-us-0.22.zip -d model
2.2 基础语音识别示例
Python (test_simple.py):
#!/usr/bin/env python3
import wave
import sys
from vosk import Model, KaldiRecognizer, SetLogLevel
# 设置日志级别,-1禁用调试消息
SetLogLevel(0)
# 打开音频文件
wf = wave.open(sys.argv[1], "rb")
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
print("音频文件必须是WAV格式的单声道PCM")
sys.exit(1)
# 加载模型
model = Model(lang="en-us")
# 创建识别器
rec = KaldiRecognizer(model, wf.getframerate())
rec.SetWords(True)
rec.SetPartialWords(True)
# 处理音频
while True:
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
print(rec.Result())
else:
print(rec.PartialResult())
# 获取最终结果
print(rec.FinalResult())
Java (DecoderDemo.java):
package org.vosk.demo;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.LibVosk;
import org.vosk.Model;
public class DecoderDemo {
public static void main(String[] argv) throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(
new BufferedInputStream(new FileInputStream("test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
}
}
Node.js (test_simple.js):
const vosk = require('vosk');
const fs = require("fs");
const { Readable } = require("stream");
const wav = require("wav");
const MODEL_PATH = "model";
const FILE_NAME = "test.wav";
if (!fs.existsSync(MODEL_PATH)) {
console.log("请下载模型并解压到" + MODEL_PATH);
process.exit();
}
vosk.setLogLevel(0);
const model = new vosk.Model(MODEL_PATH);
const wfReader = new wav.Reader();
const wfReadable = new Readable().wrap(wfReader);
wfReader.on('format', async ({ audioFormat, sampleRate, channels }) => {
if (audioFormat != 1 || channels != 1) {
console.error("音频文件必须是WAV格式的单声道PCM");
process.exit(1);
}
const rec = new vosk.Recognizer({model: model, sampleRate: sampleRate});
rec.setMaxAlternatives(10);
rec.setWords(true);
for await (const data of wfReadable) {
const end_of_speech = rec.acceptWaveform(data);
if (end_of_speech) {
console.log(JSON.stringify(rec.result(), null, 4));
}
}
console.log(JSON.stringify(rec.finalResult(), null, 4));
rec.free();
});
fs.createReadStream(FILE_NAME).pipe(wfReader).on('finish',
function (err) {
model.free();
});
2.3 音频要求与格式转换
Vosk对输入音频有特定要求:
- 采样率:通常为16000Hz(部分模型支持8000Hz)
- 格式:16位单声道PCM(WAV格式最常用)
- 声道:单声道(Mono)
使用FFmpeg转换音频格式:
# 将MP3转换为符合要求的WAV
ffmpeg -i input.mp3 -ar 16000 -ac 1 -f s16le output.wav
# 查看音频文件信息
ffmpeg -i output.wav
3. 核心概念与API详解
3.1 模型(Model)
模型是Vosk的核心组件,包含了语音识别所需的所有数据和算法。
// 模型创建与释放
VoskModel *model = vosk_model_new("model_path");
vosk_model_free(model);
// 检查词汇表中是否包含某个词
int word_id = vosk_model_find_word(model, "hello");
模型文件结构:
model/
├── am/ # 声学模型
├── ivector/ # 说话人识别模型
├── conf/ # 配置文件
├── graph/ # 解码图
│ ├── HCLG.fst # 解码网络
│ ├── words.txt # 词汇表
│ └── phones.txt # 音素表
└── README # 模型说明
3.2 识别器(Recognizer)
识别器是处理音频流并生成文本的核心组件。
3.2.1 识别器工作流程
3.2.2 识别器配置选项
# 设置日志级别
SetLogLevel(0) # 0=正常, -1=禁用, >0=调试
# 创建识别器
rec = KaldiRecognizer(model, sample_rate)
# 启用词级时间戳
rec.SetWords(True)
# 启用部分结果中的词级信息
rec.SetPartialWords(True)
# 设置最大候选结果数量
rec.SetMaxAlternatives(5)
# 启用NLSML格式输出
rec.SetNLSML(True)
# 设置端点检测模式
rec.SetEndpointerMode(1) # 0=默认, 1=短, 2=长, 3=很长
# 设置端点检测延迟
rec.SetEndpointerDelays(5.0, 0.5, 20.0) # t_start_max, t_end, t_max
3.2.3 结果格式解析
完整结果(Result):
{
"result": [
{
"conf": 1.000000,
"end": 1.110000,
"start": 0.870000,
"word": "你好"
},
{
"conf": 1.000000,
"end": 1.530000,
"start": 1.110000,
"word": "世界"
}
],
"text": "你好世界"
}
部分结果(PartialResult):
{
"partial": "你好"
}
最终结果(FinalResult):
{
"result": [
{
"conf": 1.000000,
"end": 1.110000,
"start": 0.870000,
"word": "你好"
},
{
"conf": 1.000000,
"end": 1.530000,
"start": 1.110000,
"word": "世界"
}
],
"text": "你好世界"
}
3.3 说话人识别模型(SpkModel)
Vosk支持说话人识别功能,可以识别不同的说话人。
from vosk import Model, SpkModel, KaldiRecognizer
# 加载语音识别模型和说话人模型
model = Model("model")
spk_model = SpkModel("model-spk")
# 创建识别器并关联说话人模型
rec = KaldiRecognizer(model, sample_rate)
rec.SetSpkModel(spk_model)
# 处理音频...
# 结果中将包含说话人特征向量"spk"
说话人识别结果示例:
{
"result": [...],
"text": "你好世界",
"spk": [0.123, -0.456, 0.789, ...],
"spk_frames": 120
}
4. 高级功能
4.1 麦克风实时识别
Python (test_microphone.py):
#!/usr/bin/env python3
import argparse
import queue
import sys
import sounddevice as sd
from vosk import Model, KaldiRecognizer
q = queue.Queue()
def int_or_str(text):
"""参数解析辅助函数"""
try:
return int(text)
except ValueError:
return text
def callback(indata, frames, time, status):
"""音频块回调函数(在单独线程中调用)"""
if status:
print(status, file=sys.stderr)
q.put(bytes(indata))
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
"-l", "--list-devices", action="store_true",
help="显示音频设备列表并退出")
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
"-d", "--device", type=int_or_str,
help="输入设备(数字ID或子串)")
parser.add_argument(
"-r", "--samplerate", type=int, help="采样率")
parser.add_argument(
"-m", "--model", type=str, help="语言模型; 如 en-us, fr, nl; 默认是 en-us")
args = parser.parse_args(remaining)
try:
if args.samplerate is None:
device_info = sd.query_devices(args.device, "input")
# soundfile需要整数采样率,sounddevice提供浮点数
args.samplerate = int(device_info["default_samplerate"])
if args.model is None:
model = Model(lang="en-us")
else:
model = Model(lang=args.model)
with sd.RawInputStream(samplerate=args.samplerate, blocksize = 8000,
device=args.device, dtype="int16", channels=1,
callback=callback):
print("#" * 80)
print("按Ctrl+C停止录音")
print("#" * 80)
rec = KaldiRecognizer(model, args.samplerate)
while True:
data = q.get()
if rec.AcceptWaveform(data):
print(rec.Result())
else:
print(rec.PartialResult())
except KeyboardInterrupt:
print("\n完成")
parser.exit(0)
except Exception as e:
parser.exit(type(e).__name__ + ": " + str(e))
4.2 多候选结果
启用多候选结果可以获取识别的多个可能文本及其置信度:
# 启用多候选结果
rec.SetMaxAlternatives(3)
# 处理音频...
# 解析结果
result = json.loads(rec.Result())
if "alternatives" in result:
for i, alt in enumerate(result["alternatives"]):
print(f"候选 {i+1}: {alt['text']} (置信度: {alt['confidence']:.2f})")
结果示例:
{
"text": "你好世界",
"alternatives": [
{ "text": "你好世界", "confidence": 0.97 },
{ "text": "你好是界", "confidence": 0.02 },
{ "text": "你好时间", "confidence": 0.01 }
]
}
4.3 自定义语法识别
对于特定场景,可以使用自定义语法来提高识别准确率:
# 创建带语法的识别器
grammar = '["你好", "再见", "谢谢", "不客气", "请", "对不起"]'
rec = KaldiRecognizer(model, sample_rate, grammar)
# 或者在运行时修改语法
rec.SetGrm('["打开灯", "关闭灯", "打开空调", "关闭空调"]')
语法格式支持多种模式:
// 简单列表
["是", "否", "不知道"]
// 带权重的选项
[{"command": "打开", "weight": 1.0}, {"command": "关闭", "weight": 0.5}]
// 更复杂的语法规则
{
"rules": {
"greeting": ["你好", "早上好", "下午好"],
"farewell": ["再见", "拜拜", "下次见"],
"command": ["打开 {device}", "关闭 {device}"],
"device": ["灯", "电视", "空调"]
},
"start": ["greeting", "farewell", "command"]
}
4.4 逆文本规范化(ITN)
逆文本规范化可以将口语化表达转换为标准化格式:
from vosk import Processor
# 创建文本处理器
proc = Processor("itn_tagger.fst", "itn_verbalizer.fst")
# 处理文本
print(proc.process("我明天八点十五分出发")) # 我明天8:15出发
print(proc.process("这个物品价值一千二百三十元")) # 这个物品价值1230元
print(proc.process("他的电话号码是一二三三四五六七八九零")) # 他的电话号码是1234567890
4.5 生成字幕(WebVTT)
Vosk可以生成带时间戳的字幕,适用于视频内容:
import sys
import subprocess
import json
import textwrap
from webvtt import WebVTT, Caption
from vosk import Model, KaldiRecognizer, SetLogLevel
SAMPLE_RATE = 16000
WORDS_PER_LINE = 7
SetLogLevel(-
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考