From f4a9c1ca697c4a215fdf115a8b0437fe1acc1456 Mon Sep 17 00:00:00 2001 From: cheng Date: Mon, 15 Sep 2025 17:46:22 +0800 Subject: [PATCH] =?utf8?q?4gai=E5=88=A0=E9=99=A4=E4=B8=80=E4=BA=9B?= =?utf8?q?=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../nativeui/aivoice/include/AiVoiceModel.h | 9 +- .../nativeui/aivoice/src/AiVoiceModel.cpp | 413 ++++++++++-------- .../nativeui/aivoice/src/AiVoiceView.cpp | 9 +- 3 files changed, 233 insertions(+), 198 deletions(-) diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h index c3c98a12b..6f619a1ce 100644 --- a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h +++ b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/include/AiVoiceModel.h @@ -20,6 +20,13 @@ #define AI_VOICE_ENABLE 0 +// 常量定义 +#define MAX_CHAT_CONTENT_COUNT 2 +#define DEFAULT_TIMEOUT_5S 5 //5秒 +#define DEFAULT_TIMEOUT_10S 10 //10秒 +#define DEFAULT_TIMEOUT_30S 30 //30秒 +#define DEFAULT_TIMEOUT_60S 60 //60秒 + // 设置当前使用的音频类型,0 表示 PCM,1 表示 SBC,2 表示 MSBC #define CURRENT_AIAUDIO_TYPE AIAUDIO_TYPE_SBC @@ -181,7 +188,7 @@ namespace OHOS std::string aiAnswerStr; // AI回答的问题 std::string accumulatedText; // tts播放文本 uint8_t ChatContentListCount{0}; // 列表数量 - static const uint16_t MaxChatContentListCount = 2; // 对话列表最大数量 + static const uint16_t MaxChatContentListCount = MAX_CHAT_CONTENT_COUNT; // 对话列表最大数量 ChatContentItem chatTtems[MaxChatContentListCount] = {0, "", false}; // 对话项数组 bool entryTextViewState{false}; // 进入返回结果界面的标志 std::map> selectAiModelToTextId; // pair的参数类型<模型的textid,查询模型是否可用id> diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp index f579976cc..7620f26e8 100644 --- a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp +++ b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp @@ -39,12 +39,6 @@ namespace OHOS { - // 声明定时器变量 - static osTimerId_t g_timer = nullptr; - static constexpr uint16_t THIRTY_TIME = 30 / 3; - static int Time = THIRTY_TIME; - static int AiModelConnectTimeout = 5; - AiVoiceModel::AiVoiceModel() { CreateDirectory("/user/userdata/AiRecording/"); @@ -186,8 +180,7 @@ namespace OHOS WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetSelect4gorbt() == AI_SELECT_4G"); if (GetInit_4gai_task()) { - uapi_start_AI_asr(); - + uapi_start_AI_asr(); } else { @@ -844,12 +837,13 @@ namespace OHOS if (!OHOS::AiVoiceModel::GetInstance().GetIsLimitDisplayed()) // 如果ai答案没有显示到极限了,就更新ai答案字符串 { delete_start_line_break_str(str); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "传入的str:%s", str.c_str()); aiAnswerStr += str; + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "接受字的符串:%s", aiAnswerStr.c_str()); /* -------------------------------------------------------------------------- */ // 累积接收到的文本 - accumulatedText += str; + // accumulatedText += str;//tts播放的代码去除掉 /* -------------------------------------------------------------------------- */ - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "接受字的符串:%s", aiAnswerStr.c_str()); } if (view_ != nullptr) { @@ -1008,8 +1002,6 @@ namespace OHOS { ClearQuestionAndAiAnswerStr(); StopListenAndRecordingUserQuestion(); - Time = THIRTY_TIME; - AiModelConnectTimeout = 5; AiVoiceConnectStatus = false; for (int i = 0; i < ChatContentListCount; i++) @@ -1029,12 +1021,15 @@ namespace OHOS } /* -------------------------------------------------------------------------- */ + // 声明定时器变量 + static osTimerId_t g_timer = nullptr; + static int Time = DEFAULT_TIMEOUT_10S; /*定时器到期时的处理*/ static void AIVoice_TimerCallbackProc(int data) { // 等待AI思考完成的定时器 WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIVoice_TimerCallbackProc,Time = %d", Time); - if (Time < 0) // 如果思考时间超时30s,进入连接超时界面 + if (Time < 0) // 如果思考时间超时10s,进入连接超时界面 { AiVoiceModel::GetInstance().AIVoice_StopTimer(); AiVoiceModel::GetInstance().SetErrnote("连接超时,请重新开始对话"); @@ -1139,19 +1134,18 @@ namespace OHOS WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret); } g_timer = nullptr; - Time = THIRTY_TIME; - AiModelConnectTimeout = 5; + Time = DEFAULT_TIMEOUT_10S; } } // 声明定时器变量 static osTimerId_t g_screen60s_timer = nullptr; - static int8_t SCREEN_60S_TIME = 60; // 60s + static int8_t SCREEN_60S_TIME = DEFAULT_TIMEOUT_60S; // 60s static void ai_start_screen60s_timer_callbackProc(int data) { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_start_screen60s_timer_callbackProc,time = %d", SCREEN_60S_TIME); - SCREEN_60S_TIME -= 30; + SCREEN_60S_TIME -= DEFAULT_TIMEOUT_30S; WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ai_start_screen60s_timer_callbackProc,time = %d", SCREEN_60S_TIME); if (SCREEN_60S_TIME <= 0) { @@ -1215,12 +1209,12 @@ namespace OHOS WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret); } g_screen60s_timer = nullptr; - SCREEN_60S_TIME = 60; + SCREEN_60S_TIME = DEFAULT_TIMEOUT_60S; } } void AiVoiceModel::reset_ai_screen60s_timer_time() { - SCREEN_60S_TIME = 60; + SCREEN_60S_TIME = DEFAULT_TIMEOUT_60S; WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "reset_ai_screen60s_timer_time %d", SCREEN_60S_TIME); if (nullptr == g_screen60s_timer) { @@ -1320,8 +1314,8 @@ namespace OHOS } } - static osTimerId_t g_ai_is_ready_Handle = nullptr; // 处理查询AI是否就绪定时器 - static int8_t AI_IS_READY_TIMEOUT = 5; // 5s钟超时 + static osTimerId_t g_ai_is_ready_Handle = nullptr; // 处理查询AI是否就绪定时器 + static int8_t AI_IS_READY_TIMEOUT = DEFAULT_TIMEOUT_5S; // 5s钟超时 static void AI_IS_READY_CallbackProc(int data) { if (AI_IS_READY_TIMEOUT <= 0) // 模型连接失败有5秒超时 @@ -1421,7 +1415,7 @@ namespace OHOS WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret); } g_ai_is_ready_Handle = nullptr; - AI_IS_READY_TIMEOUT = 5; + AI_IS_READY_TIMEOUT = DEFAULT_TIMEOUT_5S; } } @@ -1962,201 +1956,240 @@ extern "C" #ifdef BLE_INSTRUCT -/** - * @brief 过滤字符串中无法显示的文字(使用GetGlyphPathData接口) - * @param input_str 输入字符串 - * @param output_str 输出字符串缓冲区 - * @param max_len 输出缓冲区最大长度 - * @return 过滤后的字符串长度,-1表示失败 - */ -int32_t chat_filter_unsupported_chars(const char *input_str, char *output_str, uint32_t max_len) -{ - if (input_str == NULL || output_str == NULL || max_len == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid parameters for asr_filter_unsupported_chars\n"); - return -1; - } - - // 初始化输出缓冲区 - memset(output_str, 0, max_len); - - uint32_t input_len = strlen(input_str); - uint32_t output_pos = 0; - uint32_t input_pos = 0; - - while (input_pos < input_len && output_pos < max_len - 1) { - uint32_t char_start = input_pos; - uint32_t char_end = input_pos; - - // 获取下一个UTF-8字符 - uint32_t unicode_char = 0; - bool valid_utf8 = false; - - // 简单的UTF-8解码 - if ((unsigned char)input_str[input_pos] < 0x80) { - // ASCII字符 - unicode_char = (unsigned char)input_str[input_pos]; - char_end = input_pos + 1; - valid_utf8 = true; - } else if ((unsigned char)input_str[input_pos] >= 0xC0 && (unsigned char)input_str[input_pos] < 0xE0) { - // 2字节UTF-8字符 - if (input_pos + 1 < input_len) { - unicode_char = ((unsigned char)input_str[input_pos] & 0x1F) << 6 | - ((unsigned char)input_str[input_pos + 1] & 0x3F); - char_end = input_pos + 2; + /** + * @brief 过滤字符串中无法显示的文字(使用GetGlyphPathData接口) + * @param input_str 输入字符串 + * @param output_str 输出字符串缓冲区 + * @param max_len 输出缓冲区最大长度 + * @return 过滤后的字符串长度,-1表示失败 + */ + int32_t chat_filter_unsupported_chars(const char *input_str, char *output_str, uint32_t max_len) + { + if (input_str == NULL || output_str == NULL || max_len == 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid parameters for asr_filter_unsupported_chars\n"); + return -1; + } + + // 初始化输出缓冲区 + memset(output_str, 0, max_len); + + uint32_t input_len = strlen(input_str); + uint32_t output_pos = 0; + uint32_t input_pos = 0; + + while (input_pos < input_len && output_pos < max_len - 1) + { + uint32_t char_start = input_pos; + uint32_t char_end = input_pos; + + // 获取下一个UTF-8字符 + uint32_t unicode_char = 0; + bool valid_utf8 = false; + + // 简单的UTF-8解码 + if ((unsigned char)input_str[input_pos] < 0x80) + { + // ASCII字符 + unicode_char = (unsigned char)input_str[input_pos]; + char_end = input_pos + 1; valid_utf8 = true; } - } else if ((unsigned char)input_str[input_pos] >= 0xE0 && (unsigned char)input_str[input_pos] < 0xF0) { - // 3字节UTF-8字符 - if (input_pos + 2 < input_len) { - unicode_char = ((unsigned char)input_str[input_pos] & 0x0F) << 12 | - ((unsigned char)input_str[input_pos + 1] & 0x3F) << 6 | - ((unsigned char)input_str[input_pos + 2] & 0x3F); - char_end = input_pos + 3; - valid_utf8 = true; + else if ((unsigned char)input_str[input_pos] >= 0xC0 && (unsigned char)input_str[input_pos] < 0xE0) + { + // 2字节UTF-8字符 + if (input_pos + 1 < input_len) + { + unicode_char = ((unsigned char)input_str[input_pos] & 0x1F) << 6 | + ((unsigned char)input_str[input_pos + 1] & 0x3F); + char_end = input_pos + 2; + valid_utf8 = true; + } } - } else if ((unsigned char)input_str[input_pos] >= 0xF0 && (unsigned char)input_str[input_pos] < 0xF8) { - // 4字节UTF-8字符 - if (input_pos + 3 < input_len) { - unicode_char = ((unsigned char)input_str[input_pos] & 0x07) << 18 | - ((unsigned char)input_str[input_pos + 1] & 0x3F) << 12 | - ((unsigned char)input_str[input_pos + 2] & 0x3F) << 6 | - ((unsigned char)input_str[input_pos + 3] & 0x3F); - char_end = input_pos + 4; - valid_utf8 = true; + else if ((unsigned char)input_str[input_pos] >= 0xE0 && (unsigned char)input_str[input_pos] < 0xF0) + { + // 3字节UTF-8字符 + if (input_pos + 2 < input_len) + { + unicode_char = ((unsigned char)input_str[input_pos] & 0x0F) << 12 | + ((unsigned char)input_str[input_pos + 1] & 0x3F) << 6 | + ((unsigned char)input_str[input_pos + 2] & 0x3F); + char_end = input_pos + 3; + valid_utf8 = true; + } } - } - - if (!valid_utf8) { - // 无效的UTF-8字符,跳过 - input_pos++; - continue; - } - - // 使用GetGlyphPathData接口检查字符是否可以在字体中显示 - bool char_supported = true; - - // 对于ASCII字符,直接支持 - if (unicode_char < 0x80) { - char_supported = true; - } else { - // 使用字体引擎检查字符是否支持 - OHOS::UIFont *fontEngine = OHOS::UIFont::GetInstance(); - if (fontEngine != NULL) { - // 使用GetGlyphPathData检查字符是否支持 - OHOS::GlyphPathData path; - if (!fontEngine->GetGlyphPathData(unicode_char, 0, path)) { - // 字符不支持,标记为不支持 - char_supported = false; - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Character 0x%X not supported by font engine\n", unicode_char); - } else { - // 字符支持 - char_supported = true; + else if ((unsigned char)input_str[input_pos] >= 0xF0 && (unsigned char)input_str[input_pos] < 0xF8) + { + // 4字节UTF-8字符 + if (input_pos + 3 < input_len) + { + unicode_char = ((unsigned char)input_str[input_pos] & 0x07) << 18 | + ((unsigned char)input_str[input_pos + 1] & 0x3F) << 12 | + ((unsigned char)input_str[input_pos + 2] & 0x3F) << 6 | + ((unsigned char)input_str[input_pos + 3] & 0x3F); + char_end = input_pos + 4; + valid_utf8 = true; + } + } + + if (!valid_utf8) + { + // 无效的UTF-8字符,跳过 + input_pos++; + continue; + } + + // 使用GetGlyphPathData接口检查字符是否可以在字体中显示 + bool char_supported = true; + + // 对于ASCII字符,直接支持 + if (unicode_char < 0x80) + { + char_supported = true; + } + else + { + // 使用字体引擎检查字符是否支持 + OHOS::UIFont *fontEngine = OHOS::UIFont::GetInstance(); + if (fontEngine != NULL) + { + // 使用GetGlyphPathData检查字符是否支持 + OHOS::GlyphPathData path; + if (!fontEngine->GetGlyphPathData(unicode_char, 0, path)) + { + // 字符不支持,标记为不支持 + char_supported = false; + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Character 0x%X not supported by font engine\n", unicode_char); + } + else + { + // 字符支持 + char_supported = true; + } } - } else { - // 字体引擎不可用,使用简化的字符范围检查 - if (unicode_char >= 0x4E00 && unicode_char <= 0x9FFF) { - // 中文字符范围 - char_supported = true; - } else if (unicode_char >= 0xAC00 && unicode_char <= 0xD7AF) { - // 韩文字符范围 - char_supported = true; - } else if (unicode_char >= 0x3040 && unicode_char <= 0x309F) { - // 平假名 - char_supported = true; - } else if (unicode_char >= 0x30A0 && unicode_char <= 0x30FF) { - // 片假名 - char_supported = true; - } else if (unicode_char >= 0x2000 && unicode_char <= 0x206F) { - // 标点符号 - char_supported = true; - } else { - // 其他字符,标记为不支持 - char_supported = false; + else + { + // 字体引擎不可用,使用简化的字符范围检查 + if (unicode_char >= 0x4E00 && unicode_char <= 0x9FFF) + { + // 中文字符范围 + char_supported = true; + } + else if (unicode_char >= 0xAC00 && unicode_char <= 0xD7AF) + { + // 韩文字符范围 + char_supported = true; + } + else if (unicode_char >= 0x3040 && unicode_char <= 0x309F) + { + // 平假名 + char_supported = true; + } + else if (unicode_char >= 0x30A0 && unicode_char <= 0x30FF) + { + // 片假名 + char_supported = true; + } + else if (unicode_char >= 0x2000 && unicode_char <= 0x206F) + { + // 标点符号 + char_supported = true; + } + else + { + // 其他字符,标记为不支持 + char_supported = false; + } + } + } + + if (char_supported) + { + // 字符支持,复制到输出缓冲区 + uint32_t char_len = char_end - char_start; + if (output_pos + char_len < max_len) + { + memcpy(&output_str[output_pos], &input_str[char_start], char_len); + output_pos += char_len; + } + else + { + break; // 输出缓冲区已满 } } + else + { + // 字符不支持,跳过不支持的字符 + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Unsupported character: 0x%X, skipping\n", unicode_char); + } + + input_pos = char_end; } - - if (char_supported) { - // 字符支持,复制到输出缓冲区 - uint32_t char_len = char_end - char_start; - if (output_pos + char_len < max_len) { - memcpy(&output_str[output_pos], &input_str[char_start], char_len); - output_pos += char_len; - } else { - break; // 输出缓冲区已满 - } - } else { - // 字符不支持,跳过不支持的字符 - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Unsupported character: 0x%X, skipping\n", unicode_char); - } - - input_pos = char_end; - } - - // 确保输出字符串以null结尾 - output_str[output_pos] = '\0'; - - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Filtered string: '%s' -> '%s' (length: %d)\n", - input_str, output_str, output_pos); - - return output_pos; -} -/** - * @brief 过滤chat结果中的无法显示字符 - * @param result chat识别结果字符串 - * @return 过滤后的字符串长度,-1表示失败 - */ -int32_t chat_filter_result_chars(char *result) -{ - if (result == NULL) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " result string is NULL\n"); - return -1; - } - - uint32_t max_len = strlen(result) + 1; - char *temp_buffer = (char *)malloc(max_len); - if (temp_buffer == NULL) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for temp buffer\n"); - return -1; - } - - int32_t filtered_len = chat_filter_unsupported_chars(result, temp_buffer, max_len); - if (filtered_len >= 0) { - strcpy(result, temp_buffer); - } - - free(temp_buffer); - return filtered_len; -} + // 确保输出字符串以null结尾 + output_str[output_pos] = '\0'; + + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Filtered string: '%s' -> '%s' (length: %d)\n", + input_str, output_str, output_pos); + + return output_pos; + } + + /** + * @brief 过滤chat结果中的无法显示字符 + * @param result chat识别结果字符串 + * @return 过滤后的字符串长度,-1表示失败 + */ + int32_t chat_filter_result_chars(char *result) + { + if (result == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " result string is NULL\n"); + return -1; + } + + uint32_t max_len = strlen(result) + 1; + char *temp_buffer = (char *)malloc(max_len); + if (temp_buffer == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for temp buffer\n"); + return -1; + } + + int32_t filtered_len = chat_filter_unsupported_chars(result, temp_buffer, max_len); + if (filtered_len >= 0) + { + strcpy(result, temp_buffer); + } + free(temp_buffer); + return filtered_len; + } - #include "bleEvent.h" - #include "bleInstruct.h" +#include "bleEvent.h" +#include "bleInstruct.h" void ble_set_ai_Question_str_(char *buf) { OHOS::AiVoiceModel::GetInstance().SetUserQuestionStr(std::string(buf)); } - - void ble_set_ai_Answer_str_(char *buf,uint8_t type) + void ble_set_ai_Answer_str_(char *buf, uint8_t type) { -chat_filter_result_chars(buf); - OHOS::AiVoiceModel::GetInstance().SetAiAnswerStrStr(std::string(buf),type); + chat_filter_result_chars(buf); + OHOS::AiVoiceModel::GetInstance().SetAiAnswerStrStr(std::string(buf), type); } extern bleInstruct_t_ bleInstruct_t; void ble_AI_init(void) { - bleInstruct_t.ble_set_ai_Question_str= ble_set_ai_Question_str_; + bleInstruct_t.ble_set_ai_Question_str = ble_set_ai_Question_str_; - bleInstruct_t.ble_set_ai_Answer_str=ble_set_ai_Answer_str_; + bleInstruct_t.ble_set_ai_Answer_str = ble_set_ai_Answer_str_; } - #endif - +#endif #ifdef __cplusplus #if __cplusplus diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp index e715afb57..dbcee4be8 100644 --- a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp +++ b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceView.cpp @@ -1004,12 +1004,8 @@ namespace OHOS case AIVOICE_LISTENING_VIEWID: if (p_AivoiceListeningView) { - if (p_AivoiceListeningView) - { - delete p_AivoiceListeningView; - p_AivoiceListeningView = nullptr; - } - // p_AivoiceListeningView->StartOrStopAivoiceListeningImageAnimatorView(false); + delete p_AivoiceListeningView; + p_AivoiceListeningView = nullptr; } break; case AIVOICE_THINKING_VIEWID: @@ -1017,7 +1013,6 @@ namespace OHOS { delete p_AivoiceThinkingView; p_AivoiceThinkingView = nullptr; - // p_AivoiceThinkingView->StartOrStopAiVoiceThinkingImageAnimatorView(false); } break; case AIVOICE_SELECT_VIEW: -- 2.17.1