import 'dart:async'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import '../services/azure_asr_service.dart'; import '../services/azure_tts_service.dart'; import '../services/chat_history_service.dart'; import '../../modules/chat/models/message_model.dart'; import '../../core/utils/logger.dart'; /// 语音交互服务,用于管理原生的 VoiceInteractionService class VoiceInteractionService extends GetxService { static VoiceInteractionService get to => Get.find(); // 服务运行状态 final _isRunning = false.obs; bool get isRunning => _isRunning.value; // 语音识别状态 final _isRecognitionActive = false.obs; bool get isRecognitionActive => _isRecognitionActive.value; // 聊天记录 - 可被 ChatView 监听 final RxList personalAssistantMessages = [].obs; // 方法通道 static const MethodChannel _channel = MethodChannel('com.deep_voice.voice_interaction'); // 事件通道 static const EventChannel _eventChannel = EventChannel('com.deep_voice.voice_interaction_events'); // 配置信息 late final String _azureSpeechKey; late final String _azureSpeechRegion; late final String _volcanoAiApiKey; // 事件通道状态 bool _isEventChannelReady = false; Completer? _eventChannelReadyCompleter; // 初始化标记,避免重复初始化 bool _isInitialized = false; VoiceInteractionService() { _loadConfig(); _setupEventChannel(); } /// 从环境变量加载配置 void _loadConfig() { _azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? ''; _azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? ''; _volcanoAiApiKey = dotenv.env['VOLCANO_AI_API_KEY'] ?? ''; if (_azureSpeechKey.isEmpty || _azureSpeechRegion.isEmpty) { Logger.error('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION'); } if (_volcanoAiApiKey.isEmpty) { Logger.error('未找到火山 AI 配置。请在 .env 文件中设置 VOLCANO_AI_API_KEY'); } } /// 设置事件通道监听 void _setupEventChannel() { _eventChannelReadyCompleter = Completer(); _eventChannel.receiveBroadcastStream().listen( (event) { if (event is Map) { final String eventType = event['type'] as String? ?? ''; // 处理通道准备好的事件 if (eventType == 'channelReady') { _isEventChannelReady = true; if (!_eventChannelReadyCompleter!.isCompleted) { _eventChannelReadyCompleter!.complete(); } return; } _handleEvent(event); } }, onError: (error) { Logger.error('语音交互事件通道错误: $error'); } ); } /// 等待事件通道准备好 Future _waitForEventChannel({Duration timeout = const Duration(seconds: 5)}) async { if (_isEventChannelReady) return true; try { await _eventChannelReadyCompleter!.future.timeout(timeout); return true; } on TimeoutException { Logger.error('等待事件通道准备好超时'); return false; } } /// 初始化服务 Future init() async { // 如果已经初始化过,直接返回 if (_isInitialized) { return this; } try { // 等待事件通道准备好 final bool eventChannelReady = await _waitForEventChannel(); if (!eventChannelReady) { Logger.error('事件通道未准备好,初始化失败'); return this; } // 获取服务运行状态 await _updateServiceStatus(); // 加载个人助手的历史记录 _loadPersonalAssistantHistory(); // 标记为已初始化 _isInitialized = true; return this; } catch (e) { Logger.error('VoiceInteractionService 初始化失败: $e'); return this; } } /// 加载个人助手的历史记录 void _loadPersonalAssistantHistory() { if (Get.isRegistered()) { final historyService = Get.find(); final messages = historyService.loadHistory('personal_assistant'); if (messages.isNotEmpty) { personalAssistantMessages.assignAll(messages); } } } /// 处理来自原生端的事件 void _handleEvent(dynamic event) { try { if (event is! Map) { return; } final type = event['type'] as String?; if (type == null) { return; } switch (type) { case 'recognitionStarted': _isRecognitionActive.value = true; // 检测到后台服务的语音识别开始运行,主动停止Flutter端的语音识别和TTS // _stopFlutterVoiceServices(); break; case 'chatHistory': // 处理聊天记录 _handleChatHistory(event); break; } } catch (e) { Logger.error('处理原生端事件时出错: $e'); } } /// 处理聊天记录事件 void _handleChatHistory(Map event) { try { final agentId = event['agentId'] as String?; final userMessage = event['userMessage'] as String?; final assistantMessage = event['assistantMessage'] as String?; final timestamp = event['timestamp'] as int?; if (agentId == null || userMessage == null || assistantMessage == null || timestamp == null) { return; } // 只处理个人助手的聊天记录 if (agentId != 'personal_assistant') { return; } // 添加用户消息 personalAssistantMessages.add(Message( role: 'user', content: userMessage, timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp), )); // 添加助手消息 personalAssistantMessages.add(Message( role: 'assistant', content: assistantMessage, timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp + 1000), // 助手消息时间戳稍后 )); // 保存到历史记录 if (Get.isRegistered()) { final historyService = Get.find(); historyService.saveHistory('personal_assistant', personalAssistantMessages); } } catch (e) { Logger.error('处理聊天记录事件失败: $e'); } } /// 停止 Flutter 端的语音服务 void _stopFlutterVoiceServices() { // 停止 TTS if (Get.isRegistered()) { Get.find().stop(); } // 停止 ASR if (Get.isRegistered()) { Get.find().stopContinuousRecognition(); } } /// 启动语音交互服务 Future startService() async { if (!_isInitialized) { await init(); } try { // 启动服务 final result = await _channel.invokeMethod('startVoiceInteractionService', { 'azure_speech_key': _azureSpeechKey, 'azure_speech_region': _azureSpeechRegion, 'volcano_ai_api_key': _volcanoAiApiKey, }) ?? false; // 更新状态 if (result) { await _updateServiceStatus(); } return result; } catch (e) { Logger.error('启动语音交互服务失败: $e'); return false; } } /// 停止语音交互服务 Future stopService() async { try { final result = await _channel.invokeMethod('stopVoiceInteractionService') ?? false; // 更新状态 if (result) { await _updateServiceStatus(); } return result; } catch (e) { Logger.error('停止语音交互服务失败: $e'); return false; } } /// 暂停语音交互 Future pauseVoiceInteraction() async { try { final result = await _channel.invokeMethod('pauseVoiceInteraction') ?? false; return result; } catch (e) { Logger.error('暂停语音交互失败: $e'); return false; } } /// 更新服务运行状态 Future _updateServiceStatus() async { try { final status = await _channel.invokeMethod('isVoiceInteractionServiceRunning') ?? false; _isRunning.value = status; } catch (e) { Logger.error('获取语音交互服务状态失败: $e'); _isRunning.value = false; } } /// 释放资源 Future dispose() async { try { if (_isRunning.value) { await stopService(); } _isInitialized = false; } catch (e) { Logger.error('释放语音交互服务资源失败: $e'); } } @override void onClose() { // 清理资源 dispose(); super.onClose(); } }