You need to enable JavaScript to run this app. 如何在VOSK语音识别中使用Wave文件作为输入
优惠活动
大模型
产品
解决方案
定价
更多

如何在VOSK语音识别中使用Wave文件作为输入

问题背景

我手头的项目需要获取录音文件,经代码处理后提取文件中的文本内容,再将提取得到的文本与其他文本进行匹配校验。当前遇到的问题是:代码无法正常读取、使用已录制的音频文件。

代码核心逻辑说明:

  • init函数是代码的核心基础逻辑,负责参数解析、模型加载、配置初始化
  • verify函数用于确认语音与文本的匹配结果
原有实现代码
import argparse
import json
import os
import queue
import random
import sys
from difflib import SequenceMatcher
import numpy as np
import sounddevice as sd
import vosk

q = queue.Queue()

def int_or_str(text):
    """Helper function for argument parsing."""
    try:
        return int(text)
    except ValueError:
        return text


def callback(indata, frames, time, status):
    """This is called (from a separate thread) for each audio block."""
    if status:
        print(status, file=sys.stderr)
    q.put(bytes(indata))


def init():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument(
        '-l', '--list-devices', action='store_true',
        help='show list of audio devices and exit')
    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(
        '-f', '--filename', type=str, metavar='FILENAME',
        help='audio file to store recording to')
    parser.add_argument(
        '-m', '--model', type=str, metavar='MODEL_PATH',
        help='Path to the model')
    parser.add_argument(
        '-d', '--device', type=int_or_str,
        help='input device (numeric ID or substring)')
    parser.add_argument(
        '-r', '--samplerate', type=int, help='sampling rate')
    args = parser.parse_args(remaining)
    try:
        if args.model is None:
            args.model = "model"
        if not os.path.exists(args.model):
            print("Please download a model for your language from vosk official model page")
            print("and unpack as 'model' in the current folder.")
            parser.exit(0)
        if args.samplerate is None:
            device_info = sd.query_devices(args.device, 'input')
            # soundfile expects an int, sounddevice provides a float:
            args.samplerate = int(device_info['default_samplerate'])

        model = vosk.Model(args.model)

        if args.filename:
            dump_fn = open(args.filename, "wb")
        else:
            dump_fn = None

    except KeyboardInterrupt:
        print('\nDone')
        parser.exit(0)
    except Exception as e:
        parser.exit(type(e).__name__ + ': ' + str(e))

    return model, args
def verify(random_sentence, model, args):
    num, T_num, F_num, num_word = 0, 0, 0, 1
    with sd.RawInputStream(samplerate=args.samplerate, blocksize=8000, device=args.device, dtype='int16',
                           channels=1, callback=callback):
        rec = vosk.KaldiRecognizer(model, args.samplerate)
        print("{}) ".format(num_word), random_sentence, end='\n')
        print('=' * 30, end='\n')
        run = True
        while run:
            data = q.get()
            if rec.AcceptWaveform(data):
                res = json.loads(rec.FinalResult())
                res['text'] = res['text'].replace('ي', 'ی')             
                if SequenceMatcher(None, random_sentence, res['text']).ratio() > 0.65:                    
                    T_num, num, num_word += 1
                    
                else:
                    F_num, num, num_word += 1
                    
                run = False

    print('=' * 30)
    print('True Cases : {}\n False Cases : {}'.format(T_num, F_num))


if __name__ == "__main__":
    model, args = init()
    verify(random_sentences, model, args)
问题原因

原有代码仅支持从麦克风实时采集音频做识别,没有实现本地已录制音频文件的读取逻辑,所以无法直接使用本地音频文件做校验。

修复方案

前置依赖安装

先安装音频文件读取库:

pip install soundfile

核心修改点

  1. 移除原有实时流相关的队列、callback逻辑,新增本地音频文件读取逻辑
  2. 修改参数配置,新增本地音频文件路径必填参数
  3. 自动适配音频格式为vosk要求的16位单声道格式,兼容不同采样率的音频文件

修复后的完整代码

import argparse
import json
import os
import sys
from difflib import SequenceMatcher
import soundfile as sf
import vosk
import numpy as np

def int_or_str(text):
    """参数解析辅助函数"""
    try:
        return int(text)
    except ValueError:
        return text

def init():
    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:
        import sounddevice as sd
        print(sd.query_devices())
        parser.exit(0)
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        parents=[parser])
    parser.add_argument(
        '-a', '--audio-path', type=str, metavar='AUDIO_PATH', required=True,
        help='待识别的本地音频文件路径')
    parser.add_argument(
        '-m', '--model', type=str, metavar='MODEL_PATH',
        help='Vosk模型路径')
    parser.add_argument(
        '-r', '--samplerate', type=int, help='采样率,不填则自动读取音频文件的采样率')
    args = parser.parse_args(remaining)
    try:
        if args.model is None:
            args.model = "model"
        if not os.path.exists(args.model):
            print("请下载对应语言的Vosk模型,解压后放置在当前目录下命名为model文件夹")
            parser.exit(0)
        # 读取音频文件获取采样率
        if args.samplerate is None:
            with sf.SoundFile(args.audio_path) as f:
                args.samplerate = f.samplerate
        model = vosk.Model(args.model)
    except KeyboardInterrupt:
        print('\n已退出')
        parser.exit(0)
    except Exception as e:
        parser.exit(type(e).__name__ + ': ' + str(e))
    return model, args

def verify(random_sentence, audio_path, model, args):
    T_num, F_num = 0, 0
    rec = vosk.KaldiRecognizer(model, args.samplerate)
    rec.SetWords(True)
    # 逐块读取音频文件
    with sf.SoundFile(audio_path) as f:
        # 自动转成单声道16位整型
        if f.channels > 1:
            data = np.mean(f.read(dtype='int16'), axis=1, dtype='int16')
        else:
            data = f.read(dtype='int16')
        # 分块送入识别器
        block_size = 8000
        for i in range(0, len(data), block_size):
            block = data[i:i+block_size].tobytes()
            if rec.AcceptWaveform(block):
                break
        # 获取最终识别结果
        res = json.loads(rec.FinalResult())
        res['text'] = res['text'].replace('ي', 'ی')
        # 匹配校验
        if SequenceMatcher(None, random_sentence, res['text']).ratio() > 0.65:
            T_num += 1
            print("识别结果匹配:", res['text'])
        else:
            F_num += 1
            print("识别结果不匹配:", res['text'])
    print('=' * 30)
    print('匹配成功数: {}\n匹配失败数: {}'.format(T_num, F_num))

if __name__ == "__main__":
    model, args = init()
    # 这里替换成你实际要匹配的目标文本
    target_sentence = "你要匹配的目标文本内容"
    verify(target_sentence, args.audio_path, model, args)

使用方式

运行时通过参数指定音频路径即可:

python 脚本名.py -a 你的音频文件路径.wav

支持wav、flac等无压缩音频格式,若是mp3等压缩格式需要先转成wav格式再使用。

内容的提问来源于stack exchange,提问作者Ebrahim Mohammadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 13:15:03