添加获取ota升级包大小接口,优化解析语音聊天响应接口
authorluozheng <1732036298@qq.com>
Tue, 30 Sep 2025 08:22:55 +0000 (16:22 +0800)
committerluozheng <1732036298@qq.com>
Tue, 30 Sep 2025 08:22:55 +0000 (16:22 +0800)
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_ota.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_story_random.c

index 0264379..95e90df 100644 (file)
@@ -129,7 +129,6 @@ char *uapi_ln_get_device_id(void)
 
     if (s_cached_device_id && s_cached_device_id[0])
     {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_id cached: %s", s_cached_device_id);
         return s_cached_device_id;
     }
     /* 1. 尝试从文件读取 */
@@ -348,6 +347,16 @@ int uapi_ln_is_file_downloading(void)
     return g_ln_is_file_downloading;
 }
 
+/* 获取ota包大小 */
+static int g_ln_ota_package_size = 0;
+int uapi_ln_get_ota_package_size(void)
+{
+    return g_ln_ota_package_size;
+}
+void uapi_ln_set_ota_package_size(int size)
+{
+    g_ln_ota_package_size = size;
+}
 
 /* 下载文件
 @param url 文件URL
@@ -459,7 +468,9 @@ int uapi_ln_download_file(const char *url, const char *save_path)
     {
         ret = ERRCODE_FAIL;
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 文件下载失败删除不完整文件,save_path = %s", save_path);
-        if (unlink(save_path) < 0)
+        int ret = 0;
+        ret = unlink(save_path);
+        if (ret < 0)
         {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "删除不完整文件失败\r\n");
         }
@@ -480,7 +491,7 @@ int uapi_ln_download_file(const char *url, const char *save_path)
 /* 下载函数封装:带重试,不做UI通知与资源释放 */
 int uapi_ln_download_with_retry(const char *url, const char *save_path, int max_retries)
 {
-    if (url == NULL || save_path == NULL)
+    if (url == NULL || save_path == NULL || (max_retries <= 0 || max_retries > 10 ))
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 参数无效");
         return ERRCODE_FAIL;
index b0116bc..2f78045 100644 (file)
@@ -214,6 +214,10 @@ const char *uapi_ln_get_audio_path(void);
 const char *uapi_ln_get_user_id(void);
 //获取当前是否正在下载文件
 int uapi_ln_is_file_downloading(void);
+/* 获取ota包大小 */
+int uapi_ln_get_ota_package_size(void);
+/* 设置ota包大小 */
+void uapi_ln_set_ota_package_size(int size);
 /*文件下载函数:从URL下载到指定路径*/
 int uapi_ln_download_file(const char *url, const char *save_path);
 int uapi_ln_download_with_retry(const char *url, const char *save_path, int max_retries);
@@ -246,9 +250,6 @@ uint32_t ln_token_is_expired(int *expired_out);
 uint32_t uapi_ln_refresh_device_token(void);
 void ln_start_emoji_download(void);
 
-/* 从本地读取角色配置 */
-void ln_read_character_config(void);
-
 // 解析设备角色配置
 void ln_parse_character_config(const char *json_buf, int json_len);
 void ln_parse_character_config_local(const char *json_buf, int json_len);
index b58b724..5ab2b66 100644 (file)
@@ -31,30 +31,6 @@ static inline void ln_assign_dup(char **dst, const char *src)
     *dst = newp;
 }
 
-/* 从本地读取角色配置 */
-void ln_read_character_config(void)
-{
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] read character config");
-    FILE *file = fopen(LN_CHARACTER_CONFIG_FILE, "rb");
-    if (!file)
-    {
-        printf("[DEVICE_CHARACTER] fopen failed\n");
-        return;
-    }
-    char json_buf[1024] = {0};
-    size_t n = fread(json_buf, 1, sizeof(json_buf) - 1, file);
-    if (n == 0)
-    {
-        printf("[DEVICE_CHARACTER] empty config file\n");
-        fclose(file);
-        return;
-    }
-    json_buf[n] = '\0';
-    ln_parse_character_config_local(json_buf, (int)n);
-    fclose(file);
-    printf("[DEVICE_CHARACTER] read character config success\n");
-}
-
 /* 保存角色配置到本地 */
 static void ln_save_character_config(const char *json_buf)
 {
@@ -257,14 +233,12 @@ void ln_parse_character_config(const char *json_buf, int json_len)
                 memcpy(req.url, g_ln_character_config.avatar_screen_image, ulen + 1);
             }
         }
