*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)
{
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));
}
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,
//解析语音聊天响应
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) {
}
}
- 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') {
{
(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();
}