C# 使用Speech Recognition开发语音助手出现循环播报故障如何解决
问题根源
- 你使用了
RecognizeMode.Multiple持续识别模式,麦克风会采集所有音频输入,包括SpeechSynthesizer播报的内容 - 你的语法库(grammer.txt)包含播报内容里的触发关键词(如Hi、Hello),播报的声音被麦克风采集后会再次触发
SpeechRecognized事件,形成“识别→播报→识别播报内容→再次播报”的死循环 - 你调用
RecognizeAsyncCancel()不生效是因为没有在播报前暂停识别,也没有在播报结束后恢复识别,调用时机不符合逻辑
修复方案
你可以任选以下两种方案中的一种解决问题:
方案1:新增播报状态标记位(实现更简单,性能消耗更低)
- 首先在Form1类中新增全局状态标记:
// 标记当前是否处于播报状态 bool isSpeaking = false;
- 在构造函数中绑定播报完成事件,播报结束后自动重置标记位:
public Form1() { InitializeComponent(); // ... 保留你原有其他代码 speech.SelectVoiceByHints(VoiceGender.Male); // 新增播报完成事件绑定 speech.SpeakCompleted += (s, e) => { isSpeaking = false; }; }
- 修改识别触发逻辑,播报状态下直接忽略识别结果:
private void RecEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) { // 播报期间直接跳过处理 if (isSpeaking) return; string recognizedText = e.Result.Text; string replyContent = ""; if (recognizedText == "Hello") { replyContent = "Hi, my name is Jarvis, how can I help you"; } else if (recognizedText == "Hi") { replyContent = "It is currently " + DateTime.Now.ToLongTimeString(); } // 没有匹配回复直接返回,不播报空内容 if(string.IsNullOrEmpty(replyContent)) return; isSpeaking = true; speech.SpeakAsync(replyContent); lblresult.Text = replyContent; MessageBox.Show("a"); }
方案2:播报时暂停识别,播报结束后恢复
修改识别触发逻辑如下即可:
private void RecEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) { string recognizedText = e.Result.Text; string replyContent = ""; if (recognizedText == "Hello") { replyContent = "Hi, my name is Jarvis, how can I help you"; } else if (recognizedText == "Hi") { replyContent = "It is currently " + DateTime.Now.ToLongTimeString(); } if(string.IsNullOrEmpty(replyContent)) return; // 播报前先停止识别 RecEngine.RecognizeAsyncCancel(); // 播报完成后重新开启识别 speech.SpeakCompleted += (s, args) => { RecEngine.RecognizeAsync(RecognizeMode.Multiple); }; speech.SpeakAsync(replyContent); lblresult.Text = replyContent; MessageBox.Show("a"); }
额外优化建议
不要用同一个变量存储识别结果和回复内容,避免逻辑混淆;不要给SpeakAsync方法传入空字符串,避免触发无意义的播报。
内容的提问来源于stack exchange,提问作者Kazuya Kimihiro
相关产品推荐
相关产品推荐