+        const char *save = LN_DEVICE_SCREEN_IMAGE_FILE;
+        size_t slen = strlen(save);
+        req.save_path = (char *)malloc(slen + 1);
+        if (req.save_path)
         {
-            const char *save = LN_DEVICE_SCREEN_IMAGE_FILE;
-            size_t slen = strlen(save);
-            req.save_path = (char *)malloc(slen + 1);
-            if (req.save_path)
-            {
-                memcpy(req.save_path, save, slen + 1);
-            }
+            memcpy(req.save_path, save, slen + 1);
         }
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE, (char *)&req, sizeof(req));
     }
@@ -283,183 +257,6 @@ void ln_parse_character_config(const char *json_buf, int json_len)
     ln_clear_character_config();
 }
 
-// 本地解析
-void ln_parse_character_config_local(const char *json_buf, int json_len)
-{
-    if (!json_buf || json_len <= 0)
-    {
-        printf("[DEVICE_CHARACTER] invalid json input\n");
-        return;
-    }
-
-    char *text = (char *)malloc((size_t)json_len + 1);
-    if (!text)
-        return;
-    memcpy(text, json_buf, (size_t)json_len);
-    text[json_len] = '\0';
-
-    cJSON *root = cJSON_Parse(text);
-    if (!root)
-    {
-        printf("[DEVICE_CHARACTER] json parse failed\n");
-        free(text);
-        return;
-    }
-
-    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
-    cJSON *message = cJSON_GetObjectItem(root, "message");
-    if (errorCode && !cJSON_IsNull(errorCode))
-    {
-        printf("[DEVICE_CHARACTER] server error: %s\n", cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown");
-        printf("[DEVICE_CHARACTER] server message: %s\n", cJSON_IsString(message) ? message->valuestring : "unknown");
-        // 推送协议错误通知到UI
-        push_api_error_notification(cJSON_IsString(message) ? message->valuestring : "unknown");
-        cJSON_Delete(root);
-        free(text);
-        return;
-    }
-
-    cJSON *data = cJSON_GetObjectItem(root, "data");
-    if (!data || !cJSON_IsObject(data))
-    {
-        printf("[DEVICE_CHARACTER] no data object\n");
-        cJSON_Delete(root);
-        free(text);
-        return;
-    }
-
-    /* 基础字段 */
-    cJSON *cid = cJSON_GetObjectItem(data, "characterId");
-    cJSON *cname = cJSON_GetObjectItem(data, "characterName");
-    ln_assign_dup(&g_ln_character_config.character_id,
-                  (cid && cJSON_IsString(cid)) ? cid->valuestring : "");
-
-    ln_assign_dup(&g_ln_character_config.character_name,
-                  (cname && cJSON_IsString(cname)) ? cname->valuestring : "");
-
-    // "data": {
-    // "characterId": "char_001",
-    // "characterName": "小艾",
-    // "characterAvatar": {
-    //   "eyesShape": "upturned-eyes",
-    //   "hairColor": "blue",
-    //   "eyesColor": "green",
-    //   "hairStyle": "side-parted-comma",
-    //   "deviceScreen": "https://example.com/new_avatar.bin",
-    //   "screenImageAsEmoji": true
-    // }
-
-    /* 头像配置 */
-    cJSON *avatar = cJSON_GetObjectItem(data, "characterAvatar");
-    if (avatar && cJSON_IsObject(avatar))
-    {
-        cJSON *hairColor = cJSON_GetObjectItem(avatar, "hairColor");
-        cJSON *eyesColor = cJSON_GetObjectItem(avatar, "eyesColor");
-        cJSON *hairStyle = cJSON_GetObjectItem(avatar, "hairStyle");
-        cJSON *eyesShape = cJSON_GetObjectItem(avatar, "eyesShape");
-        cJSON *deviceScreen = cJSON_GetObjectItem(avatar, "deviceScreen");
-        cJSON *deviceScreenAsEmoji = cJSON_GetObjectItem(avatar, "screenImageAsEmoji");
-
-        ln_assign_dup(&g_ln_character_config.avatar_hair_color,
-                      (hairColor && cJSON_IsString(hairColor)) ? hairColor->valuestring : "");
-
-        ln_assign_dup(&g_ln_character_config.avatar_eyes_color,
-                      (eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : "");
-
-        ln_assign_dup(&g_ln_character_config.avatar_hair_style,
-                      (hairStyle && cJSON_IsString(hairStyle)) ? hairStyle->valuestring : "");
-
-        ln_assign_dup(&g_ln_character_config.avatar_eyes_shape,
-                      (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : "");
-
-        ln_assign_dup(&g_ln_character_config.avatar_screen_image,
-                      (deviceScreen && cJSON_IsString(deviceScreen)) ? deviceScreen->valuestring : "");
-
-        g_ln_character_config.avatar_screen_image_as_emoji =
-            (deviceScreenAsEmoji && cJSON_IsBool(deviceScreenAsEmoji)) ? (cJSON_IsTrue(deviceScreenAsEmoji) ? 1 : 0) : 0;
-    }
-    else
-    {
-        /* 缺省时清空结构体字段 */
-        ln_assign_dup(&g_ln_character_config.avatar_hair_color, "");
-        ln_assign_dup(&g_ln_character_config.avatar_eyes_color, "");
-        ln_assign_dup(&g_ln_character_config.avatar_hair_style, "");
-        ln_assign_dup(&g_ln_character_config.avatar_eyes_shape, "");
-        ln_assign_dup(&g_ln_character_config.avatar_screen_image, "");
-        g_ln_character_config.avatar_screen_image_as_emoji = 0;
-    }
-
-    // 将json体落库
-    ln_save_character_config(text);
-
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] push character config change notification");
-
-    /* 打印解析结果 */
-    printf("[DEVICE_CHARACTER] parsed:\n");
-    printf("  character_id: %s\n", g_ln_character_config.character_id ? g_ln_character_config.character_id : "");
-    printf("  character_name: %s\n", g_ln_character_config.character_name ? g_ln_character_config.character_name : "");
-    printf("  avatar_hair_color: %s\n", g_ln_character_config.avatar_hair_color ? g_ln_character_config.avatar_hair_color : "");
-    printf("  avatar_eyes_color: %s\n", g_ln_character_config.avatar_eyes_color ? g_ln_character_config.avatar_eyes_color : "");
-    printf("  avatar_hair_style: %s\n", g_ln_character_config.avatar_hair_style ? g_ln_character_config.avatar_hair_style : "");
-    printf("  avatar_eyes_shape: %s\n", g_ln_character_config.avatar_eyes_shape ? g_ln_character_config.avatar_eyes_shape : "");
-    printf("  avatar_screen_image: %s\n", g_ln_character_config.avatar_screen_image ? g_ln_character_config.avatar_screen_image : "");
-    printf("  avatar_screen_image_as_emoji: %d\n", g_ln_character_config.avatar_screen_image_as_emoji);
-
-    // 如果LN_DEVICE_SCREEN_IMAGE_FILE存在直接发送切换屏保通知
-    if (access(LN_DEVICE_SCREEN_IMAGE_FILE, F_OK) != -1)
-    {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片存在,直接发送切换屏保通知");
-        push_download_success_notification(DOWNLOAD_FILE_TYPE_SCREEN_IMAGE);
-    }
-    else
-    {
-        // 如果屏保图片不为空,则保存到本地
-        if (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0 && g_ln_character_config.avatar_screen_image_as_emoji == 1)
-        {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片不为空,下载屏保图片");
-            // 下载屏保图片,eg:"https://example.com/new_avatar.bin"
-            ln_download_file_req_t req;
-            memset(&req, 0, sizeof(req));
-            /* 分配与拷贝,发送方分配,接收方负责释放 */
-            if (g_ln_character_config.avatar_screen_image)
-            {
-                size_t ulen = strlen(g_ln_character_config.avatar_screen_image);
-                req.url = (char *)malloc(ulen + 1);
-                if (req.url)
-                {
-                    memcpy(req.url, g_ln_character_config.avatar_screen_image, ulen + 1);
-                }
-            }
-            {
-                const char *save = LN_DEVICE_SCREEN_IMAGE_FILE;
-                size_t slen = strlen(save);
-                req.save_path = (char *)malloc(slen + 1);
-                if (req.save_path)
-                {
-                    memcpy(req.save_path, save, slen + 1);
-                }
-            }
-            
-            //通知ui切换slice下载屏保
-            push_download_file_notification(DOWNLOAD_FILE_TYPE_SCREEN_IMAGE);
-
-            do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE, (char *)&req, sizeof(req));
-        }
-
-        /* 推送角色配置更改通知 */
-        push_character_config_change_notification(g_ln_character_config.character_id,
-                                                  g_ln_character_config.character_name,
-                                                  g_ln_character_config.avatar_eyes_shape,
-                                                  g_ln_character_config.avatar_hair_color,
-                                                  g_ln_character_config.avatar_eyes_color,
-                                                  g_ln_character_config.avatar_hair_style,
-                                                  g_ln_character_config.avatar_screen_image_as_emoji);
-
-        cJSON_Delete(root);
-        free(text);
-        ln_clear_character_config();
-    }
-}
 
 // 获取设备角色信息
 uint32_t ln_device_get_character_http(const char *device_id,
index ceaa880..7c91ff8 100644 (file)
@@ -165,6 +165,8 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len)
     cJSON *packageUrl  = cJSON_GetObjectItem(data, "packageUrl");
     cJSON *packageMd5  = cJSON_GetObjectItem(data, "packageMd5");
     cJSON *packageSize = cJSON_GetObjectItem(data, "packageSize");
+    uapi_ln_set_ota_package_size(packageSize ? (int)packageSize->valuedouble : 0);
+
     if (!(targetVersion && cJSON_IsString(targetVersion) && updateType && (cJSON_IsNumber(updateType) || cJSON_IsString(updateType))))
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] task fields invalid");
index d2366ba..e7cf97c 100644 (file)
@@ -204,71 +204,105 @@ uint32_t ln_story_random_http(const char *device_id,
 //解析语音聊天响应
 void ln_parse_voice_chat_response(const char *json_str, int json_len)
 {
-    printf("%s\n", json_str);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s\n", json_str);
     cJSON *root = cJSON_Parse(json_str);
     if (!root)
     {
-        printf("parse failed\n");
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "parse failed\n");
         return;
     }
     cJSON *data = cJSON_GetObjectItem(root, "data");
-    if (!data)
+    if (!data || !cJSON_IsObject(data))
     {
-        printf("data is null\n");
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "data is null\n");
         cJSON_Delete(root);
         return;
     }
