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.

264 lines
6.8 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';
/// 火山语音识别服务
/// 负责与原生层的火山语音识别引擎交互
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;
@override
void onInit() {
super.onInit();
_loadCredentials();
_setupEventListener();
}
/// 加载火山语音识别的凭证
void _loadCredentials() {
try {
_appKey = dotenv.env['VOLC_SPEECH_APP_KEY'] ?? '';
_accessKey = dotenv.env['VOLC_SPEECH_ACCESS_KEY'] ?? '';
if (_appKey.isEmpty || _accessKey.isEmpty) {
debugPrint('警告: 火山语音识别凭证未设置,请在 .env 文件中设置 VOLC_SPEECH_APP_KEY 和 VOLC_SPEECH_ACCESS_KEY');
}
} catch (e) {
debugPrint('加载火山语音识别凭证失败: $e');
}
}
/// 设置事件监听器
void _setupEventListener() {
try {
_eventSubscription = _eventChannel.receiveBroadcastStream().listen(
(dynamic event) {
_handleEvent(event.toString());
},
onError: (dynamic error) {
debugPrint('事件通道错误: $error');
if (onError != null) {
onError!('事件通道错误: $error');
}
},
);
} catch (e) {
debugPrint('设置事件监听器失败: $e');
}
}
/// 处理来自原生层的事件
void _handleEvent(String eventJson) {
try {
final eventData = jsonDecode(eventJson);
final eventName = eventData['event'];
final data = eventData['data'];
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;
}
} catch (e) {
debugPrint('处理事件失败: $e');
}
}
/// 处理状态事件
void _handleStatusEvent(String status) {
switch (status) {
case 'initialized':
isInitialized.value = true;
isConnecting.value = false;
break;
case 'listening':
isListening.value = true;
break;
case 'idle':
isListening.value = false;
break;
}
if (onConnectionStatusChanged != null) {
onConnectionStatusChanged!(status);
}
}
/// 处理识别结果事件
void _handleResultEvent(String resultJson) {
try {
final resultData = jsonDecode(resultJson);
final text = resultData['text'];
final isFinal = resultData['isFinal'];
// 更新识别文本
recognizedText.value = text;
// 调用回调函数
if (onRecognitionResult != null) {
onRecognitionResult!(text);
}
// 如果是最终结果,调用完成回调
if (isFinal && text.isNotEmpty) {
if (onSentenceComplete != null) {
onSentenceComplete!(text);
}
if (onRecognitionComplete != null) {
onRecognitionComplete!();
}
}
} catch (e) {
debugPrint('处理识别结果失败: $e');
}
}
/// 处理错误事件
void _handleErrorEvent(String errorJson) {
try {
final errorData = jsonDecode(errorJson);
final errorMessage = errorData['message'];
debugPrint('语音识别错误: $errorMessage');
if (onError != null) {
onError!(errorMessage);
}
} catch (e) {
debugPrint('处理错误事件失败: $e');
}
}
/// 处理 VAD 事件
void _handleVadEvent(String vadState) {
// 可以根据需要处理 VAD 状态变化
debugPrint('VAD 状态: $vadState');
}
/// 初始化语音识别引擎
Future<void> initialize() async {
try {
isConnecting.value = true;
// 检查凭证
if (_appKey.isEmpty || _accessKey.isEmpty) {
throw '火山语音识别凭证未设置';
}
// 调用原生方法初始化引擎
final result = await _methodChannel.invokeMethod<String>(
'initialize',
{
'appKey': _appKey,
'accessKey': _accessKey,
},
);
debugPrint('初始化结果: $result');
// 初始化成功后,状态会通过事件通道更新
} catch (e) {
isConnecting.value = false;
debugPrint('初始化语音识别引擎失败: $e');
if (onError != null) {
onError!('初始化失败: $e');
}
rethrow;
}
}
/// 开始语音识别
Future<void> startRecognition() async {
try {
// 检查是否已初始化
if (!isInitialized.value) {
await initialize();
}
// 调用原生方法开始识别
final result = await _methodChannel.invokeMethod<String>('startRecognition');
debugPrint('开始识别结果: $result');
// 状态会通过事件通道更新
} catch (e) {
debugPrint('开始语音识别失败: $e');
if (onError != null) {
onError!('开始识别失败: $e');
}
rethrow;
}
}
/// 停止语音识别
Future<void> stopRecognition() async {
try {
// 检查是否已初始化
if (!isInitialized.value) {
return;
}
// 调用原生方法停止识别
final result = await _methodChannel.invokeMethod<String>('stopRecognition');
debugPrint('停止识别结果: $result');
// 状态会通过事件通道更新
} catch (e) {
debugPrint('停止语音识别失败: $e');
if (onError != null) {
onError!('停止识别失败: $e');
}
}
}
@override
void onClose() {
// 取消事件订阅
_eventSubscription?.cancel();
// 停止识别
stopRecognition();
super.onClose();
}
}