Browse Source

v0.1

newdev_shunjiawei
wolfplus 2 years ago
parent
commit
ab4bf7319a
  1. 178
      lib/data/services/background_agent_service.dart
  2. 25
      lib/data/services/volcano_tts_service.dart

178
lib/data/services/background_agent_service.dart

@ -46,31 +46,95 @@ class BackgroundAgentService extends GetxService {
// 添加一个标志,表示系统是否正在播放 TTS // 添加一个标志,表示系统是否正在播放 TTS
bool _isSpeaking = false; bool _isSpeaking = false;
// 添加一个订阅,用于监听 TTS 状态变化
StreamSubscription? _ttsSpeakingSubscription;
// 添加一个变量来跟踪当前的AI响应流订阅 // 添加一个变量来跟踪当前的AI响应流订阅
StreamSubscription? _aiResponseSubscription; StreamSubscription? _aiResponseSubscription;
// 添加一个标志,表示是否应该取消当前的AI响应 // 添加一个标志,表示是否应该取消当前的AI响应
bool _shouldCancelAiResponse = false; bool _shouldCancelAiResponse = false;
// 添加一个变量来跟踪最后一次 TTS 状态变化的时间
DateTime? _lastTtsStateChangeTime;
BackgroundAgentService() BackgroundAgentService()
: _aiService = VolcanoAIService(), : _aiService = VolcanoAIService(),
_ttsService = Get.find<VolcanoTtsService>(), _ttsService = Get.find<VolcanoTtsService>(),
_voiceRecognitionService = Get.find<VoiceRecognitionService>() { _voiceRecognitionService = Get.find<VoiceRecognitionService>() {
// 监听 TTS 播放状态 // 不再监听 TTS 播放状态,而是使用定期检查
_ttsSpeakingSubscription = _ttsService.isPlaying.listen((speaking) { // 初始化 TTS 状态
_isSpeaking = speaking; _isSpeaking = _ttsService.isActuallyPlaying();
print('TTS 播放状态变化: $_isSpeaking'); _lastTtsStateChangeTime = DateTime.now();
// 添加定期检查实际播放状态的计时器
Timer.periodic(const Duration(seconds: 1), (timer) {
// 检查实际播放状态
final actuallyPlaying = _ttsService.isActuallyPlaying();
// 如果 TTS 停止播放,且正在进行语音识别,重新启动无语音超时计时器 // 如果状态发生变化,更新状态并记录时间
if (!speaking && _isListening && _hasRecognizedSpeech && _noSpeechTimer == null) { if (_isSpeaking != actuallyPlaying) {
_startNoSpeechTimer(); print('TTS 播放状态变化: $_isSpeaking -> $actuallyPlaying');
_isSpeaking = actuallyPlaying;
_lastTtsStateChangeTime = DateTime.now();
// 如果 TTS 服务的 isPlaying 与实际状态不一致,尝试修正
if (actuallyPlaying != _ttsService.isPlaying.value) {
try {
_ttsService.isPlaying.value = actuallyPlaying;
print('已修正 TTS 服务的播放状态');
} catch (e) {
print('修正 TTS 播放状态失败: $e');
}
}
// 如果 TTS 停止播放,且正在进行语音识别,重新启动无语音超时计时器
if (!actuallyPlaying && _isListening && _hasRecognizedSpeech && _noSpeechTimer == null) {
_startNoSpeechTimer();
}
}
// 如果正在处理交互,进行更全面的检查
if (_isProcessing) {
_checkAndUpdateTtsState();
} }
}); });
} }
// 添加一个方法来检查和更新 TTS 状态
void _checkAndUpdateTtsState() {
try {
// 获取实际播放状态
final actuallyPlaying = _ttsService.isActuallyPlaying();
// 如果状态显示正在播放,但已经很长时间没有状态变化,强制重置
if (actuallyPlaying && _lastTtsStateChangeTime != null) {
final now = DateTime.now();
final difference = now.difference(_lastTtsStateChangeTime!);
// 如果超过15秒没有状态变化,强制重置
if (difference.inSeconds > 15) {
print('强制重置 TTS 状态:已经 ${difference.inSeconds} 秒没有状态变化');
try {
// 停止 TTS 播放
_ttsService.stop();
// 强制更新状态
_isSpeaking = false;
_ttsService.isPlaying.value = false;
// 更新最后状态变化时间
_lastTtsStateChangeTime = DateTime.now();
print('TTS 状态已强制重置');
} catch (e) {
print('强制重置 TTS 状态失败: $e');
}
}
}
} catch (e) {
print('检查 TTS 播放状态失败: $e');
}
}
// 处理蓝牙耳机按钮触发的交互 // 处理蓝牙耳机按钮触发的交互
Future<void> handleAgentInteraction(String systemPrompt) async { Future<void> handleAgentInteraction(String systemPrompt) async {
if (_isProcessing) { if (_isProcessing) {
@ -110,9 +174,26 @@ class BackgroundAgentService extends GetxService {
// 启动无语音超时计时器 // 启动无语音超时计时器
void _startNoSpeechTimer() { void _startNoSpeechTimer() {
// 检查 TTS 播放状态,使用 isActuallyPlaying 获取实际状态
_isSpeaking = _ttsService.isActuallyPlaying();
// 如果系统正在播放 TTS,不启动计时器 // 如果系统正在播放 TTS,不启动计时器
if (_isSpeaking) { if (_isSpeaking) {
print('系统正在播放 TTS,不启动无语音超时计时器'); print('系统正在播放 TTS,不启动无语音超时计时器 (isPlaying.value: ${_ttsService.isPlaying.value}, 实际播放状态: $_isSpeaking)');
// 即使TTS正在播放,也设置一个更长的安全超时,防止系统永远卡在循环中
_noSpeechTimer?.cancel();
_noSpeechTimer = Timer(const Duration(seconds: 30), () {
// 再次检查 TTS 状态,使用 isActuallyPlaying
_isSpeaking = _ttsService.isActuallyPlaying();
print('安全超时触发:即使TTS正在播放,30秒内没有新的语音输入,强制退出循环交互 (实际播放状态: $_isSpeaking)');
if (_recognitionCompleter != null && !_recognitionCompleter!.isCompleted) {
_recognitionCompleter!.complete('');
}
_shouldContinueInteraction = false;
});
return; return;
} }
@ -121,10 +202,17 @@ class BackgroundAgentService extends GetxService {
// 设置新的计时器,如果 10 秒内没有新的识别结果,且系统没有在播放 TTS,则认为用户已经停止交互 // 设置新的计时器,如果 10 秒内没有新的识别结果,且系统没有在播放 TTS,则认为用户已经停止交互
_noSpeechTimer = Timer(const Duration(seconds: 10), () { _noSpeechTimer = Timer(const Duration(seconds: 10), () {
// 再次检查是否正在播放 TTS // 再次检查是否正在播放 TTS,使用 isActuallyPlaying
_isSpeaking = _ttsService.isActuallyPlaying();
print('无语音超时计时器触发,当前 TTS 播放状态: $_isSpeaking (isPlaying.value: ${_ttsService.isPlaying.value}, 实际播放状态: $_isSpeaking)');
if (!_isSpeaking && _isListening && _recognitionCompleter != null && !_recognitionCompleter!.isCompleted) { if (!_isSpeaking && _isListening && _recognitionCompleter != null && !_recognitionCompleter!.isCompleted) {
print('10秒内没有新的语音输入,且系统没有在播放 TTS,退出循环交互'); print('10秒内没有新的语音输入,且系统没有在播放 TTS,退出循环交互');
_recognitionCompleter!.complete(''); _recognitionCompleter!.complete('');
// 直接设置标志,停止循环交互
_shouldContinueInteraction = false;
} }
}); });
@ -138,6 +226,9 @@ class BackgroundAgentService extends GetxService {
_hasFinalResult = false; _hasFinalResult = false;
try { try {
// 强制重置 TTS 状态,确保不会因为错误的状态导致系统卡住
_resetTtsStateIfNeeded();
// 先播放一个简短的提示音或提示语,表示开始监听 // 先播放一个简短的提示音或提示语,表示开始监听
try { try {
await _ttsService.speak("我在听"); await _ttsService.speak("我在听");
@ -175,8 +266,8 @@ class BackgroundAgentService extends GetxService {
_noSpeechTimer = null; _noSpeechTimer = null;
// 如果没有识别到语音,则停止循环交互 // 如果没有识别到语音,则停止循环交互
if (!_hasRecognizedSpeech) { if (!_hasRecognizedSpeech || userInput.trim().isEmpty) {
print('没有识别到用户语音,退出循环交互'); print('没有识别到用户语音或识别结果为空,退出循环交互');
// 停止语音识别 // 停止语音识别
if (_isListening) { if (_isListening) {
@ -199,17 +290,7 @@ class BackgroundAgentService extends GetxService {
// 只有在退出交互时才停止语音识别 // 只有在退出交互时才停止语音识别
} catch (e) { } catch (e) {
print('语音识别过程出错: $e'); print('语音识别过程出错: $e');
// 如果语音识别失败,尝试使用默认问候语
userInput = '你好,请帮我回答一个问题';
// 尝试重置语音识别服务
try {
await stopVoiceRecognition();
await Future.delayed(const Duration(milliseconds: 500));
await _voiceRecognitionService.initialize();
} catch (resetError) {
print('重置语音识别服务失败: $resetError');
}
} finally { } finally {
// 清理资源,但保持语音识别状态 // 清理资源,但保持语音识别状态
_recognitionCompleter = null; _recognitionCompleter = null;
@ -405,6 +486,18 @@ class BackgroundAgentService extends GetxService {
print('收到最终识别结果,立即处理: ${event.text}'); print('收到最终识别结果,立即处理: ${event.text}');
_recognitionCompleter!.complete(event.text); _recognitionCompleter!.complete(event.text);
} }
} else {
// 如果最终结果为空,但之前有中间结果,仍然标记为有语音
if (_hasRecognizedSpeech) {
print('最终识别结果为空,但之前有中间结果,使用最后的中间结果');
if (_recognitionCompleter != null && !_recognitionCompleter!.isCompleted) {
_recognitionCompleter!.complete(recognizedText.value);
}
} else {
// 如果最终结果为空,且没有中间结果,重新启动无语音超时计时器
print('最终识别结果为空,且没有中间结果,重新启动无语音超时计时器');
_startNoSpeechTimer();
}
} }
print('最终识别结果: ${event.text}'); print('最终识别结果: ${event.text}');
} else if (event.type == RecognitionEventType.intermediateResult) { } else if (event.type == RecognitionEventType.intermediateResult) {
@ -537,9 +630,42 @@ class BackgroundAgentService extends GetxService {
_recognitionSubscription?.cancel(); _recognitionSubscription?.cancel();
_silenceTimer?.cancel(); _silenceTimer?.cancel();
_noSpeechTimer?.cancel(); _noSpeechTimer?.cancel();
_ttsSpeakingSubscription?.cancel();
_aiResponseSubscription?.cancel(); _aiResponseSubscription?.cancel();
_shouldContinueInteraction = false; _shouldContinueInteraction = false;
super.onClose(); super.onClose();
} }
// 添加一个方法来强制重置 TTS 状态
void _resetTtsStateIfNeeded() {
// 检查 TTS 状态,使用 isActuallyPlaying 获取实际状态
bool isCurrentlyPlaying = false;
try {
isCurrentlyPlaying = _ttsService.isActuallyPlaying();
} catch (e) {
print('获取实际播放状态失败: $e');
isCurrentlyPlaying = _ttsService.isPlaying.value;
}
// 如果实际状态与当前状态不一致,更新它
if (_isSpeaking != isCurrentlyPlaying) {
print('重置前检测到 TTS 播放状态不一致,修正: _isSpeaking=$_isSpeaking, 实际=${isCurrentlyPlaying}');
_isSpeaking = isCurrentlyPlaying;
// 如果实际状态与 TTS 服务的 isPlaying 不一致,尝试修正 TTS 服务的状态
if (isCurrentlyPlaying != _ttsService.isPlaying.value) {
try {
_ttsService.isPlaying.value = isCurrentlyPlaying;
print('已修正 TTS 服务的播放状态');
} catch (e) {
print('修正 TTS 播放状态失败: $e');
}
}
// 更新最后一次状态变化的时间
_lastTtsStateChangeTime = DateTime.now();
}
// 检查是否需要强制重置
_checkAndUpdateTtsState();
}
} }

25
lib/data/services/volcano_tts_service.dart

@ -576,6 +576,31 @@ class VolcanoTtsService extends GetxService {
} }
} }
// 添加一个方法来检查音频播放器是否真正在播放
bool isActuallyPlaying() {
try {
// 检查播放器状态
final isPlayerPlaying = _audioPlayer.playing;
// 检查播放列表是否为空
final hasAudioSource = _playlist.length > 0;
// 只有当播放器正在播放且播放列表不为空时,才认为真正在播放
final actuallyPlaying = isPlayerPlaying && hasAudioSource;
// 如果状态不一致,记录日志
if (isPlaying.value != actuallyPlaying) {
print('音频播放状态不一致: isPlaying.value=${isPlaying.value}, 实际播放状态=$actuallyPlaying (播放器状态=$isPlayerPlaying, 播放列表长度=${_playlist.length})');
}
return actuallyPlaying;
} catch (e) {
print('检查实际播放状态失败: $e');
// 如果检查失败,返回当前的 isPlaying 值
return isPlaying.value;
}
}
Future<void> _reinitializePlayer() async { Future<void> _reinitializePlayer() async {
try { try {
await stop(); await stop();

Loading…
Cancel
Save