-    cJSON *textContent = cJSON_GetObjectItem(data, "textContent");
-    if (!textContent)
+
+    /* 新协议:data 下还有一层 data,textContent/intention/npcEmotion 在 data.data 中 */
+    cJSON *payload = cJSON_GetObjectItem(data, "data");
+
+    const char *text_str = NULL;
+    const char *intention_str = NULL;
+    const char *npc_emotion_str = NULL;
+
+    if (payload && cJSON_IsObject(payload))
     {
-        printf("textContent is null\n");
-        cJSON_Delete(root);
-        return;
+        cJSON *textContent = cJSON_GetObjectItem(payload, "textContent");
+        if (!(textContent && cJSON_IsString(textContent) && textContent->valuestring))
+        {
+            /* 兼容 text 字段名 */
+            textContent = cJSON_GetObjectItem(payload, "text");
+        }
+        if (textContent && cJSON_IsString(textContent) && textContent->valuestring)
+        {
+            text_str = textContent->valuestring;
+        }
+
+        cJSON *intention = cJSON_GetObjectItem(payload, "intention");
+        if (intention && cJSON_IsString(intention) && intention->valuestring)
+        {
+            intention_str = intention->valuestring;
+        }
+
+        cJSON *npcEmotion = cJSON_GetObjectItem(payload, "npcEmotion");
+        if (npcEmotion && cJSON_IsString(npcEmotion) && npcEmotion->valuestring)
+        {
+            npc_emotion_str = npcEmotion->valuestring;
+        }
     }
