import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:speech_to_text/speech_to_text.dart'; import 'package:speech_to_text/speech_recognition_result.dart'; import '../../core/utils/logger.dart'; /// ASR状态枚举 enum AsrState { notInitialized, // 未初始化 initialized, // 已初始化 listening, // 正在监听 notListening, // 未监听 error // 错误状态 } /// Flutter ASR服务,负责本地语音转文本功能 class FlutterAsrService extends GetxService { // 语音识别实例 late SpeechToText _speech; // 当前ASR状态 final Rx _asrState = AsrState.notInitialized.obs; AsrState get asrState => _asrState.value; // 可用的语音识别语言 final RxList _locales = [].obs; List get locales => _locales; // 当前选择的语言 final RxString _currentLocale = ''.obs; String get currentLocale => _currentLocale.value; // 识别结果 final RxString _lastWords = ''.obs; String get lastWords => _lastWords.value; // 识别准确度 final RxDouble _confidence = 0.0.obs; double get confidence => _confidence.value; // 是否可用 final RxBool _isAvailable = false.obs; bool get isAvailable => _isAvailable.value; // 是否正在监听 bool get isListening => _speech.isListening; // 识别结果流 final _recognitionResultsController = StreamController.broadcast(); Stream get recognitionResults => _recognitionResultsController.stream; @override void onInit() { super.onInit(); _initSpeech(); } /// 初始化语音识别 Future _initSpeech() async { _speech = SpeechToText(); try { final available = await _speech.initialize( onStatus: _onStatusChanged, onError: _onErrorListener, debugLogging: kDebugMode, ); _isAvailable.value = available; if (available) { _asrState.value = AsrState.initialized; // 获取可用的语言 final locales = await _speech.locales(); _locales.assignAll(locales); // 默认选择系统语言,如果支持的话 final systemLocale = await _speech.systemLocale(); if (systemLocale != null) { _currentLocale.value = systemLocale.localeId; } else if (_locales.isNotEmpty) { _currentLocale.value = _locales.first.localeId; } Logger.info('语音识别初始化成功,可用语言数量: ${_locales.length}'); } else { _asrState.value = AsrState.error; Logger.error('语音识别不可用'); } } catch (e) { _asrState.value = AsrState.error; _isAvailable.value = false; Logger.error('语音识别初始化失败: $e'); } } /// 开始监听 /// /// [listenFor] 监听时长,默认30秒 /// [pauseFor] 暂停时长,默认3秒,超过此时长无语音输入会自动停止 /// [partialResults] 是否返回部分结果,默认true /// [onDevice] 是否使用设备本地识别,默认false /// [listenMode] 监听模式,默认设备默认模式 Future startListening({ Duration listenFor = const Duration(seconds: 30), Duration pauseFor = const Duration(seconds: 3), bool partialResults = true, bool onDevice = false, ListenMode listenMode = ListenMode.deviceDefault, }) async { if (!_isAvailable.value) { Logger.error('语音识别不可用,无法开始监听'); return false; } // 清空上次的识别结果 _lastWords.value = ''; _confidence.value = 0.0; try { final started = await _speech.listen( onResult: _onSpeechResult, listenFor: listenFor, pauseFor: pauseFor, localeId: _currentLocale.value, listenOptions: SpeechListenOptions( partialResults: partialResults, onDevice: onDevice, listenMode: listenMode, ), ); if (started) { _asrState.value = AsrState.listening; Logger.info('开始语音识别监听'); } else { Logger.error('开始语音识别监听失败'); } return started; } catch (e) { Logger.error('开始语音识别监听出错: $e'); return false; } } /// 停止监听 Future stopListening() async { if (!_speech.isListening) return; try { await _speech.stop(); _asrState.value = AsrState.notListening; Logger.info('停止语音识别监听'); } catch (e) { Logger.error('停止语音识别监听出错: $e'); } } /// 取消监听 Future cancelListening() async { if (!_speech.isListening) return; try { await _speech.cancel(); _lastWords.value = ''; _confidence.value = 0.0; _asrState.value = AsrState.notListening; Logger.info('取消语音识别监听'); } catch (e) { Logger.error('取消语音识别监听出错: $e'); } } /// 设置当前语言 void setLocale(String localeId) { if (_currentLocale.value != localeId) { _currentLocale.value = localeId; Logger.info('设置语音识别语言: $localeId'); } } /// 语音识别结果回调 void _onSpeechResult(SpeechRecognitionResult result) { final resultText = result.recognizedWords; _lastWords.value = resultText; if (result.finalResult) { // 计算置信度 - 仅在最终结果时有效 if (result.alternates.isNotEmpty) { _confidence.value = result.alternates.first.confidence; } // 发送最终结果到流 _recognitionResultsController.add(resultText); Logger.info('语音识别最终结果: "$resultText", 置信度: ${_confidence.value}'); _asrState.value = AsrState.notListening; } else { // 部分结果 Logger.info('语音识别部分结果: "$resultText"'); } } /// 状态变化回调 void _onStatusChanged(String status) { Logger.info('语音识别状态变化: $status'); switch (status) { case 'listening': _asrState.value = AsrState.listening; break; case 'notListening': _asrState.value = AsrState.notListening; break; case 'done': _asrState.value = AsrState.notListening; break; } } /// 错误回调 void _onErrorListener(dynamic error) { Logger.error('语音识别错误: ${error.errorMsg}'); _asrState.value = AsrState.error; } @override void onClose() { _speech.cancel(); _recognitionResultsController.close(); super.onClose(); } }