import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; /// 微软语音识别服务 /// /// 该服务提供了通过平台通道与 Android 上的 Microsoft Speech SDK 交互的接口 class VoiceRecognitionService { static const MethodChannel _channel = MethodChannel('com.example.deep_voice/speech_recognition'); static const EventChannel _eventChannel = EventChannel('com.example.deep_voice/speech_recognition_events'); bool _isInitialized = false; late final String _subscriptionKey; late final String _serviceRegion; // 连续识别相关 bool _isContinuousRecognitionActive = false; StreamController? _eventStreamController; StreamSubscription? _eventSubscription; // 公开的事件流 Stream? _recognitionStream; Stream? get recognitionStream => _recognitionStream; // 最新的识别结果 String _latestRecognizedText = ''; String get latestRecognizedText => _latestRecognizedText; VoiceRecognitionService() { _loadConfig(); } /// 从环境变量加载配置 void _loadConfig() { _subscriptionKey = dotenv.env['AZURE_SPEECH_KEY'] ?? ''; _serviceRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? ''; if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) { throw Exception('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION'); } } /// 初始化微软语音识别 SDK /// /// 返回 true 表示初始化成功,否则抛出 PlatformException Future initialize() async { if (_isInitialized) return true; try { final bool result = await _channel.invokeMethod('initialize', { 'subscriptionKey': _subscriptionKey, 'serviceRegion': _serviceRegion, }); _isInitialized = result; return result; } on PlatformException catch (e) { print('语音识别初始化失败: ${e.message}'); _isInitialized = false; throw e; } } /// 执行一次性语音识别 /// /// 返回识别的文本,如果识别失败则抛出 PlatformException Future recognizeSpeech() async { if (!_isInitialized) { throw Exception('语音识别服务未初始化,请先调用 initialize()'); } try { final String result = await _channel.invokeMethod('recognizeOnce'); return result; } on PlatformException catch (e) { print('语音识别失败: ${e.message}'); throw e; } } /// 开始连续语音识别 /// /// 返回一个包含识别事件的流,如果开始失败则抛出 PlatformException Future> startContinuousRecognition() async { if (!_isInitialized) { throw Exception('语音识别服务未初始化,请先调用 initialize()'); } if (_isContinuousRecognitionActive) { throw Exception('连续语音识别已经在进行中'); } try { // 创建事件流控制器 _eventStreamController = StreamController.broadcast(); // 设置事件监听 _eventSubscription = _eventChannel .receiveBroadcastStream() .listen(_handleRecognitionEvent, onError: _handleRecognitionError); // 开始连续识别 final bool result = await _channel.invokeMethod('startContinuousRecognition'); _isContinuousRecognitionActive = result; // 设置公开的流 _recognitionStream = _eventStreamController!.stream; return _recognitionStream!; } on PlatformException catch (e) { print('开始连续语音识别失败: ${e.message}'); _cleanupEventStream(); throw e; } } /// 停止连续语音识别 /// /// 返回 true 表示停止成功,否则抛出 PlatformException Future stopContinuousRecognition() async { if (!_isInitialized) { throw Exception('语音识别服务未初始化,请先调用 initialize()'); } if (!_isContinuousRecognitionActive) { return true; // 已经停止,直接返回成功 } try { final bool result = await _channel.invokeMethod('stopContinuousRecognition'); _isContinuousRecognitionActive = !result; // 清理事件流 _cleanupEventStream(); return result; } on PlatformException catch (e) { print('停止连续语音识别失败: ${e.message}'); throw e; } } /// 检查连续识别是否活跃 bool isContinuousRecognitionActive() { return _isContinuousRecognitionActive; } /// 处理来自原生端的识别事件 void _handleRecognitionEvent(dynamic event) { if (event is! Map) return; final Map eventMap = event; final String eventType = eventMap['eventType'] as String? ?? ''; switch (eventType) { case 'finalResult': final String text = eventMap['text'] as String? ?? ''; _latestRecognizedText = text; _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.finalResult, text: text, )); break; case 'intermediateResult': final String text = eventMap['text'] as String? ?? ''; _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.intermediateResult, text: text, )); break; case 'sessionStarted': _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.sessionStarted, )); break; case 'sessionStopped': _isContinuousRecognitionActive = false; _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.sessionStopped, )); break; case 'canceled': _isContinuousRecognitionActive = false; final String reason = eventMap['reason'] as String? ?? ''; final String errorDetails = eventMap['errorDetails'] as String? ?? ''; _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.canceled, error: '$reason: $errorDetails', )); break; case 'error': final String error = eventMap['error'] as String? ?? ''; _eventStreamController?.add(RecognitionEvent( type: RecognitionEventType.error, error: error, )); break; } } /// 处理识别事件流错误 void _handleRecognitionError(Object error) { _eventStreamController?.addError(error); _cleanupEventStream(); } /// 清理事件流资源 void _cleanupEventStream() { _eventSubscription?.cancel(); _eventSubscription = null; _eventStreamController?.close(); _eventStreamController = null; _recognitionStream = null; _isContinuousRecognitionActive = false; } /// 释放资源 Future dispose() async { try { if (_isContinuousRecognitionActive) { await stopContinuousRecognition(); } await _channel.invokeMethod('dispose'); _cleanupEventStream(); _isInitialized = false; } catch (e) { print('释放语音识别资源失败: $e'); } } } /// 识别事件类型 enum RecognitionEventType { /// 最终识别结果 finalResult, /// 中间识别结果(实时反馈) intermediateResult, /// 会话开始 sessionStarted, /// 会话结束 sessionStopped, /// 识别取消 canceled, /// 识别错误 error, } /// 识别事件 class RecognitionEvent { /// 事件类型 final RecognitionEventType type; /// 识别文本(仅在 finalResult 和 intermediateResult 类型中有效) final String text; /// 错误信息(仅在 error 和 canceled 类型中有效) final String error; RecognitionEvent({ required this.type, this.text = '', this.error = '', }); @override String toString() { return 'RecognitionEvent{type: $type, text: $text, error: $error}'; } }