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.
248 lines
6.9 KiB
248 lines
6.9 KiB
import 'package:flutter/services.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
import '../services/azure_asr_service.dart';
|
|
import '../services/azure_tts_service.dart';
|
|
import '../services/chat_history_service.dart';
|
|
import '../../modules/chat/models/message_model.dart';
|
|
import '../../core/utils/logger.dart';
|
|
|
|
/// 语音交互服务,用于管理原生的 VoiceInteractionService
|
|
class VoiceInteractionService extends GetxService {
|
|
static VoiceInteractionService get to => Get.find();
|
|
|
|
// 服务运行状态
|
|
final _isRunning = false.obs;
|
|
bool get isRunning => _isRunning.value;
|
|
|
|
// 语音识别状态
|
|
final _isRecognitionActive = false.obs;
|
|
bool get isRecognitionActive => _isRecognitionActive.value;
|
|
|
|
// 聊天记录 - 可被 ChatView 监听
|
|
final RxList<Message> personalAssistantMessages = <Message>[].obs;
|
|
|
|
// 方法通道
|
|
final MethodChannel _channel = const MethodChannel('com.deep_voice.voice_interaction');
|
|
|
|
// 事件通道
|
|
final EventChannel _eventChannel = const EventChannel('com.deep_voice.voice_interaction_events');
|
|
|
|
// 事件流订阅
|
|
Stream<dynamic>? _eventStream;
|
|
|
|
// 初始化标记,避免重复初始化
|
|
static bool _isInitialized = false;
|
|
|
|
/// 初始化服务
|
|
Future<VoiceInteractionService> init() async {
|
|
// 如果已经初始化过,直接返回
|
|
if (_isInitialized) {
|
|
return this;
|
|
}
|
|
|
|
try {
|
|
// 获取服务运行状态
|
|
await _updateServiceStatus();
|
|
|
|
// 设置事件监听
|
|
_setupEventChannel();
|
|
|
|
// 加载个人助手的历史记录
|
|
_loadPersonalAssistantHistory();
|
|
|
|
// 标记为已初始化
|
|
_isInitialized = true;
|
|
return this;
|
|
} catch (e) {
|
|
Logger.error('VoiceInteractionService 初始化失败', e);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/// 加载个人助手的历史记录
|
|
void _loadPersonalAssistantHistory() {
|
|
if (Get.isRegistered<ChatHistoryService>()) {
|
|
final historyService = Get.find<ChatHistoryService>();
|
|
final messages = historyService.loadHistory('personal_assistant');
|
|
if (messages.isNotEmpty) {
|
|
personalAssistantMessages.assignAll(messages);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 设置事件通道监听
|
|
void _setupEventChannel() {
|
|
try {
|
|
_eventStream = _eventChannel.receiveBroadcastStream();
|
|
_eventStream?.listen(
|
|
_handleEvent,
|
|
onError: (error) {
|
|
Logger.error('语音交互事件通道错误', error);
|
|
}
|
|
);
|
|
} catch (e) {
|
|
Logger.error('设置事件通道监听失败', e);
|
|
}
|
|
}
|
|
|
|
/// 处理来自原生端的事件
|
|
void _handleEvent(dynamic event) {
|
|
try {
|
|
if (event is! Map) {
|
|
return;
|
|
}
|
|
|
|
final type = event['type'] as String?;
|
|
if (type == null) {
|
|
return;
|
|
}
|
|
|
|
switch (type) {
|
|
case 'channelReady':
|
|
break;
|
|
case 'recognitionStarted':
|
|
_isRecognitionActive.value = true;
|
|
|
|
// 检测到后台服务的语音识别开始运行,主动停止Flutter端的语音识别和TTS
|
|
// _stopFlutterVoiceServices();
|
|
break;
|
|
case 'chatHistory':
|
|
// 处理聊天记录
|
|
_handleChatHistory(event);
|
|
break;
|
|
}
|
|
} catch (e) {
|
|
Logger.error('处理原生端事件时出错', e);
|
|
}
|
|
}
|
|
|
|
/// 处理聊天记录事件
|
|
void _handleChatHistory(Map<dynamic, dynamic> event) {
|
|
try {
|
|
final agentId = event['agentId'] as String?;
|
|
final userMessage = event['userMessage'] as String?;
|
|
final assistantMessage = event['assistantMessage'] as String?;
|
|
final timestamp = event['timestamp'] as int?;
|
|
|
|
if (agentId == null || userMessage == null || assistantMessage == null || timestamp == null) {
|
|
return;
|
|
}
|
|
|
|
// 只处理个人助手的聊天记录
|
|
if (agentId != 'personal_assistant') {
|
|
return;
|
|
}
|
|
|
|
// 添加用户消息
|
|
personalAssistantMessages.add(Message(
|
|
role: 'user',
|
|
content: userMessage,
|
|
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp),
|
|
));
|
|
|
|
// 添加助手消息
|
|
personalAssistantMessages.add(Message(
|
|
role: 'assistant',
|
|
content: assistantMessage,
|
|
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp + 1000), // 助手消息时间戳稍后
|
|
));
|
|
|
|
// 保存到历史记录
|
|
if (Get.isRegistered<ChatHistoryService>()) {
|
|
final historyService = Get.find<ChatHistoryService>();
|
|
historyService.saveHistory('personal_assistant', personalAssistantMessages);
|
|
}
|
|
} catch (e) {
|
|
Logger.error('处理聊天记录事件失败', e);
|
|
}
|
|
}
|
|
|
|
/// 停止 Flutter 端的语音服务
|
|
void _stopFlutterVoiceServices() {
|
|
// 停止 TTS
|
|
if (Get.isRegistered<AzureTtsService>()) {
|
|
Get.find<AzureTtsService>().stop();
|
|
}
|
|
|
|
// 停止 ASR
|
|
if (Get.isRegistered<AzureAsrService>()) {
|
|
Get.find<AzureAsrService>().stopContinuousRecognition();
|
|
}
|
|
}
|
|
|
|
/// 启动语音交互服务
|
|
Future<bool> startService() async {
|
|
try {
|
|
// 获取 Azure 配置
|
|
final azureKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
|
|
final azureRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
|
|
|
|
// 获取火山 AI 配置
|
|
final volcanoApiKey = dotenv.env['VOLCANO_AI_API_KEY'] ?? '';
|
|
|
|
// 启动服务
|
|
final result = await _channel.invokeMethod<bool>('startVoiceInteractionService', {
|
|
'azure_speech_key': azureKey,
|
|
'azure_speech_region': azureRegion,
|
|
'volcano_ai_api_key': volcanoApiKey,
|
|
}) ?? false;
|
|
|
|
// 更新状态
|
|
if (result) {
|
|
await _updateServiceStatus();
|
|
}
|
|
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('启动语音交互服务失败', e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 停止语音交互服务
|
|
Future<bool> stopService() async {
|
|
try {
|
|
final result = await _channel.invokeMethod<bool>('stopVoiceInteractionService') ?? false;
|
|
|
|
// 更新状态
|
|
if (result) {
|
|
await _updateServiceStatus();
|
|
}
|
|
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('停止语音交互服务失败', e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 暂停语音交互
|
|
Future<bool> pauseVoiceInteraction() async {
|
|
try {
|
|
final result = await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false;
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('暂停语音交互失败', e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 更新服务运行状态
|
|
Future<void> _updateServiceStatus() async {
|
|
try {
|
|
final status = await _channel.invokeMethod<bool>('isVoiceInteractionServiceRunning') ?? false;
|
|
_isRunning.value = status;
|
|
} catch (e) {
|
|
Logger.error('获取语音交互服务状态失败', e);
|
|
_isRunning.value = false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
// 清理资源
|
|
_eventStream = null;
|
|
super.onClose();
|
|
}
|
|
}
|