break;
case WS_EVENT_DISCONNECTED:
printf("[LN][WS] Event: Disconnected\n");
- g_ws_connected = WS_STATE_DISCONNECTED;
+ g_ws_connected = WS_STATE_DISCONNECTED;
// 触发断连事件
if (g_ws_message_callback != NULL) {
g_ws_message_callback(NULL, WS_CMD_DISCONNECTED);
}
- /* 断开后增加重连计数,由监督线程在下一次连接时携带 */
- if (g_ws_running) {
- if (g_ws_reconnect_count < 0xFFFFFFFFu) {
- g_ws_reconnect_count++;
- }
- }
+ /* 断开后增加重连计数,由监督线程在下一次连接时携带 */
+ if (g_ws_running) {
+ if (g_ws_reconnect_count < 0xFFFFFFFFu) {
+ g_ws_reconnect_count++;
+ }
+ }
break;
default:
printf("[LN][WS] Event: Unknown event type %d\n", event_type);
// 开始新的音频聊天
int ln_ws_start_audio_chat(ln_audio_chat_command_t command_type)
{
+ if(g_ws_connected != WS_STATE_CONNECTED)
+ {
+ printf("[LN][WS] g_ws_connected!=WS_STATE_CONNECTED");
+ return 0;
+ }
+
if (g_audio_chat_ctx.is_active) {
printf("[LN][WS] Audio chat already active: %s\n", g_audio_chat_ctx.chat_id);
return 0;
}
+ // AI_ForceInterrupt();
// 设置命令类型
g_audio_chat_command_type = command_type;
return uapi_ws_send_text(text);
}
+/* 发送随机故事请求 */
+int ln_ws_send_random_story_request(const char *story_theme)
+{
+ if (!story_theme) {
+ printf("[LN][WS] Invalid story theme parameter\n");
+ return -1;
+ }
+
+ if (g_ws_connected != WS_STATE_CONNECTED) {
+ printf("[LN][WS] Cannot send random story request, connection state: %d\n", g_ws_connected);
+ return -1;
+ }
+
+ // 生成聊天ID(使用当前对话ID)
+ char chat_id[128];
+ generate_chat_id(chat_id, sizeof(chat_id));
+
+ // 生成消息ID
+ char message_id[128];
+ generate_message_id(message_id, sizeof(message_id), chat_id, 1);
+
+ // 构建JSON消息
+ cJSON *json = cJSON_CreateObject();
+ if (!json) {
+ printf("[LN][WS] Failed to create JSON object\n");
+ return -1;
+ }
+
+ // 添加基本字段
+ cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+ cJSON_AddNumberToObject(json, "timestamp", (double)time(NULL));
+ cJSON_AddStringToObject(json, "messageId", message_id);
+ cJSON_AddStringToObject(json, "command", "RandomStoryRequest");
+
+ // 添加data字段
+ cJSON *data = cJSON_CreateObject();
+ if (!data) {
+ printf("[LN][WS] Failed to create data JSON object\n");
+ cJSON_Delete(json);
+ return -1;
+ }
+
+ cJSON_AddStringToObject(data, "chatId", chat_id);
+ cJSON_AddStringToObject(data, "storyTheme", story_theme);
+ cJSON_AddItemToObject(json, "data", data);
+
+ // 转换为字符串
+ char *json_string = cJSON_Print(json);
+ if (!json_string) {
+ printf("[LN][WS] Failed to convert JSON to string\n");
+ cJSON_Delete(json);
+ return -1;
+ }
+
+ printf("[LN][WS] Sending RandomStoryRequest: %s\n", json_string);
+
+ // 发送消息
+ int ret = uapi_ws_send_text(json_string);
+
+ // 清理资源
+ free(json_string);
+ cJSON_Delete(json);
+
+ if (ret == 0) {
+ printf("[LN][WS] RandomStoryRequest sent successfully\n");
+ } else {
+ printf("[LN][WS] Failed to send RandomStoryRequest\n");
+ }
+
+ return ret;
+}
+
/* 停止:关闭心跳并关闭连接 */
int ln_ws_stop(void)
return WS_CMD_VOICE_CHAT_RESPONSE;
} else if (strcmp(command_str, "ChooseStoryResponse") == 0) {
return WS_CMD_CHOOSE_STORY_RESPONSE;
+ } else if (strcmp(command_str, "RandomStoryResponse") == 0) {
+ return WS_CMD_RANDOM_STORY_RESPONSE;
} else {
return WS_CMD_UNKNOWN;
}
// "data":{"audioUrl":"http://ambybox-api.test.leiniao.com/ambybox-device-api/file/774317549446_20250926175018_1758880218961.mp3",
// "textContent":"(颔首,夹着烟的手指轻敲桌面)来者何人?"}}}
+
+// {
+// "deviceId": "DEVICE_001",
+// "timestamp": 1640995201,
+// "messageId": "random_story_response_001",
+// "command": "RandomStoryResponse",
+// "data": {
+// "chatId": "random_story_12345",
+// "finished": false,
+// "data": {
+// "storyTheme": "冒险故事",
+// "storyContent": "在一个阳光明媚的早晨",
+// "storyAudioUrl": "https://example.com/story/audio/chunk_001.mp3",
+// "storyDuration": null
+// },
+// "errorCode": null
+// }
+// }
static int ln_ws_parse_data_message(const char *json_str, ws_data_msg_t *data_msg)
{
if (!json_str || !data_msg) {
strncpy(data_msg->command_str, command->valuestring, sizeof(data_msg->command_str) - 1);
data_msg->command_str[sizeof(data_msg->command_str) - 1] = '\0';
data_msg->command = ln_ws_parse_command_string(command->valuestring);
+
+ // 对于未知命令,记录日志但不返回错误
+ if (data_msg->command == WS_CMD_UNKNOWN) {
+ printf("[LN][WS] Unknown command received: %s\n", command->valuestring);
+ }
} else {
printf("[LN][WS] Missing or invalid command in message\n");
cJSON_Delete(root);
data_msg->finished ? "true" : "false", data_msg->chat_id, data_msg->text_content, data_msg->audio_url);
}
+ // 解析RandomStoryResponse特定字段
+ if (data_msg->command == WS_CMD_RANDOM_STORY_RESPONSE) {
+ cJSON *data_obj = cJSON_GetObjectItem(root, "data");
+ if (data_obj && cJSON_IsObject(data_obj)) {
+ // 解析finished字段
+ cJSON *finished = cJSON_GetObjectItem(data_obj, "finished");
+ if (finished && cJSON_IsBool(finished)) {
+ data_msg->finished = cJSON_IsTrue(finished);
+ }
+
+ // 解析chatId字段
+ cJSON *chat_id = cJSON_GetObjectItem(data_obj, "chatId");
+ if (chat_id && cJSON_IsString(chat_id) && chat_id->valuestring) {
+ strncpy(data_msg->chat_id, chat_id->valuestring, sizeof(data_msg->chat_id) - 1);
+ data_msg->chat_id[sizeof(data_msg->chat_id) - 1] = '\0';
+ }
+
+ // 解析data.data字段
+ cJSON *data_data = cJSON_GetObjectItem(data_obj, "data");
+ if (data_data && cJSON_IsObject(data_data)) {
+ // 解析storyTheme字段,存储到text_content中
+ cJSON *story_theme = cJSON_GetObjectItem(data_data, "storyTheme");
+ if (story_theme && cJSON_IsString(story_theme) && story_theme->valuestring) {
+ strncpy(data_msg->text_content, story_theme->valuestring, sizeof(data_msg->text_content) - 1);
+ data_msg->text_content[sizeof(data_msg->text_content) - 1] = '\0';
+ }
+
+ // 解析storyContent字段(RandomStoryResponse特有)
+ cJSON *story_content = cJSON_GetObjectItem(data_data, "storyContent");
+ if (story_content && cJSON_IsString(story_content) && story_content->valuestring) {
+ // 如果text_content为空,使用storyContent填充
+ if (strlen(data_msg->text_content) == 0) {
+ strncpy(data_msg->text_content, story_content->valuestring, sizeof(data_msg->text_content) - 1);
+ data_msg->text_content[sizeof(data_msg->text_content) - 1] = '\0';
+ }
+ }
+
+ // 解析storyAudioUrl字段,存储到audio_url中
+ cJSON *story_audio_url = cJSON_GetObjectItem(data_data, "storyAudioUrl");
+ if (story_audio_url && cJSON_IsString(story_audio_url) && story_audio_url->valuestring) {
+ strncpy(data_msg->audio_url, story_audio_url->valuestring, sizeof(data_msg->audio_url) - 1);
+ data_msg->audio_url[sizeof(data_msg->audio_url) - 1] = '\0';
+ }
+ }
+ }
+
+ printf("[LN][WS] RandomStoryResponse parsed: finished=%s, chatId=%s, storyTheme=%s, storyContent=%s, storyAudioUrl=%s\n",
+ data_msg->finished ? "true" : "false", data_msg->chat_id, data_msg->text_content,
+ data_msg->text_content, data_msg->audio_url);
+ }
+
// 保存原始JSON字符串
data_msg->raw_json = (char*)malloc(strlen(json_str) + 1);
if (data_msg->raw_json) {
break;
case WS_CMD_PONG:
if (data_msg) {
- printf("[LN][WS] Default: Processing Pong message\n");
- // 更新心跳状态、记录响应时间等
+ printf("[LN][WS] Default: Processing Pong message\n");
+ // 更新心跳状态、记录响应时间等
}
break;
case WS_CMD_CHARACTER_CHANGE:
if (data_msg) {
- printf("[LN][WS] Default: Processing CharacterChange message\n");
+ printf("[LN][WS] Default: Processing CharacterChange message\n");
}
break;
case WS_CMD_SLEEP_MODE_START:
if (data_msg) {
- printf("[LN][WS] Default: Processing SleepModeStart message\n");
+ printf("[LN][WS] Default: Processing SleepModeStart message\n");
}
break;
case WS_CMD_SLEEP_MODE_END:
if (data_msg) {
- printf("[LN][WS] Default: Processing SleepModeEnd message\n");
+ printf("[LN][WS] Default: Processing SleepModeEnd message\n");
}
break;
case WS_CMD_DEVICE_BIND:
if (data_msg) {
- printf("[LN][WS] Default: Processing DeviceBind message\n");
+ printf("[LN][WS] Default: Processing DeviceBind message\n");
}
break;
case WS_CMD_DEVICE_UNBIND:
if (data_msg) {
- printf("[LN][WS] Default: Processing DeviceUnbind message\n");
+ printf("[LN][WS] Default: Processing DeviceUnbind message\n");
}
break;
case WS_CMD_SCHEDULE_REMINDER:
if (data_msg) {
- printf("[LN][WS] Default: Processing ScheduleReminder message\n");
+ printf("[LN][WS] Default: Processing ScheduleReminder message\n");
}
break;
case WS_CMD_SCHEDULE_REMINDER_CFG:
if (data_msg) {
- printf("[LN][WS] Default: Processing ScheduleReminderConfig message\n");
+ printf("[LN][WS] Default: Processing ScheduleReminderConfig message\n");
}
break;
case WS_CMD_VOICE_CHAT_RESPONSE:
printf("[LN][WS] Story Audio URL: %s\n", data_msg->audio_url);
}
break;
+ case WS_CMD_RANDOM_STORY_RESPONSE:
+ if (data_msg) {
+ printf("[LN][WS] Default: Processing RandomStoryResponse message\n");
+ printf("[LN][WS] RandomStoryResponse details: finished=%s, chatId=%s\n",
+ data_msg->finished ? "true" : "false", data_msg->chat_id);
+ printf("[LN][WS] Story Theme: %s\n", data_msg->text_content);
+ printf("[LN][WS] Story Audio URL: %s\n", data_msg->audio_url);
+ }
+ break;
+ case WS_CMD_UNKNOWN:
+ if (data_msg) {
+ printf("[LN][WS] Default: Processing unknown command message\n");
+ printf("[LN][WS] Unknown command details: command=%s, deviceId=%s, messageId=%s\n",
+ data_msg->command_str, data_msg->device_id, data_msg->message_id);
+ if (data_msg->raw_json) {
+ printf("[LN][WS] Raw JSON: %s\n", data_msg->raw_json);
+ }
+ }
+ break;
default:
printf("[LN][WS] Default: Processing unknown command: %d\n", type);
break;
printf("[LN][WS] Not enough data for Base64 decode yet: %zu\n", g_base64_cache_size);
}
}
+
+
+// {
+// "deviceId": "DEVICE_001",
+// "timestamp": 1640995200,
+// "messageId": "random_story_001",
+// "command": "RandomStoryRequest",
+// "data": {
+// "chatId": "random_story_12345",
+// "storyTheme": "冒险"
+// }
+// }
+
+
////////////////////////////////////////////////////////////////////////////
// int uapi_ln_download_mp3_file(const char *url)