From af32daa25bb8c751143aab8169e484aa40d5294b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Wed, 3 Sep 2025 12:05:39 +0800 Subject: [PATCH] =?utf8?q?=E6=9B=B4=E6=96=B0ai=E7=9A=84=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + code/sdk/zhihui/ai/CMakeLists.txt | 5 +- code/sdk/zhihui/ai/Makefile | 5 +- code/sdk/zhihui/ai/example/ai_at_cmd.c | 25 +- code/sdk/zhihui/ai/example/ai_demo.c | 6 + code/sdk/zhihui/ai/include/ai_asr_service.h | 185 ++++++ code/sdk/zhihui/ai/include/ai_chat_service.h | 170 +++++ code/sdk/zhihui/ai/include/ai_core_types.h | 22 + code/sdk/zhihui/ai/include/ai_services.h | 151 +---- code/sdk/zhihui/ai/include/ai_tts_service.h | 199 ++++++ code/sdk/zhihui/ai/src/ai_asr_service.c | 464 +++++++++++++ code/sdk/zhihui/ai/src/ai_chat_service.c | 417 ++++++++++++ .../sdk/zhihui/ai/src/ai_connection_manager.c | 205 +++++- code/sdk/zhihui/ai/src/ai_memory_pool.c | 2 +- code/sdk/zhihui/ai/src/ai_services.c | 624 +++--------------- code/sdk/zhihui/ai/src/ai_tts_service.c | 467 +++++++++++++ 16 files changed, 2252 insertions(+), 696 deletions(-) create mode 100644 code/sdk/zhihui/ai/include/ai_asr_service.h create mode 100644 code/sdk/zhihui/ai/include/ai_chat_service.h create mode 100644 code/sdk/zhihui/ai/include/ai_tts_service.h create mode 100644 code/sdk/zhihui/ai/src/ai_asr_service.c create mode 100644 code/sdk/zhihui/ai/src/ai_chat_service.c create mode 100644 code/sdk/zhihui/ai/src/ai_tts_service.c diff --git a/.gitignore b/.gitignore index 498f53b9a..658467c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ code/sdk/interim_binary/brandy/libs/bt/evb_standard/liteos/br/libbt_host_audio_m fileschecksum.txt file.bin file_tmp.bin +code/sdk/zhihui/ai/build/ diff --git a/code/sdk/zhihui/ai/CMakeLists.txt b/code/sdk/zhihui/ai/CMakeLists.txt index 0d9202537..693d10cd2 100644 --- a/code/sdk/zhihui/ai/CMakeLists.txt +++ b/code/sdk/zhihui/ai/CMakeLists.txt @@ -21,8 +21,11 @@ set(AI_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_connection_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_memory_pool.c ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_services.c +${CMAKE_CURRENT_SOURCE_DIR}/src/ai_asr_service.c +${CMAKE_CURRENT_SOURCE_DIR}/src/ai_chat_service.c +${CMAKE_CURRENT_SOURCE_DIR}/src/ai_tts_service.c ${CMAKE_CURRENT_SOURCE_DIR}/example/ai_at_cmd.c -${CMAKE_CURRENT_SOURCE_DIR}/example/ai_demo.c +# ${CMAKE_CURRENT_SOURCE_DIR}/example/ai_demo.c ) set(SOURCES diff --git a/code/sdk/zhihui/ai/Makefile b/code/sdk/zhihui/ai/Makefile index 67ed0308b..b08c024f5 100644 --- a/code/sdk/zhihui/ai/Makefile +++ b/code/sdk/zhihui/ai/Makefile @@ -16,7 +16,10 @@ BUILD_DIR = build # 源文件 SOURCES = $(SRC_DIR)/ai_connection_manager.c \ $(SRC_DIR)/ai_memory_pool.c \ - $(SRC_DIR)/ai_services.c + $(SRC_DIR)/ai_services.c \ + $(SRC_DIR)/ai_asr_service.c \ + $(SRC_DIR)/ai_chat_service.c \ + $(SRC_DIR)/ai_tts_service.c # 示例文件 EXAMPLE_SOURCES = $(EXAMPLE_DIR)/ai_demo.c \ diff --git a/code/sdk/zhihui/ai/example/ai_at_cmd.c b/code/sdk/zhihui/ai/example/ai_at_cmd.c index 79af5b5ca..b3fd99012 100644 --- a/code/sdk/zhihui/ai/example/ai_at_cmd.c +++ b/code/sdk/zhihui/ai/example/ai_at_cmd.c @@ -48,9 +48,15 @@ extern "C" { #define AI_AT_FAILED (-1) /* 测试配置常量 */ +#if 0 #define AI_AT_DEMO_ASR_URL "ws://amp.raisound.com/asr/ws" #define AI_AT_DEMO_CHAT_URL "ws://amp.raisound.com/chat/ws" #define AI_AT_DEMO_TTS_URL "ws://amp.raisound.com/tts/ws" +#else +#define AI_AT_DEMO_ASR_URL "ws://192.168.1.100:8080/asr/ws" +#define AI_AT_DEMO_CHAT_URL "ws://192.168.1.100:8080/chat/ws" +#define AI_AT_DEMO_TTS_URL "ws://192.168.1.100:8080/tts/ws" +#endif #define AI_AT_DEMO_AUDIO_SIZE 1024 #define AI_AT_DEMO_CHAT_MESSAGE "你好,我是AI助手AT命令测试程序" #define AI_AT_DEMO_TTS_TEXT "欢迎使用AI语音服务AT命令测试" @@ -219,9 +225,9 @@ static uint32_t at_ai_init(uint8_t *para, uint32_t paraLen, char *strCommonCmd) } // 4. 设置回调函数 - g_ai_services_context.asr_result_cb = ai_asr_result_callback; - g_ai_services_context.chat_response_cb = ai_chat_response_callback; - g_ai_services_context.tts_result_cb = ai_tts_result_callback; + ai_asr_set_callbacks(&g_ai_services_context, ai_asr_result_callback, NULL, NULL, NULL); + ai_chat_set_callbacks(&g_ai_services_context, ai_chat_response_callback, NULL, NULL, NULL); + ai_tts_set_callbacks(&g_ai_services_context, ai_tts_result_callback, NULL, NULL, NULL); g_ai_at_initialized = true; printf("[AI_AT] AI服务初始化成功\n"); @@ -241,17 +247,26 @@ static uint32_t at_ai_connect(uint8_t *para, uint32_t paraLen, char *strCommonCm printf("[AI_AT] 执行 AT^AICONNECT - 连接AI服务\n"); + printf("[AI_AT] [DEBUG] Checking initialization status...\n"); if (!g_ai_at_initialized) { printf("[AI_AT] AI服务未初始化,请先执行 AT^AIINIT\n"); return ERRCODE_FAIL; } + printf("[AI_AT] [DEBUG] Initialization check passed\n"); + + /* 启动连接管理器,恢复正常WebSocket连接 */ + printf("[AI_AT] 启动AI服务连接管理器...\n"); + printf("[AI_AT] [DEBUG] About to call ai_connection_manager_start_all()...\n"); ai_error_t ret = ai_connection_manager_start_all(); + printf("[AI_AT] [DEBUG] ai_connection_manager_start_all() returned: %d\n", ret); if (ret == AI_OK) { - printf("[AI_AT] 所有AI服务连接启动成功\n"); + printf("[AI_AT] 连接管理器启动成功\n"); + printf("[AI_AT] 状态:所有AI服务连接线程已启动\n"); + printf("[AI_AT] WebSocket连接功能已恢复正常\n"); return ERRCODE_SUCC; } else { - printf("[AI_AT] AI服务连接启动失败: %d\n", ret); + printf("[AI_AT] 连接管理器启动失败: %d\n", ret); return ERRCODE_FAIL; } } diff --git a/code/sdk/zhihui/ai/example/ai_demo.c b/code/sdk/zhihui/ai/example/ai_demo.c index 1abac93a8..49c0e599b 100644 --- a/code/sdk/zhihui/ai/example/ai_demo.c +++ b/code/sdk/zhihui/ai/example/ai_demo.c @@ -37,9 +37,15 @@ /* ================================ 演示配置 ================================ */ +#if 0 #define DEMO_ASR_URL "ws://amp.raisound.com/asr/ws" #define DEMO_CHAT_URL "ws://amp.raisound.com/chat/ws" #define DEMO_TTS_URL "ws://amp.raisound.com/tts/ws" +#else +#define DEMO_ASR_URL "ws://192.168.1.100:8080/asr/ws" +#define DEMO_CHAT_URL "ws://192.168.1.100:8080/chat/ws" +#define DEMO_TTS_URL "ws://192.168.1.100:8080/tts/ws" +#endif #define DEMO_AUDIO_DATA_SIZE 1024 // 演示音频数据大小 #define DEMO_CHAT_MESSAGE "你好,我是AI助手演示程序" diff --git a/code/sdk/zhihui/ai/include/ai_asr_service.h b/code/sdk/zhihui/ai/include/ai_asr_service.h new file mode 100644 index 000000000..29bc7495c --- /dev/null +++ b/code/sdk/zhihui/ai/include/ai_asr_service.h @@ -0,0 +1,185 @@ +/** + * @file ai_asr_service.h + * @brief AI语音识别(ASR)服务接口定义 + * @version 2.0 + * @date 2024-01-20 + */ + +#ifndef AI_ASR_SERVICE_H +#define AI_ASR_SERVICE_H + +#include "ai_core_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================ ASR服务类型定义 ================================ */ + +/** + * @brief ASR状态枚举 + */ +typedef enum { + ASR_STATE_IDLE = 0, // 空闲状态 + ASR_STATE_LISTENING, // 监听状态 + ASR_STATE_RECOGNIZING, // 识别中 + ASR_STATE_COMPLETED, // 识别完成 + ASR_STATE_ERROR // 错误状态 +} asr_state_t; + +/** + * @brief ASR配置结构体 + */ +typedef struct { + char language[16]; // 语言代码,如"zh-CN" + bool enable_vad; // 是否启用语音活动检测 + bool enable_punctuation; // 是否启用标点符号 + bool enable_partial_results; // 是否启用部分结果 + uint32_t silence_timeout_ms; // 静音超时时间(毫秒) + uint32_t max_duration_ms; // 最大录音时长(毫秒) +} asr_config_t; + +/** + * @brief ASR识别结果结构体 + */ +typedef struct { + char text[256]; // 识别文本 + float confidence; // 置信度(0.0-1.0) + bool is_final; // 是否为最终结果 + uint32_t start_time_ms; // 开始时间(毫秒) + uint32_t end_time_ms; // 结束时间(毫秒) + char session_id[32]; // 会话ID +} asr_result_t; + +/** + * @brief ASR服务上下文结构体 + */ +typedef struct { + asr_state_t state; // 当前状态 + asr_config_t config; // 配置信息 + char current_session_id[32]; // 当前会话ID + uint32_t last_activity_time; // 最后活动时间 + + /* 回调函数 */ + asr_result_callback_t result_cb; + asr_error_callback_t error_cb; + asr_state_callback_t state_cb; + void *user_data; +} asr_service_context_t; + +/* ================================ ASR服务接口 ================================ */ + +/** + * @brief 初始化ASR服务 + * @param context ASR服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_init(asr_service_context_t *context); + +/** + * @brief 销毁ASR服务 + * @param context ASR服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_destroy(asr_service_context_t *context); + +/** + * @brief 配置ASR服务 + * @param context ASR服务上下文 + * @param config ASR配置 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_configure(asr_service_context_t *context, const asr_config_t *config); + +/** + * @brief 设置ASR回调函数 + * @param context ASR服务上下文 + * @param result_cb 结果回调 + * @param error_cb 错误回调 + * @param state_cb 状态回调 + * @param user_data 用户数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_set_callbacks(asr_service_context_t *context, + asr_result_callback_t result_cb, + asr_error_callback_t error_cb, + asr_state_callback_t state_cb, + void *user_data); + +/** + * @brief 启动ASR识别 + * @param context ASR服务上下文 + * @param session_id 会话ID(可选,为NULL时使用默认) + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_start(asr_service_context_t *context, const char *session_id); + +/** + * @brief 发送音频数据 + * @param context ASR服务上下文 + * @param audio_data 音频数据 + * @param data_size 数据大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_send_audio(asr_service_context_t *context, const uint8_t *audio_data, uint32_t data_size); + +/** + * @brief 停止ASR识别 + * @param context ASR服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_stop(asr_service_context_t *context); + +/** + * @brief 获取ASR状态 + * @param context ASR服务上下文 + * @return asr_state_t ASR状态 + */ +asr_state_t ai_asr_service_get_state(asr_service_context_t *context); + +/** + * @brief 获取ASR状态名称 + * @param state ASR状态 + * @return const char* 状态名称 + */ +const char* ai_asr_service_get_state_name(asr_state_t state); + +/** + * @brief 创建默认ASR配置 + * @param config ASR配置结构体 + */ +void ai_asr_service_create_default_config(asr_config_t *config); + +/** + * @brief 处理ASR服务响应 + * @param context ASR服务上下文 + * @param json_data JSON响应数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_handle_response(asr_service_context_t *context, const char *json_data); + +/** + * @brief 构建ASR启动消息 + * @param session_id 会话ID + * @param config ASR配置 + * @param json_buffer JSON缓冲区 + * @param buffer_size 缓冲区大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_build_start_message(const char *session_id, const asr_config_t *config, + char *json_buffer, size_t buffer_size); + +/** + * @brief 构建ASR停止消息 + * @param session_id 会话ID + * @param json_buffer JSON缓冲区 + * @param buffer_size 缓冲区大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_asr_service_build_stop_message(const char *session_id, char *json_buffer, size_t buffer_size); + +#ifdef __cplusplus +} +#endif + +#endif /* AI_ASR_SERVICE_H */ \ No newline at end of file diff --git a/code/sdk/zhihui/ai/include/ai_chat_service.h b/code/sdk/zhihui/ai/include/ai_chat_service.h new file mode 100644 index 000000000..bed5fa35e --- /dev/null +++ b/code/sdk/zhihui/ai/include/ai_chat_service.h @@ -0,0 +1,170 @@ +/** + * @file ai_chat_service.h + * @brief AI对话(Chat)服务接口定义 + * @version 2.0 + * @date 2024-01-20 + */ + +#ifndef AI_CHAT_SERVICE_H +#define AI_CHAT_SERVICE_H + +#include "ai_core_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================ Chat服务类型定义 ================================ */ + +/** + * @brief Chat状态枚举 + */ +typedef enum { + CHAT_STATE_IDLE = 0, // 空闲状态 + CHAT_STATE_SENDING, // 发送中 + CHAT_STATE_WAITING, // 等待响应 + CHAT_STATE_RECEIVING, // 接收中 + CHAT_STATE_COMPLETED, // 完成 + CHAT_STATE_ERROR // 错误状态 +} chat_state_t; + +/** + * @brief Chat配置结构体 + */ +typedef struct { + char model_name[32]; // 模型名称,如"qwen-plus" + float temperature; // 温度参数(0.0-2.0) + uint16_t max_tokens; // 最大令牌数 + float top_p; // Top-p参数 + bool stream; // 是否流式输出 + uint32_t timeout_ms; // 超时时间(毫秒) +} chat_config_t; + +/** + * @brief Chat消息结构体 + */ +typedef struct { + char role[16]; // 角色:user/assistant/system + char content[512]; // 消息内容 + char message_id[32]; // 消息ID + char session_id[32]; // 会话ID + uint32_t timestamp; // 时间戳 + bool is_final; // 是否为最终消息 +} chat_message_t; + +/** + * @brief Chat服务上下文结构体 + */ +typedef struct { + chat_state_t state; // 当前状态 + chat_config_t config; // 配置信息 + char current_session_id[32]; // 当前会话ID + uint32_t last_activity_time; // 最后活动时间 + + /* 回调函数 */ + chat_response_callback_t response_cb; + chat_error_callback_t error_cb; + chat_state_callback_t state_cb; + void *user_data; +} chat_service_context_t; + +/* ================================ Chat服务接口 ================================ */ + +/** + * @brief 初始化Chat服务 + * @param context Chat服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_init(chat_service_context_t *context); + +/** + * @brief 销毁Chat服务 + * @param context Chat服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_destroy(chat_service_context_t *context); + +/** + * @brief 配置Chat服务 + * @param context Chat服务上下文 + * @param config Chat配置 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_configure(chat_service_context_t *context, const chat_config_t *config); + +/** + * @brief 设置Chat回调函数 + * @param context Chat服务上下文 + * @param response_cb 响应回调 + * @param error_cb 错误回调 + * @param state_cb 状态回调 + * @param user_data 用户数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_set_callbacks(chat_service_context_t *context, + chat_response_callback_t response_cb, + chat_error_callback_t error_cb, + chat_state_callback_t state_cb, + void *user_data); + +/** + * @brief 发送Chat消息 + * @param context Chat服务上下文 + * @param message 消息内容 + * @param session_id 会话ID(可选,为NULL时使用默认) + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_send_message(chat_service_context_t *context, const char *message, const char *session_id); + +/** + * @brief 获取Chat状态 + * @param context Chat服务上下文 + * @return chat_state_t Chat状态 + */ +chat_state_t ai_chat_service_get_state(chat_service_context_t *context); + +/** + * @brief 获取Chat状态名称 + * @param state Chat状态 + * @return const char* 状态名称 + */ +const char* ai_chat_service_get_state_name(chat_state_t state); + +/** + * @brief 创建默认Chat配置 + * @param config Chat配置结构体 + */ +void ai_chat_service_create_default_config(chat_config_t *config); + +/** + * @brief 处理Chat服务响应 + * @param context Chat服务上下文 + * @param json_data JSON响应数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_handle_response(chat_service_context_t *context, const char *json_data); + +/** + * @brief 构建Chat消息 + * @param message 消息内容 + * @param session_id 会话ID + * @param config Chat配置 + * @param json_buffer JSON缓冲区 + * @param buffer_size 缓冲区大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_chat_service_build_message(const char *message, const char *session_id, const chat_config_t *config, + char *json_buffer, size_t buffer_size); + +/** + * @brief 生成消息ID + * @param message_id 消息ID缓冲区 + * @param buffer_size 缓冲区大小 + */ +void ai_chat_service_generate_message_id(char *message_id, size_t buffer_size); + +#ifdef __cplusplus +} +#endif + +#endif /* AI_CHAT_SERVICE_H */ \ No newline at end of file diff --git a/code/sdk/zhihui/ai/include/ai_core_types.h b/code/sdk/zhihui/ai/include/ai_core_types.h index c3273bc10..a9503425b 100644 --- a/code/sdk/zhihui/ai/include/ai_core_types.h +++ b/code/sdk/zhihui/ai/include/ai_core_types.h @@ -239,6 +239,28 @@ typedef struct { /* 事件回调函数类型 */ typedef void (*ai_event_callback_t)(const ai_event_t *event, void *user_data); +/* ================================ 服务回调函数类型 ================================ */ + +/* 前向声明 */ +struct asr_result; +struct chat_message; +struct tts_result; + +/* ASR回调函数类型 */ +typedef void (*asr_result_callback_t)(const struct asr_result *result, void *user_data); +typedef void (*asr_error_callback_t)(int error_code, const char *error_msg, void *user_data); +typedef void (*asr_state_callback_t)(int old_state, int new_state, void *user_data); + +/* Chat回调函数类型 */ +typedef void (*chat_response_callback_t)(const struct chat_message *message, void *user_data); +typedef void (*chat_error_callback_t)(int error_code, const char *error_msg, void *user_data); +typedef void (*chat_state_callback_t)(int old_state, int new_state, void *user_data); + +/* TTS回调函数类型 */ +typedef void (*tts_result_callback_t)(const struct tts_result *result, void *user_data); +typedef void (*tts_error_callback_t)(int error_code, const char *error_msg, void *user_data); +typedef void (*tts_state_callback_t)(int old_state, int new_state, void *user_data); + /* ================================ 系统兼容性定义 ================================ */ #ifdef __TEST_MODE__ diff --git a/code/sdk/zhihui/ai/include/ai_services.h b/code/sdk/zhihui/ai/include/ai_services.h index ec865dcea..5a91b5520 100644 --- a/code/sdk/zhihui/ai/include/ai_services.h +++ b/code/sdk/zhihui/ai/include/ai_services.h @@ -19,156 +19,25 @@ extern "C" { #endif #include "ai_core_types.h" +#include "ai_asr_service.h" +#include "ai_chat_service.h" +#include "ai_tts_service.h" -/* ================================ ASR服务定义 ================================ */ +/* ================================ 统一服务管理定义 ================================ */ -typedef enum { - ASR_STATE_IDLE = 0, // 空闲状态 - ASR_STATE_LISTENING, // 监听中 - ASR_STATE_RECOGNIZING, // 识别中 - ASR_STATE_COMPLETED, // 识别完成 - ASR_STATE_ERROR // 错误状态 -} asr_state_t; +/* 注意:ASR、Chat、TTS的具体类型定义现在在各自的独立头文件中 */ -typedef struct { - char session_id[AI_MAX_SESSION_ID_LENGTH]; // 会话ID - char text[AI_MAX_TEXT_LENGTH]; // 识别文本 - float confidence; // 置信度 (0.0-1.0) - bool is_final; // 是否最终结果 - bool is_partial; // 是否部分结果 - uint32_t start_time_ms; // 开始时间 - uint32_t end_time_ms; // 结束时间 - uint32_t duration_ms; // 持续时间 -} asr_result_t; - -typedef struct { - bool enable_vad; // 启用语音活动检测 - bool enable_punctuation; // 启用标点符号 - bool enable_partial_results; // 启用部分结果 - uint16_t silence_timeout_ms; // 静音超时时间 - uint16_t max_duration_ms; // 最大录音时长 - char language[8]; // 语言代码 "zh-CN" -} asr_config_t; - -/* ASR回调函数类型 */ -typedef void (*asr_result_callback_t)(const asr_result_t *result, void *user_data); -typedef void (*asr_error_callback_t)(int error_code, const char *error_msg, void *user_data); -typedef void (*asr_state_callback_t)(asr_state_t old_state, asr_state_t new_state, void *user_data); - -/* ================================ Chat服务定义 ================================ */ - -typedef enum { - CHAT_STATE_IDLE = 0, // 空闲状态 - CHAT_STATE_SENDING, // 发送中 - CHAT_STATE_WAITING, // 等待响应 - CHAT_STATE_RECEIVING, // 接收中 - CHAT_STATE_COMPLETED, // 完成 - CHAT_STATE_ERROR // 错误状态 -} chat_state_t; - -typedef enum { - CHAT_ROLE_USER = 0, // 用户角色 - CHAT_ROLE_ASSISTANT, // 助手角色 - CHAT_ROLE_SYSTEM // 系统角色 -} chat_role_t; - -typedef struct { - char session_id[AI_MAX_SESSION_ID_LENGTH]; // 会话ID - char message_id[32]; // 消息ID - chat_role_t role; // 角色 - char content[AI_MAX_TEXT_LENGTH]; // 消息内容 - uint32_t timestamp; // 时间戳 - bool is_streaming; // 是否流式响应 - bool is_final; // 是否最终响应 -} chat_message_t; - -typedef struct { - char model_name[32]; // 模型名称 - float temperature; // 温度参数 (0.0-2.0) - uint16_t max_tokens; // 最大令牌数 - float top_p; // Top-p参数 - bool stream; // 流式输出 - uint16_t timeout_ms; // 超时时间 -} chat_config_t; - -/* Chat回调函数类型 */ -typedef void (*chat_response_callback_t)(const chat_message_t *message, void *user_data); -typedef void (*chat_error_callback_t)(int error_code, const char *error_msg, void *user_data); -typedef void (*chat_state_callback_t)(chat_state_t old_state, chat_state_t new_state, void *user_data); - -/* ================================ TTS服务定义 ================================ */ - -typedef enum { - TTS_STATE_IDLE = 0, // 空闲状态 - TTS_STATE_SYNTHESIZING, // 合成中 - TTS_STATE_PLAYING, // 播放中 - TTS_STATE_COMPLETED, // 完成 - TTS_STATE_ERROR // 错误状态 -} tts_state_t; - -typedef enum { - TTS_VOICE_XIAOYUN = 0, // 小云 - TTS_VOICE_XIAOGANG, // 小刚 - TTS_VOICE_XIAOMEI, // 小美 - TTS_VOICE_XIAOLI, // 小丽 - TTS_VOICE_COUNT // 语音总数 -} tts_voice_type_t; -typedef struct { - char session_id[AI_MAX_SESSION_ID_LENGTH]; // 会话ID - uint8_t *audio_data; // 音频数据 - uint32_t audio_size; // 音频大小 - uint32_t sample_rate; // 采样率 - uint8_t channels; // 声道数 - uint8_t bits_per_sample; // 位深度 - bool is_final; // 是否最终数据 - uint32_t sequence; // 序列号 -} tts_result_t; - -typedef struct { - tts_voice_type_t voice_type; // 语音类型 - uint8_t volume; // 音量 (0-100) - uint8_t speed; // 语速 (0-100, 50为正常) - uint8_t pitch; // 音调 (0-100, 50为正常) - bool auto_play; // 自动播放 - uint16_t timeout_ms; // 超时时间 -} tts_config_t; - -/* TTS回调函数类型 */ -typedef void (*tts_result_callback_t)(const tts_result_t *result, void *user_data); -typedef void (*tts_error_callback_t)(int error_code, const char *error_msg, void *user_data); -typedef void (*tts_state_callback_t)(tts_state_t old_state, tts_state_t new_state, void *user_data); /* ================================ 服务上下文结构 ================================ */ typedef struct { - ai_service_type_t service_type; // 服务类型 - asr_state_t asr_state; // ASR状态 - chat_state_t chat_state; // Chat状态 - tts_state_t tts_state; // TTS状态 - - asr_config_t asr_config; // ASR配置 - chat_config_t chat_config; // Chat配置 - tts_config_t tts_config; // TTS配置 - - /* ASR回调 */ - asr_result_callback_t asr_result_cb; - asr_error_callback_t asr_error_cb; - asr_state_callback_t asr_state_cb; - - /* Chat回调 */ - chat_response_callback_t chat_response_cb; - chat_error_callback_t chat_error_cb; - chat_state_callback_t chat_state_cb; - - /* TTS回调 */ - tts_result_callback_t tts_result_cb; - tts_error_callback_t tts_error_cb; - tts_state_callback_t tts_state_cb; - - void *user_data; // 用户数据 + /* 独立服务上下文 */ + asr_service_context_t asr_context; // ASR服务上下文 + chat_service_context_t chat_context; // Chat服务上下文 + tts_service_context_t tts_context; // TTS服务上下文 - /* 内部状态 */ + /* 统一管理状态 */ char current_session_id[AI_MAX_SESSION_ID_LENGTH]; // 当前会话ID uint32_t last_activity_time; // 最后活动时间 bool is_initialized; // 初始化标志 diff --git a/code/sdk/zhihui/ai/include/ai_tts_service.h b/code/sdk/zhihui/ai/include/ai_tts_service.h new file mode 100644 index 000000000..6f24bfa58 --- /dev/null +++ b/code/sdk/zhihui/ai/include/ai_tts_service.h @@ -0,0 +1,199 @@ +/** + * @file ai_tts_service.h + * @brief AI语音合成(TTS)服务接口定义 + * @version 2.0 + * @date 2024-01-20 + */ + +#ifndef AI_TTS_SERVICE_H +#define AI_TTS_SERVICE_H + +#include "ai_core_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================ TTS服务类型定义 ================================ */ + +/** + * @brief TTS状态枚举 + */ +typedef enum { + TTS_STATE_IDLE = 0, // 空闲状态 + TTS_STATE_SYNTHESIZING, // 合成中 + TTS_STATE_PLAYING, // 播放中 + TTS_STATE_COMPLETED, // 完成 + TTS_STATE_ERROR // 错误状态 +} tts_state_t; + +/** + * @brief TTS语音类型枚举 + */ +typedef enum { + TTS_VOICE_XIAOYUN = 0, // 小云 + TTS_VOICE_XIAOGANG, // 小刚 + TTS_VOICE_XIAOMEI, // 小美 + TTS_VOICE_XIAOLI, // 小丽 + TTS_VOICE_COUNT // 语音类型数量 +} tts_voice_type_t; + +/** + * @brief TTS配置结构体 + */ +typedef struct { + tts_voice_type_t voice_type; // 语音类型 + uint8_t volume; // 音量(0-100) + uint8_t speed; // 语速(0-100) + uint8_t pitch; // 音调(0-100) + bool auto_play; // 是否自动播放 + uint32_t timeout_ms; // 超时时间(毫秒) +} tts_config_t; + +/** + * @brief TTS合成结果结构体 + */ +typedef struct { + char text[256]; // 合成文本 + uint8_t *audio_data; // 音频数据 + uint32_t audio_size; // 音频大小 + uint32_t sample_rate; // 采样率 + uint16_t channels; // 声道数 + uint16_t bits_per_sample; // 位深度 + char session_id[32]; // 会话ID + uint32_t duration_ms; // 音频时长(毫秒) + bool is_final; // 是否为最终结果 +} tts_result_t; + +/** + * @brief TTS服务上下文结构体 + */ +typedef struct { + tts_state_t state; // 当前状态 + tts_config_t config; // 配置信息 + char current_session_id[32]; // 当前会话ID + uint32_t last_activity_time; // 最后活动时间 + + /* 回调函数 */ + tts_result_callback_t result_cb; + tts_error_callback_t error_cb; + tts_state_callback_t state_cb; + void *user_data; +} tts_service_context_t; + +/* ================================ TTS服务接口 ================================ */ + +/** + * @brief 初始化TTS服务 + * @param context TTS服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_init(tts_service_context_t *context); + +/** + * @brief 销毁TTS服务 + * @param context TTS服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_destroy(tts_service_context_t *context); + +/** + * @brief 配置TTS服务 + * @param context TTS服务上下文 + * @param config TTS配置 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_configure(tts_service_context_t *context, const tts_config_t *config); + +/** + * @brief 设置TTS回调函数 + * @param context TTS服务上下文 + * @param result_cb 结果回调 + * @param error_cb 错误回调 + * @param state_cb 状态回调 + * @param user_data 用户数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_set_callbacks(tts_service_context_t *context, + tts_result_callback_t result_cb, + tts_error_callback_t error_cb, + tts_state_callback_t state_cb, + void *user_data); + +/** + * @brief 开始TTS合成 + * @param context TTS服务上下文 + * @param text 要合成的文本 + * @param session_id 会话ID(可选,为NULL时使用默认) + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_synthesize(tts_service_context_t *context, const char *text, const char *session_id); + +/** + * @brief 停止TTS合成 + * @param context TTS服务上下文 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_stop(tts_service_context_t *context); + +/** + * @brief 获取TTS状态 + * @param context TTS服务上下文 + * @return tts_state_t TTS状态 + */ +tts_state_t ai_tts_service_get_state(tts_service_context_t *context); + +/** + * @brief 获取TTS状态名称 + * @param state TTS状态 + * @return const char* 状态名称 + */ +const char* ai_tts_service_get_state_name(tts_state_t state); + +/** + * @brief 获取语音类型名称 + * @param voice_type 语音类型 + * @return const char* 语音名称 + */ +const char* ai_tts_service_get_voice_name(tts_voice_type_t voice_type); + +/** + * @brief 创建默认TTS配置 + * @param config TTS配置结构体 + */ +void ai_tts_service_create_default_config(tts_config_t *config); + +/** + * @brief 处理TTS服务响应 + * @param context TTS服务上下文 + * @param json_data JSON响应数据 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_handle_response(tts_service_context_t *context, const char *json_data); + +/** + * @brief 构建TTS请求 + * @param text 要合成的文本 + * @param session_id 会话ID + * @param config TTS配置 + * @param json_buffer JSON缓冲区 + * @param buffer_size 缓冲区大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_build_request(const char *text, const char *session_id, const tts_config_t *config, + char *json_buffer, size_t buffer_size); + +/** + * @brief 构建TTS停止消息 + * @param session_id 会话ID + * @param json_buffer JSON缓冲区 + * @param buffer_size 缓冲区大小 + * @return ai_error_t 错误码 + */ +ai_error_t ai_tts_service_build_stop_message(const char *session_id, char *json_buffer, size_t buffer_size); + +#ifdef __cplusplus +} +#endif + +#endif /* AI_TTS_SERVICE_H */ \ No newline at end of file diff --git a/code/sdk/zhihui/ai/src/ai_asr_service.c b/code/sdk/zhihui/ai/src/ai_asr_service.c new file mode 100644 index 000000000..6b605411f --- /dev/null +++ b/code/sdk/zhihui/ai/src/ai_asr_service.c @@ -0,0 +1,464 @@ +/** + * @file ai_asr_service.c + * @brief AI语音识别(ASR)服务实现 + * @version 2.0 + * @date 2024-01-20 + */ + +#include "ai_asr_service.h" +#include "ai_connection_manager.h" +#include "ai_memory_pool.h" +#include +#include +#include +#include + +#ifndef __TEST_MODE__ +#include "wearable_log.h" +#include "dev_authentication.h" +#define AI_LOG_TAG "AI_ASR" +#define AI_LOGI(fmt, ...) WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#else +#define AI_LOGI(fmt, ...) printf("[AI_ASR] " fmt "\n", ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) printf("[AI_ASR] ERROR: " fmt "\n", ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) printf("[AI_ASR] WARN: " fmt "\n", ##__VA_ARGS__) +#endif + +/* ================================ 内部常量定义 ================================ */ + +#define JSON_BUFFER_SIZE 512 // JSON缓冲区大小 +#define MAX_AUDIO_CHUNK_SIZE 1024 // 最大音频块大小 + +/* ASR状态名称映射 */ +static const char* g_asr_state_names[] = { + "IDLE", "LISTENING", "RECOGNIZING", "COMPLETED", "ERROR" +}; + +/* ================================ 内部函数声明 ================================ */ + +static uint32_t get_current_timestamp(void); +static ai_error_t change_asr_state(asr_service_context_t *context, asr_state_t new_state); +static ai_error_t parse_asr_response(const char *json_data, asr_result_t *result); + +/* ================================ 公共接口实现 ================================ */ + +ai_error_t ai_asr_service_init(asr_service_context_t *context) +{ + if (context == NULL) { + AI_LOGE("Invalid context parameter"); + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Initializing ASR service..."); + + /* 初始化上下文 */ + memset(context, 0, sizeof(asr_service_context_t)); + + /* 设置默认状态 */ + context->state = ASR_STATE_IDLE; + + /* 创建默认配置 */ + ai_asr_service_create_default_config(&context->config); + + /* 生成初始会话ID */ + uint32_t timestamp = get_current_timestamp(); + uint32_t random = rand(); + snprintf(context->current_session_id, sizeof(context->current_session_id), + "asr_%08x_%04x", timestamp, random & 0xFFFF); + + context->last_activity_time = get_current_timestamp(); + + AI_LOGI("ASR service initialized successfully"); + return AI_OK; +} + +ai_error_t ai_asr_service_destroy(asr_service_context_t *context) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Destroying ASR service..."); + + /* 停止活动服务 */ + if (context->state != ASR_STATE_IDLE) { + ai_asr_service_stop(context); + } + + /* 重置上下文 */ + memset(context, 0, sizeof(asr_service_context_t)); + + AI_LOGI("ASR service destroyed"); + return AI_OK; +} + +ai_error_t ai_asr_service_configure(asr_service_context_t *context, const asr_config_t *config) +{ + if (context == NULL || config == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + memcpy(&context->config, config, sizeof(asr_config_t)); + AI_LOGI("ASR configured: language=%s, vad=%s, punctuation=%s", + config->language, + config->enable_vad ? "enabled" : "disabled", + config->enable_punctuation ? "enabled" : "disabled"); + + return AI_OK; +} + +ai_error_t ai_asr_service_set_callbacks(asr_service_context_t *context, + asr_result_callback_t result_cb, + asr_error_callback_t error_cb, + asr_state_callback_t state_cb, + void *user_data) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + context->result_cb = result_cb; + context->error_cb = error_cb; + context->state_cb = state_cb; + context->user_data = user_data; + + AI_LOGI("ASR callbacks set"); + return AI_OK; +} + +ai_error_t ai_asr_service_start(asr_service_context_t *context, const char *session_id) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state != ASR_STATE_IDLE) { + AI_LOGW("ASR already active, stopping first"); + ai_asr_service_stop(context); + } + + /* 使用提供的会话ID或当前会话ID */ + const char *use_session_id = session_id ? session_id : context->current_session_id; + + AI_LOGI("Starting ASR with session ID: %s", use_session_id); + + /* 检查ASR连接状态 */ + ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_ASR); + if (conn_state != AI_CONN_STATE_CONNECTED) { + AI_LOGE("ASR service not connected"); + return AI_ERROR_SERVICE_UNAVAILABLE; + } + + /* 构建启动消息 */ + char json_buffer[JSON_BUFFER_SIZE]; + ai_error_t ret = ai_asr_service_build_start_message(use_session_id, &context->config, json_buffer, sizeof(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to build ASR start message"); + return ret; + } + + /* 发送启动消息 */ + ret = ai_connection_manager_send_data(AI_SERVICE_ASR, json_buffer, strlen(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to send ASR start message"); + return ret; + } + + /* 更新状态 */ + change_asr_state(context, ASR_STATE_LISTENING); + strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_asr_service_send_audio(asr_service_context_t *context, const uint8_t *audio_data, uint32_t data_size) +{ + if (context == NULL || audio_data == NULL || data_size == 0) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state != ASR_STATE_LISTENING && context->state != ASR_STATE_RECOGNIZING) { + AI_LOGW("ASR not in listening/recognizing state"); + return AI_ERROR_STATE_INVALID; + } + + /* 检查数据大小 */ + if (data_size > MAX_AUDIO_CHUNK_SIZE) { + AI_LOGW("Audio chunk too large: %u bytes, splitting", data_size); + + /* 分块发送 */ + uint32_t offset = 0; + while (offset < data_size) { + uint32_t chunk_size = (data_size - offset > MAX_AUDIO_CHUNK_SIZE) ? + MAX_AUDIO_CHUNK_SIZE : (data_size - offset); + + ai_error_t ret = ai_asr_service_send_audio(context, audio_data + offset, chunk_size); + if (ret != AI_OK) { + return ret; + } + offset += chunk_size; + } + return AI_OK; + } + + /* 构建音频数据消息 */ + ai_buffer_t *buffer = ai_memory_pool_alloc_network(AI_SERVICE_ASR, data_size + 64); + if (buffer == NULL) { + AI_LOGE("Failed to allocate network buffer for audio data"); + return AI_ERROR_MEMORY_ALLOC; + } + + /* 简化的二进制数据发送(实际实现中可能需要Base64编码) */ + memcpy(buffer->buffer, audio_data, data_size); + buffer->used = data_size; + + ai_error_t ret = ai_connection_manager_send_data(AI_SERVICE_ASR, (const char*)buffer->buffer, buffer->used); + + ai_memory_pool_free(buffer); + + if (ret != AI_OK) { + AI_LOGE("Failed to send audio data"); + return ret; + } + + /* 更新状态 */ + if (context->state == ASR_STATE_LISTENING) { + change_asr_state(context, ASR_STATE_RECOGNIZING); + } + + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_asr_service_stop(asr_service_context_t *context) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state == ASR_STATE_IDLE) { + return AI_OK; // 已经停止 + } + + AI_LOGI("Stopping ASR"); + + /* 构建停止消息 */ + char json_buffer[JSON_BUFFER_SIZE]; + ai_error_t ret = ai_asr_service_build_stop_message(context->current_session_id, json_buffer, sizeof(json_buffer)); + if (ret == AI_OK) { + ai_connection_manager_send_data(AI_SERVICE_ASR, json_buffer, strlen(json_buffer)); + } + + /* 更新状态 */ + change_asr_state(context, ASR_STATE_IDLE); + + return AI_OK; +} + +asr_state_t ai_asr_service_get_state(asr_service_context_t *context) +{ + if (context == NULL) { + return ASR_STATE_ERROR; + } + + return context->state; +} + +const char* ai_asr_service_get_state_name(asr_state_t state) +{ + if (state >= sizeof(g_asr_state_names) / sizeof(g_asr_state_names[0])) { + return "UNKNOWN"; + } + + return g_asr_state_names[state]; +} + +void ai_asr_service_create_default_config(asr_config_t *config) +{ + if (config == NULL) { + return; + } + + memset(config, 0, sizeof(asr_config_t)); + config->enable_vad = true; + config->enable_punctuation = true; + config->enable_partial_results = true; + config->silence_timeout_ms = 3000; // 3秒静音超时 + config->max_duration_ms = 30000; // 30秒最大录音时长 + strncpy(config->language, "zh-CN", sizeof(config->language) - 1); +} + +ai_error_t ai_asr_service_handle_response(asr_service_context_t *context, const char *json_data) +{ + if (context == NULL || json_data == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Handling ASR response: %.100s...", json_data); + + /* 解析ASR响应 */ + asr_result_t result; + ai_error_t ret = parse_asr_response(json_data, &result); + if (ret != AI_OK) { + AI_LOGE("Failed to parse ASR response"); + change_asr_state(context, ASR_STATE_ERROR); + if (context->error_cb != NULL) { + context->error_cb(ret, "Failed to parse ASR response", context->user_data); + } + return ret; + } + + /* 更新状态 */ + if (result.is_final) { + change_asr_state(context, ASR_STATE_COMPLETED); + } + + /* 调用结果回调 */ + if (context->result_cb != NULL) { + context->result_cb(&result, context->user_data); + } + + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_asr_service_build_start_message(const char *session_id, const asr_config_t *config, + char *json_buffer, size_t buffer_size) +{ + if (session_id == NULL || config == NULL || json_buffer == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 构建ASR启动消息 */ + int ret = snprintf(json_buffer, buffer_size, + "{" + "\"type\":\"start\"," + "\"session_id\":\"%s\"," + "\"config\":{" + "\"language\":\"%s\"," + "\"enable_vad\":%s," + "\"enable_punctuation\":%s," + "\"enable_partial_results\":%s," + "\"silence_timeout_ms\":%d," + "\"max_duration_ms\":%d" + "}" + "}", + session_id, + config->language, + config->enable_vad ? "true" : "false", + config->enable_punctuation ? "true" : "false", + config->enable_partial_results ? "true" : "false", + config->silence_timeout_ms, + config->max_duration_ms + ); + + if (ret < 0 || ret >= (int)buffer_size) { + AI_LOGE("JSON buffer too small for ASR start message"); + return AI_ERROR_BUFFER_OVERFLOW; + } + + return AI_OK; +} + +ai_error_t ai_asr_service_build_stop_message(const char *session_id, char *json_buffer, size_t buffer_size) +{ + if (session_id == NULL || json_buffer == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + int ret = snprintf(json_buffer, buffer_size, + "{\"type\":\"stop\",\"session_id\":\"%s\"}", session_id); + + if (ret < 0 || ret >= (int)buffer_size) { + AI_LOGE("JSON buffer too small for ASR stop message"); + return AI_ERROR_BUFFER_OVERFLOW; + } + + return AI_OK; +} + +/* ================================ 内部函数实现 ================================ */ + +static uint32_t get_current_timestamp(void) +{ +#ifndef __TEST_MODE__ + return (uint32_t)(osKernelGetTickCount() * 1000 / osKernelGetTickFreq()); +#else + return (uint32_t)time(NULL); +#endif +} + +static ai_error_t change_asr_state(asr_service_context_t *context, asr_state_t new_state) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + asr_state_t old_state = context->state; + if (old_state != new_state) { + context->state = new_state; + + AI_LOGI("ASR state changed: %s -> %s", + g_asr_state_names[old_state], + g_asr_state_names[new_state]); + + /* 调用状态回调 */ + if (context->state_cb != NULL) { + context->state_cb(old_state, new_state, context->user_data); + } + } + + return AI_OK; +} + +static ai_error_t parse_asr_response(const char *json_data, asr_result_t *result) +{ + if (json_data == NULL || result == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 简化的JSON解析实现 */ + memset(result, 0, sizeof(asr_result_t)); + + /* 在实际实现中,这里应该使用完整的JSON解析库 */ + /* 这里只是一个简化的示例 */ + + /* 查找文本字段 */ + const char *text_start = strstr(json_data, "\"text\":\""); + if (text_start != NULL) { + text_start += 8; // 跳过 "text":" + const char *text_end = strchr(text_start, '"'); + if (text_end != NULL) { + size_t text_len = text_end - text_start; + if (text_len < sizeof(result->text)) { + strncpy(result->text, text_start, text_len); + result->text[text_len] = '\0'; + } + } + } + + /* 查找置信度字段 */ + const char *confidence_start = strstr(json_data, "\"confidence\":"); + if (confidence_start != NULL) { + result->confidence = atof(confidence_start + 13); + } else { + result->confidence = 0.9f; // 默认置信度 + } + + /* 查找是否为最终结果 */ + result->is_final = (strstr(json_data, "\"is_final\":true") != NULL); + + /* 设置时间戳 */ + result->start_time_ms = 0; + result->end_time_ms = get_current_timestamp(); + + AI_LOGI("Parsed ASR result: text='%s', confidence=%.2f, final=%s", + result->text, result->confidence, result->is_final ? "true" : "false"); + + return AI_OK; +} \ No newline at end of file diff --git a/code/sdk/zhihui/ai/src/ai_chat_service.c b/code/sdk/zhihui/ai/src/ai_chat_service.c new file mode 100644 index 000000000..1808b1eae --- /dev/null +++ b/code/sdk/zhihui/ai/src/ai_chat_service.c @@ -0,0 +1,417 @@ +/** + * @file ai_chat_service.c + * @brief AI对话(Chat)服务实现 + * @version 2.0 + * @date 2024-01-20 + */ + +#include "ai_chat_service.h" +#include "ai_connection_manager.h" +#include "ai_memory_pool.h" +#include +#include +#include +#include + +#ifndef __TEST_MODE__ +#include "wearable_log.h" +#include "dev_authentication.h" +#define AI_LOG_TAG "AI_CHAT" +#define AI_LOGI(fmt, ...) WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#else +#define AI_LOGI(fmt, ...) printf("[AI_CHAT] " fmt "\n", ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) printf("[AI_CHAT] ERROR: " fmt "\n", ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) printf("[AI_CHAT] WARN: " fmt "\n", ##__VA_ARGS__) +#endif + +/* ================================ 内部常量定义 ================================ */ + +#define JSON_BUFFER_SIZE 512 // JSON缓冲区大小 +#define MESSAGE_ID_LENGTH 16 // 消息ID长度 + +/* Chat状态名称映射 */ +static const char* g_chat_state_names[] = { + "IDLE", "SENDING", "WAITING", "RECEIVING", "COMPLETED", "ERROR" +}; + +/* ================================ 内部函数声明 ================================ */ + +static uint32_t get_current_timestamp(void); +static ai_error_t change_chat_state(chat_service_context_t *context, chat_state_t new_state); +static ai_error_t parse_chat_response(const char *json_data, chat_message_t *message); + +/* ================================ 公共接口实现 ================================ */ + +ai_error_t ai_chat_service_init(chat_service_context_t *context) +{ + if (context == NULL) { + AI_LOGE("Invalid context parameter"); + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Initializing Chat service..."); + + /* 初始化上下文 */ + memset(context, 0, sizeof(chat_service_context_t)); + + /* 设置默认状态 */ + context->state = CHAT_STATE_IDLE; + + /* 创建默认配置 */ + ai_chat_service_create_default_config(&context->config); + + /* 生成初始会话ID */ + uint32_t timestamp = get_current_timestamp(); + uint32_t random = rand(); + snprintf(context->current_session_id, sizeof(context->current_session_id), + "chat_%08x_%04x", timestamp, random & 0xFFFF); + + context->last_activity_time = get_current_timestamp(); + + AI_LOGI("Chat service initialized successfully"); + return AI_OK; +} + +ai_error_t ai_chat_service_destroy(chat_service_context_t *context) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Destroying Chat service..."); + + /* 重置上下文 */ + memset(context, 0, sizeof(chat_service_context_t)); + + AI_LOGI("Chat service destroyed"); + return AI_OK; +} + +ai_error_t ai_chat_service_configure(chat_service_context_t *context, const chat_config_t *config) +{ + if (context == NULL || config == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + memcpy(&context->config, config, sizeof(chat_config_t)); + AI_LOGI("Chat configured: model=%s, temperature=%.2f, max_tokens=%d", + config->model_name, config->temperature, config->max_tokens); + + return AI_OK; +} + +ai_error_t ai_chat_service_set_callbacks(chat_service_context_t *context, + chat_response_callback_t response_cb, + chat_error_callback_t error_cb, + chat_state_callback_t state_cb, + void *user_data) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + context->response_cb = response_cb; + context->error_cb = error_cb; + context->state_cb = state_cb; + context->user_data = user_data; + + AI_LOGI("Chat callbacks set"); + return AI_OK; +} + +ai_error_t ai_chat_service_send_message(chat_service_context_t *context, const char *message, const char *session_id) +{ + if (context == NULL || message == NULL || strlen(message) == 0) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state != CHAT_STATE_IDLE) { + AI_LOGW("Chat busy, current state: %s", g_chat_state_names[context->state]); + return AI_ERROR_STATE_INVALID; + } + + /* 使用提供的会话ID或当前会话ID */ + const char *use_session_id = session_id ? session_id : context->current_session_id; + + AI_LOGI("Sending chat message: %.50s... (session: %s)", message, use_session_id); + + /* 检查Chat连接状态 */ + ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_CHAT); + if (conn_state != AI_CONN_STATE_CONNECTED) { + AI_LOGE("Chat service not connected"); + return AI_ERROR_SERVICE_UNAVAILABLE; + } + + /* 构建聊天消息 */ + char json_buffer[JSON_BUFFER_SIZE]; + ai_error_t ret = ai_chat_service_build_message(message, use_session_id, &context->config, json_buffer, sizeof(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to build chat message"); + return ret; + } + + /* 发送消息 */ + change_chat_state(context, CHAT_STATE_SENDING); + + ret = ai_connection_manager_send_data(AI_SERVICE_CHAT, json_buffer, strlen(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to send chat message"); + change_chat_state(context, CHAT_STATE_ERROR); + return ret; + } + + /* 更新状态 */ + change_chat_state(context, CHAT_STATE_WAITING); + strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +chat_state_t ai_chat_service_get_state(chat_service_context_t *context) +{ + if (context == NULL) { + return CHAT_STATE_ERROR; + } + + return context->state; +} + +const char* ai_chat_service_get_state_name(chat_state_t state) +{ + if (state >= sizeof(g_chat_state_names) / sizeof(g_chat_state_names[0])) { + return "UNKNOWN"; + } + + return g_chat_state_names[state]; +} + +void ai_chat_service_create_default_config(chat_config_t *config) +{ + if (config == NULL) { + return; + } + + memset(config, 0, sizeof(chat_config_t)); + strncpy(config->model_name, "qwen-plus", sizeof(config->model_name) - 1); + config->temperature = 0.7f; + config->max_tokens = 512; // 适合LiteOS-M的较小值 + config->top_p = 0.9f; + config->stream = true; + config->timeout_ms = 15000; // 15秒超时 +} + +ai_error_t ai_chat_service_handle_response(chat_service_context_t *context, const char *json_data) +{ + if (context == NULL || json_data == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Handling Chat response: %.100s...", json_data); + + /* 解析Chat响应 */ + chat_message_t message; + ai_error_t ret = parse_chat_response(json_data, &message); + if (ret != AI_OK) { + AI_LOGE("Failed to parse Chat response"); + change_chat_state(context, CHAT_STATE_ERROR); + if (context->error_cb != NULL) { + context->error_cb(ret, "Failed to parse Chat response", context->user_data); + } + return ret; + } + + /* 更新状态 */ + if (message.is_final) { + change_chat_state(context, CHAT_STATE_COMPLETED); + } else { + change_chat_state(context, CHAT_STATE_RECEIVING); + } + + /* 调用响应回调 */ + if (context->response_cb != NULL) { + context->response_cb(&message, context->user_data); + } + + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_chat_service_build_message(const char *message, const char *session_id, const chat_config_t *config, + char *json_buffer, size_t buffer_size) +{ + if (message == NULL || session_id == NULL || config == NULL || json_buffer == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 生成消息ID */ + char message_id[MESSAGE_ID_LENGTH + 1]; + ai_chat_service_generate_message_id(message_id, sizeof(message_id)); + + /* 构建Chat消息 */ + int ret = snprintf(json_buffer, buffer_size, + "{" + "\"type\":\"chat\"," + "\"session_id\":\"%s\"," + "\"message_id\":\"%s\"," + "\"message\":{" + "\"role\":\"user\"," + "\"content\":\"%s\"" + "}," + "\"config\":{" + "\"model\":\"%s\"," + "\"temperature\":%.2f," + "\"max_tokens\":%d," + "\"top_p\":%.2f," + "\"stream\":%s" + "}" + "}", + session_id, + message_id, + message, + config->model_name, + config->temperature, + config->max_tokens, + config->top_p, + config->stream ? "true" : "false" + ); + + if (ret < 0 || ret >= (int)buffer_size) { + AI_LOGE("JSON buffer too small for chat message"); + return AI_ERROR_BUFFER_OVERFLOW; + } + + return AI_OK; +} + +void ai_chat_service_generate_message_id(char *message_id, size_t buffer_size) +{ + if (message_id == NULL || buffer_size < MESSAGE_ID_LENGTH + 1) { + return; + } + + uint32_t timestamp = get_current_timestamp(); + uint16_t random = rand() & 0xFFFF; + + snprintf(message_id, buffer_size, "msg_%08x_%04x", timestamp, random); +} + +/* ================================ 内部函数实现 ================================ */ + +static uint32_t get_current_timestamp(void) +{ +#ifndef __TEST_MODE__ + return (uint32_t)(osKernelGetTickCount() * 1000 / osKernelGetTickFreq()); +#else + return (uint32_t)time(NULL); +#endif +} + +static ai_error_t change_chat_state(chat_service_context_t *context, chat_state_t new_state) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + chat_state_t old_state = context->state; + if (old_state != new_state) { + context->state = new_state; + + AI_LOGI("Chat state changed: %s -> %s", + g_chat_state_names[old_state], + g_chat_state_names[new_state]); + + /* 调用状态回调 */ + if (context->state_cb != NULL) { + context->state_cb(old_state, new_state, context->user_data); + } + } + + return AI_OK; +} + +static ai_error_t parse_chat_response(const char *json_data, chat_message_t *message) +{ + if (json_data == NULL || message == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 简化的JSON解析实现 */ + memset(message, 0, sizeof(chat_message_t)); + + /* 在实际实现中,这里应该使用完整的JSON解析库 */ + /* 这里只是一个简化的示例 */ + + /* 查找角色字段 */ + const char *role_start = strstr(json_data, "\"role\":\""); + if (role_start != NULL) { + role_start += 8; // 跳过 "role":" + const char *role_end = strchr(role_start, '"'); + if (role_end != NULL) { + size_t role_len = role_end - role_start; + if (role_len < sizeof(message->role)) { + strncpy(message->role, role_start, role_len); + message->role[role_len] = '\0'; + } + } + } else { + strcpy(message->role, "assistant"); // 默认角色 + } + + /* 查找内容字段 */ + const char *content_start = strstr(json_data, "\"content\":\""); + if (content_start != NULL) { + content_start += 11; // 跳过 "content":" + const char *content_end = strchr(content_start, '"'); + if (content_end != NULL) { + size_t content_len = content_end - content_start; + if (content_len < sizeof(message->content)) { + strncpy(message->content, content_start, content_len); + message->content[content_len] = '\0'; + } + } + } + + /* 查找消息ID字段 */ + const char *msg_id_start = strstr(json_data, "\"message_id\":\""); + if (msg_id_start != NULL) { + msg_id_start += 14; // 跳过 "message_id":" + const char *msg_id_end = strchr(msg_id_start, '"'); + if (msg_id_end != NULL) { + size_t msg_id_len = msg_id_end - msg_id_start; + if (msg_id_len < sizeof(message->message_id)) { + strncpy(message->message_id, msg_id_start, msg_id_len); + message->message_id[msg_id_len] = '\0'; + } + } + } + + /* 查找会话ID字段 */ + const char *session_id_start = strstr(json_data, "\"session_id\":\""); + if (session_id_start != NULL) { + session_id_start += 14; // 跳过 "session_id":" + const char *session_id_end = strchr(session_id_start, '"'); + if (session_id_end != NULL) { + size_t session_id_len = session_id_end - session_id_start; + if (session_id_len < sizeof(message->session_id)) { + strncpy(message->session_id, session_id_start, session_id_len); + message->session_id[session_id_len] = '\0'; + } + } + } + + /* 查找是否为最终消息 */ + message->is_final = (strstr(json_data, "\"is_final\":true") != NULL) || + (strstr(json_data, "\"finish_reason\":") != NULL); + + /* 设置时间戳 */ + message->timestamp = get_current_timestamp(); + + AI_LOGI("Parsed Chat message: role='%s', content='%.50s...', final=%s", + message->role, message->content, message->is_final ? "true" : "false"); + + return AI_OK; +} \ No newline at end of file diff --git a/code/sdk/zhihui/ai/src/ai_connection_manager.c b/code/sdk/zhihui/ai/src/ai_connection_manager.c index 827895e42..8097b1be6 100644 --- a/code/sdk/zhihui/ai/src/ai_connection_manager.c +++ b/code/sdk/zhihui/ai/src/ai_connection_manager.c @@ -290,32 +290,67 @@ ai_error_t ai_connection_manager_start_all(void) return AI_ERROR_NOT_INITIALIZED; } - AI_LOGI("Starting all connections concurrently..."); + AI_LOGI("[DEBUG] ai_connection_manager_start_all: Entry point"); + AI_LOGI("[DEBUG] Setting global state to CONNECTING..."); g_connection_manager.global_state = AI_STATE_CONNECTING; + AI_LOGI("[DEBUG] Global state set successfully"); + + AI_LOGI("[DEBUG] Setting is_running to true..."); g_connection_manager.is_running = true; + AI_LOGI("[DEBUG] is_running set successfully"); /* 记录连接开始时间 */ + AI_LOGI("[DEBUG] Getting current timestamp..."); uint32_t start_time = get_current_timestamp(); + AI_LOGI("[DEBUG] Current timestamp: %u", start_time); + + AI_LOGI("[DEBUG] Setting last_connect_timestamp..."); g_connection_manager.metrics.last_connect_timestamp = start_time; + AI_LOGI("[DEBUG] last_connect_timestamp set successfully"); /* 并发启动所有连接线程 */ + AI_LOGI("[DEBUG] Starting connection thread creation loop..."); + AI_LOGI("[DEBUG] AI_SERVICE_COUNT = %d", AI_SERVICE_COUNT); + for (int i = 0; i < AI_SERVICE_COUNT; i++) { + AI_LOGI("[DEBUG] Creating thread for service %d (%s)...", i, g_service_names[i]); + ai_error_t ret = connection_thread_create((ai_service_type_t)i); + AI_LOGI("[DEBUG] connection_thread_create returned: %d", ret); + if (ret != AI_OK) { - AI_LOGE("Failed to create connection thread for service %s", g_service_names[i]); + AI_LOGE("[DEBUG] Failed to create connection thread for service %s, error: %d", g_service_names[i], ret); return ret; } + + AI_LOGI("[DEBUG] Thread created successfully for service %s", g_service_names[i]); + +#ifndef __TEST_MODE__ + AI_LOGI("[DEBUG] Calling osDelay(100)..."); + /* 给线程一些时间启动,避免竞态条件 */ + osDelay(100); // 100ms延迟 + AI_LOGI("[DEBUG] osDelay(100) completed"); +#endif } + AI_LOGI("[DEBUG] All connection threads created, checking heartbeat timer..."); + #ifndef __TEST_MODE__ /* 启动心跳定时器 */ + AI_LOGI("[DEBUG] Checking heartbeat_timer: %p", g_connection_manager.heartbeat_timer); if (g_connection_manager.heartbeat_timer != NULL) { + AI_LOGI("[DEBUG] Starting heartbeat timer with interval %u ms...", + g_connection_manager.config.keepalive_interval_ms); osTimerStart(g_connection_manager.heartbeat_timer, g_connection_manager.config.keepalive_interval_ms); + AI_LOGI("[DEBUG] Heartbeat timer started successfully"); + } else { + AI_LOGI("[DEBUG] Heartbeat timer is NULL, skipping"); } #endif + AI_LOGI("[DEBUG] ai_connection_manager_start_all: About to return AI_OK"); AI_LOGI("All connection threads started"); return AI_OK; } @@ -580,39 +615,114 @@ const char* ai_connection_manager_get_state_name(ai_global_state_t state) static ai_error_t connection_thread_create(ai_service_type_t service_type) { + AI_LOGI("[DEBUG] connection_thread_create: Entry, service_type=%d", service_type); + if (service_type >= AI_SERVICE_COUNT) { + AI_LOGE("[DEBUG] Invalid service_type: %d >= %d", service_type, AI_SERVICE_COUNT); return AI_ERROR_INVALID_PARAM; } + AI_LOGI("[DEBUG] Getting connection info for service %d...", service_type); ai_connection_info_t *conn = &g_connection_manager.connections[service_type]; + AI_LOGI("[DEBUG] Connection info pointer: %p", conn); #ifndef __TEST_MODE__ + AI_LOGI("[DEBUG] Creating osThreadAttr_t structure..."); + + /* 使用更保守的线程配置以避免创建失败 */ osThreadAttr_t thread_attr = { - .stack_size = AI_CONNECTION_STACK_SIZE, - .priority = g_connection_manager.config.connection_thread_priority + .stack_size = 2048, // 减少栈大小到2KB + .name = "connection_thread", + .priority = osPriorityNormal // 使用标准优先级 }; + //在psram里分配栈内存 + if(thread_attr.stack_mem == NULL) + { + thread_attr.stack_mem = memalign(16,thread_attr.stack_size); + if(thread_attr.stack_mem == NULL) + { + AI_LOGE("[DEBUG] Thread stack memory allocation failed"); + } + } + + AI_LOGI("[DEBUG] Thread attributes: stack_size=%u, priority=%d", + thread_attr.stack_size, (int)thread_attr.priority); + AI_LOGI("[DEBUG] Original config priority was: %d", g_connection_manager.config.connection_thread_priority); + + AI_LOGI("[DEBUG] Skipping thread name setting to avoid exception..."); + AI_LOGI("[DEBUG] service_type=%d, service_name=%s", service_type, g_service_names[service_type]); + + /* 临时禁用线程名称设置以避免异常 */ + + AI_LOGI("[DEBUG] Calling osThreadNew..."); + AI_LOGI("[DEBUG] Parameters: entry=%p, argument=%p, attr=%p", + connection_thread_entry, (void*)service_type, &thread_attr); - snprintf((char*)thread_attr.name, sizeof(thread_attr.name), "ai_conn_%s", g_service_names[service_type]); + /* 恢复实际线程创建,使用优化的配置 */ + AI_LOGI("[DEBUG] Creating thread with optimized configuration..."); conn->thread_id = osThreadNew(connection_thread_entry, (void*)service_type, &thread_attr); + AI_LOGI("[DEBUG] osThreadNew returned: %p", conn->thread_id); + if (conn->thread_id == NULL) { - AI_LOGE("Failed to create connection thread for service %s", g_service_names[service_type]); - return AI_ERROR_MEMORY_ALLOC; + AI_LOGE("[DEBUG] Thread creation failed, trying with minimal configuration..."); + + /* 尝试使用最小配置 */ + osThreadAttr_t minimal_attr = { + .stack_size = 1024, // 最小栈大小1KB + .name = "connection_thread_minimal", + .priority = osPriorityNormal + }; + //在psram里分配栈内存 + if(thread_attr.stack_mem == NULL) + { + thread_attr.stack_mem = memalign(16,thread_attr.stack_size); + if(thread_attr.stack_mem == NULL) + { + AI_LOGE("[DEBUG] Thread stack memory allocation failed"); + } + } + conn->thread_id = osThreadNew(connection_thread_entry, (void*)service_type, &minimal_attr); + AI_LOGI("[DEBUG] Minimal config osThreadNew returned: %p", conn->thread_id); + + if (conn->thread_id == NULL) { + AI_LOGE("[DEBUG] Thread creation failed even with minimal config"); + return AI_ERROR_MEMORY_ALLOC; + } else { + AI_LOGW("[DEBUG] Thread created with minimal configuration (1KB stack)"); + } + } else { + AI_LOGI("[DEBUG] Thread created successfully with optimized configuration"); } + + /* 设置初始连接状态 */ + conn->state = AI_CONN_STATE_DISCONNECTED; + + AI_LOGI("[DEBUG] Thread created successfully for service %s, thread_id=%p", + g_service_names[service_type], conn->thread_id); #else - AI_LOGI("TEST: Created connection thread for service %s", g_service_names[service_type]); + AI_LOGI("[DEBUG] TEST MODE: Simulating thread creation for service %s", g_service_names[service_type]); conn->thread_id = (void*)1; // 模拟线程ID + AI_LOGI("[DEBUG] TEST MODE: Thread ID set to %p", conn->thread_id); #endif + AI_LOGI("[DEBUG] connection_thread_create: Returning AI_OK"); return AI_OK; } static void connection_thread_entry(void *argument) { + AI_LOGI("[DEBUG] connection_thread_entry: Entry, argument=%p", argument); + + AI_LOGI("[DEBUG] Converting argument to service_type..."); ai_service_type_t service_type = (ai_service_type_t)(uintptr_t)argument; + AI_LOGI("[DEBUG] service_type=%d", service_type); + + AI_LOGI("[DEBUG] Getting connection info..."); ai_connection_info_t *conn = &g_connection_manager.connections[service_type]; + AI_LOGI("[DEBUG] Connection info pointer: %p", conn); - AI_LOGI("Connection thread started for service %s", g_service_names[service_type]); + AI_LOGI("[DEBUG] Connection thread started for service %s", g_service_names[service_type]); while (g_connection_manager.is_running) { if (conn->state == AI_CONN_STATE_DISCONNECTED) { @@ -661,10 +771,14 @@ static void connection_thread_entry(void *argument) conn->retry_count, g_connection_manager.config.max_retry_count); - if (conn->retry_count >= g_connection_manager.config.max_retry_count) { - AI_LOGE("Service %s connection failed after %d retries", + /* 为了安全,限制重试次数为1次 */ + if (conn->retry_count >= 1) { + AI_LOGW("Service %s connection disabled for safety after %d attempts", g_service_names[service_type], conn->retry_count); + /* 设置为永久断开状态,不再重试 */ + conn->state = AI_CONN_STATE_ERROR; + /* 发送连接失败事件 */ send_event(AI_EVENT_ERROR_OCCURRED, service_type, &ret); break; @@ -716,10 +830,24 @@ static ai_error_t websocket_connect(ai_connection_info_t *conn_info) return AI_ERROR_INVALID_PARAM; } + /* 验证服务类型有效性 */ + if (conn_info->service_type >= AI_SERVICE_COUNT) { + AI_LOGE("Invalid service type: %d", conn_info->service_type); + return AI_ERROR_INVALID_PARAM; + } + + /* 确保管理器仍然在运行 */ + if (!g_manager_initialized || !g_connection_manager.is_running) { + AI_LOGE("Connection manager not running"); + return AI_ERROR_NOT_INITIALIZED; + } + AI_LOGI("Connecting to %s: %s", g_service_names[conn_info->service_type], conn_info->url); #ifndef __TEST_MODE__ - /* 创建WebSocket客户端 */ + /* 恢复实际WebSocket连接 */ + AI_LOGI("Creating WebSocket client for service %s", g_service_names[conn_info->service_type]); + conn_info->websocket = WebSocketClientConstructor(websocket_on_connected, websocket_on_message, websocket_on_error, websocket_on_disconnected); if (conn_info->websocket < 0) { @@ -727,14 +855,19 @@ static ai_error_t websocket_connect(ai_connection_info_t *conn_info) return AI_ERROR_MEMORY_ALLOC; } - /* 连接到服务器 */ + AI_LOGI("WebSocket client created successfully, fd=%d", conn_info->websocket); + conn_info->state = AI_CONN_STATE_CONNECTING; + int ret = WebSocketClientConnect(conn_info->websocket, conn_info->url); if (ret != 0) { AI_LOGE("WebSocket connection failed: %d", ret); WebSocketClientClose(conn_info->websocket); conn_info->websocket = -1; + conn_info->state = AI_CONN_STATE_DISCONNECTED; return AI_ERROR_CONNECTION_FAILED; } + + AI_LOGI("WebSocket connection initiated for service %s", g_service_names[conn_info->service_type]); #else /* 测试模式下模拟连接成功 */ conn_info->websocket = 1; // 模拟WebSocket文件描述符 @@ -762,12 +895,24 @@ static ai_connection_info_t* find_connection_by_websocket(int websocket_fd) static void websocket_on_connected(int client) { + /* 安全检查:确保管理器已初始化 */ + if (!g_manager_initialized) { + AI_LOGE("Connection manager not initialized"); + return; + } + ai_connection_info_t *conn_info = find_connection_by_websocket(client); if (conn_info == NULL) { AI_LOGE("Cannot find connection info for WebSocket client %d", client); return; } + /* 验证服务类型有效性 */ + if (conn_info->service_type >= AI_SERVICE_COUNT) { + AI_LOGE("Invalid service type: %d", conn_info->service_type); + return; + } + AI_LOGI("WebSocket connected for service %s", g_service_names[conn_info->service_type]); #ifndef __TEST_MODE__ @@ -789,11 +934,23 @@ static void websocket_on_connected(int client) static void websocket_on_message(int client, const char *data, size_t length, bool isFinished) { (void)isFinished; // 暂时不处理分片消息 + + /* 安全检查:确保管理器已初始化 */ + if (!g_manager_initialized) { + return; + } + ai_connection_info_t *conn_info = find_connection_by_websocket(client); if (conn_info == NULL || data == NULL || length == 0) { return; } + /* 验证服务类型有效性 */ + if (conn_info->service_type >= AI_SERVICE_COUNT) { + AI_LOGE("Invalid service type: %d", conn_info->service_type); + return; + } + AI_LOGI("Received %zu bytes from service %s", length, g_service_names[conn_info->service_type]); /* 更新统计 */ @@ -814,11 +971,22 @@ static void websocket_on_message(int client, const char *data, size_t length, bo static void websocket_on_error(int client, struct WebSocketErrorResult errorResult) { + /* 安全检查:确保管理器已初始化 */ + if (!g_manager_initialized) { + return; + } + ai_connection_info_t *conn_info = find_connection_by_websocket(client); if (conn_info == NULL) { return; } + /* 验证服务类型有效性 */ + if (conn_info->service_type >= AI_SERVICE_COUNT) { + AI_LOGE("Invalid service type: %d", conn_info->service_type); + return; + } + AI_LOGE("WebSocket error for service %s: %d - %s", g_service_names[conn_info->service_type], errorResult.errorCode, errorResult.errorMessage ? errorResult.errorMessage : "Unknown"); @@ -831,11 +999,22 @@ static void websocket_on_error(int client, struct WebSocketErrorResult errorResu static void websocket_on_disconnected(int client) { + /* 安全检查:确保管理器已初始化 */ + if (!g_manager_initialized) { + return; + } + ai_connection_info_t *conn_info = find_connection_by_websocket(client); if (conn_info == NULL) { return; } + /* 验证服务类型有效性 */ + if (conn_info->service_type >= AI_SERVICE_COUNT) { + AI_LOGE("Invalid service type: %d", conn_info->service_type); + return; + } + AI_LOGW("WebSocket disconnected for service %s", g_service_names[conn_info->service_type]); conn_info->state = AI_CONN_STATE_DISCONNECTED; diff --git a/code/sdk/zhihui/ai/src/ai_memory_pool.c b/code/sdk/zhihui/ai/src/ai_memory_pool.c index bc2842cf2..0eccfcd18 100644 --- a/code/sdk/zhihui/ai/src/ai_memory_pool.c +++ b/code/sdk/zhihui/ai/src/ai_memory_pool.c @@ -41,7 +41,7 @@ static const struct { {AI_AUDIO_IN_BUFFER_SIZE * 2, AI_AUDIO_IN_BUFFER_SIZE, 2}, // AUDIO_IN: 2个2KB块 {AI_AUDIO_OUT_BUFFER_SIZE * 2, AI_AUDIO_OUT_BUFFER_SIZE, 2}, // AUDIO_OUT: 2个1KB块 {AI_NETWORK_POOL_SIZE, 256, 12}, // NETWORK: 12个256B块 - {AI_CONNECTION_BUFFER_SIZE * 3, AI_CONNECTION_BUFFER_SIZE, 3} // CONNECTION: 3个1KB块 + {AI_CONNECTION_BUFFER_SIZE * 6, AI_CONNECTION_BUFFER_SIZE, 6} // CONNECTION: 6个1KB块 (3个服务 x 2个缓冲区) }; /* ================================ 内部函数声明 ================================ */ diff --git a/code/sdk/zhihui/ai/src/ai_services.c b/code/sdk/zhihui/ai/src/ai_services.c index 918894dfe..8f4139f5d 100644 --- a/code/sdk/zhihui/ai/src/ai_services.c +++ b/code/sdk/zhihui/ai/src/ai_services.c @@ -1,11 +1,14 @@ /** * @file ai_services.c - * @brief AI服务统一接口实现 - LiteOS-M优化版v2 + * @brief AI服务统一管理接口实现 - LiteOS-M优化版v2 * @version 2.0 * @date 2024-01-20 */ #include "ai_services.h" +#include "ai_asr_service.h" +#include "ai_chat_service.h" +#include "ai_tts_service.h" #include "ai_connection_manager.h" #include "ai_memory_pool.h" #include @@ -26,44 +29,10 @@ #define AI_LOGW(fmt, ...) printf("[AI_SERVICES] WARN: " fmt "\n", ##__VA_ARGS__) #endif -/* ================================ 内部常量定义 ================================ */ - -#define JSON_BUFFER_SIZE 512 // JSON缓冲区大小 -#define MESSAGE_ID_LENGTH 16 // 消息ID长度 -#define MAX_AUDIO_CHUNK_SIZE 1024 // 最大音频块大小 - -/* 语音类型名称映射 */ -static const char* g_voice_names[TTS_VOICE_COUNT] = { - "xiaoyun", "xiaogang", "xiaomei", "xiaoli" -}; - -/* 状态名称映射 */ -static const char* g_asr_state_names[] = { - "IDLE", "LISTENING", "RECOGNIZING", "COMPLETED", "ERROR" -}; - -static const char* g_chat_state_names[] = { - "IDLE", "SENDING", "WAITING", "RECEIVING", "COMPLETED", "ERROR" -}; - -static const char* g_tts_state_names[] = { - "IDLE", "SYNTHESIZING", "PLAYING", "COMPLETED", "ERROR" -}; - /* ================================ 内部函数声明 ================================ */ -static ai_error_t build_asr_start_message(const char *session_id, const asr_config_t *config, char *json_buffer, size_t buffer_size); -static ai_error_t build_chat_message(const char *message, const char *session_id, const chat_config_t *config, char *json_buffer, size_t buffer_size); -static ai_error_t build_tts_request(const char *text, const char *session_id, const tts_config_t *config, char *json_buffer, size_t buffer_size); -static ai_error_t parse_asr_response(const char *json_data, asr_result_t *result); -static ai_error_t parse_chat_response(const char *json_data, chat_message_t *message); -static ai_error_t parse_tts_response(const char *json_data, tts_result_t *result); -static void generate_message_id(char *message_id, size_t buffer_size); static uint32_t get_current_timestamp(void); static void connection_event_handler(const ai_event_t *event, void *user_data); -static ai_error_t change_asr_state(ai_services_context_t *context, asr_state_t new_state); -static ai_error_t change_chat_state(ai_services_context_t *context, chat_state_t new_state); -static ai_error_t change_tts_state(ai_services_context_t *context, tts_state_t new_state); /* ================================ 公共接口实现 ================================ */ @@ -84,17 +53,29 @@ ai_error_t ai_services_init(ai_services_context_t *context) /* 初始化上下文 */ memset(context, 0, sizeof(ai_services_context_t)); - /* 设置默认状态 */ - context->asr_state = ASR_STATE_IDLE; - context->chat_state = CHAT_STATE_IDLE; - context->tts_state = TTS_STATE_IDLE; + /* 初始化各个服务 */ + ai_error_t ret = ai_asr_service_init(&context->asr_context); + if (ret != AI_OK) { + AI_LOGE("Failed to initialize ASR service: %d", ret); + return ret; + } - /* 创建默认配置 */ - ai_asr_create_default_config(&context->asr_config); - ai_chat_create_default_config(&context->chat_config); - ai_tts_create_default_config(&context->tts_config); + ret = ai_chat_service_init(&context->chat_context); + if (ret != AI_OK) { + AI_LOGE("Failed to initialize Chat service: %d", ret); + ai_asr_service_destroy(&context->asr_context); + return ret; + } - /* 生成初始会话ID */ + ret = ai_tts_service_init(&context->tts_context); + if (ret != AI_OK) { + AI_LOGE("Failed to initialize TTS service: %d", ret); + ai_asr_service_destroy(&context->asr_context); + ai_chat_service_destroy(&context->chat_context); + return ret; + } + + /* 生成统一会话ID */ ai_services_generate_session_id(context->current_session_id, sizeof(context->current_session_id)); context->last_activity_time = get_current_timestamp(); @@ -116,14 +97,10 @@ ai_error_t ai_services_destroy(ai_services_context_t *context) AI_LOGI("Destroying AI services..."); - /* 停止所有活动服务 */ - if (context->asr_state != ASR_STATE_IDLE) { - ai_asr_stop(context); - } - - if (context->tts_state != TTS_STATE_IDLE) { - ai_tts_stop(context); - } + /* 销毁各个服务 */ + ai_asr_service_destroy(&context->asr_context); + ai_chat_service_destroy(&context->chat_context); + ai_tts_service_destroy(&context->tts_context); /* 重置上下文 */ memset(context, 0, sizeof(ai_services_context_t)); @@ -132,7 +109,7 @@ ai_error_t ai_services_destroy(ai_services_context_t *context) return AI_OK; } -/* ================================ ASR服务接口实现 ================================ */ +/* ================================ ASR服务接口包装 ================================ */ ai_error_t ai_asr_configure(ai_services_context_t *context, const asr_config_t *config) { @@ -144,13 +121,7 @@ ai_error_t ai_asr_configure(ai_services_context_t *context, const asr_config_t * return AI_ERROR_NOT_INITIALIZED; } - memcpy(&context->asr_config, config, sizeof(asr_config_t)); - AI_LOGI("ASR configured: language=%s, vad=%s, punctuation=%s", - config->language, - config->enable_vad ? "enabled" : "disabled", - config->enable_punctuation ? "enabled" : "disabled"); - - return AI_OK; + return ai_asr_service_configure(&context->asr_context, config); } ai_error_t ai_asr_set_callbacks(ai_services_context_t *context, @@ -167,13 +138,7 @@ ai_error_t ai_asr_set_callbacks(ai_services_context_t *context, return AI_ERROR_NOT_INITIALIZED; } - context->asr_result_cb = result_cb; - context->asr_error_cb = error_cb; - context->asr_state_cb = state_cb; - context->user_data = user_data; - - AI_LOGI("ASR callbacks set"); - return AI_OK; + return ai_asr_service_set_callbacks(&context->asr_context, result_cb, error_cb, state_cb, user_data); } ai_error_t ai_asr_start(ai_services_context_t *context, const char *session_id) @@ -186,49 +151,15 @@ ai_error_t ai_asr_start(ai_services_context_t *context, const char *session_id) return AI_ERROR_NOT_INITIALIZED; } - if (context->asr_state != ASR_STATE_IDLE) { - AI_LOGW("ASR already active, stopping first"); - ai_asr_stop(context); - } - - /* 使用提供的会话ID或当前会话ID */ + /* 使用统一会话ID或提供的会话ID */ const char *use_session_id = session_id ? session_id : context->current_session_id; - AI_LOGI("Starting ASR with session ID: %s", use_session_id); - - /* 检查ASR连接状态 */ - ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_ASR); - if (conn_state != AI_CONN_STATE_CONNECTED) { - AI_LOGE("ASR service not connected"); - return AI_ERROR_SERVICE_UNAVAILABLE; - } - - /* 构建启动消息 */ - char json_buffer[JSON_BUFFER_SIZE]; - ai_error_t ret = build_asr_start_message(use_session_id, &context->asr_config, json_buffer, sizeof(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to build ASR start message"); - return ret; - } - - /* 发送启动消息 */ - ret = ai_connection_manager_send_data(AI_SERVICE_ASR, json_buffer, strlen(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to send ASR start message"); - return ret; - } - - /* 更新状态 */ - change_asr_state(context, ASR_STATE_LISTENING); - strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); - context->last_activity_time = get_current_timestamp(); - - return AI_OK; + return ai_asr_service_start(&context->asr_context, use_session_id); } ai_error_t ai_asr_send_audio(ai_services_context_t *context, const uint8_t *audio_data, uint32_t data_size) { - if (context == NULL || audio_data == NULL || data_size == 0) { + if (context == NULL) { return AI_ERROR_INVALID_PARAM; } @@ -236,58 +167,7 @@ ai_error_t ai_asr_send_audio(ai_services_context_t *context, const uint8_t *audi return AI_ERROR_NOT_INITIALIZED; } - if (context->asr_state != ASR_STATE_LISTENING && context->asr_state != ASR_STATE_RECOGNIZING) { - AI_LOGW("ASR not in listening/recognizing state"); - return AI_ERROR_STATE_INVALID; - } - - /* 检查数据大小 */ - if (data_size > MAX_AUDIO_CHUNK_SIZE) { - AI_LOGW("Audio chunk too large: %u bytes, splitting", data_size); - - /* 分块发送 */ - uint32_t offset = 0; - while (offset < data_size) { - uint32_t chunk_size = (data_size - offset > MAX_AUDIO_CHUNK_SIZE) ? - MAX_AUDIO_CHUNK_SIZE : (data_size - offset); - - ai_error_t ret = ai_asr_send_audio(context, audio_data + offset, chunk_size); - if (ret != AI_OK) { - return ret; - } - offset += chunk_size; - } - return AI_OK; - } - - /* 构建音频数据消息 */ - ai_buffer_t *buffer = ai_memory_pool_alloc_network(AI_SERVICE_ASR, data_size + 64); - if (buffer == NULL) { - AI_LOGE("Failed to allocate network buffer for audio data"); - return AI_ERROR_MEMORY_ALLOC; - } - - /* 简化的二进制数据发送(实际实现中可能需要Base64编码) */ - memcpy(buffer->buffer, audio_data, data_size); - buffer->used = data_size; - - ai_error_t ret = ai_connection_manager_send_data(AI_SERVICE_ASR, (const char*)buffer->buffer, buffer->used); - - ai_memory_pool_free(buffer); - - if (ret != AI_OK) { - AI_LOGE("Failed to send audio data"); - return ret; - } - - /* 更新状态 */ - if (context->asr_state == ASR_STATE_LISTENING) { - change_asr_state(context, ASR_STATE_RECOGNIZING); - } - - context->last_activity_time = get_current_timestamp(); - - return AI_OK; + return ai_asr_service_send_audio(&context->asr_context, audio_data, data_size); } ai_error_t ai_asr_stop(ai_services_context_t *context) @@ -300,23 +180,7 @@ ai_error_t ai_asr_stop(ai_services_context_t *context) return AI_ERROR_NOT_INITIALIZED; } - if (context->asr_state == ASR_STATE_IDLE) { - return AI_OK; // 已经停止 - } - - AI_LOGI("Stopping ASR"); - - /* 发送停止消息 */ - char stop_message[] = "{\"type\":\"stop\",\"session_id\":\"%s\"}"; - char json_buffer[JSON_BUFFER_SIZE]; - snprintf(json_buffer, sizeof(json_buffer), stop_message, context->current_session_id); - - ai_connection_manager_send_data(AI_SERVICE_ASR, json_buffer, strlen(json_buffer)); - - /* 更新状态 */ - change_asr_state(context, ASR_STATE_IDLE); - - return AI_OK; + return ai_asr_service_stop(&context->asr_context); } asr_state_t ai_asr_get_state(ai_services_context_t *context) @@ -325,10 +189,10 @@ asr_state_t ai_asr_get_state(ai_services_context_t *context) return ASR_STATE_ERROR; } - return context->asr_state; + return ai_asr_service_get_state(&context->asr_context); } -/* ================================ Chat服务接口实现 ================================ */ +/* ================================ Chat服务接口包装 ================================ */ ai_error_t ai_chat_configure(ai_services_context_t *context, const chat_config_t *config) { @@ -340,11 +204,7 @@ ai_error_t ai_chat_configure(ai_services_context_t *context, const chat_config_t return AI_ERROR_NOT_INITIALIZED; } - memcpy(&context->chat_config, config, sizeof(chat_config_t)); - AI_LOGI("Chat configured: model=%s, temperature=%.2f, max_tokens=%d", - config->model_name, config->temperature, config->max_tokens); - - return AI_OK; + return ai_chat_service_configure(&context->chat_context, config); } ai_error_t ai_chat_set_callbacks(ai_services_context_t *context, @@ -361,18 +221,12 @@ ai_error_t ai_chat_set_callbacks(ai_services_context_t *context, return AI_ERROR_NOT_INITIALIZED; } - context->chat_response_cb = response_cb; - context->chat_error_cb = error_cb; - context->chat_state_cb = state_cb; - context->user_data = user_data; - - AI_LOGI("Chat callbacks set"); - return AI_OK; + return ai_chat_service_set_callbacks(&context->chat_context, response_cb, error_cb, state_cb, user_data); } ai_error_t ai_chat_send_message(ai_services_context_t *context, const char *message, const char *session_id) { - if (context == NULL || message == NULL || strlen(message) == 0) { + if (context == NULL) { return AI_ERROR_INVALID_PARAM; } @@ -380,47 +234,10 @@ ai_error_t ai_chat_send_message(ai_services_context_t *context, const char *mess return AI_ERROR_NOT_INITIALIZED; } - if (context->chat_state != CHAT_STATE_IDLE) { - AI_LOGW("Chat busy, current state: %s", g_chat_state_names[context->chat_state]); - return AI_ERROR_STATE_INVALID; - } - - /* 使用提供的会话ID或当前会话ID */ + /* 使用统一会话ID或提供的会话ID */ const char *use_session_id = session_id ? session_id : context->current_session_id; - AI_LOGI("Sending chat message: %.50s... (session: %s)", message, use_session_id); - - /* 检查Chat连接状态 */ - ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_CHAT); - if (conn_state != AI_CONN_STATE_CONNECTED) { - AI_LOGE("Chat service not connected"); - return AI_ERROR_SERVICE_UNAVAILABLE; - } - - /* 构建聊天消息 */ - char json_buffer[JSON_BUFFER_SIZE]; - ai_error_t ret = build_chat_message(message, use_session_id, &context->chat_config, json_buffer, sizeof(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to build chat message"); - return ret; - } - - /* 发送消息 */ - change_chat_state(context, CHAT_STATE_SENDING); - - ret = ai_connection_manager_send_data(AI_SERVICE_CHAT, json_buffer, strlen(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to send chat message"); - change_chat_state(context, CHAT_STATE_ERROR); - return ret; - } - - /* 更新状态 */ - change_chat_state(context, CHAT_STATE_WAITING); - strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); - context->last_activity_time = get_current_timestamp(); - - return AI_OK; + return ai_chat_service_send_message(&context->chat_context, message, use_session_id); } chat_state_t ai_chat_get_state(ai_services_context_t *context) @@ -429,10 +246,10 @@ chat_state_t ai_chat_get_state(ai_services_context_t *context) return CHAT_STATE_ERROR; } - return context->chat_state; + return ai_chat_service_get_state(&context->chat_context); } -/* ================================ TTS服务接口实现 ================================ */ +/* ================================ TTS服务接口包装 ================================ */ ai_error_t ai_tts_configure(ai_services_context_t *context, const tts_config_t *config) { @@ -444,11 +261,7 @@ ai_error_t ai_tts_configure(ai_services_context_t *context, const tts_config_t * return AI_ERROR_NOT_INITIALIZED; } - memcpy(&context->tts_config, config, sizeof(tts_config_t)); - AI_LOGI("TTS configured: voice=%s, volume=%d, speed=%d", - ai_tts_get_voice_name(config->voice_type), config->volume, config->speed); - - return AI_OK; + return ai_tts_service_configure(&context->tts_context, config); } ai_error_t ai_tts_set_callbacks(ai_services_context_t *context, @@ -465,18 +278,12 @@ ai_error_t ai_tts_set_callbacks(ai_services_context_t *context, return AI_ERROR_NOT_INITIALIZED; } - context->tts_result_cb = result_cb; - context->tts_error_cb = error_cb; - context->tts_state_cb = state_cb; - context->user_data = user_data; - - AI_LOGI("TTS callbacks set"); - return AI_OK; + return ai_tts_service_set_callbacks(&context->tts_context, result_cb, error_cb, state_cb, user_data); } ai_error_t ai_tts_synthesize(ai_services_context_t *context, const char *text, const char *session_id) { - if (context == NULL || text == NULL || strlen(text) == 0) { + if (context == NULL) { return AI_ERROR_INVALID_PARAM; } @@ -484,46 +291,10 @@ ai_error_t ai_tts_synthesize(ai_services_context_t *context, const char *text, c return AI_ERROR_NOT_INITIALIZED; } - if (context->tts_state != TTS_STATE_IDLE) { - AI_LOGW("TTS busy, current state: %s", g_tts_state_names[context->tts_state]); - return AI_ERROR_STATE_INVALID; - } - - /* 使用提供的会话ID或当前会话ID */ + /* 使用统一会话ID或提供的会话ID */ const char *use_session_id = session_id ? session_id : context->current_session_id; - AI_LOGI("Starting TTS synthesis: %.50s... (session: %s)", text, use_session_id); - - /* 检查TTS连接状态 */ - ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_TTS); - if (conn_state != AI_CONN_STATE_CONNECTED) { - AI_LOGE("TTS service not connected"); - return AI_ERROR_SERVICE_UNAVAILABLE; - } - - /* 构建TTS请求 */ - char json_buffer[JSON_BUFFER_SIZE]; - ai_error_t ret = build_tts_request(text, use_session_id, &context->tts_config, json_buffer, sizeof(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to build TTS request"); - return ret; - } - - /* 发送请求 */ - change_tts_state(context, TTS_STATE_SYNTHESIZING); - - ret = ai_connection_manager_send_data(AI_SERVICE_TTS, json_buffer, strlen(json_buffer)); - if (ret != AI_OK) { - AI_LOGE("Failed to send TTS request"); - change_tts_state(context, TTS_STATE_ERROR); - return ret; - } - - /* 更新状态 */ - strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); - context->last_activity_time = get_current_timestamp(); - - return AI_OK; + return ai_tts_service_synthesize(&context->tts_context, text, use_session_id); } ai_error_t ai_tts_stop(ai_services_context_t *context) @@ -536,23 +307,7 @@ ai_error_t ai_tts_stop(ai_services_context_t *context) return AI_ERROR_NOT_INITIALIZED; } - if (context->tts_state == TTS_STATE_IDLE) { - return AI_OK; // 已经停止 - } - - AI_LOGI("Stopping TTS"); - - /* 发送停止消息 */ - char stop_message[] = "{\"type\":\"stop\",\"session_id\":\"%s\"}"; - char json_buffer[JSON_BUFFER_SIZE]; - snprintf(json_buffer, sizeof(json_buffer), stop_message, context->current_session_id); - - ai_connection_manager_send_data(AI_SERVICE_TTS, json_buffer, strlen(json_buffer)); - - /* 更新状态 */ - change_tts_state(context, TTS_STATE_IDLE); - - return AI_OK; + return ai_tts_service_stop(&context->tts_context); } tts_state_t ai_tts_get_state(ai_services_context_t *context) @@ -561,54 +316,24 @@ tts_state_t ai_tts_get_state(ai_services_context_t *context) return TTS_STATE_ERROR; } - return context->tts_state; + return ai_tts_service_get_state(&context->tts_context); } /* ================================ 辅助函数实现 ================================ */ void ai_asr_create_default_config(asr_config_t *config) { - if (config == NULL) { - return; - } - - memset(config, 0, sizeof(asr_config_t)); - config->enable_vad = true; - config->enable_punctuation = true; - config->enable_partial_results = true; - config->silence_timeout_ms = 3000; // 3秒静音超时 - config->max_duration_ms = 30000; // 30秒最大录音时长 - strncpy(config->language, "zh-CN", sizeof(config->language) - 1); + ai_asr_service_create_default_config(config); } void ai_chat_create_default_config(chat_config_t *config) { - if (config == NULL) { - return; - } - - memset(config, 0, sizeof(chat_config_t)); - strncpy(config->model_name, "qwen-plus", sizeof(config->model_name) - 1); - config->temperature = 0.7f; - config->max_tokens = 512; // 适合LiteOS-M的较小值 - config->top_p = 0.9f; - config->stream = true; - config->timeout_ms = 15000; // 15秒超时 + ai_chat_service_create_default_config(config); } void ai_tts_create_default_config(tts_config_t *config) { - if (config == NULL) { - return; - } - - memset(config, 0, sizeof(tts_config_t)); - config->voice_type = TTS_VOICE_XIAOYUN; - config->volume = 80; // 80%音量 - config->speed = 50; // 正常语速 - config->pitch = 50; // 正常音调 - config->auto_play = true; - config->timeout_ms = 10000; // 10秒超时 + ai_tts_service_create_default_config(config); } void ai_services_generate_session_id(char *session_id, size_t buffer_size) @@ -626,11 +351,7 @@ void ai_services_generate_session_id(char *session_id, size_t buffer_size) const char* ai_tts_get_voice_name(tts_voice_type_t voice_type) { - if (voice_type >= TTS_VOICE_COUNT) { - return "unknown"; - } - - return g_voice_names[voice_type]; + return ai_tts_service_get_voice_name(voice_type); } const char* ai_services_get_state_string(ai_service_type_t service_type, ai_services_context_t *context) @@ -641,14 +362,11 @@ const char* ai_services_get_state_string(ai_service_type_t service_type, ai_serv switch (service_type) { case AI_SERVICE_ASR: - return (context->asr_state < sizeof(g_asr_state_names)/sizeof(g_asr_state_names[0])) ? - g_asr_state_names[context->asr_state] : "UNKNOWN"; + return ai_asr_service_get_state_name(ai_asr_service_get_state(&context->asr_context)); case AI_SERVICE_CHAT: - return (context->chat_state < sizeof(g_chat_state_names)/sizeof(g_chat_state_names[0])) ? - g_chat_state_names[context->chat_state] : "UNKNOWN"; + return ai_chat_service_get_state_name(ai_chat_service_get_state(&context->chat_context)); case AI_SERVICE_TTS: - return (context->tts_state < sizeof(g_tts_state_names)/sizeof(g_tts_state_names[0])) ? - g_tts_state_names[context->tts_state] : "UNKNOWN"; + return ai_tts_service_get_state_name(ai_tts_service_get_state(&context->tts_context)); default: return "UNKNOWN"; } @@ -656,138 +374,6 @@ const char* ai_services_get_state_string(ai_service_type_t service_type, ai_serv /* ================================ 内部函数实现 ================================ */ -static ai_error_t build_asr_start_message(const char *session_id, const asr_config_t *config, char *json_buffer, size_t buffer_size) -{ - if (session_id == NULL || config == NULL || json_buffer == NULL) { - return AI_ERROR_INVALID_PARAM; - } - - /* 构建ASR启动消息 */ - int ret = snprintf(json_buffer, buffer_size, - "{" - "\"type\":\"start\"," - "\"session_id\":\"%s\"," - "\"config\":{" - "\"language\":\"%s\"," - "\"enable_vad\":%s," - "\"enable_punctuation\":%s," - "\"enable_partial_results\":%s," - "\"silence_timeout_ms\":%d," - "\"max_duration_ms\":%d" - "}" - "}", - session_id, - config->language, - config->enable_vad ? "true" : "false", - config->enable_punctuation ? "true" : "false", - config->enable_partial_results ? "true" : "false", - config->silence_timeout_ms, - config->max_duration_ms - ); - - if (ret < 0 || ret >= buffer_size) { - AI_LOGE("JSON buffer too small for ASR start message"); - return AI_ERROR_BUFFER_OVERFLOW; - } - - return AI_OK; -} - -static ai_error_t build_chat_message(const char *message, const char *session_id, const chat_config_t *config, char *json_buffer, size_t buffer_size) -{ - if (message == NULL || session_id == NULL || config == NULL || json_buffer == NULL) { - return AI_ERROR_INVALID_PARAM; - } - - /* 生成消息ID */ - char message_id[MESSAGE_ID_LENGTH + 1]; - generate_message_id(message_id, sizeof(message_id)); - - /* 构建Chat消息 */ - int ret = snprintf(json_buffer, buffer_size, - "{" - "\"type\":\"chat\"," - "\"session_id\":\"%s\"," - "\"message_id\":\"%s\"," - "\"message\":{" - "\"role\":\"user\"," - "\"content\":\"%s\"" - "}," - "\"config\":{" - "\"model\":\"%s\"," - "\"temperature\":%.2f," - "\"max_tokens\":%d," - "\"top_p\":%.2f," - "\"stream\":%s" - "}" - "}", - session_id, - message_id, - message, - config->model_name, - config->temperature, - config->max_tokens, - config->top_p, - config->stream ? "true" : "false" - ); - - if (ret < 0 || ret >= buffer_size) { - AI_LOGE("JSON buffer too small for chat message"); - return AI_ERROR_BUFFER_OVERFLOW; - } - - return AI_OK; -} - -static ai_error_t build_tts_request(const char *text, const char *session_id, const tts_config_t *config, char *json_buffer, size_t buffer_size) -{ - if (text == NULL || session_id == NULL || config == NULL || json_buffer == NULL) { - return AI_ERROR_INVALID_PARAM; - } - - /* 构建TTS请求 */ - int ret = snprintf(json_buffer, buffer_size, - "{" - "\"type\":\"synthesize\"," - "\"session_id\":\"%s\"," - "\"text\":\"%s\"," - "\"config\":{" - "\"voice\":\"%s\"," - "\"volume\":%d," - "\"speed\":%d," - "\"pitch\":%d," - "\"auto_play\":%s" - "}" - "}", - session_id, - text, - ai_tts_get_voice_name(config->voice_type), - config->volume, - config->speed, - config->pitch, - config->auto_play ? "true" : "false" - ); - - if (ret < 0 || ret >= buffer_size) { - AI_LOGE("JSON buffer too small for TTS request"); - return AI_ERROR_BUFFER_OVERFLOW; - } - - return AI_OK; -} - -static void generate_message_id(char *message_id, size_t buffer_size) -{ - if (message_id == NULL || buffer_size < MESSAGE_ID_LENGTH + 1) { - return; - } - - uint32_t timestamp = get_current_timestamp(); - uint16_t random = rand() & 0xFFFF; - - snprintf(message_id, buffer_size, "msg_%08x_%04x", timestamp, random); -} - static uint32_t get_current_timestamp(void) { #ifndef __TEST_MODE__ @@ -797,71 +383,41 @@ static uint32_t get_current_timestamp(void) #endif } -static ai_error_t change_asr_state(ai_services_context_t *context, asr_state_t new_state) -{ - if (context == NULL) { - return AI_ERROR_INVALID_PARAM; - } - - asr_state_t old_state = context->asr_state; - if (old_state != new_state) { - context->asr_state = new_state; - - AI_LOGI("ASR state changed: %s -> %s", - g_asr_state_names[old_state], - g_asr_state_names[new_state]); - - /* 调用状态回调 */ - if (context->asr_state_cb != NULL) { - context->asr_state_cb(old_state, new_state, context->user_data); - } - } - - return AI_OK; -} - -static ai_error_t change_chat_state(ai_services_context_t *context, chat_state_t new_state) +static void connection_event_handler(const ai_event_t *event, void *user_data) { - if (context == NULL) { - return AI_ERROR_INVALID_PARAM; + if (event == NULL) { + return; } - chat_state_t old_state = context->chat_state; - if (old_state != new_state) { - context->chat_state = new_state; - - AI_LOGI("Chat state changed: %s -> %s", - g_chat_state_names[old_state], - g_chat_state_names[new_state]); - - /* 调用状态回调 */ - if (context->chat_state_cb != NULL) { - context->chat_state_cb(old_state, new_state, context->user_data); - } + ai_services_context_t *context = (ai_services_context_t*)user_data; + if (context == NULL || !context->is_initialized) { + return; } - return AI_OK; -} - -static ai_error_t change_tts_state(ai_services_context_t *context, tts_state_t new_state) -{ - if (context == NULL) { - return AI_ERROR_INVALID_PARAM; - } + AI_LOGI("Connection event: service=%d, type=%d", event->service, event->type); - tts_state_t old_state = context->tts_state; - if (old_state != new_state) { - context->tts_state = new_state; - - AI_LOGI("TTS state changed: %s -> %s", - g_tts_state_names[old_state], - g_tts_state_names[new_state]); - - /* 调用状态回调 */ - if (context->tts_state_cb != NULL) { - context->tts_state_cb(old_state, new_state, context->user_data); - } + /* 根据事件类型和服务类型处理响应 */ + switch (event->service) { + case AI_SERVICE_ASR: + if (event->type == AI_EVENT_DATA_RECEIVED && event->payload.data.data != NULL) { + ai_asr_service_handle_response(&context->asr_context, (const char*)event->payload.data.data); + } + break; + + case AI_SERVICE_CHAT: + if (event->type == AI_EVENT_DATA_RECEIVED && event->payload.data.data != NULL) { + ai_chat_service_handle_response(&context->chat_context, (const char*)event->payload.data.data); + } + break; + + case AI_SERVICE_TTS: + if (event->type == AI_EVENT_DATA_RECEIVED && event->payload.data.data != NULL) { + ai_tts_service_handle_response(&context->tts_context, (const char*)event->payload.data.data); + } + break; + + default: + AI_LOGW("Unknown service type: %d", event->service); + break; } - - return AI_OK; } \ No newline at end of file diff --git a/code/sdk/zhihui/ai/src/ai_tts_service.c b/code/sdk/zhihui/ai/src/ai_tts_service.c new file mode 100644 index 000000000..9c9cf8b86 --- /dev/null +++ b/code/sdk/zhihui/ai/src/ai_tts_service.c @@ -0,0 +1,467 @@ +/** + * @file ai_tts_service.c + * @brief AI语音合成(TTS)服务实现 + * @version 2.0 + * @date 2024-01-20 + */ + +#include "ai_tts_service.h" +#include "ai_connection_manager.h" +#include "ai_memory_pool.h" +#include +#include +#include +#include + +#ifndef __TEST_MODE__ +#include "wearable_log.h" +#include "dev_authentication.h" +#define AI_LOG_TAG "AI_TTS" +#define AI_LOGI(fmt, ...) WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[%s] " fmt, AI_LOG_TAG, ##__VA_ARGS__) +#else +#define AI_LOGI(fmt, ...) printf("[AI_TTS] " fmt "\n", ##__VA_ARGS__) +#define AI_LOGE(fmt, ...) printf("[AI_TTS] ERROR: " fmt "\n", ##__VA_ARGS__) +#define AI_LOGW(fmt, ...) printf("[AI_TTS] WARN: " fmt "\n", ##__VA_ARGS__) +#endif + +/* ================================ 内部常量定义 ================================ */ + +#define JSON_BUFFER_SIZE 512 // JSON缓冲区大小 + +/* 语音类型名称映射 */ +static const char* g_voice_names[TTS_VOICE_COUNT] = { + "xiaoyun", "xiaogang", "xiaomei", "xiaoli" +}; + +/* TTS状态名称映射 */ +static const char* g_tts_state_names[] = { + "IDLE", "SYNTHESIZING", "PLAYING", "COMPLETED", "ERROR" +}; + +/* ================================ 内部函数声明 ================================ */ + +static uint32_t get_current_timestamp(void); +static ai_error_t change_tts_state(tts_service_context_t *context, tts_state_t new_state); +static ai_error_t parse_tts_response(const char *json_data, tts_result_t *result); + +/* ================================ 公共接口实现 ================================ */ + +ai_error_t ai_tts_service_init(tts_service_context_t *context) +{ + if (context == NULL) { + AI_LOGE("Invalid context parameter"); + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Initializing TTS service..."); + + /* 初始化上下文 */ + memset(context, 0, sizeof(tts_service_context_t)); + + /* 设置默认状态 */ + context->state = TTS_STATE_IDLE; + + /* 创建默认配置 */ + ai_tts_service_create_default_config(&context->config); + + /* 生成初始会话ID */ + uint32_t timestamp = get_current_timestamp(); + uint32_t random = rand(); + snprintf(context->current_session_id, sizeof(context->current_session_id), + "tts_%08x_%04x", timestamp, random & 0xFFFF); + + context->last_activity_time = get_current_timestamp(); + + AI_LOGI("TTS service initialized successfully"); + return AI_OK; +} + +ai_error_t ai_tts_service_destroy(tts_service_context_t *context) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Destroying TTS service..."); + + /* 停止活动服务 */ + if (context->state != TTS_STATE_IDLE) { + ai_tts_service_stop(context); + } + + /* 重置上下文 */ + memset(context, 0, sizeof(tts_service_context_t)); + + AI_LOGI("TTS service destroyed"); + return AI_OK; +} + +ai_error_t ai_tts_service_configure(tts_service_context_t *context, const tts_config_t *config) +{ + if (context == NULL || config == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + memcpy(&context->config, config, sizeof(tts_config_t)); + AI_LOGI("TTS configured: voice=%s, volume=%d, speed=%d", + ai_tts_service_get_voice_name(config->voice_type), config->volume, config->speed); + + return AI_OK; +} + +ai_error_t ai_tts_service_set_callbacks(tts_service_context_t *context, + tts_result_callback_t result_cb, + tts_error_callback_t error_cb, + tts_state_callback_t state_cb, + void *user_data) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + context->result_cb = result_cb; + context->error_cb = error_cb; + context->state_cb = state_cb; + context->user_data = user_data; + + AI_LOGI("TTS callbacks set"); + return AI_OK; +} + +ai_error_t ai_tts_service_synthesize(tts_service_context_t *context, const char *text, const char *session_id) +{ + if (context == NULL || text == NULL || strlen(text) == 0) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state != TTS_STATE_IDLE) { + AI_LOGW("TTS busy, current state: %s", g_tts_state_names[context->state]); + return AI_ERROR_STATE_INVALID; + } + + /* 使用提供的会话ID或当前会话ID */ + const char *use_session_id = session_id ? session_id : context->current_session_id; + + AI_LOGI("Starting TTS synthesis: %.50s... (session: %s)", text, use_session_id); + + /* 检查TTS连接状态 */ + ai_connection_state_t conn_state = ai_connection_manager_get_connection_state(AI_SERVICE_TTS); + if (conn_state != AI_CONN_STATE_CONNECTED) { + AI_LOGE("TTS service not connected"); + return AI_ERROR_SERVICE_UNAVAILABLE; + } + + /* 构建TTS请求 */ + char json_buffer[JSON_BUFFER_SIZE]; + ai_error_t ret = ai_tts_service_build_request(text, use_session_id, &context->config, json_buffer, sizeof(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to build TTS request"); + return ret; + } + + /* 发送请求 */ + change_tts_state(context, TTS_STATE_SYNTHESIZING); + + ret = ai_connection_manager_send_data(AI_SERVICE_TTS, json_buffer, strlen(json_buffer)); + if (ret != AI_OK) { + AI_LOGE("Failed to send TTS request"); + change_tts_state(context, TTS_STATE_ERROR); + return ret; + } + + /* 更新状态 */ + strncpy(context->current_session_id, use_session_id, sizeof(context->current_session_id) - 1); + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_tts_service_stop(tts_service_context_t *context) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + if (context->state == TTS_STATE_IDLE) { + return AI_OK; // 已经停止 + } + + AI_LOGI("Stopping TTS"); + + /* 构建停止消息 */ + char json_buffer[JSON_BUFFER_SIZE]; + ai_error_t ret = ai_tts_service_build_stop_message(context->current_session_id, json_buffer, sizeof(json_buffer)); + if (ret == AI_OK) { + ai_connection_manager_send_data(AI_SERVICE_TTS, json_buffer, strlen(json_buffer)); + } + + /* 更新状态 */ + change_tts_state(context, TTS_STATE_IDLE); + + return AI_OK; +} + +tts_state_t ai_tts_service_get_state(tts_service_context_t *context) +{ + if (context == NULL) { + return TTS_STATE_ERROR; + } + + return context->state; +} + +const char* ai_tts_service_get_state_name(tts_state_t state) +{ + if (state >= sizeof(g_tts_state_names) / sizeof(g_tts_state_names[0])) { + return "UNKNOWN"; + } + + return g_tts_state_names[state]; +} + +const char* ai_tts_service_get_voice_name(tts_voice_type_t voice_type) +{ + if (voice_type >= TTS_VOICE_COUNT) { + return "unknown"; + } + + return g_voice_names[voice_type]; +} + +void ai_tts_service_create_default_config(tts_config_t *config) +{ + if (config == NULL) { + return; + } + + memset(config, 0, sizeof(tts_config_t)); + config->voice_type = TTS_VOICE_XIAOYUN; + config->volume = 80; // 80%音量 + config->speed = 50; // 正常语速 + config->pitch = 50; // 正常音调 + config->auto_play = true; + config->timeout_ms = 10000; // 10秒超时 +} + +ai_error_t ai_tts_service_handle_response(tts_service_context_t *context, const char *json_data) +{ + if (context == NULL || json_data == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + AI_LOGI("Handling TTS response: %.100s...", json_data); + + /* 解析TTS响应 */ + tts_result_t result; + ai_error_t ret = parse_tts_response(json_data, &result); + if (ret != AI_OK) { + AI_LOGE("Failed to parse TTS response"); + change_tts_state(context, TTS_STATE_ERROR); + if (context->error_cb != NULL) { + context->error_cb(ret, "Failed to parse TTS response", context->user_data); + } + return ret; + } + + /* 更新状态 */ + if (result.is_final) { + if (context->config.auto_play && result.audio_data != NULL) { + change_tts_state(context, TTS_STATE_PLAYING); + // 这里应该调用音频播放接口 + // play_audio(result.audio_data, result.audio_size); + change_tts_state(context, TTS_STATE_COMPLETED); + } else { + change_tts_state(context, TTS_STATE_COMPLETED); + } + } + + /* 调用结果回调 */ + if (context->result_cb != NULL) { + context->result_cb(&result, context->user_data); + } + + context->last_activity_time = get_current_timestamp(); + + return AI_OK; +} + +ai_error_t ai_tts_service_build_request(const char *text, const char *session_id, const tts_config_t *config, + char *json_buffer, size_t buffer_size) +{ + if (text == NULL || session_id == NULL || config == NULL || json_buffer == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 构建TTS请求 */ + int ret = snprintf(json_buffer, buffer_size, + "{" + "\"type\":\"synthesize\"," + "\"session_id\":\"%s\"," + "\"text\":\"%s\"," + "\"config\":{" + "\"voice\":\"%s\"," + "\"volume\":%d," + "\"speed\":%d," + "\"pitch\":%d," + "\"auto_play\":%s" + "}" + "}", + session_id, + text, + ai_tts_service_get_voice_name(config->voice_type), + config->volume, + config->speed, + config->pitch, + config->auto_play ? "true" : "false" + ); + + if (ret < 0 || ret >= (int)buffer_size) { + AI_LOGE("JSON buffer too small for TTS request"); + return AI_ERROR_BUFFER_OVERFLOW; + } + + return AI_OK; +} + +ai_error_t ai_tts_service_build_stop_message(const char *session_id, char *json_buffer, size_t buffer_size) +{ + if (session_id == NULL || json_buffer == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + int ret = snprintf(json_buffer, buffer_size, + "{\"type\":\"stop\",\"session_id\":\"%s\"}", session_id); + + if (ret < 0 || ret >= (int)buffer_size) { + AI_LOGE("JSON buffer too small for TTS stop message"); + return AI_ERROR_BUFFER_OVERFLOW; + } + + return AI_OK; +} + +/* ================================ 内部函数实现 ================================ */ + +static uint32_t get_current_timestamp(void) +{ +#ifndef __TEST_MODE__ + return (uint32_t)(osKernelGetTickCount() * 1000 / osKernelGetTickFreq()); +#else + return (uint32_t)time(NULL); +#endif +} + +static ai_error_t change_tts_state(tts_service_context_t *context, tts_state_t new_state) +{ + if (context == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + tts_state_t old_state = context->state; + if (old_state != new_state) { + context->state = new_state; + + AI_LOGI("TTS state changed: %s -> %s", + g_tts_state_names[old_state], + g_tts_state_names[new_state]); + + /* 调用状态回调 */ + if (context->state_cb != NULL) { + context->state_cb(old_state, new_state, context->user_data); + } + } + + return AI_OK; +} + +static ai_error_t parse_tts_response(const char *json_data, tts_result_t *result) +{ + if (json_data == NULL || result == NULL) { + return AI_ERROR_INVALID_PARAM; + } + + /* 简化的JSON解析实现 */ + memset(result, 0, sizeof(tts_result_t)); + + /* 在实际实现中,这里应该使用完整的JSON解析库 */ + /* 这里只是一个简化的示例 */ + + /* 查找文本字段 */ + const char *text_start = strstr(json_data, "\"text\":\""); + if (text_start != NULL) { + text_start += 8; // 跳过 "text":" + const char *text_end = strchr(text_start, '"'); + if (text_end != NULL) { + size_t text_len = text_end - text_start; + if (text_len < sizeof(result->text)) { + strncpy(result->text, text_start, text_len); + result->text[text_len] = '\0'; + } + } + } + + /* 查找会话ID字段 */ + const char *session_id_start = strstr(json_data, "\"session_id\":\""); + if (session_id_start != NULL) { + session_id_start += 14; // 跳过 "session_id":" + const char *session_id_end = strchr(session_id_start, '"'); + if (session_id_end != NULL) { + size_t session_id_len = session_id_end - session_id_start; + if (session_id_len < sizeof(result->session_id)) { + strncpy(result->session_id, session_id_start, session_id_len); + result->session_id[session_id_len] = '\0'; + } + } + } + + /* 查找音频数据大小 */ + const char *audio_size_start = strstr(json_data, "\"audio_size\":"); + if (audio_size_start != NULL) { + result->audio_size = atoi(audio_size_start + 13); + } + + /* 查找采样率 */ + const char *sample_rate_start = strstr(json_data, "\"sample_rate\":"); + if (sample_rate_start != NULL) { + result->sample_rate = atoi(sample_rate_start + 14); + } else { + result->sample_rate = 16000; // 默认采样率 + } + + /* 查找声道数 */ + const char *channels_start = strstr(json_data, "\"channels\":"); + if (channels_start != NULL) { + result->channels = atoi(channels_start + 11); + } else { + result->channels = 1; // 默认单声道 + } + + /* 查找位深度 */ + const char *bits_start = strstr(json_data, "\"bits_per_sample\":"); + if (bits_start != NULL) { + result->bits_per_sample = atoi(bits_start + 18); + } else { + result->bits_per_sample = 16; // 默认16位 + } + + /* 查找音频时长 */ + const char *duration_start = strstr(json_data, "\"duration_ms\":"); + if (duration_start != NULL) { + result->duration_ms = atoi(duration_start + 14); + } + + /* 查找是否为最终结果 */ + result->is_final = (strstr(json_data, "\"is_final\":true") != NULL) || + (strstr(json_data, "\"status\":\"completed\"") != NULL); + + /* 注意:这里没有实际解析音频数据,在实际实现中需要处理Base64编码的音频数据 */ + result->audio_data = NULL; + + AI_LOGI("Parsed TTS result: text='%s', size=%u, rate=%u, final=%s", + result->text, result->audio_size, result->sample_rate, + result->is_final ? "true" : "false"); + + return AI_OK; +} \ No newline at end of file -- 2.17.1