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.

391 lines
15 KiB

import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'dart:developer' as developer;
/// 火山语音识别服务
/// 负责与原生层的火山语音识别引擎交互
class VoiceRecognitionService extends GetxService {
// 方法通道,用于调用原生方法
static const MethodChannel _methodChannel =
MethodChannel('com.example.deep_voice/speech_recognition');
// 事件通道,用于接收原生层的事件
static const EventChannel _eventChannel =
EventChannel('com.example.deep_voice/speech_recognition_events');
// 状态变量
final isInitialized = false.obs;
final isListening = false.obs;
final isConnecting = true.obs;
// 识别结果
final recognizedText = ''.obs;
// 回调函数
Function(String)? onRecognitionResult;
Function(String)? onError;
Function()? onRecognitionComplete;
Function(String)? onConnectionStatusChanged;
Function(String)? onSentenceComplete;
// 事件流订阅
StreamSubscription? _eventSubscription;
// 火山语音识别的 AppKey 和 AccessKey
late final String _appKey;
late final String _accessKey;
late final String _cluster;
@override
void onInit() {
developer.log('VoiceRecognitionService: 初始化服务', name: 'VoiceRecognition');
super.onInit();
_loadCredentials();
_setupEventListener();
}
/// 加载火山语音识别的凭证
void _loadCredentials() {
try {
_appKey = dotenv.env['VOLC_SPEECH_APP_KEY'] ?? '';
_accessKey = dotenv.env['VOLC_SPEECH_ACCESS_KEY'] ?? '';
_cluster = dotenv.env['VOLC_SPEECH_CLUSTER'] ?? 'volcano_asr';
developer.log('VoiceRecognitionService: 加载凭证 - AppKey: ${_appKey.isNotEmpty ? '已设置' : '未设置'}, AccessKey: ${_accessKey.isNotEmpty ? '已设置' : '未设置'}, Cluster: $_cluster', name: 'VoiceRecognition');
if (_appKey.isEmpty || _accessKey.isEmpty) {
developer.log('VoiceRecognitionService: 警告 - 火山语音识别凭证未设置,请在 .env 文件中设置 VOLC_SPEECH_APP_KEY 和 VOLC_SPEECH_ACCESS_KEY', name: 'VoiceRecognition');
}
} catch (e, stack) {
developer.log('VoiceRecognitionService: 加载火山语音识别凭证失败: $e', name: 'VoiceRecognition');
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 设置事件监听器
void _setupEventListener() {
try {
developer.log('VoiceRecognitionService: 设置事件监听器', name: 'VoiceRecognition');
_eventSubscription = _eventChannel.receiveBroadcastStream().listen(
(dynamic event) {
_handleEvent(event.toString());
},
onError: (dynamic error) {
developer.log('VoiceRecognitionService: 事件通道错误: $error', name: 'VoiceRecognition');
if (onError != null) {
onError!('事件通道错误: $error');
}
},
);
} catch (e, stack) {
developer.log('VoiceRecognitionService: 设置事件监听器失败: $e', name: 'VoiceRecognition');
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 处理来自原生层的事件
void _handleEvent(String eventJson) {
try {
developer.log('VoiceRecognitionService: 收到原始事件数据: $eventJson', name: 'VoiceRecognition');
final eventData = jsonDecode(eventJson);
final eventName = eventData['event'];
final data = eventData['data'];
developer.log('VoiceRecognitionService: 收到事件: $eventName, 数据: $data', name: 'VoiceRecognition');
switch (eventName) {
case 'status':
_handleStatusEvent(data.toString());
break;
case 'result':
_handleResultEvent(data.toString());
break;
case 'error':
_handleErrorEvent(data.toString());
break;
case 'vad':
_handleVadEvent(data.toString());
break;
default:
developer.log('VoiceRecognitionService: 未知事件类型: $eventName', name: 'VoiceRecognition');
break;
}
} catch (e, stack) {
developer.log('VoiceRecognitionService: 处理事件失败: $e', name: 'VoiceRecognition');
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 处理状态事件
void _handleStatusEvent(String status) {
developer.log('VoiceRecognitionService: 状态变更: $status', name: 'VoiceRecognition');
switch (status) {
case 'initialized':
isInitialized.value = true;
isConnecting.value = false;
developer.log('VoiceRecognitionService: 引擎初始化完成', name: 'VoiceRecognition');
break;
case 'listening':
isListening.value = true;
developer.log('VoiceRecognitionService: 开始监听', name: 'VoiceRecognition');
break;
case 'idle':
isListening.value = false;
developer.log('VoiceRecognitionService: 停止监听', name: 'VoiceRecognition');
break;
}
if (onConnectionStatusChanged != null) {
onConnectionStatusChanged!(status);
}
}
/// 处理识别结果事件
void _handleResultEvent(String resultJson) {
try {
final resultData = jsonDecode(resultJson);
final text = resultData['text'];
final isFinal = resultData['isFinal'];
developer.log('VoiceRecognitionService: 识别结果: $text, 是否最终结果: $isFinal', name: 'VoiceRecognition');
// 更新识别文本
recognizedText.value = text;
// 调用回调函数
if (onRecognitionResult != null) {
onRecognitionResult!(text);
}
// 如果是最终结果,调用完成回调
if (isFinal && text.isNotEmpty) {
developer.log('VoiceRecognitionService: 句子识别完成: $text', name: 'VoiceRecognition');
if (onSentenceComplete != null) {
onSentenceComplete!(text);
}
if (onRecognitionComplete != null) {
onRecognitionComplete!();
}
}
} catch (e, stack) {
developer.log('VoiceRecognitionService: 处理识别结果失败: $e', name: 'VoiceRecognition');
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 处理错误事件
void _handleErrorEvent(String errorJson) {
try {
final errorData = jsonDecode(errorJson);
final errorMessage = errorData['message'];
final errorCode = errorData['code'] ?? 'unknown';
developer.log('VoiceRecognitionService: 语音识别错误: 代码=$errorCode, 消息=$errorMessage', name: 'VoiceRecognition', error: errorMessage);
if (onError != null) {
onError!(errorMessage);
}
} catch (e, stack) {
developer.log('VoiceRecognitionService: 处理错误事件失败: $e', name: 'VoiceRecognition');
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 处理 VAD 事件
void _handleVadEvent(String vadState) {
// 可以根据需要处理 VAD 状态变化
developer.log('VoiceRecognitionService: VAD 状态: $vadState', name: 'VoiceRecognition');
}
/// 检查引擎能力和支持的指令
Future<void> checkEngineCapabilities() async {
try {
developer.log('VoiceRecognitionService: 检查引擎能力', name: 'VoiceRecognition');
// 检查是否已初始化
if (!isInitialized.value) {
developer.log('VoiceRecognitionService: 引擎未初始化,尝试初始化', name: 'VoiceRecognition');
await initialize();
}
// 调用原生方法检查引擎能力
final result = await _methodChannel.invokeMethod<String>('checkEngineCapabilities');
developer.log('VoiceRecognitionService: 引擎能力检查结果: $result', name: 'VoiceRecognition');
if (result != null) {
try {
final capabilities = jsonDecode(result);
developer.log('VoiceRecognitionService: 引擎版本: ${capabilities['version']}', name: 'VoiceRecognition');
if (capabilities['supported_params'] != null) {
developer.log('VoiceRecognitionService: 支持的参数: ${capabilities['supported_params']}', name: 'VoiceRecognition');
}
if (capabilities['supported_directives'] != null) {
developer.log('VoiceRecognitionService: 支持的指令: ${capabilities['supported_directives']}', name: 'VoiceRecognition');
}
} catch (e) {
developer.log('VoiceRecognitionService: 解析能力结果失败: $e', name: 'VoiceRecognition');
}
}
} catch (e, stack) {
developer.log('VoiceRecognitionService: 检查引擎能力失败: $e', name: 'VoiceRecognition', error: e);
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
}
}
/// 初始化语音识别引擎
Future<void> initialize() async {
try {
developer.log('VoiceRecognitionService: 开始初始化语音引擎', name: 'VoiceRecognition');
isConnecting.value = true;
// 检查凭证
if (_appKey.isEmpty || _accessKey.isEmpty) {
developer.log('VoiceRecognitionService: 凭证未设置,无法初始化', name: 'VoiceRecognition', error: '火山语音识别凭证未设置');
throw '火山语音识别凭证未设置';
}
// 添加详细日志
developer.log('VoiceRecognitionService: 使用凭证 AppKey: $_appKey, AccessKey: ${_accessKey.substring(0, 4)}***, Cluster: $_cluster', name: 'VoiceRecognition');
// 调用原生方法初始化引擎
try {
final result = await _methodChannel.invokeMethod<String>(
'initialize',
{
'appKey': _appKey,
'accessKey': _accessKey,
'cluster': _cluster,
},
);
developer.log('VoiceRecognitionService: 初始化结果: $result', name: 'VoiceRecognition');
// 初始化成功后,检查引擎能力
await checkEngineCapabilities();
} catch (e) {
developer.log('VoiceRecognitionService: 初始化方法调用失败: $e', name: 'VoiceRecognition', error: e);
// 尝试检查引擎是否已初始化
try {
final isEngineInitialized = await _methodChannel.invokeMethod<bool>('isInitialized') ?? false;
if (isEngineInitialized) {
developer.log('VoiceRecognitionService: 引擎已经初始化,忽略错误', name: 'VoiceRecognition');
isInitialized.value = true;
isConnecting.value = false;
// 引擎已初始化,检查引擎能力
await checkEngineCapabilities();
return;
}
} catch (checkError) {
developer.log('VoiceRecognitionService: 检查引擎初始化状态失败: $checkError', name: 'VoiceRecognition');
}
// 如果检查失败或引擎未初始化,则重新抛出异常
rethrow;
}
// 初始化成功后,状态会通过事件通道更新
} catch (e, stack) {
isConnecting.value = false;
developer.log('VoiceRecognitionService: 初始化语音识别引擎失败: $e', name: 'VoiceRecognition', error: e);
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
String errorMessage = '初始化失败: $e';
// 提供更具体的错误信息
if (e.toString().contains('error code: -7')) {
errorMessage = '初始化失败: 无法创建日志目录,请检查应用权限';
developer.log('VoiceRecognitionService: 错误代码 -7: 无法创建日志目录', name: 'VoiceRecognition');
} else if (e.toString().contains('INIT_ERROR')) {
errorMessage = '初始化失败: 引擎初始化错误,请检查网络连接和凭证';
developer.log('VoiceRecognitionService: INIT_ERROR: 引擎初始化错误', name: 'VoiceRecognition');
}
if (onError != null) {
onError!(errorMessage);
}
rethrow;
}
}
/// 开始语音识别
Future<void> startRecognition() async {
try {
developer.log('VoiceRecognitionService: 开始语音识别', name: 'VoiceRecognition');
// 检查是否已初始化
if (!isInitialized.value) {
developer.log('VoiceRecognitionService: 引擎未初始化,尝试初始化', name: 'VoiceRecognition');
await initialize();
}
developer.log('VoiceRecognitionService: 调用原生方法 startRecognition', name: 'VoiceRecognition');
// 调用原生方法开始识别
final result = await _methodChannel.invokeMethod<String>('startRecognition');
developer.log('VoiceRecognitionService: 开始识别结果: $result', name: 'VoiceRecognition');
// 状态会通过事件通道更新
} catch (e, stack) {
developer.log('VoiceRecognitionService: 开始语音识别失败: $e', name: 'VoiceRecognition', error: e);
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
if (onError != null) {
onError!('开始识别失败: $e');
}
rethrow;
}
}
/// 停止语音识别
Future<void> stopRecognition() async {
try {
developer.log('VoiceRecognitionService: 停止语音识别', name: 'VoiceRecognition');
// 检查是否已初始化
if (!isInitialized.value) {
developer.log('VoiceRecognitionService: 引擎未初始化,无法停止识别', name: 'VoiceRecognition');
return;
}
developer.log('VoiceRecognitionService: 调用原生方法 stopRecognition', name: 'VoiceRecognition');
// 调用原生方法停止识别
final result = await _methodChannel.invokeMethod<String>('stopRecognition');
developer.log('VoiceRecognitionService: 停止识别结果: $result', name: 'VoiceRecognition');
// 状态会通过事件通道更新
} catch (e, stack) {
developer.log('VoiceRecognitionService: 停止语音识别失败: $e', name: 'VoiceRecognition', error: e);
developer.log('VoiceRecognitionService: 错误堆栈: $stack', name: 'VoiceRecognition');
if (onError != null) {
onError!('停止识别失败: $e');
}
}
}
@override
void onClose() {
developer.log('VoiceRecognitionService: 关闭服务', name: 'VoiceRecognition');
// 取消事件订阅
_eventSubscription?.cancel();
// 停止识别
stopRecognition();
super.onClose();
}
}