From 827ed7c74b5b69368959d9442c82182190847d79 Mon Sep 17 00:00:00 2001 From: cheng Date: Sun, 21 Sep 2025 16:03:35 +0800 Subject: [PATCH] =?utf8?q?=E9=9B=B7=E9=B8=9F=EF=BC=9A=E8=81=9A=E5=90=88?= =?utf8?q?=E5=B9=B3=E5=8F=B0ai=E6=8E=A5=E5=85=A5=EF=BC=8Cui=E6=98=BE?= =?utf8?q?=E7=A4=BA=E6=9C=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../thunderbird/include/ThunderBirdModel.h | 5 ++ .../src/ThunderBirdDialogueView.cpp | 3 +- .../thunderbird/src/ThunderBirdModel.cpp | 56 ++++++++++++++++++- .../thunderbird/src/ThunderBirdPresenter.cpp | 31 +++++++--- .../ai_old/websocket_server_example.cpp | 36 ++++++++++-- .../zhihui/ai_old/websocket_server_manager.h | 12 ++++ code/sdk/zhihui/leiniao/imsl_ln/ln_api.c | 49 +++++++++++----- 7 files changed, 164 insertions(+), 28 deletions(-) diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h index 3b30d5607..4cfa4c40c 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h @@ -151,6 +151,9 @@ namespace OHOS // 对话状态相关函数 int GetConversationStatus(); + bool Get_is_all_services_ready(); + void init_all_callback(void); + private: ThunderBirdModel(); virtual ~ThunderBirdModel(); @@ -194,6 +197,8 @@ namespace OHOS int m_networkType; // 网络类型 bool m_hasNetwork; // 网络连接标志位 bool m_networkStatusChanged; // 网络状态变化标志位 + + bool is_all_services_ready = false; }; } diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdDialogueView.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdDialogueView.cpp index 3a66221cf..309773efb 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdDialogueView.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdDialogueView.cpp @@ -179,7 +179,7 @@ namespace OHOS } if(ThunderBirdModel::GetInstance()->IsTextEmpty() == true) { - UpdateDialogueText("保镖小姐 , 你来啦"); + UpdateDialogueText("等待网络连接"); } else { @@ -235,6 +235,7 @@ namespace OHOS } void ThunderBirdDialogueView::UpdateDialogueText(const char *text) { + if(!TextLabel || !TextLabel_Y) return; TextLabel->SetText(text); TextLabel_Y->SetText(text); } diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp index 72bf9808b..149cfe1d9 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp @@ -30,6 +30,11 @@ #include "custom_runtime.h" #include "ln_api.h" #include "kv_store.h" + + #define JUHEPINGTAI 1 + #if JUHEPINGTAI + #include "websocket_server_manager.h" + #endif namespace OHOS { enum OTA_STATUS @@ -713,7 +718,7 @@ // 添加文本内容 m_currentTimeStr = textId; - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetTextStr: added text, current length: %zu", m_currentTimeStr.length()); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetTextStr: added text, current length: %zu", m_currentTimeStr.length()); } void ThunderBirdModel::ClearTextStr() @@ -1020,6 +1025,10 @@ // 获取一下OTA 是否有最新版本 ota_update_boot(); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Network connected, calling HTTP service"); + #if JUHEPINGTAI + uapi_init_all_websocket_servers(); + uapi_start_all_websocket_servers(); // 连接服务器 + #endif } else { // 网络断开,记录状态变化日志 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Network disconnected"); @@ -1028,6 +1037,18 @@ SetNetworkStatusChanged(false); } + #if JUHEPINGTAI + if(is_all_services_ready == false) + { + if (are_all_services_ready())//如果返回的是true就可以开始对话了 + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Network disconnected"); + init_all_callback(); + is_all_services_ready = true; + } + } + #endif + // 更新设备状态 UpdateDeviceStatus(); @@ -1085,6 +1106,11 @@ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "StatusCallback: status=%d", static_cast(m_currentStatus)); } + + bool ThunderBirdModel::Get_is_all_services_ready() + { + return is_all_services_ready; + } // ==================== 状态管理相关函数实现 ==================== /** @@ -1348,5 +1374,33 @@ m_networkStatusChanged = changed; } + + void ws_register_chat_filter_cb(char *result) + { + } + void ws_register_ai_question_cb(char *buf) + { + } + + void ws_register_ai_answer_cb(char *buf, uint8_t type) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ws_register_ai_answer_cb:%s\n", buf ? buf : ""); + if (buf && buf[0] != '\0') { + // 先写入文本,再置对话标志,避免UI读到标志已置但文本尚未更新 + ThunderBirdModel::GetInstance()->SetTextStr(buf); + set_start_conversation_flag(START_CONVERSATION_FLAG_START); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ws_register_ai_answer_cb: empty buf, skip update"); + } + } + + void ThunderBirdModel::init_all_callback(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "init_all_callback\n"); + // ws_register_chat_filter_callback(ws_register_chat_filter_cb); + // ws_register_ai_question_callback(ws_register_ai_question_cb); + ws_register_ai_answer_callback(ws_register_ai_answer_cb); + } + } \ No newline at end of file diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp index 1f427da93..96c1949a8 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp @@ -167,10 +167,22 @@ namespace OHOS { //判断是否为开始对话 如果是开始对话 则更新对话数据 if(ThunderBirdModel::GetInstance()->GetConversationStatus() == 1){ - //更新对话数据 - std::string dialogueText = ThunderBirdModel::GetInstance()->GetTextStr(); - //只有一行 是拼接 还是直接覆盖? - ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(dialogueText.c_str()); + //更新对话数据 + std::string dialogueText = ThunderBirdModel::GetInstance()->GetTextStr(); + //只有一行 是拼接 还是直接覆盖? + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateDialogueText:%s\n",dialogueText.c_str()); + ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(dialogueText.c_str()); + } + else{ + //如果不是对话 需要判断 是否服务准备好 + if(ThunderBirdModel::GetInstance()->Get_is_all_services_ready() == false) + { + ThunderBirdDialogueView::GetInstance()->UpdateDialogueText( "等待网络连接" ); + } + else + { + ThunderBirdDialogueView::GetInstance()->UpdateDialogueText( "网络连接成功" ); + } } } } @@ -305,16 +317,19 @@ namespace OHOS */ void ThunderBirdPresenter::HandleDialogueFunction(int16_t currentView, int16_t currentSubView) { + bool flag = ThunderBirdModel::GetInstance()->Get_is_all_services_ready(); if (currentView == THUNDERBIRD_DIALOGUEVIEW && - currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING) { + currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING && flag == true) { // 停止录音并发送 - ThunderBirdModel::GetInstance()->StopRecording(); + // ThunderBirdModel::GetInstance()->StopRecording(); ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_SPEAKING); - ThunderBirdModel::GetInstance()->SendRecording(); + // ThunderBirdModel::GetInstance()->SendRecording(); + uapi_stop_AI_asr(); } else { // 开始录音 ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_LISTENING); - ThunderBirdModel::GetInstance()->StartRecording(); + // ThunderBirdModel::GetInstance()->StartRecording(); + uapi_start_AI_asr(); } } diff --git a/code/sdk/zhihui/ai_old/websocket_server_example.cpp b/code/sdk/zhihui/ai_old/websocket_server_example.cpp index 0cac1e780..00b709b6e 100644 --- a/code/sdk/zhihui/ai_old/websocket_server_example.cpp +++ b/code/sdk/zhihui/ai_old/websocket_server_example.cpp @@ -35,7 +35,12 @@ static uint8_t asr_is_ready=0; tts_ready_status_t tts_is_ready = TTS_READY_NOT_SENT; -/* 外部函数声明 */ +/* 可注册回调:通过管理器注册 */ +static void (*g_ai_question_cb)(char *buf) = NULL; +static void (*g_ai_answer_cb)(char *buf, uint8_t type) = NULL; +static void (*g_chat_filter_cb)(char *result) = NULL; + +/* 不再使用默认BLE回退,未注册时打印日志 */ extern void ble_set_ai_Question_str(char *str); extern void ble_set_ai_Answer_str(char *str, uint8_t type); extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint16_t type); @@ -176,7 +181,7 @@ void handle_asr_data(const ws_event_data_t *event_data) if(data.is_end) { ai_chat_send_txt(0, data.result_text, g_chat_server->client,false); - ble_set_ai_Question_str(data.result_text); + if (g_ai_question_cb) g_ai_question_cb(data.result_text); else printf("[WS][ASR] ai_question 回调未注册,丢弃内容: %s\n", data.result_text); } break; @@ -262,6 +267,11 @@ void handle_chat_data(const ws_event_data_t *event_data) // 解析Chat结果 char buf[512]={0}; chat_event_type_t ret=chat_result_analysis((char*)event_data->data, buf, 512); + if (g_chat_filter_cb) { + g_chat_filter_cb(buf); + } else { + printf("[WS][CHAT] chat_filter_result_chars 未注册,使用原始内容\n"); + } // 根据事件类型进行处理 switch (ret) { @@ -278,13 +288,13 @@ void handle_chat_data(const ws_event_data_t *event_data) case CHAT_EVENT_MIDDLE: printf("Chat event: MIDDLE - Content: %s\n", buf); - ble_set_ai_Answer_str(buf, 2); + if (g_ai_answer_cb) g_ai_answer_cb(buf, 2); else printf("[WS][CHAT] ai_answer 回调未注册,丢弃内容: %s\n", buf); uapi_tts_process_text(g_tts_server->client,buf,(tts_is_ready == TTS_READY_SUCCESS_READY)); break; case CHAT_EVENT_END: printf("Chat event: END - Final content: %s\n", buf); - ble_set_ai_Answer_str(buf, 2); + if (g_ai_answer_cb) g_ai_answer_cb(buf, 2); else printf("[WS][CHAT] ai_answer 回调未注册,丢弃内容: %s\n", buf); uapi_tts_process_text(g_tts_server->client,buf,(tts_is_ready == TTS_READY_SUCCESS_READY)); uapi_cache_stop_command(g_tts_server->client,(tts_is_ready == TTS_READY_SUCCESS_READY)); @@ -307,6 +317,22 @@ void handle_chat_data(const ws_event_data_t *event_data) } } +/* 对外注册接口实现 */ +void ws_register_chat_filter_callback(chat_filter_result_chars_cb_t cb) +{ + g_chat_filter_cb = cb; +} + +void ws_register_ai_question_callback(ai_question_cb_t cb) +{ + g_ai_question_cb = cb; +} + +void ws_register_ai_answer_callback(ai_answer_cb_t cb) +{ + g_ai_answer_cb = cb; +} + /** * @brief 提取JSON内容(简化实现) @@ -521,6 +547,8 @@ errcode_t start_all_websocket_servers(void) // ai_media_init(); old_Start_AIVoice(AIVoiceDataCallback_,nullptr); + /* 不进行默认回退注册,未注册时仅打印错误日志 */ + printf("All WebSocket servers started successfully\n"); return ERRCODE_SUCC; } diff --git a/code/sdk/zhihui/ai_old/websocket_server_manager.h b/code/sdk/zhihui/ai_old/websocket_server_manager.h index 6c0c2d071..d16e8e162 100644 --- a/code/sdk/zhihui/ai_old/websocket_server_manager.h +++ b/code/sdk/zhihui/ai_old/websocket_server_manager.h @@ -269,6 +269,18 @@ errcode_t ws_server_set_interrupt_flag(ws_server_type_t server_type, uint8_t int */ uint8_t ws_server_get_interrupt_flag(ws_server_type_t server_type); +/* ========================= AI 文本回调注册(新增) ========================= */ +/* 聊天结果过滤回调:可对结果字符串进行原地过滤/修改 */ +typedef void (*chat_filter_result_chars_cb_t)(char *result); +/* BLE 问题/答案上报回调 */ +typedef void (*ai_question_cb_t)(char *buf); +typedef void (*ai_answer_cb_t)(char *buf, uint8_t type); + +/* 注册接口(线程安全由调用方保证)*/ +void ws_register_chat_filter_callback(chat_filter_result_chars_cb_t cb); +void ws_register_ai_question_callback(ai_question_cb_t cb); +void ws_register_ai_answer_callback(ai_answer_cb_t cb); + #ifdef __cplusplus } diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c index 9e9053972..707256e31 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c @@ -743,6 +743,7 @@ static uint32_t ln_download_mp3_file_advanced(const char *audio_url, const char { if (client_data.contentBlockLen > 0) { + printf("download mp3 file advanced: contentBlockLen=%d\n", client_data.contentBlockLen); #if TEST_MP3_DOWNLOAD /* 一边下载到文件,一边推送到播放器队列,尝试边下边播 */ size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd); @@ -760,8 +761,18 @@ static uint32_t ln_download_mp3_file_advanced(const char *audio_url, const char /* 非阻塞入队,队列满则忽略该块 */ //播放下载的音频 - (void)ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen); - + int ret = ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen); + if (ret != 0) + { + printf("download mp3 file advanced: write failed, ret=%d\n", ret); + // 写失败重新写 + LOS_Msleep(100); + ret = ln_audio_player_write((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen); + if (ret != 0) + { + printf("download mp3 file advanced: write failed, ret=%d\n", ret); + } + } } else { @@ -1124,7 +1135,20 @@ static void ln_http_server_send_task(void const *arg) if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN) { printf("LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN:获取雷鸟设备Token\n"); - uapi_ln_get_device_token(); + uint32_t ret = ln_get_device_token_http(uapi_ln_get_device_id(), uapi_ln_get_device_iccid(), uapi_ln_get_device_model(), uapi_ln_get_device_version()); + if (ret == ERRCODE_SUCC) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN_HTTP_SERVER_SEND_TASK] 获取雷鸟设备Token成功\n"); + ret = ln_ws_start(ln_ws_process_message); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN_HTTP_SERVER_SEND_TASK] 启动WebSocket失败: %d\n", ret); + } + } + else + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN_HTTP_SERVER_SEND_TASK] 获取雷鸟设备Token失败\n"); + } } else if (mail.cmd == LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM) { @@ -1251,21 +1275,18 @@ static void ln_http_server_recv_task(void const *arg) //推送给ui if(mail.data) { - push_text_to_ui(mail.data); } } else if (mail.cmd == LN_HTTP_RECV_STORY_CHOOSE) { tag = "STORY_CHOOSE"; //推送给ui if(mail.data) { - push_text_to_ui(mail.data); } } else if (mail.cmd == LN_HTTP_RECV_STORY_RANDOM) { tag = "STORY_RANDOM"; //推送给ui if(mail.data) { - push_text_to_ui(mail.data); } } else if (mail.cmd == LN_HTTP_RECV_STORY_EXIT) { tag = "STORY_EXIT"; @@ -1460,14 +1481,14 @@ errcode_t uapi_ln_http_server_init(void) /* 不中断HTTP服务,按需可返回失败 */ } - /* 创建WebSocket自动启动任务:每3秒检测一次网络并启动WS */ - ln_ws_autostart_taskcfg.create_queue_handle = NULL; - ln_ws_autostart_taskcfg.attr.name = "ln_ws_autostart_task"; - ln_ws_autostart_taskcfg.attr.priority = osPriorityNormal; - ln_ws_autostart_taskcfg.attr.stack_size = 0x500; - ln_ws_autostart_taskcfg.func = ln_ws_autostart_task; - ln_ws_autostart_taskcfg.use_mem = USE_EXTEND_MEM; - (void)uapi_create_osThread_custom(&ln_ws_autostart_taskcfg); + // /* 创建WebSocket自动启动任务:每3秒检测一次网络并启动WS */ + // ln_ws_autostart_taskcfg.create_queue_handle = NULL; + // ln_ws_autostart_taskcfg.attr.name = "ln_ws_autostart_task"; + // ln_ws_autostart_taskcfg.attr.priority = osPriorityNormal; + // ln_ws_autostart_taskcfg.attr.stack_size = 0x1000; + // ln_ws_autostart_taskcfg.func = ln_ws_autostart_task; + // ln_ws_autostart_taskcfg.use_mem = USE_EXTEND_MEM; + // (void)uapi_create_osThread_custom(&ln_ws_autostart_taskcfg); return ERRCODE_SUCC; } -- 2.17.1