import 'dart:async'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import '../models/events/voice_interaction_event.dart'; import '../../core/utils/logger.dart'; import '../../modules/chat/models/message_model.dart'; import 'chat_history_service.dart'; /// 语音交互服务接口 /// /// 管理与平台原生语音交互服务的通信,提供统一的接口供应用使用 class VoiceInteractionService extends GetxService { static VoiceInteractionService get to => Get.find(); // 方法通道 static const MethodChannel _channel = MethodChannel('com.deep_voice.voice_interaction'); // 事件通道 static const EventChannel _eventChannel = EventChannel('com.deep_voice.voice_interaction_events'); // 服务状态 final _isServiceRunning = false.obs; bool get isServiceRunning => _isServiceRunning.value; // 流控制器 final _eventStreamController = StreamController.broadcast(); // 事件流 Stream get eventStream => _eventStreamController.stream; // 事件通道订阅 StreamSubscription? _eventSubscription; // 标记是否初始化 bool _isInitialized = false; // 配置信息 late String _azureSpeechKey; late String _azureSpeechRegion; late String _openaiApiKey; late String _openaiBaseUrl; // 聊天历史服务 late final ChatHistoryService _chatHistoryService; /// 设置事件通道 void _setupEventChannel() { _eventSubscription = _eventChannel .receiveBroadcastStream() .listen(_handleVoiceInteractionEvent, onError: (error) { Logger.error('语音交互事件通道错误: $error'); }); } /// 从环境变量加载配置 void _loadConfig() { _azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? ''; _azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? ''; _openaiApiKey = dotenv.env['OPENAI_API_KEY'] ?? ''; _openaiBaseUrl = dotenv.env['OPENAI_BASE_URL'] ?? ''; if (_azureSpeechKey.isEmpty || _azureSpeechRegion.isEmpty) { Logger.warning('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION'); } } /// 处理来自原生层的事件 void _handleVoiceInteractionEvent(dynamic event) { if (event is! Map) return; final eventMap = event as Map; final String eventType = eventMap['type'] as String? ?? ''; // final int timestamp = eventMap['timestamp'] as int? ?? DateTime.now().millisecondsSinceEpoch; Logger.info('收到语音交互事件: $eventType'); switch (eventType) { case 'recognition_started': // 语音识别开始事件 final recognitionEvent = RecognitionStartedEvent( timestamp: DateTime.now().millisecondsSinceEpoch, ); _eventStreamController.add(recognitionEvent); break; case 'chat_history_updated': // 聊天历史更新事件 final String agentId = eventMap['agentId'] as String? ?? ''; final String userMessage = eventMap['userMessage'] as String? ?? ''; final String assistantMessage = eventMap['assistantMessage'] as String? ?? ''; final chatHistoryEvent = ChatHistoryEvent( agentId: agentId, userMessage: userMessage, assistantMessage: assistantMessage, timestamp: DateTime.now().millisecondsSinceEpoch, ); _eventStreamController.add(chatHistoryEvent); // 保存聊天历史到ChatHistoryService _saveChatHistory(agentId, userMessage, assistantMessage, DateTime.now().millisecondsSinceEpoch); break; } } /// 保存聊天历史 void _saveChatHistory(String agentId, String userMessage, String assistantMessage, int timestamp) { try { // 检查参数有效性 if (userMessage.isEmpty) { return; } // 创建用户消息和助手消息 final userMsg = Message( role: 'user', content: userMessage, timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp), ); final assistantMsg = Message( role: 'assistant', content: assistantMessage, timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp + 1), // 确保助手消息时间戳晚于用户消息 ); // 加载现有历史记录 final existingMessages = _chatHistoryService.loadHistory(agentId); // 添加新消息 existingMessages.addAll([userMsg, assistantMsg]); // 保存更新后的历史记录 _chatHistoryService.saveHistory(agentId, existingMessages); Logger.info('已保存聊天历史: agentId=$agentId'); } catch (e) { Logger.error('保存聊天历史失败: $e'); } } /// 初始化服务 Future initialize() async { if (_isInitialized) return true; try { Logger.info('正在初始化语音交互服务...'); // 获取聊天历史服务 try { _chatHistoryService = Get.find(); } catch (e) { Logger.warning('获取ChatHistoryService失败,将创建新实例'); _chatHistoryService = Get.put(ChatHistoryService()); } // 设置事件通道 _setupEventChannel(); // 加载配置 _loadConfig(); // 检查服务是否已在运行 final bool running = await checkServiceStatus(); // 如果服务未运行,启动服务 if (!running) { // 启动语音交互服务 final success = await startService(); if (!success) { Logger.error('语音交互服务启动失败'); return false; } } _isInitialized = true; Logger.info('语音交互服务初始化完成'); return true; } catch (e) { Logger.error('语音交互服务初始化失败: $e'); return false; } } /// 启动语音交互服务 Future startService() async { try { Logger.info('启动语音交互服务...'); // 使用已加载的配置信息 final result = await _channel.invokeMethod('startService', { 'azure_speech_key': _azureSpeechKey, 'azure_speech_region': _azureSpeechRegion, 'openai_api_key': _openaiApiKey, 'openai_base_url': _openaiBaseUrl, }) ?? false; if (result) { _isServiceRunning.value = true; Logger.info('语音交互服务已启动'); } else { Logger.error('启动语音交互服务失败'); } return result; } catch (e) { Logger.error('启动语音交互服务时发生错误: $e'); return false; } } /// 停止语音交互服务 Future stopService() async { try { Logger.info('停止语音交互服务...'); final result = await _channel.invokeMethod('stopService') ?? false; if (result) { _isServiceRunning.value = false; Logger.info('语音交互服务已停止'); } else { Logger.error('停止语音交互服务失败'); } return result; } catch (e) { Logger.error('停止语音交互服务时发生错误: $e'); return false; } } /// 检查服务是否运行 Future checkServiceStatus() async { try { final bool result = await _channel.invokeMethod('isServiceRunning') ?? false; _isServiceRunning.value = result; return result; } catch (e) { Logger.error('检查服务状态时发生错误: $e'); return false; } } /// 暂停语音交互 Future pauseVoiceInteraction() async { try { Logger.info('暂停后台语音交互...'); final result = await _channel.invokeMethod('pauseVoiceInteraction') ?? false; if (result) { Logger.info('语音交互已暂停'); } else { Logger.error('暂停语音交互失败'); } return result; } catch (e) { Logger.error('暂停语音交互时发生错误: $e'); return false; } } /// 资源释放 @override void onClose() { _eventSubscription?.cancel(); _eventStreamController.close(); super.onClose(); } }