You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

458 lines
14 KiB

import 'dart:async';
import 'package:get/get.dart';
import 'package:flutter/widgets.dart';
import '../../core/utils/logger.dart';
import '../providers/agent_provider.dart';
import '../models/agent.dart';
import '../../modules/chat/controllers/chat_controller.dart';
import '../../modules/chat/models/message_model.dart';
import 'azure_asr_service.dart';
import 'volcano_ai_service.dart';
import 'volcano_tts_api_service.dart';
import 'chat_history_service.dart';
/// 后台代理服务,用于在应用处于后台时处理AI交互
class BackgroundAgentService extends GetxService {
// 服务实例
final AzureAsrService _asrService = Get.find<AzureAsrService>();
final VolcanoAIService _aiService = Get.find<VolcanoAIService>();
final VolcanoTtsApiService _ttsService = Get.find<VolcanoTtsApiService>();
final ChatHistoryService _historyService = Get.find<ChatHistoryService>();
// 状态控制
final RxBool isProcessing = false.obs;
final RxBool isListening = false.obs;
// 语音识别状态
final RxString recognizedText = ''.obs;
// 流式响应控制
StreamSubscription? _recognitionSubscription;
StreamSubscription? _aiResponseSubscription;
// 定时器,用于检测无活动超时
Timer? _inactivityTimer;
// 当前处理的Agent
Agent? _currentAgent;
// 消息历史 - 与ChatController共享
List<Map<String, String>> get messageHistory {
// 首先尝试从ChatController获取消息历史
if (Get.isRegistered<ChatController>()) {
final chatController = Get.find<ChatController>();
// 检查ChatController是否正在与personal_assistant交互
if (chatController.agent?.id == 'personal_assistant') {
return chatController.messages.map((m) => {
'role': m.role,
'content': m.content,
}).toList();
}
}
// 如果无法从ChatController获取,则使用本地存储的历史记录
if (_localMessageHistory.isEmpty) {
_loadChatHistory();
}
return _localMessageHistory;
}
// 本地消息历史备份
final List<Map<String, String>> _localMessageHistory = [];
// 构造函数
BackgroundAgentService() {
Logger.info('BackgroundAgentService 已创建');
}
// TTS是否正在播放,直接从VolcanoTtsApiService获取
bool get isTtsSpeaking => _ttsService.isPlaying;
@override
void onClose() {
// 取消所有订阅
_recognitionSubscription?.cancel();
_aiResponseSubscription?.cancel();
// 停止TTS
if (_ttsService.isPlaying) {
_ttsService.stop();
}
// 停止语音识别
if (isListening.value) {
_asrService.stopContinuousRecognition();
}
// 取消定时器
_inactivityTimer?.cancel();
super.onClose();
}
/// 开始代理交互
///
/// [agentId] 要交互的代理ID
Future<void> startAgentInteraction(String agentId) async {
// 先说"我在听",然后再播放欢迎消息
const listeningMessage = "我在听";
_ttsService.speakSingle(listeningMessage);
// 防止重复处理
if (isProcessing.value) {
Logger.warning('已经在处理交互,忽略此次请求');
return;
}
isProcessing.value = true;
try {
// 获取Agent
final agent = AgentProvider.getAgentById(agentId);
if (agent == null) {
Logger.error('无法获取Agent: $agentId');
isProcessing.value = false;
return;
}
_currentAgent = agent;
// 加载该Agent的聊天历史
_loadChatHistory();
// 启动语音识别 - 保持持续识别状态
await _startVoiceRecognition();
// 启动无活动定时器
_startInactivityTimer();
} catch (e) {
Logger.error('启动代理交互失败', e);
isProcessing.value = false;
}
}
/// 启动语音识别
Future<void> _startVoiceRecognition() async {
if (isListening.value) {
// 如果已经在监听,不需要重新启动
Logger.info('语音识别已经在运行,无需重新启动');
return;
}
try {
// 启动语音识别
final success = await _asrService.startContinuousRecognition();
if (success) {
isListening.value = true;
recognizedText.value = '';
// 监听识别事件
_recognitionSubscription = _asrService.recognitionStream?.listen(
(event) {
// 重置无活动定时器
_resetInactivityTimer();
switch (event.type) {
case RecognitionEventType.recognizing:
// 实时更新识别文本
if (event.text.isNotEmpty) {
recognizedText.value = event.text;
// 如果正在播放TTS,检测到用户说话则中断当前播放和AI回复
if (_ttsService.isPlaying && event.text.trim().length > 3) {
_interruptCurrentResponse("检测到用户说话,中断当前响应");
}
}
break;
case RecognitionEventType.finalResult:
// 最终结果
if (event.text.isNotEmpty) {
recognizedText.value = event.text;
// 处理识别到的文本
_processRecognizedText(event.text);
// 重置识别文本但保持识别状态
recognizedText.value = '';
}
break;
case RecognitionEventType.sessionStopped:
case RecognitionEventType.canceled:
// 会话结束,表示识别在其它地方被启动,直接退出后台服务
isListening.value = false;
Logger.info('语音识别会话被中止,退出后台代理服务');
stopInteraction();
break;
default:
break;
}
},
onError: (error) {
Logger.error('语音识别错误', error);
isListening.value = false;
// 如果出错,尝试重新启动语音识别
_restartVoiceRecognition();
},
);
} else {
Logger.error('启动语音识别失败');
isProcessing.value = false;
}
} catch (e) {
Logger.error('启动语音识别失败', e);
isListening.value = false;
isProcessing.value = false;
}
}
/// 处理识别到的文本
Future<void> _processRecognizedText(String text) async {
if (text.trim().isEmpty || _currentAgent == null) return;
try {
// 添加用户消息到历史记录
_addMessageToHistory('user', text);
// 启动TTS会话,使用当前Agent的voice
_ttsService.startSession(_currentAgent!.voice);
// 获取AI响应
String fullResponse = '';
// 获取AI响应流
final responseStream = _aiService.sendMessageStream(
messages: messageHistory,
systemPrompt: _currentAgent!.systemPrompt,
);
// 订阅响应流
_aiResponseSubscription = responseStream.listen(
(chunk) {
fullResponse += chunk;
// 如果TTS启用,发送到TTS
_ttsService.speak(chunk);
// 重置无活动定时器
_resetInactivityTimer();
},
onDone: () {
// 添加AI响应到历史记录
_addMessageToHistory('assistant', fullResponse);
// 结束TTS会话
_ttsService.endSession();
// 注意:我们不再在这里重启语音识别,因为它应该已经在运行
},
onError: (error) {
Logger.error('AI响应错误', error);
// 播放错误消息
const errorMessage = '抱歉,我遇到了一些问题,无法回应您的请求。';
_ttsService.speak(errorMessage);
// 添加错误消息到历史记录
_addMessageToHistory('assistant', errorMessage);
// 结束TTS会话
_ttsService.endSession();
},
);
} catch (e) {
Logger.error('处理识别文本失败', e);
// 播放错误消息
const errorMessage = '抱歉,我遇到了一些问题,无法回应您的请求。';
_ttsService.speak(errorMessage);
// 添加错误消息到历史记录
_addMessageToHistory('assistant', errorMessage);
}
}
/// 重新启动语音识别(仅在识别会话意外终止时使用)
Future<void> _restartVoiceRecognition() async {
// 停止当前的语音识别
if (isListening.value) {
await _asrService.stopContinuousRecognition();
isListening.value = false;
// 取消当前的订阅
_recognitionSubscription?.cancel();
_recognitionSubscription = null;
}
// 等待一段时间,确保资源被正确释放
await Future.delayed(Duration(milliseconds: 500));
// 重新启动语音识别
await _startVoiceRecognition();
}
/// 添加消息到历史记录
void _addMessageToHistory(String role, String content) {
// 添加到本地历史记录
_localMessageHistory.add({
'role': role,
'content': content,
});
// 保持本地历史记录不超过10条消息
if (_localMessageHistory.length > 10) {
_localMessageHistory.removeAt(0);
}
// 如果ChatController可用,同步消息到ChatController
if (Get.isRegistered<ChatController>()) {
final chatController = Get.find<ChatController>();
if (chatController.agent?.id == 'personal_assistant') {
// 向ChatController添加消息
final message = Message(
role: role,
content: content,
timestamp: DateTime.now(),
);
chatController.addMessage(message);
}
} else {
// 如果ChatController不可用,保存到本地存储
_saveChatHistory();
}
}
// 加载聊天历史
void _loadChatHistory() {
if (_currentAgent == null) return;
try {
// 加载聊天历史
final messages = _historyService.loadHistory(_currentAgent!.id);
// 清空本地历史,然后添加加载的历史
_localMessageHistory.clear();
// 将Message转换为Map格式
if (messages.isNotEmpty) {
for (final message in messages) {
_localMessageHistory.add({
'role': message.role,
'content': message.content,
});
}
Logger.info('已加载${messages.length}条聊天历史记录,代理: ${_currentAgent!.id}');
}
} catch (e) {
Logger.error('加载聊天历史记录失败', e);
}
}
// 保存聊天历史
void _saveChatHistory() {
if (_currentAgent == null) return;
try {
// 将本地历史转换为Message列表
final messages = _localMessageHistory.map((m) => Message(
role: m['role']!,
content: m['content']!,
timestamp: DateTime.now(),
)).toList();
// 保存到ChatHistoryService
_historyService.saveHistory(_currentAgent!.id, messages);
} catch (e) {
Logger.error('保存聊天历史记录失败', e);
}
}
/// 启动无活动定时器
void _startInactivityTimer() {
_inactivityTimer?.cancel();
_inactivityTimer = Timer(Duration(seconds: 30), () {
// 如果30秒内没有TTS输出或用户说话,停止语音识别
if (!_ttsService.isPlaying && isProcessing.value) {
Logger.info('检测到30秒内无活动,停止语音识别');
stopInteraction();
}
});
}
/// 重置无活动定时器
void _resetInactivityTimer() {
if (_inactivityTimer != null) {
_inactivityTimer!.cancel();
_startInactivityTimer();
}
}
/// 中断当前响应
void _interruptCurrentResponse(String reason) {
Logger.info(reason);
// 停止TTS
if (_ttsService.isPlaying) {
_ttsService.stop();
}
// 取消AI响应流订阅
_aiResponseSubscription?.cancel();
_aiResponseSubscription = null;
}
/// 响应新的媒体事件(双击媒体按钮)
Future<void> respondToNewMediaEvent() async {
// 不管当前状态如何,总是中断当前响应
_interruptCurrentResponse("检测到新的媒体事件,中断当前响应");
// 回答"我在听"
const listeningMessage = "我在听";
_ttsService.speakSingle(listeningMessage);
// 不需要重启语音识别,因为它应该已经在运行
// 如果识别会话已经终止,确保重新启动
if (!isListening.value) {
await _restartVoiceRecognition();
}
// 重置无活动定时器
_resetInactivityTimer();
}
/// 停止当前交互
Future<void> stopInteraction() async {
try {
// 保存聊天历史
_saveChatHistory();
// 取消所有订阅
_recognitionSubscription?.cancel();
_aiResponseSubscription?.cancel();
// 停止TTS
if (_ttsService.isPlaying) {
_ttsService.stop();
}
// 停止语音识别
// if (isListening.value) {
// await _asrService.stopContinuousRecognition();
// isListening.value = false;
// }
// 取消定时器
_inactivityTimer?.cancel();
// 重置状态
isProcessing.value = false;
_currentAgent = null;
Logger.info('已停止后台代理交互');
} catch (e) {
Logger.error('停止交互失败', e);
}
}
}