-    printf("用户文本内容: %s\n", textContent->valuestring);
-    push_text_to_ui(textContent->valuestring);
 
-    cJSON *intention = cJSON_GetObjectItem(data, "intention");
-    if (!intention)
+    if (text_str && text_str[0])
     {
-        printf("intention is null\n");
-        cJSON_Delete(root);
-        return;
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "用户文本内容: %s\n", text_str);
+        push_text_to_ui(text_str);
+    }
+    else
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "textContent is null\n");
+    }
+
+    if (intention_str)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "用户意图识别结果: %s\n", intention_str);
+        if(strcmp(intention_str, "StartSleepMode") == 0)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始哄睡\n");
+            push_sleep_mode_start_notification(NULL, 1); // 1意图识别结果
+            ln_ws_send_random_story_request(NULL);
+        }
+        else if(strcmp(intention_str, "EndSleepMode") == 0)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "结束哄睡\n");
+            push_sleep_mode_end_notification();
+        }
     }
-    printf("用户意图识别结果: %s\n", intention->valuestring);
-    if(strcmp(intention->valuestring, "StartSleepMode") == 0)
+    else
     {
-        printf("开始哄睡\n");
-        push_sleep_mode_start_notification(NULL, 1);//1意图识别结果,不是小程序直接发起
-        //通知websocket发送随机故事请求
-        ln_ws_send_random_story_request(NULL);
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "intention is null\n");
     }
