|
|
@ -37,19 +37,12 @@ class VoiceInputController extends GetxController { |
|
|
// 添加一个标志,表示是否已经收到最终结果 |
|
|
// 添加一个标志,表示是否已经收到最终结果 |
|
|
bool _hasFinalResult = false; |
|
|
bool _hasFinalResult = false; |
|
|
|
|
|
|
|
|
// 添加一个计时器,用于在一段时间没有新的识别结果时提交当前结果 |
|
|
|
|
|
Timer? _silenceTimer; |
|
|
|
|
|
|
|
|
|
|
|
// 添加一个计时器,用于定期更新用户说话状态 |
|
|
// 添加一个计时器,用于定期更新用户说话状态 |
|
|
Timer? _speakingCheckTimer; |
|
|
Timer? _speakingCheckTimer; |
|
|
|
|
|
|
|
|
// 最后一次识别到语音的时间 |
|
|
// 最后一次识别到语音的时间 |
|
|
DateTime? _lastSpeechTime; |
|
|
DateTime? _lastSpeechTime; |
|
|
|
|
|
|
|
|
// 添加一个变量来跟踪空结果的数量 |
|
|
|
|
|
int _emptyResultCount = 0; |
|
|
|
|
|
static const int _maxEmptyResults = 3; |
|
|
|
|
|
|
|
|
|
|
|
// Callbacks |
|
|
// Callbacks |
|
|
final Function(String) onRecordingResult; |
|
|
final Function(String) onRecordingResult; |
|
|
final VoidCallback onClosePanel; |
|
|
final VoidCallback onClosePanel; |
|
|
@ -132,7 +125,6 @@ class VoiceInputController extends GetxController { |
|
|
recognizedText.value = ''; // 清空识别文本,但不再在面板中显示 |
|
|
recognizedText.value = ''; // 清空识别文本,但不再在面板中显示 |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasFinalResult = false; |
|
|
_hasFinalResult = false; |
|
|
_emptyResultCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
// 创建一个 Completer 来处理语音识别完成 |
|
|
// 创建一个 Completer 来处理语音识别完成 |
|
|
_recognitionCompleter = Completer<String>(); |
|
|
_recognitionCompleter = Completer<String>(); |
|
|
@ -152,7 +144,6 @@ class VoiceInputController extends GetxController { |
|
|
if (event.text.isNotEmpty) { |
|
|
if (event.text.isNotEmpty) { |
|
|
_hasRecognizedSpeech = true; |
|
|
_hasRecognizedSpeech = true; |
|
|
_lastSpeechTime = DateTime.now(); |
|
|
_lastSpeechTime = DateTime.now(); |
|
|
_emptyResultCount = 0; // 重置空结果计数 |
|
|
|
|
|
|
|
|
|
|
|
// 设置用户正在说话状态 |
|
|
// 设置用户正在说话状态 |
|
|
isUserSpeaking.value = true; |
|
|
isUserSpeaking.value = true; |
|
|
@ -163,25 +154,6 @@ class VoiceInputController extends GetxController { |
|
|
_ttsService.stop(); |
|
|
_ttsService.stop(); |
|
|
_ttsService.endSession(); // 结束当前TTS会话 |
|
|
_ttsService.endSession(); // 结束当前TTS会话 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 取消之前的静默计时器 |
|
|
|
|
|
_silenceTimer?.cancel(); |
|
|
|
|
|
|
|
|
|
|
|
// 设置新的静默计时器,如果 2 秒内没有新的识别结果,则认为用户已经停止说话 |
|
|
|
|
|
_silenceTimer = Timer(const Duration(seconds: 2), () { |
|
|
|
|
|
if (_hasRecognizedSpeech && !_hasFinalResult && |
|
|
|
|
|
_recognitionCompleter != null && !_recognitionCompleter!.isCompleted) { |
|
|
|
|
|
print('用户停止说话 2 秒,使用当前识别结果: ${event.text}'); |
|
|
|
|
|
_recognitionCompleter!.complete(event.text); |
|
|
|
|
|
|
|
|
|
|
|
// 调用最终结果回调,发送识别到的句子 |
|
|
|
|
|
onRecordingResult(event.text); |
|
|
|
|
|
|
|
|
|
|
|
// 清空识别状态,准备下一句 |
|
|
|
|
|
_hasRecognizedSpeech = false; |
|
|
|
|
|
_hasFinalResult = false; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 调用识别中回调,将中间结果传递给ChatController |
|
|
// 调用识别中回调,将中间结果传递给ChatController |
|
|
@ -199,29 +171,26 @@ class VoiceInputController extends GetxController { |
|
|
// 不再更新面板中的识别文本 |
|
|
// 不再更新面板中的识别文本 |
|
|
_hasRecognizedSpeech = true; |
|
|
_hasRecognizedSpeech = true; |
|
|
_lastSpeechTime = DateTime.now(); |
|
|
_lastSpeechTime = DateTime.now(); |
|
|
_emptyResultCount = 0; // 重置空结果计数 |
|
|
|
|
|
|
|
|
|
|
|
// 调用最终结果回调,发送识别到的句子 |
|
|
// 调用最终结果回调,发送识别到的句子 |
|
|
onRecordingResult(event.text); |
|
|
onRecordingResult(event.text); |
|
|
|
|
|
|
|
|
// 清空识别状态,准备下一句 |
|
|
// 清空识别状态,准备下一句,但不停止识别 |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasFinalResult = false; |
|
|
_hasFinalResult = false; |
|
|
|
|
|
|
|
|
|
|
|
// 完成当前识别,但不停止连续识别 |
|
|
|
|
|
if (_recognitionCompleter != null && !_recognitionCompleter!.isCompleted) { |
|
|
|
|
|
_recognitionCompleter!.complete(event.text); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
// 如果最终结果为空,但之前有中间结果,仍然标记为有语音 |
|
|
// 如果最终结果为空,但之前有中间结果,仍然标记为有语音 |
|
|
if (_hasRecognizedSpeech) { |
|
|
if (_hasRecognizedSpeech) { |
|
|
print('最终识别结果为空,但之前有中间结果,使用最后的中间结果'); |
|
|
print('最终识别结果为空,但之前有中间结果,使用最后的中间结果'); |
|
|
|
|
|
|
|
|
// 这里不再需要使用recognizedText.value,因为我们已经在中间结果中传递了文本 |
|
|
// 清空识别状态,准备下一句,但不停止识别 |
|
|
// 而且ChatController已经在UI中显示了最新的识别结果 |
|
|
|
|
|
|
|
|
|
|
|
// 清空识别状态,准备下一句 |
|
|
|
|
|
_hasRecognizedSpeech = false; |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasFinalResult = false; |
|
|
_hasFinalResult = false; |
|
|
} else { |
|
|
|
|
|
// 如果最终结果为空,且没有中间结果,增加空结果计数 |
|
|
|
|
|
_emptyResultCount++; |
|
|
|
|
|
print('收到空的最终结果,当前空结果计数: $_emptyResultCount / $_maxEmptyResults'); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
@ -258,9 +227,6 @@ class VoiceInputController extends GetxController { |
|
|
restartRecognition(); |
|
|
restartRecognition(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 等待语音识别完成 |
|
|
|
|
|
final result = await _recognitionCompleter!.future; |
|
|
|
|
|
|
|
|
|
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
print('语音识别失败: $e'); |
|
|
print('语音识别失败: $e'); |
|
|
Get.snackbar( |
|
|
Get.snackbar( |
|
|
@ -271,9 +237,10 @@ class VoiceInputController extends GetxController { |
|
|
isRecording.value = false; |
|
|
isRecording.value = false; |
|
|
} finally { |
|
|
} finally { |
|
|
// 清理资源 |
|
|
// 清理资源 |
|
|
|
|
|
if (_recognitionCompleter != null && !_recognitionCompleter!.isCompleted) { |
|
|
|
|
|
_recognitionCompleter!.complete(''); |
|
|
|
|
|
} |
|
|
_recognitionCompleter = null; |
|
|
_recognitionCompleter = null; |
|
|
_silenceTimer?.cancel(); |
|
|
|
|
|
_silenceTimer = null; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -299,10 +266,6 @@ class VoiceInputController extends GetxController { |
|
|
await _recognitionSubscription?.cancel(); |
|
|
await _recognitionSubscription?.cancel(); |
|
|
_recognitionSubscription = null; |
|
|
_recognitionSubscription = null; |
|
|
|
|
|
|
|
|
// 取消计时器 |
|
|
|
|
|
_silenceTimer?.cancel(); |
|
|
|
|
|
_silenceTimer = null; |
|
|
|
|
|
|
|
|
|
|
|
// 停止连续识别 |
|
|
// 停止连续识别 |
|
|
if (_voiceService.isContinuousRecognitionActive()) { |
|
|
if (_voiceService.isContinuousRecognitionActive()) { |
|
|
await _voiceService.stopContinuousRecognition(); |
|
|
await _voiceService.stopContinuousRecognition(); |
|
|
@ -311,7 +274,6 @@ class VoiceInputController extends GetxController { |
|
|
isRecording.value = false; |
|
|
isRecording.value = false; |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasRecognizedSpeech = false; |
|
|
_hasFinalResult = false; |
|
|
_hasFinalResult = false; |
|
|
_emptyResultCount = 0; |
|
|
|
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
print('停止语音识别失败: $e'); |
|
|
print('停止语音识别失败: $e'); |
|
|
isRecording.value = false; |
|
|
isRecording.value = false; |
|
|
@ -354,6 +316,7 @@ class VoiceInputController extends GetxController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 默认情况下,如果正在录音但没有最近的语音识别,随机生成一个说话状态 |
|
|
// 默认情况下,如果正在录音但没有最近的语音识别,随机生成一个说话状态 |
|
|
|
|
|
// 保持这个功能,让麦克风图标有动画效果 |
|
|
if (isRecording.value) { |
|
|
if (isRecording.value) { |
|
|
// 随机生成一个值,有20%的概率认为用户正在说话 |
|
|
// 随机生成一个值,有20%的概率认为用户正在说话 |
|
|
isUserSpeaking.value = Random().nextDouble() < 0.2; |
|
|
isUserSpeaking.value = Random().nextDouble() < 0.2; |
|
|
|