Browse Source

v005.fix

weicu
wolfplus 2 years ago
parent
commit
a4dbf2228b
  1. 45
      android/app/src/main/kotlin/com/example/deep_voice/MainActivity.kt
  2. 142
      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() registerVoiceInteractionReceiver()
// 不再自动启动服务,由用户通过 Flutter 界面手动启动 // 自动启动语音交互服务
Log.d(TAG, "MainActivity 已创建,但不会自动启动 VoiceInteractionService") Log.d(TAG, "MainActivity 已创建,自动启动 VoiceInteractionService")
autoStartVoiceInteractionService()
// 确保 Flutter 引擎准备好后立即设置事件通道 // 确保 Flutter 引擎准备好后立即设置事件通道
flutterEngine?.let { engine -> 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() { override fun onDestroy() {
// 注销广播接收器 // 注销广播接收器
try { try {

142
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 audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
Log.d(TAG, "AudioManager初始化完成")
initServices() initServices()
initMediaSession() initMediaSession()
registerMediaButtonReceiver() registerMediaButtonReceiver()
// 设置为媒体播放状态 // 设置为媒体播放状态
setPlaybackState(PlaybackStateCompat.STATE_PLAYING) setPlaybackState(PlaybackStateCompat.STATE_PLAYING)
Log.d(TAG, "设置播放状态为PLAYING")
// 启动监控和前台服务 // 启动监控和前台服务
startMonitoring() startMonitoring()
startForegroundServiceWithNotification() startForegroundServiceWithNotification()
Log.d(TAG, "VoiceInteractionService 初始化完成,等待蓝牙按键事件...") Log.d(TAG, "VoiceInteractionService 初始化完成,等待蓝牙按键事件...")
// 延迟3秒后测试按键处理功能
// Handler(Looper.getMainLooper()).postDelayed({
// testMediaButtonEvent()
// }, 3000)
} }
/** /**
@ -163,6 +171,7 @@ class VoiceInteractionService : Service() {
* 初始化 MediaSession * 初始化 MediaSession
*/ */
private fun initMediaSession() { private fun initMediaSession() {
Log.d(TAG, "开始初始化MediaSession")
mediaSession = MediaSessionCompat(applicationContext, "VoiceServiceSession") mediaSession = MediaSessionCompat(applicationContext, "VoiceServiceSession")
// 设置标志和状态 // 设置标志和状态
@ -170,10 +179,13 @@ class VoiceInteractionService : Service() {
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
) )
Log.d(TAG, "MediaSession标志设置完成")
// 设置回调 // 设置回调
mediaSession.setCallback(object : MediaSessionCompat.Callback() { mediaSession.setCallback(object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
Log.d(TAG, "收到媒体按钮事件: $mediaButtonEvent")
val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
} else { } else {
@ -181,43 +193,75 @@ class VoiceInteractionService : Service() {
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as? KeyEvent mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as? KeyEvent
} }
if (keyEvent != null && keyEvent.action == KeyEvent.ACTION_DOWN) { if (keyEvent != null) {
Log.d(TAG, "解析到按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
if (keyEvent.action == KeyEvent.ACTION_DOWN) {
when (keyEvent.keyCode) { when (keyEvent.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PLAY -> {
KeyEvent.KEYCODE_MEDIA_PAUSE, Log.d(TAG, "检测到MEDIA_PLAY按键")
KeyEvent.KEYCODE_HEADSETHOOK, handleDoubleClick()
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { 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 currentTime = System.currentTimeMillis()
val timeDiff = currentTime - lastKeyEventTime val timeDiff = currentTime - lastKeyEventTime
Log.d(TAG, "按键时间差: $timeDiff ms, 当前计数: $keyEventCount")
if (timeDiff < 500) { // 500毫秒内的按键视为连续按键 if (timeDiff < 500) { // 500毫秒内的按键视为连续按键
keyEventCount++ keyEventCount++
Log.d(TAG, "连续按键,计数增加到: $keyEventCount")
if (keyEventCount == 1) { // 这是第二次按键,即双击 if (keyEventCount == 1) { // 这是第二次按键,即双击
Log.d(TAG, "检测到双击,执行处理")
handleDoubleClick() handleDoubleClick()
keyEventCount = 0 keyEventCount = 0
return true return true
} }
} else { } else {
Log.d(TAG, "非连续按键,重置计数")
keyEventCount = 0 keyEventCount = 0
} }
lastKeyEventTime = currentTime lastKeyEventTime = currentTime
// 单击也处理 // 单击也处理
Log.d(TAG, "单击也处理")
handleDoubleClick()
return true
}
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
Log.d(TAG, "检测到MEDIA_PLAY_PAUSE按键")
handleDoubleClick() handleDoubleClick()
return true return true
} }
else -> {
Log.d(TAG, "检测到其他按键: ${keyEvent.keyCode}")
}
} }
} else {
Log.d(TAG, "非ACTION_DOWN事件: ${keyEvent.action}")
}
} else {
Log.d(TAG, "Intent中没有KeyEvent")
} }
return super.onMediaButtonEvent(mediaButtonEvent) return super.onMediaButtonEvent(mediaButtonEvent)
} }
override fun onPlay() { override fun onPlay() {
Log.d(TAG, "收到onPlay回调")
handleDoubleClick() handleDoubleClick()
return super.onPlay() return super.onPlay()
} }
override fun onPause() { override fun onPause() {
Log.d(TAG, "收到onPause回调")
handleDoubleClick() handleDoubleClick()
return super.onPause() return super.onPause()
} }
@ -225,14 +269,20 @@ class VoiceInteractionService : Service() {
// 激活 MediaSession // 激活 MediaSession
mediaSession.isActive = true mediaSession.isActive = true
Log.d(TAG, "MediaSession已激活")
} }
/** /**
* 注册媒体按钮接收器 * 注册媒体按钮接收器
*/ */
private fun registerMediaButtonReceiver() { private fun registerMediaButtonReceiver() {
try {
val mediaButtonReceiver = ComponentName(packageName, MediaButtonReceiver::class.java.name) val mediaButtonReceiver = ComponentName(packageName, MediaButtonReceiver::class.java.name)
audioManager.registerMediaButtonEventReceiver(mediaButtonReceiver) 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() { private fun handleDoubleClick() {
Log.d(TAG, "处理双击事件")
// 停止当前TTS播放 // 停止当前TTS播放
stopCurrentTTS() stopCurrentTTS()
@ -290,8 +342,10 @@ class VoiceInteractionService : Service() {
// 启动或重置语音识别 // 启动或重置语音识别
if (!isRecognitionActive) { if (!isRecognitionActive) {
Log.d(TAG, "语音识别未激活,开始启动")
startVoiceRecognition() startVoiceRecognition()
} else { } else {
Log.d(TAG, "语音识别已激活,更新活动时间")
updateLastActivityTime() updateLastActivityTime()
hasSpeechDetected = false hasSpeechDetected = false
} }
@ -576,8 +630,12 @@ class VoiceInteractionService : Service() {
* 当 Service 被启动时调用 * 当 Service 被启动时调用
*/ */
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand: intent=$intent, action=${intent?.action}")
// 处理媒体按键 Intent // 处理媒体按键 Intent
if (intent?.action == Intent.ACTION_MEDIA_BUTTON) { if (intent?.action == Intent.ACTION_MEDIA_BUTTON) {
Log.d(TAG, "收到媒体按钮Intent: ${intent.extras}")
val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val keyEvent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
} else { } else {
@ -586,17 +644,27 @@ class VoiceInteractionService : Service() {
} }
if (keyEvent != null) { if (keyEvent != null) {
Log.d(TAG, "从Intent中解析到按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
handleKeyEvent(keyEvent) handleKeyEvent(keyEvent)
} else { } else {
Log.d(TAG, "Intent中没有按键事件,直接处理双击")
handleDoubleClick() handleDoubleClick()
} }
} else if (intent?.action == ACTION_PAUSE_VOICE_INTERACTION) { } else if (intent?.action == ACTION_PAUSE_VOICE_INTERACTION) {
// 处理来自 Flutter 的暂停请求 // 处理来自 Flutter 的暂停请求
Log.d(TAG, "收到暂停请求")
pauseVoiceInteraction() pauseVoiceInteraction()
} else {
Log.d(TAG, "收到其他Intent: action=${intent?.action}")
} }
// 让 MediaSession 处理 Intent // 让 MediaSession 处理 Intent
try {
MediaButtonReceiver.handleIntent(mediaSession, intent) MediaButtonReceiver.handleIntent(mediaSession, intent)
Log.d(TAG, "MediaButtonReceiver处理Intent完成")
} catch (e: Exception) {
Log.e(TAG, "MediaButtonReceiver处理Intent失败: ${e.message}", e)
}
return START_STICKY return START_STICKY
} }
@ -605,28 +673,50 @@ class VoiceInteractionService : Service() {
* 处理按键事件 * 处理按键事件
*/ */
private fun handleKeyEvent(keyEvent: KeyEvent) { private fun handleKeyEvent(keyEvent: KeyEvent) {
Log.d(TAG, "处理按键事件: action=${keyEvent.action}, keyCode=${keyEvent.keyCode}")
if (keyEvent.action == KeyEvent.ACTION_DOWN) { if (keyEvent.action == KeyEvent.ACTION_DOWN) {
when (keyEvent.keyCode) { when (keyEvent.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PLAY -> {
KeyEvent.KEYCODE_MEDIA_PAUSE, Log.d(TAG, "处理MEDIA_PLAY按键")
KeyEvent.KEYCODE_HEADSETHOOK, handleDoubleClick()
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { }
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
Log.d(TAG, "处理MEDIA_PAUSE按键")
handleDoubleClick()
}
KeyEvent.KEYCODE_HEADSETHOOK -> {
Log.d(TAG, "处理HEADSETHOOK按键")
// 检测双击 // 检测双击
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
val timeDiff = currentTime - lastKeyEventTime val timeDiff = currentTime - lastKeyEventTime
Log.d(TAG, "按键时间差: $timeDiff ms, 当前计数: $keyEventCount")
if (timeDiff < 500) { // 500毫秒内的按键视为连续按键 if (timeDiff < 500) { // 500毫秒内的按键视为连续按键
keyEventCount++ keyEventCount++
Log.d(TAG, "连续按键,计数增加到: $keyEventCount")
if (keyEventCount == 1) { // 这是第二次按键,即双击 if (keyEventCount == 1) { // 这是第二次按键,即双击
Log.d(TAG, "检测到双击,执行处理")
handleDoubleClick() handleDoubleClick()
keyEventCount = 0 keyEventCount = 0
} }
} else { } else {
Log.d(TAG, "非连续按键,重置计数")
keyEventCount = 0 keyEventCount = 0
} }
lastKeyEventTime = currentTime 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) 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); Get.lazyPut<VolcanoTranslationService>(() => VolcanoTranslationService(), fenix: true);
// 语音交互服务 - 使用 putAsync 确保 init 方法被调用 // 语音交互服务 - 使用 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:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
@ -23,16 +24,82 @@ class VoiceInteractionService extends GetxService {
final RxList<Message> personalAssistantMessages = <Message>[].obs; 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 { Future<VoiceInteractionService> init() async {
@ -42,12 +109,16 @@ class VoiceInteractionService extends GetxService {
} }
try { try {
// 等待事件通道准备好
final bool eventChannelReady = await _waitForEventChannel();
if (!eventChannelReady) {
Logger.error('事件通道未准备好,初始化失败');
return this;
}
// 获取服务运行状态 // 获取服务运行状态
await _updateServiceStatus(); await _updateServiceStatus();
// 设置事件监听
_setupEventChannel();
// 加载个人助手的历史记录 // 加载个人助手的历史记录
_loadPersonalAssistantHistory(); _loadPersonalAssistantHistory();
@ -55,7 +126,7 @@ class VoiceInteractionService extends GetxService {
_isInitialized = true; _isInitialized = true;
return this; return this;
} catch (e) { } catch (e) {
Logger.error('VoiceInteractionService 初始化失败', e); Logger.error('VoiceInteractionService 初始化失败: $e');
return this; 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) { void _handleEvent(dynamic event) {
try { try {
@ -99,8 +155,6 @@ class VoiceInteractionService extends GetxService {
} }
switch (type) { switch (type) {
case 'channelReady':
break;
case 'recognitionStarted': case 'recognitionStarted':
_isRecognitionActive.value = true; _isRecognitionActive.value = true;
@ -113,7 +167,7 @@ class VoiceInteractionService extends GetxService {
break; break;
} }
} catch (e) { } catch (e) {
Logger.error('处理原生端事件时出错', e); Logger.error('处理原生端事件时出错: $e');
} }
} }
@ -154,7 +208,7 @@ class VoiceInteractionService extends GetxService {
historyService.saveHistory('personal_assistant', personalAssistantMessages); historyService.saveHistory('personal_assistant', personalAssistantMessages);
} }
} catch (e) { } catch (e) {
Logger.error('处理聊天记录事件失败', e); Logger.error('处理聊天记录事件失败: $e');
} }
} }
@ -173,19 +227,16 @@ class VoiceInteractionService extends GetxService {
/// 启动语音交互服务 /// 启动语音交互服务
Future<bool> startService() async { Future<bool> startService() async {
try { if (!_isInitialized) {
// 获取 Azure 配置 await init();
final azureKey = dotenv.env['AZURE_SPEECH_KEY'] ?? ''; }
final azureRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
// 获取火山 AI 配置
final volcanoApiKey = dotenv.env['VOLCANO_AI_API_KEY'] ?? '';
try {
// 启动服务 // 启动服务
final result = await _channel.invokeMethod<bool>('startVoiceInteractionService', { final result = await _channel.invokeMethod<bool>('startVoiceInteractionService', {
'azure_speech_key': azureKey, 'azure_speech_key': _azureSpeechKey,
'azure_speech_region': azureRegion, 'azure_speech_region': _azureSpeechRegion,
'volcano_ai_api_key': volcanoApiKey, 'volcano_ai_api_key': _volcanoAiApiKey,
}) ?? false; }) ?? false;
// 更新状态 // 更新状态
@ -195,7 +246,7 @@ class VoiceInteractionService extends GetxService {
return result; return result;
} catch (e) { } catch (e) {
Logger.error('启动语音交互服务失败', e); Logger.error('启动语音交互服务失败: $e');
return false; return false;
} }
} }
@ -212,7 +263,7 @@ class VoiceInteractionService extends GetxService {
return result; return result;
} catch (e) { } catch (e) {
Logger.error('停止语音交互服务失败', e); Logger.error('停止语音交互服务失败: $e');
return false; return false;
} }
} }
@ -223,7 +274,7 @@ class VoiceInteractionService extends GetxService {
final result = await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false; final result = await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false;
return result; return result;
} catch (e) { } catch (e) {
Logger.error('暂停语音交互失败', e); Logger.error('暂停语音交互失败: $e');
return false; return false;
} }
} }
@ -234,15 +285,28 @@ class VoiceInteractionService extends GetxService {
final status = await _channel.invokeMethod<bool>('isVoiceInteractionServiceRunning') ?? false; final status = await _channel.invokeMethod<bool>('isVoiceInteractionServiceRunning') ?? false;
_isRunning.value = status; _isRunning.value = status;
} catch (e) { } catch (e) {
Logger.error('获取语音交互服务状态失败', e); Logger.error('获取语音交互服务状态失败: $e');
_isRunning.value = false; _isRunning.value = false;
} }
} }
/// 释放资源
Future<void> dispose() async {
try {
if (_isRunning.value) {
await stopService();
}
_isInitialized = false;
} catch (e) {
Logger.error('释放语音交互服务资源失败: $e');
}
}
@override @override
void onClose() { void onClose() {
// 清理资源 // 清理资源
_eventStream = null; dispose();
super.onClose(); 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 '../../../data/models/agent.dart';
import '../../../core/utils/logger.dart'; import '../../../core/utils/logger.dart';
import '../../../data/services/chat_history_service.dart'; import '../../../data/services/chat_history_service.dart';
import '../../../data/services/voice_interaction_service.dart';
class ChatController extends GetxController { class ChatController extends GetxController {
// 服务 // 服务
@ -17,7 +16,6 @@ class ChatController extends GetxController {
final AzureTtsService _ttsService = Get.find<AzureTtsService>(); final AzureTtsService _ttsService = Get.find<AzureTtsService>();
final AzureAsrService _asrService = Get.find<AzureAsrService>(); final AzureAsrService _asrService = Get.find<AzureAsrService>();
final ChatHistoryService _historyService = Get.find<ChatHistoryService>(); final ChatHistoryService _historyService = Get.find<ChatHistoryService>();
final VoiceInteractionService _voiceInteractionService = Get.find<VoiceInteractionService>();
// 添加ScrollController用于控制列表滚动 // 添加ScrollController用于控制列表滚动
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
@ -49,9 +47,6 @@ class ChatController extends GetxController {
StreamSubscription? _aiResponseSubscription; StreamSubscription? _aiResponseSubscription;
StreamSubscription? _recognitionSubscription; StreamSubscription? _recognitionSubscription;
// 语音交互服务消息监听
Worker? _personalAssistantMessagesWorker;
// 取消标志 // 取消标志
bool _shouldCancelAiResponse = false; bool _shouldCancelAiResponse = false;
@ -60,8 +55,6 @@ class ChatController extends GetxController {
super.onInit(); super.onInit();
Logger.info('ChatController onInit'); Logger.info('ChatController onInit');
// 从路由参数获取Agent信息 // 从路由参数获取Agent信息
final Map<String, dynamic> args = Get.arguments ?? {}; final Map<String, dynamic> args = Get.arguments ?? {};
final String agentId = args['agentId'] ?? 'personal_assistant'; final String agentId = args['agentId'] ?? 'personal_assistant';
@ -76,24 +69,12 @@ class ChatController extends GetxController {
agent = foundAgent; agent = foundAgent;
// 暂停后台语音交互服务,避免与聊天页面的语音功能相互干扰
// if (Get.isRegistered<VoiceInteractionService>()) {
// await VoiceInteractionService.to.pauseVoiceInteraction();
// Logger.info('已暂停后台语音交互服务');
// }
// 设置TTS服务 // 设置TTS服务
await _ttsService.setVoice(agent.voice); await _ttsService.setVoice(agent.voice);
// 加载聊天历史 // 加载聊天历史
_loadChatHistory(); _loadChatHistory();
// 如果是个人助手,监听语音交互服务的消息更新
if (agent.id == 'personal_assistant') {
_setupPersonalAssistantMessagesListener();
}
// 如果没有历史记录,添加欢迎消息 // 如果没有历史记录,添加欢迎消息
if (messages.isEmpty && agent.welcomeMessage.isNotEmpty) { if (messages.isEmpty && agent.welcomeMessage.isNotEmpty) {
messages.add(Message( messages.add(Message(
@ -118,37 +99,6 @@ class ChatController extends GetxController {
}); });
} }
/// 设置个人助手消息监听器
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 @override
void onClose() { void onClose() {
Logger.info('ChatController onClose'); Logger.info('ChatController onClose');
@ -157,7 +107,6 @@ class ChatController extends GetxController {
scrollController.dispose(); scrollController.dispose();
_aiResponseSubscription?.cancel(); _aiResponseSubscription?.cancel();
_recognitionSubscription?.cancel(); _recognitionSubscription?.cancel();
_personalAssistantMessagesWorker?.dispose();
// 停止TTS // 停止TTS
_ttsService.stop(); _ttsService.stop();
@ -555,31 +504,11 @@ class ChatController extends GetxController {
// 删除存储的历史记录 // 删除存储的历史记录
_historyService.clearHistory(agent.id); _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() { 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); final history = _historyService.loadHistory(agent.id);
if (history.isNotEmpty) { if (history.isNotEmpty) {
messages.clear(); messages.clear();
@ -590,11 +519,6 @@ class ChatController extends GetxController {
// 保存聊天历史 // 保存聊天历史
void _saveChatHistory() { void _saveChatHistory() {
_historyService.saveHistory(agent.id, messages); _historyService.saveHistory(agent.id, messages);
// 如果是个人助手,同时更新语音交互服务的消息
if (agent.id == 'personal_assistant' && Get.isRegistered<VoiceInteractionService>()) {
_voiceInteractionService.personalAssistantMessages.assignAll(messages);
}
} }
// 添加消息,供外部调用 // 添加消息,供外部调用

Loading…
Cancel
Save