要在.NET Framework 4.8中使用C#实现离线实时语音识别,可以使用开源库Vosk(支持离线ASR)配合音频处理库NAudio。
步骤 1:安装依赖库
1.1.
安装NuGet包:
- Install-Package NAudio(处理音频输入)
- Install-Package Vosk(离线语音识别引擎)
2.2.
下载语音模型:
- 前往 Vosk Models 下载适合的模型(如小型英文模型 vosk-model-small-en-us-0.15)。
- 解压模型到项目目录(如 Models/vosk-model-small-en-us-0.15)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NAudio.Wave;
using Vosk;
using System.Windows.Forms;
namespace 语音识别
{
public class RealTimeSpeechRecognizer
{
private readonly VoskRecognizer _recognizer;
private readonly WaveInEvent _waveIn;
private readonly RichTextBox _rtb;
public RealTimeSpeechRecognizer(string modelPath, RichTextBox rtb)
{
_rtb = rtb;
// 初始化Vosk
Model model = new Model(modelPath);
_recognizer = new VoskRecognizer(model, 16000.0f);
_recognizer.SetWords(true);
// 初始化音频输入
_waveIn = new WaveInEvent
{
WaveFormat = new WaveFormat(16000, 16, 1),
DeviceNumber = 0
};
_waveIn.DataAvailable += OnAudioDataAvailable;
}
public void StartListening() => _waveIn.StartRecording();
public void StopListening() => _waveIn.StopRecording();
// 解析JSON结果(兼容部分结果)
private string ParseJsonResult(string json, bool isPartial = false)
{
dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
return isPartial ? obj.partial : obj.text;
}
// 线程安全更新RichTextBox
private void ShowText(string text)
{
if (_rtb.InvokeRequired)
{
_rtb.BeginInvoke(new Action<string>(ShowText), text);
}
else
{
_rtb.AppendText(text);
_rtb.ScrollToCaret();
}
}
// 其他字段和构造函数保持不变...
private string _lastPartialText = string.Empty;
private void OnAudioDataAvailable(object sender, WaveInEventArgs e)
{
if (_recognizer.AcceptWaveform(e.Buffer, e.BytesRecorded))
{
string result = ParseJsonResult(_recognizer.Result());
ClearLastPartial(); // 清理临时部分
AppendFinalText(result);
}
else
{
string partial = ParseJsonResult(_recognizer.PartialResult(), isPartial: true);
UpdatePartialText(partial);
}
}
private void UpdatePartialText(string newPartial)
{
if (newPartial == _lastPartialText) return;
// 在主线程更新UI
_rtb.BeginInvoke(new Action(() =>
{
int selectionStart = _rtb.TextLength - _lastPartialText.Length;
// 删除旧临时内容
if (selectionStart >= 0 && _lastPartialText.Length > 0)
{
_rtb.Select(selectionStart, _lastPartialText.Length);
_rtb.SelectedText = "";
}
// 追加新内容
_rtb.AppendText(newPartial);
_rtb.ScrollToCaret();
// 更新临时记录
_lastPartialText = newPartial;
}));
}
private void AppendFinalText(string text)
{
_rtb.BeginInvoke(new Action(() =>
{
_rtb.AppendText(text + "\n");
_lastPartialText = string.Empty; // 重置临时部分
}));
}
private void ClearLastPartial()
{
if (string.IsNullOrEmpty(_lastPartialText)) return;
_rtb.BeginInvoke(new Action(() =>
{
int start = _rtb.TextLength - _lastPartialText.Length;
if (start >= 0)
{
_rtb.Select(start, _lastPartialText.Length);
_rtb.SelectedText = "";
}
}));
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 语音识别
{
public partial class Form1 : Form
{
private RealTimeSpeechRecognizer _recognizer;
public Form1()
{
InitializeComponent();
btnStop.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
_recognizer.StopListening();
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
string modelPath = @"E:\Models\vosk-model-small-cn-0.22"; // 中文模型路径
_recognizer = new RealTimeSpeechRecognizer(modelPath, richTextBox1);
btnStart.Enabled = false;
btnStop.Enabled = true;
_recognizer.StartListening();
}
}
}