Browse Source

v005.fix

newdev_shunjiawei
wolfplus 2 years ago
parent
commit
95fc10c7ca
  1. 45
      android/app/src/main/kotlin/com/example/deep_voice/MainActivity.kt
  2. 182
      android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt
  3. 2
      lib/core/bindings/initial_binding.dart
  4. 150
      lib/data/services/voice_interaction_service.dart
  5. 78
      lib/modules/chat/controllers/chat_controller.dart

45
android/app/src/main/kotlin/com/example/deep_voice/MainActivity.kt

@ -82,8 +82,9 @@ class MainActivity: FlutterActivity() {
// 注册广播接收器
registerVoiceInteractionReceiver()
// 不再自动启动服务,由用户通过 Flutter 界面手动启动
Log.d(TAG, "MainActivity 已创建,但不会自动启动 VoiceInteractionService")
// 自动启动语音交互服务
Log.d(TAG, "MainActivity 已创建,自动启动 VoiceInteractionService")
autoStartVoiceInteractionService()
// 确保 Flutter 引擎准备好后立即设置事件通道
flutterEngine?.let { engine ->
@ -569,6 +570,46 @@ class MainActivity: FlutterActivity() {
}
}
/**
* 自动启动语音交互服务
*/
private fun autoStartVoiceInteractionService() {
// 检查服务是否已经在运行
if (VoiceInteractionService.isServiceRunning()) {
Log.d(TAG, "语音交互服务已经在运行,无需重复启动")
return
}
Log.d(TAG, "自动启动语音交互服务")
try {
// 创建 Intent 并启动服务
val serviceIntent = Intent(this, VoiceInteractionService::class.java)
// 在 Android O 及以上版本,需要使用 startForegroundService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "使用startForegroundService启动服务")
startForegroundService(serviceIntent)
} else {
Log.d(TAG, "使用startService启动服务")
startService(serviceIntent)
}
Log.d(TAG, "语音交互服务自动启动命令已发送")
// 检查服务是否成功启动
Handler(Looper.getMainLooper()).postDelayed({
if (VoiceInteractionService.isServiceRunning()) {
Log.d(TAG, "语音交互服务已成功启动")
} else {
Log.e(TAG, "语音交互服务启动失败")
}
}, 1000)
} catch (e: Exception) {
Log.e(TAG, "启动语音交互服务时出错: ${e.message}", e)
}
}
override fun onDestroy() {
// 注销广播接收器
try {

182
android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt

@ -102,18 +102,26 @@ class VoiceInteractionService : Service() {
// 初始化组件
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
Log.d(TAG, "AudioManager初始化完成")
initServices()
initMediaSession()
registerMediaButtonReceiver()
// 设置为媒体播放状态
setPlaybackState(PlaybackStateCompat.STATE_PLAYING)
Log.d(TAG, "设置播放状态为PLAYING")
// 启动监控和前台服务
startMonitoring()
startForegroundServiceWithNotification()
Log.d(TAG, "VoiceInteractionService 初始化完成,等待蓝牙按键事件...")
// 延迟3秒后测试按键处理功能
// Handler(Looper.getMainLooper()).postDelayed({
// testMediaButtonEvent()
// }, 3000)
}
/**
@ -163,6 +171,7 @@ class VoiceInteractionService : Service() {
* 初始化 MediaSession
*/
private fun initMediaSession() {
Log.d(TAG, "开始初始化MediaSession")
mediaSession = MediaSessionCompat(applicationContext, "VoiceServiceSession")
// 设置标志和状态
@ -170,10 +179,13 @@ class VoiceInteractionService : Service() {
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)
Log.d(TAG, "MediaSession标志设置完成")
// 设置回调
mediaSession.setCallback(object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
Log.d(TAG, "收到媒体按钮事件: $mediaButtonEvent")
val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
} else {
@ -181,43 +193,75 @@ class VoiceInteractionService : Service() {
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as? KeyEvent
}
if (keyEvent != null && keyEvent.action == KeyEvent.ACTION_DOWN) {
when (keyEvent.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY,
KeyEvent.KEYCODE_MEDIA_PAUSE,
KeyEvent.KEYCODE_HEADSETHOOK,
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
// 检测双击
val currentTime = System.currentTimeMillis()
val timeDiff = currentTime - lastKeyEventTime
if (timeDiff < 500) { // 500毫秒内的按键视为连续按键
keyEventCount++
if (keyEventCount == 1) { // 这是第二次按键,即双击
handleDoubleClick()
if (keyEvent != null) {
Log.d(TAG, "解析到按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
if (keyEvent.action == KeyEvent.ACTION_DOWN) {
when (keyEvent.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY -> {
Log.d(TAG, "检测到MEDIA_PLAY按键")
handleDoubleClick()
return true
}
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
Log.d(TAG, "检测到MEDIA_PAUSE按键")
handleDoubleClick()
return true
}
KeyEvent.KEYCODE_HEADSETHOOK -> {
Log.d(TAG, "检测到HEADSETHOOK按键")
// 检测双击
val currentTime = System.currentTimeMillis()
val timeDiff = currentTime - lastKeyEventTime
Log.d(TAG, "按键时间差: $timeDiff ms, 当前计数: $keyEventCount")
if (timeDiff < 500) { // 500毫秒内的按键视为连续按键
keyEventCount++
Log.d(TAG, "连续按键,计数增加到: $keyEventCount")
if (keyEventCount == 1) { // 这是第二次按键,即双击
Log.d(TAG, "检测到双击,执行处理")
handleDoubleClick()
keyEventCount = 0
return true
}
} else {
Log.d(TAG, "非连续按键,重置计数")
keyEventCount = 0
return true
}
} else {
keyEventCount = 0
lastKeyEventTime = currentTime
// 单击也处理
Log.d(TAG, "单击也处理")
handleDoubleClick()
return true
}
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
Log.d(TAG, "检测到MEDIA_PLAY_PAUSE按键")
handleDoubleClick()
return true
}
else -> {
Log.d(TAG, "检测到其他按键: ${keyEvent.keyCode}")
}
lastKeyEventTime = currentTime
// 单击也处理
handleDoubleClick()
return true
}
} else {
Log.d(TAG, "非ACTION_DOWN事件: ${keyEvent.action}")
}
} else {
Log.d(TAG, "Intent中没有KeyEvent")
}
return super.onMediaButtonEvent(mediaButtonEvent)
}
override fun onPlay() {
Log.d(TAG, "收到onPlay回调")
handleDoubleClick()
return super.onPlay()
}
override fun onPause() {
Log.d(TAG, "收到onPause回调")
handleDoubleClick()
return super.onPause()
}
@ -225,14 +269,20 @@ class VoiceInteractionService : Service() {
// 激活 MediaSession
mediaSession.isActive = true
Log.d(TAG, "MediaSession已激活")
}
/**
* 注册媒体按钮接收器
*/
private fun registerMediaButtonReceiver() {
val mediaButtonReceiver = ComponentName(packageName, MediaButtonReceiver::class.java.name)
audioManager.registerMediaButtonEventReceiver(mediaButtonReceiver)
try {
val mediaButtonReceiver = ComponentName(packageName, MediaButtonReceiver::class.java.name)
audioManager.registerMediaButtonEventReceiver(mediaButtonReceiver)
Log.d(TAG, "媒体按钮接收器注册成功: $mediaButtonReceiver")
} catch (e: Exception) {
Log.e(TAG, "媒体按钮接收器注册失败: ${e.message}", e)
}
}
/**
@ -276,6 +326,8 @@ class VoiceInteractionService : Service() {
* 处理双击事件
*/
private fun handleDoubleClick() {
Log.d(TAG, "处理双击事件")
// 停止当前TTS播放
stopCurrentTTS()
@ -290,8 +342,10 @@ class VoiceInteractionService : Service() {
// 启动或重置语音识别
if (!isRecognitionActive) {
Log.d(TAG, "语音识别未激活,开始启动")
startVoiceRecognition()
} else {
Log.d(TAG, "语音识别已激活,更新活动时间")
updateLastActivityTime()
hasSpeechDetected = false
}
@ -576,8 +630,12 @@ class VoiceInteractionService : Service() {
* 当 Service 被启动时调用
*/
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand: intent=$intent, action=${intent?.action}")
// 处理媒体按键 Intent
if (intent?.action == Intent.ACTION_MEDIA_BUTTON) {
Log.d(TAG, "收到媒体按钮Intent: ${intent.extras}")
val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
} else {
@ -586,17 +644,27 @@ class VoiceInteractionService : Service() {
}
if (keyEvent != null) {
Log.d(TAG, "从Intent中解析到按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
handleKeyEvent(keyEvent)
} else {
Log.d(TAG, "Intent中没有按键事件,直接处理双击")
handleDoubleClick()
}
} else if (intent?.action == ACTION_PAUSE_VOICE_INTERACTION) {
// 处理来自 Flutter 的暂停请求
Log.d(TAG, "收到暂停请求")
pauseVoiceInteraction()
} else {
Log.d(TAG, "收到其他Intent: action=${intent?.action}")
}
// 让 MediaSession 处理 Intent
MediaButtonReceiver.handleIntent(mediaSession, intent)
try {
MediaButtonReceiver.handleIntent(mediaSession, intent)
Log.d(TAG, "MediaButtonReceiver处理Intent完成")
} catch (e: Exception) {
Log.e(TAG, "MediaButtonReceiver处理Intent失败: ${e.message}", e)
}
return START_STICKY
}
@ -605,28 +673,50 @@ class VoiceInteractionService : Service() {
* 处理按键事件
*/
private fun handleKeyEvent(keyEvent: KeyEvent) {
Log.d(TAG, "处理按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
if (keyEvent.action == KeyEvent.ACTION_DOWN) {
when (keyEvent.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY,
KeyEvent.KEYCODE_MEDIA_PAUSE,
KeyEvent.KEYCODE_HEADSETHOOK,
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
KeyEvent.KEYCODE_MEDIA_PLAY -> {
Log.d(TAG, "处理MEDIA_PLAY按键")
handleDoubleClick()
}
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
Log.d(TAG, "处理MEDIA_PAUSE按键")
handleDoubleClick()
}
KeyEvent.KEYCODE_HEADSETHOOK -> {
Log.d(TAG, "处理HEADSETHOOK按键")
// 检测双击
val currentTime = System.currentTimeMillis()
val timeDiff = currentTime - lastKeyEventTime
Log.d(TAG, "按键时间差: $timeDiff ms, 当前计数: $keyEventCount")
if (timeDiff < 500) { // 500毫秒内的按键视为连续按键
keyEventCount++
Log.d(TAG, "连续按键,计数增加到: $keyEventCount")
if (keyEventCount == 1) { // 这是第二次按键,即双击
Log.d(TAG, "检测到双击,执行处理")
handleDoubleClick()
keyEventCount = 0
}
} else {
Log.d(TAG, "非连续按键,重置计数")
keyEventCount = 0
}
lastKeyEventTime = currentTime
}
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
Log.d(TAG, "处理MEDIA_PLAY_PAUSE按键")
handleDoubleClick()
}
else -> {
Log.d(TAG, "处理其他按键: ${keyEvent.keyCode}")
}
}
} else {
Log.d(TAG, "非ACTION_DOWN事件: ${keyEvent.action}")
}
}
@ -709,4 +799,38 @@ class VoiceInteractionService : Service() {
// 发送广播
sendBroadcast(intent)
}
/**
* 测试媒体按钮事件处理
*/
private fun testMediaButtonEvent() {
Log.d(TAG, "开始测试媒体按钮事件处理")
try {
// 创建一个模拟的HEADSETHOOK按键事件
val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)
// 创建一个包含按键事件的Intent
val intent = Intent(Intent.ACTION_MEDIA_BUTTON).apply {
putExtra(Intent.EXTRA_KEY_EVENT, keyEvent)
}
// 直接调用onMediaButtonEvent方法
Log.d(TAG, "直接调用onMediaButtonEvent方法")
val result = mediaSession.controller.dispatchMediaButtonEvent(keyEvent)
Log.d(TAG, "dispatchMediaButtonEvent结果: $result")
// 通过MediaButtonReceiver发送Intent
Log.d(TAG, "通过MediaButtonReceiver发送Intent")
MediaButtonReceiver.handleIntent(mediaSession, intent)
// 直接调用handleKeyEvent方法
Log.d(TAG, "直接调用handleKeyEvent方法")
handleKeyEvent(keyEvent)
Log.d(TAG, "测试媒体按钮事件处理完成")
} catch (e: Exception) {
Log.e(TAG, "测试媒体按钮事件处理失败: ${e.message}", e)
}
}
}

2
lib/core/bindings/initial_binding.dart

@ -24,6 +24,6 @@ class InitialBinding extends Bindings {
Get.lazyPut<VolcanoTranslationService>(() => VolcanoTranslationService(), fenix: true);
// 语音交互服务 - 使用 putAsync 确保 init 方法被调用
Get.putAsync<VoiceInteractionService>(() => VoiceInteractionService().init(), permanent: true);
Get.lazyPut<VoiceInteractionService>(() => VoiceInteractionService(), fenix: true);
}
}

150
lib/data/services/voice_interaction_service.dart

@ -1,3 +1,4 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
@ -23,16 +24,82 @@ class VoiceInteractionService extends GetxService {
final RxList<Message> personalAssistantMessages = <Message>[].obs;
// 方法通道
final MethodChannel _channel = const MethodChannel('com.deep_voice.voice_interaction');
static const MethodChannel _channel = MethodChannel('com.deep_voice.voice_interaction');
// 事件通道
final EventChannel _eventChannel = const EventChannel('com.deep_voice.voice_interaction_events');
static const EventChannel _eventChannel = EventChannel('com.deep_voice.voice_interaction_events');
// 事件流订阅
Stream<dynamic>? _eventStream;
// 配置信息
late final String _azureSpeechKey;
late final String _azureSpeechRegion;
late final String _volcanoAiApiKey;
// 事件通道状态
bool _isEventChannelReady = false;
Completer<void>? _eventChannelReadyCompleter;
// 初始化标记,避免重复初始化
static bool _isInitialized = false;
bool _isInitialized = false;
VoiceInteractionService() {
_loadConfig();
_setupEventChannel();
}
/// 从环境变量加载配置
void _loadConfig() {
_azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
_azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
_volcanoAiApiKey = dotenv.env['VOLCANO_AI_API_KEY'] ?? '';
if (_azureSpeechKey.isEmpty || _azureSpeechRegion.isEmpty) {
Logger.error('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION');
}
if (_volcanoAiApiKey.isEmpty) {
Logger.error('未找到火山 AI 配置。请在 .env 文件中设置 VOLCANO_AI_API_KEY');
}
}
/// 设置事件通道监听
void _setupEventChannel() {
_eventChannelReadyCompleter = Completer<void>();
_eventChannel.receiveBroadcastStream().listen(
(event) {
if (event is Map) {
final String eventType = event['type'] as String? ?? '';
// 处理通道准备好的事件
if (eventType == 'channelReady') {
_isEventChannelReady = true;
if (!_eventChannelReadyCompleter!.isCompleted) {
_eventChannelReadyCompleter!.complete();
}
return;
}
_handleEvent(event);
}
},
onError: (error) {
Logger.error('语音交互事件通道错误: $error');
}
);
}
/// 等待事件通道准备好
Future<bool> _waitForEventChannel({Duration timeout = const Duration(seconds: 5)}) async {
if (_isEventChannelReady) return true;
try {
await _eventChannelReadyCompleter!.future.timeout(timeout);
return true;
} on TimeoutException {
Logger.error('等待事件通道准备好超时');
return false;
}
}
/// 初始化服务
Future<VoiceInteractionService> init() async {
@ -42,12 +109,16 @@ class VoiceInteractionService extends GetxService {
}
try {
// 等待事件通道准备好
final bool eventChannelReady = await _waitForEventChannel();
if (!eventChannelReady) {
Logger.error('事件通道未准备好,初始化失败');
return this;
}
// 获取服务运行状态
await _updateServiceStatus();
// 设置事件监听
_setupEventChannel();
// 加载个人助手的历史记录
_loadPersonalAssistantHistory();
@ -55,7 +126,7 @@ class VoiceInteractionService extends GetxService {
_isInitialized = true;
return this;
} catch (e) {
Logger.error('VoiceInteractionService 初始化失败', e);
Logger.error('VoiceInteractionService 初始化失败: $e');
return this;
}
}
@ -71,21 +142,6 @@ class VoiceInteractionService extends GetxService {
}
}
/// 设置事件通道监听
void _setupEventChannel() {
try {
_eventStream = _eventChannel.receiveBroadcastStream();
_eventStream?.listen(
_handleEvent,
onError: (error) {
Logger.error('语音交互事件通道错误', error);
}
);
} catch (e) {
Logger.error('设置事件通道监听失败', e);
}
}
/// 处理来自原生端的事件
void _handleEvent(dynamic event) {
try {
@ -99,8 +155,6 @@ class VoiceInteractionService extends GetxService {
}
switch (type) {
case 'channelReady':
break;
case 'recognitionStarted':
_isRecognitionActive.value = true;
@ -113,7 +167,7 @@ class VoiceInteractionService extends GetxService {
break;
}
} catch (e) {
Logger.error('处理原生端事件时出错', e);
Logger.error('处理原生端事件时出错: $e');
}
}
@ -154,7 +208,7 @@ class VoiceInteractionService extends GetxService {
historyService.saveHistory('personal_assistant', personalAssistantMessages);
}
} catch (e) {
Logger.error('处理聊天记录事件失败', e);
Logger.error('处理聊天记录事件失败: $e');
}
}
@ -173,19 +227,16 @@ class VoiceInteractionService extends GetxService {
/// 启动语音交互服务
Future<bool> startService() async {
if (!_isInitialized) {
await init();
}
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,
'azure_speech_key': _azureSpeechKey,
'azure_speech_region': _azureSpeechRegion,
'volcano_ai_api_key': _volcanoAiApiKey,
}) ?? false;
// 更新状态
@ -195,7 +246,7 @@ class VoiceInteractionService extends GetxService {
return result;
} catch (e) {
Logger.error('启动语音交互服务失败', e);
Logger.error('启动语音交互服务失败: $e');
return false;
}
}
@ -212,7 +263,7 @@ class VoiceInteractionService extends GetxService {
return result;
} catch (e) {
Logger.error('停止语音交互服务失败', e);
Logger.error('停止语音交互服务失败: $e');
return false;
}
}
@ -223,7 +274,7 @@ class VoiceInteractionService extends GetxService {
final result = await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false;
return result;
} catch (e) {
Logger.error('暂停语音交互失败', e);
Logger.error('暂停语音交互失败: $e');
return false;
}
}
@ -234,15 +285,28 @@ class VoiceInteractionService extends GetxService {
final status = await _channel.invokeMethod<bool>('isVoiceInteractionServiceRunning') ?? false;
_isRunning.value = status;
} catch (e) {
Logger.error('获取语音交互服务状态失败', e);
Logger.error('获取语音交互服务状态失败: $e');
_isRunning.value = false;
}
}
/// 释放资源
Future<void> dispose() async {
try {
if (_isRunning.value) {
await stopService();
}
_isInitialized = false;
} catch (e) {
Logger.error('释放语音交互服务资源失败: $e');
}
}
@override
void onClose() {
// 清理资源
_eventStream = null;
dispose();
super.onClose();
}
}

78
lib/modules/chat/controllers/chat_controller.dart

@ -9,7 +9,6 @@ import '../../../data/providers/agent_provider.dart';
import '../../../data/models/agent.dart';
import '../../../core/utils/logger.dart';
import '../../../data/services/chat_history_service.dart';
import '../../../data/services/voice_interaction_service.dart';
class ChatController extends GetxController {
// 服务
@ -17,7 +16,6 @@ class ChatController extends GetxController {
final AzureTtsService _ttsService = Get.find<AzureTtsService>();
final AzureAsrService _asrService = Get.find<AzureAsrService>();
final ChatHistoryService _historyService = Get.find<ChatHistoryService>();
final VoiceInteractionService _voiceInteractionService = Get.find<VoiceInteractionService>();
// 添加ScrollController用于控制列表滚动
final ScrollController scrollController = ScrollController();
@ -48,9 +46,6 @@ class ChatController extends GetxController {
// 流式响应控制
StreamSubscription? _aiResponseSubscription;
StreamSubscription? _recognitionSubscription;
// 语音交互服务消息监听
Worker? _personalAssistantMessagesWorker;
// 取消标志
bool _shouldCancelAiResponse = false;
@ -60,8 +55,6 @@ class ChatController extends GetxController {
super.onInit();
Logger.info('ChatController onInit');
// 从路由参数获取Agent信息
final Map<String, dynamic> args = Get.arguments ?? {};
final String agentId = args['agentId'] ?? 'personal_assistant';
@ -75,24 +68,12 @@ class ChatController extends GetxController {
}
agent = foundAgent;
// 暂停后台语音交互服务,避免与聊天页面的语音功能相互干扰
// if (Get.isRegistered<VoiceInteractionService>()) {
// await VoiceInteractionService.to.pauseVoiceInteraction();
// Logger.info('已暂停后台语音交互服务');
// }
// 设置TTS服务
await _ttsService.setVoice(agent.voice);
// 加载聊天历史
_loadChatHistory();
// 如果是个人助手,监听语音交互服务的消息更新
if (agent.id == 'personal_assistant') {
_setupPersonalAssistantMessagesListener();
}
// 如果没有历史记录,添加欢迎消息
if (messages.isEmpty && agent.welcomeMessage.isNotEmpty) {
@ -117,37 +98,6 @@ class ChatController extends GetxController {
_scrollToBottom();
});
}
/// 设置个人助手消息监听器
void _setupPersonalAssistantMessagesListener() {
// 取消之前的监听器(如果有)
_personalAssistantMessagesWorker?.dispose();
// 设置新的监听器
_personalAssistantMessagesWorker = ever(
_voiceInteractionService.personalAssistantMessages,
(List<Message> updatedMessages) {
if (agent.id == 'personal_assistant' && updatedMessages.isNotEmpty) {
Logger.info('检测到语音交互服务的个人助手消息更新,同步到聊天视图');
// 中断当前响应
_interruptCurrentResponse("检测到语音交互服务的消息更新,中断当前响应");
// 更新消息列表
messages.assignAll(updatedMessages);
// 滚动到底部
_scrollToBottom();
}
}
);
// 初始同步
if (_voiceInteractionService.personalAssistantMessages.isNotEmpty) {
messages.assignAll(_voiceInteractionService.personalAssistantMessages);
Logger.info('初始同步语音交互服务的个人助手消息,消息数: ${_voiceInteractionService.personalAssistantMessages.length}');
}
}
@override
void onClose() {
@ -157,7 +107,6 @@ class ChatController extends GetxController {
scrollController.dispose();
_aiResponseSubscription?.cancel();
_recognitionSubscription?.cancel();
_personalAssistantMessagesWorker?.dispose();
// 停止TTS
_ttsService.stop();
@ -555,31 +504,11 @@ class ChatController extends GetxController {
// 删除存储的历史记录
_historyService.clearHistory(agent.id);
// 如果是个人助手,同时清空语音交互服务的消息
if (agent.id == 'personal_assistant' && Get.isRegistered<VoiceInteractionService>()) {
_voiceInteractionService.personalAssistantMessages.clear();
_voiceInteractionService.personalAssistantMessages.add(Message(
role: 'assistant',
content: agent.welcomeMessage,
timestamp: DateTime.now(),
));
}
}
// 加载聊天历史
void _loadChatHistory() {
// 如果是个人助手,优先使用语音交互服务中的消息
if (agent.id == 'personal_assistant' &&
Get.isRegistered<VoiceInteractionService>() &&
_voiceInteractionService.personalAssistantMessages.isNotEmpty) {
messages.clear();
messages.addAll(_voiceInteractionService.personalAssistantMessages);
Logger.info('从语音交互服务加载个人助手的历史记录,消息数: ${messages.length}');
return;
}
// 否则从历史服务加载
// 从历史服务加载
final history = _historyService.loadHistory(agent.id);
if (history.isNotEmpty) {
messages.clear();
@ -590,11 +519,6 @@ class ChatController extends GetxController {
// 保存聊天历史
void _saveChatHistory() {
_historyService.saveHistory(agent.id, messages);
// 如果是个人助手,同时更新语音交互服务的消息
if (agent.id == 'personal_assistant' && Get.isRegistered<VoiceInteractionService>()) {
_voiceInteractionService.personalAssistantMessages.assignAll(messages);
}
}
// 添加消息,供外部调用

Loading…
Cancel
Save