From 974ea540b7ff120a47aef7a905e929870eee032a Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 30 Sep 2025 11:34:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E9=9F=B3=E4=B9=90=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...kotlin-compiler-2007526241707140332.salive | 0 .../agent/controllers/agent_controller.dart | 19 +++++++-------- lib/modules/agent/views/message_bubble.dart | 2 +- .../agent_service/AgentService.kt | 24 ++++++++++++------- .../chat_api/QQMusicSystemFunctionHandler.kt | 15 ++++++++++-- 5 files changed, 38 insertions(+), 22 deletions(-) delete mode 100644 android/.kotlin/sessions/kotlin-compiler-2007526241707140332.salive diff --git a/android/.kotlin/sessions/kotlin-compiler-2007526241707140332.salive b/android/.kotlin/sessions/kotlin-compiler-2007526241707140332.salive deleted file mode 100644 index e69de29bb..000000000 diff --git a/lib/modules/agent/controllers/agent_controller.dart b/lib/modules/agent/controllers/agent_controller.dart index d6563ce10..6119f49ef 100644 --- a/lib/modules/agent/controllers/agent_controller.dart +++ b/lib/modules/agent/controllers/agent_controller.dart @@ -755,7 +755,7 @@ class AgentController extends GetxController with WidgetsBindingObserver { final responseId = event.data['responseId'] ?? ''; // final result = event.data['result']; final metaStr = event.data['meta'] ?? ''; - // final functionCall = event.data['function_call'] ?? ''; + final functionCall = event.data['function_call'] ?? ''; Logger.i(TAG, 'Flutter 结束调用 mcp: $metaStr'); if (metaStr.isNotEmpty) { Map metaResult = {}; @@ -790,16 +790,7 @@ class AgentController extends GetxController with WidgetsBindingObserver { ); } } - final musicKey = metaResult.keys.firstWhere( - (key) => key.contains("music"), - orElse: () => "", - ); - if (musicKey.isNotEmpty) { - Future.delayed(Duration(seconds: 1), () { - _qqmusicManager.syncCurrentPlayInfo(isOpenPlay: true); - }); - // } - } else if (metaResult.containsKey("maps_route_navigation")) { + if (metaResult.containsKey("maps_route_navigation")) { final maps_route_navigation = metaResult["maps_route_navigation"]; if (maps_route_navigation is Map) { @@ -858,6 +849,12 @@ class AgentController extends GetxController with WidgetsBindingObserver { } } } + if (functionCall.contains("music")) { + Future.delayed(Duration(seconds: 1), () { + _qqmusicManager.syncCurrentPlayInfo(isOpenPlay: false); + }); + // } + } break; default: break; diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index 8922a0cb4..f5b24bd04 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -160,7 +160,7 @@ class MessageBubble extends GetView { ); } - if (!isUser && message.isEmpty) { + if (!isUser && message.isEmpty && meta == null) { return _buildTypingIndicator(); } diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt index 9813f425d..84dfaaca3 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt @@ -1091,14 +1091,22 @@ object AgentService : CoroutineScope { iscard = resultmap["iscard"] as Boolean; if (iscard){ aiMetadata = resultmap["meta"] as String; - } - sendEvent( - "function_call_result", mapOf( - "function_call" to functionCall.toString(), - "result" to functionCallResult.toString(), - "meta" to aiMetadata, + sendEvent( + "function_call_result", mapOf( + "function_call" to functionCall.toString(), + "result" to functionCallResult.toString(), + "meta" to aiMetadata, + ) ) - ) + }else{ + sendEvent( + "function_call_result", mapOf( + "function_call" to functionCall.toString(), + "result" to functionCallResult.toString(), + ) + ) + } + Log.e( TAG, "liwei--------------- AI Call onFunctionCallResult broadcast:$broadcast reply:$reply iscard:$iscard" @@ -1940,7 +1948,7 @@ object AgentService : CoroutineScope { } else { Log.w(TAG, "card_musiclist.musics 不是一个数组") } - } else if (toolname == "qqmusic_searchandplay_songs" && meta.has("data")) { //qq音乐 + } else if (toolname == "qqmusic_search_songs" && meta.has("data")) { //qq音乐 //"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}" val musics = meta.optJSONArray("data") if (musics != null) { diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt index 79ac37e95..1736c1a0d 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt @@ -139,12 +139,22 @@ private class QQMusicSearchOnlyHandler(private val context: Context?) : Function override suspend fun handle(arguments: Map): String { return try { val keyword = arguments["keyword"] as? String ?: return "{\"success\": false, \"message\": \"缺少搜索关键词\"}" - val searchType = arguments["searchType"] as? Int ?: 0 // 默认搜索歌曲 + val searchType = arguments["searchType"] as? Int ?: 0 val qqMusicSingleton = QQMusicSingleton.getInstance() - // 使用 suspendCoroutine 将回调转换为协程 + // 使用 suspendCoroutine 将回调转换为协程,并添加防重复调用机制 suspendCoroutine { continuation -> + var isResumed = false // 添加标志防止重复调用 + qqMusicSingleton.searchSongs(keyword) { searchResult -> + // 检查是否已经恢复过协程 + if (isResumed) { + Log.w("QQMusicSearchOnlyHandler", "检测到重复回调,忽略") + return@searchSongs + } + + isResumed = true // 标记已处理 + val result = if (searchResult.isSuccess) { val songs = searchResult.getOrNull() ?: emptyList() @@ -181,6 +191,7 @@ private class QQMusicSearchOnlyHandler(private val context: Context?) : Function val error = searchResult.exceptionOrNull() "{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}" } + // 恢复协程执行 continuation.resume(result) }