-    else if(strcmp(intention->valuestring, "EndSleepMode") == 0)
+
+    if (npc_emotion_str)
     {
-        printf("结束哄睡\n");
-        push_sleep_mode_end_notification();
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NPC情感状态: %s\n", npc_emotion_str);
     }
-    cJSON *npcEmotion = cJSON_GetObjectItem(data, "npcEmotion");
-    if (!npcEmotion)
+    else
     {
-        printf("NPC情感状态 is null\n");
-        cJSON_Delete(root);
-        return;
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "NPC情感状态 is null\n");
     }
-    printf("NPC情感状态: %s\n", npcEmotion->valuestring);
     cJSON_Delete(root);
 }
 
 /* 解析哄睡模式开始:提取data.storyTheme并触发随机故事 */
 void ln_parse_sleep_mode_start(const char *json_str, int json_len)
 {
-    printf("[LN][SLEEP_START] parse json\n");
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] parse json\n");
        (void)json_len;
        if (json_str == NULL) {
-               printf("[LN][SLEEP_START] invalid json\n");
+               WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] invalid json\n");
                return;
        }
-       printf("[LN][SLEEP_START] parse json\n");
+       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] parse json\n");
        const char *theme = NULL;
        cJSON *root = cJSON_Parse(json_str);
        if (root) {
@@ -281,7 +315,7 @@ void ln_parse_sleep_mode_start(const char *json_str, int json_len)
                }
        }
 
-       printf("[LN][SLEEP_START] storyTheme=%s\n", theme);
+       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] storyTheme=%s\n", theme);
     // 该接口不需要任何参数,系统会自动生成随机主题的故事
     // storyTheme=随机
     if(theme == NULL || theme[0] == '\0') {
@@ -298,7 +332,7 @@ void ln_parse_sleep_mode_end(const char *json_str, int json_len)
 {
        (void)json_str;
        (void)json_len;
-       printf("[LN][SLEEP_END] received\n");
+       WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_END] received\n");
        /* 标记故事结束,供UI状态机使用 */
     push_sleep_mode_end_notification();
 }