--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "netstack/http/include/httpclient.h"
+#include "chat_https_servrt.h"
+
+/* @brief http request buffer */
+#define REQ_BUF_SIZE 2048
+static char req_buf[REQ_BUF_SIZE];
+
+/* @brief http response buffer */
+#define RSP_BUF_SIZE 2048
+static char rsp_buf[RSP_BUF_SIZE] = {0};
+
+
+// { 1
+// "userId": "user123",
+// "characterId": "char456",
+// "message": "你好,请介绍⼀下你⾃⼰"
+// }
+
+
+// {
+// "errorCode": null,
+// "message": null,
+// "data": {
+// "message": "你好!我是你的AI助⼿,很⾼兴为你服务。我可以帮助你解答问题、提供建议或者
+// 陪你聊天。请问有什么我可以帮助你的吗?"
+// }
+// }
+
+/**
+ * @brief 解析HTTP响应JSON数据,提取data.message字段
+ * @param json_str JSON字符串
+ * @param out_message 输出消息缓冲区
+ * @param max_len 缓冲区最大长度
+ * @return 0成功,-1失败
+ */
+int parse_http_response_message(const char *json_str, char *out_message, size_t max_len)
+{
+ if (!json_str || !out_message || max_len == 0) {
+ return -1;
+ }
+
+ // 初始化输出缓冲区
+ memset(out_message, 0, max_len);
+
+ // 查找data.message字段
+ const char *data_start = strstr(json_str, "\"data\"");
+ if (data_start) {
+ const char *data_message_start = strstr(data_start, "\"message\"");
+ if (data_message_start) {
+ data_message_start = strchr(data_message_start, ':');
+ if (data_message_start) {
+ data_message_start++; // 跳过冒号
+ while (*data_message_start == ' ' || *data_message_start == '\t') {
+ data_message_start++; // 跳过空格
+ }
+ // 查找引号
+ const char *quote_start = strchr(data_message_start, '"');
+ if (quote_start) {
+ quote_start++; // 跳过开始引号
+ const char *quote_end = strchr(quote_start, '"');
+ if (quote_end) {
+ size_t len = quote_end - quote_start;
+ if (len < max_len) {
+ strncpy(out_message, quote_start, len);
+ out_message[len] = '\0';
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+int http_posttest(const char *message, char *out_message, size_t max_len)
+{
+ HttpClient client = {0};
+ HttpClientData client_data = {0};
+ char *req_url = "https://ambybox-api.test.leiniao.com/ambybox-device-api/v1/textChat/chat?deviceId=860132060562402&deviceToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJXWVNaIiwiZGV2aWNlTW9kZWwiOiJBQjEwMSIsImRldmljZVZlcnNpb24iOiJWQjY1MF8yMDI1MDkxOV8x\NDI4MDMiLCJkZXZpY2VJZCI6Ijg2MDEzMjA2MDU2MjQwMiIsImV4cCI6MTc2MDg1OTE5OX0.B6zIfQyE9iGLlknIIDomQ3jnWxdNtcF5LHVrKS9WQFg";
+ int ret = -1;
+ //
+ // 构建JSON数据,使用第13行开始的格式
+ char json_data[512];
+ snprintf(json_data, sizeof(json_data),
+ "{"
+ "\"userId\": \"test_user_001\","
+ "\"characterId\": \"char_001\","
+ "\"message\": \"%s\""
+ "}",
+ message ? message : "你好,请介绍一下你自己");
+
+ client_data.postBuf = json_data;
+ size_t length = strlen(client_data.postBuf);
+ client_data.postBufLen = length;
+
+ memset(req_buf, 0, sizeof(req_buf));
+ client_data.headerBuf = req_buf;
+ client_data.headerBufLen = sizeof(req_buf);
+
+ memset(rsp_buf, 0, sizeof(rsp_buf));
+ client_data.responseBuf = rsp_buf;
+ client_data.responseBufLen= sizeof(rsp_buf);
+
+ printf("\n http request: %s \r\n", req_url);
+ printf("JSON data: %s \r\n", json_data);
+
+
+ char *header_buf = (char *)malloc(128);
+ if (!header_buf)
+ return ret;
+ int hdr = snprintf(header_buf,128,
+ "deviceId: %s \r\n"
+ "Content-Type: application/json\r\n","860132060562402");
+ if (hdr <= 0)
+ {
+ free(header_buf);
+ return ret;
+ }
+ HttpClientSetCustomHeader(&client, header_buf);
+
+
+ ret = HttpClientPostRequest(&client, req_url, &client_data);
+ if (ret >= 0 && client.responseCode == 200) {
+ printf("http test success!\r\n");
+
+ // 解析响应数据中的message字段
+ if (out_message && max_len > 0) {
+ if (parse_http_response_message(client_data.responseBuf, out_message, max_len) == 0) {
+ printf("Response message: %s\n", out_message);
+ } else {
+ printf("Failed to parse response message\n");
+ memset(out_message, 0, max_len);
+ }
+ }
+
+ ret = 0;
+ } else {
+ printf("responsecode = %d \n", client.responseCode);
+ printf("http test failed! ret= 0x%x \r\n", ret);
+
+ // 如果请求失败,清空输出缓冲区
+ if (out_message && max_len > 0) {
+ memset(out_message, 0, max_len);
+ }
+ }
+ return ret;
+}
\ No newline at end of file
extern int32_t VoiceCallVolteSample(int32_t argc, const char **argv);
static bool uapi_send_single_tts_text(WebSocketClient *tts_client, const char *text);
+static bool tts_cache_ensure_capacity(int required_size);
/* TTS 配置和常量 */
#define AI_MAX_RETRY_COUNT 3
static bool tts_has_stop_cached = false; // 是否缓存了stop命令
// static bool tts_is_ready = false; // TTS是否准备就绪
+/* TTS 缓存互斥锁 */
+static osMutexId_t tts_cache_mutex = NULL;
+
+/**
+ * @brief 带互斥锁保护的缓存追加操作
+ * @param buf 要追加的文本
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_append_with_mutex(const char *buf)
+{
+ if (tts_cache_mutex != NULL) {
+ if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+ int buf_len = strlen(buf);
+ int required_size = tts_cached_length + buf_len + 1; // 预留结束符空间
+
+ // 确保有足够的空间
+ if (!tts_cache_ensure_capacity(required_size)) {
+ printf("TTS cache allocation failed\n");
+ osMutexRelease(tts_cache_mutex);
+ return false;
+ }
+
+ // 追加文本到缓存字符串
+ strcat(tts_cached_text, buf);
+ tts_cached_length += buf_len;
+ printf("TTS text appended to cache (length: %d/%d): %s\n", tts_cached_length, tts_cached_capacity, buf);
+
+ osMutexRelease(tts_cache_mutex);
+ return true;
+ } else {
+ printf("Failed to acquire TTS cache mutex for append\n");
+ return false;
+ }
+ } else {
+ // 如果互斥锁未初始化,直接操作(向后兼容)
+ int buf_len = strlen(buf);
+ int required_size = tts_cached_length + buf_len + 1; // 预留结束符空间
+
+ // 确保有足够的空间
+ if (!tts_cache_ensure_capacity(required_size)) {
+ printf("TTS cache allocation failed\n");
+ return false;
+ }
+
+ // 追加文本到缓存字符串
+ strcat(tts_cached_text, buf);
+ tts_cached_length += buf_len;
+ printf("TTS text appended to cache (length: %d/%d): %s\n", tts_cached_length, tts_cached_capacity, buf);
+ return true;
+ }
+}
+
+/**
+ * @brief 带互斥锁保护的缓存清空操作
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_clear_with_mutex(void)
+{
+ if (tts_cache_mutex != NULL) {
+ if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+ if (tts_cached_text != NULL) {
+ memset(tts_cached_text, 0, tts_cached_capacity);
+ }
+ tts_cached_length = 0;
+ tts_has_stop_cached = false; // 同时清空stop缓存标志
+ osMutexRelease(tts_cache_mutex);
+ printf("TTS cache cleared with mutex protection\n");
+ return true;
+ } else {
+ printf("Failed to acquire TTS cache mutex for clear\n");
+ return false;
+ }
+ } else {
+ // 如果互斥锁未初始化,直接清空(向后兼容)
+ if (tts_cached_text != NULL) {
+ memset(tts_cached_text, 0, tts_cached_capacity);
+ }
+ tts_cached_length = 0;
+ tts_has_stop_cached = false; // 同时清空stop缓存标志
+ printf("TTS cache cleared without mutex (mutex not available)\n");
+ return true;
+ }
+}
+
+/**
+ * @brief 带互斥锁保护的获取缓存长度操作
+ * @return 缓存长度
+ */
+static int tts_cache_get_length_with_mutex(void)
+{
+ int length = 0;
+
+ if (tts_cache_mutex != NULL) {
+ if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+ length = tts_cached_length;
+ osMutexRelease(tts_cache_mutex);
+ } else {
+ printf("Failed to acquire TTS cache mutex for count\n");
+ length = 0;
+ }
+ } else {
+ // 如果互斥锁未初始化,直接返回(向后兼容)
+ length = tts_cached_length;
+ }
+
+ return length;
+}
+
+/**
+ * @brief 带互斥锁保护的检查缓存是否有内容
+ * @return true 有内容,false 无内容
+ */
+static bool tts_cache_has_content_with_mutex(void)
+{
+ bool has_content = false;
+
+ if (tts_cache_mutex != NULL) {
+ if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+ has_content = (tts_cached_length > 0);
+ osMutexRelease(tts_cache_mutex);
+ } else {
+ printf("Failed to acquire TTS cache mutex for check\n");
+ has_content = false;
+ }
+ } else {
+ // 如果互斥锁未初始化,直接检查(向后兼容)
+ has_content = (tts_cached_length > 0);
+ }
+
+ return has_content;
+}
+
+/**
+ * @brief 带互斥锁保护的发送缓存文本操作
+ * @param tts_client TTS WebSocket客户端
+ * @return true 成功,false 失败
+ */
+static bool tts_cache_send_with_mutex(WebSocketClient *tts_client)
+{
+ if (tts_cache_mutex != NULL) {
+ if (osMutexAcquire(tts_cache_mutex, osWaitForever) == osOK) {
+ bool result = false;
+
+ if (tts_cached_length > 0) {
+ printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+ result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+ if (!result) {
+ printf("Failed to send cached text: %s\n", tts_cached_text);
+ } else {
+ printf("Successfully sent cached text: %s\n", tts_cached_text);
+ }
+
+ // 发送完成后清空缓存
+ if (tts_cached_text != NULL) {
+ memset(tts_cached_text, 0, tts_cached_capacity);
+ }
+ tts_cached_length = 0;
+ tts_has_stop_cached = false; // 同时清空stop缓存标志
+ printf("TTS cache cleared after sending\n");
+ }
+
+ osMutexRelease(tts_cache_mutex);
+ return result;
+ } else {
+ printf("Failed to acquire TTS cache mutex for send\n");
+ return false;
+ }
+ } else {
+ // 如果互斥锁未初始化,直接操作(向后兼容)
+ bool result = false;
+
+ if (tts_cached_length > 0) {
+ printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
+ result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+ if (!result) {
+ printf("Failed to send cached text: %s\n", tts_cached_text);
+ } else {
+ printf("Successfully sent cached text: %s\n", tts_cached_text);
+ }
+
+ // 发送完成后清空缓存
+ if (tts_cached_text != NULL) {
+ memset(tts_cached_text, 0, tts_cached_capacity);
+ }
+ tts_cached_length = 0;
+ tts_has_stop_cached = false; // 同时清空stop缓存标志
+ printf("TTS cache cleared after sending\n");
+ }
+
+ return result;
+ }
+}
+
/**
* @brief 初始化TTS缓存内存
* @return true 成功,false 失败
memset(tts_cached_text, 0, TTS_MAX_CACHED_LENGTH);
printf("TTS cache initialized with %d bytes\n", TTS_MAX_CACHED_LENGTH);
}
+
+ // 创建互斥锁
+ if (tts_cache_mutex == NULL) {
+ tts_cache_mutex = osMutexNew(NULL);
+ if (tts_cache_mutex == NULL) {
+ printf("Failed to create TTS cache mutex\n");
+ return false;
+ }
+ printf("TTS cache mutex created\n");
+ }
+
return true;
}
tts_cached_length = 0;
printf("TTS cache deinitialized\n");
}
+
+ // 删除互斥锁
+ if (tts_cache_mutex != NULL) {
+ osMutexDelete(tts_cache_mutex);
+ tts_cache_mutex = NULL;
+ printf("TTS cache mutex deleted\n");
+ }
}
/**
// 如果ready为false,将文本追加到缓存字符串
if (!ready) {
if (buf && strlen(buf) > 0) {
- int buf_len = strlen(buf);
- int required_size = tts_cached_length + buf_len + 1; // 预留结束符空间
-
- // 确保有足够的空间
- if (!tts_cache_ensure_capacity(required_size)) {
- printf("TTS cache allocation failed\n");
- return false;
- }
-
- // 追加文本到缓存字符串
- strcat(tts_cached_text, buf);
- tts_cached_length += buf_len;
- printf("TTS text appended to cache (length: %d/%d): %s\n", tts_cached_length, tts_cached_capacity, buf);
+ return tts_cache_append_with_mutex(buf);
}
return true;
}
// 如果ready为true,先发送缓存的文本,然后发送本次携带的内容
- if (tts_cached_length > 0) {
- printf("TTS ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
- bool result = uapi_send_single_tts_text(tts_client, tts_cached_text);
+ if (tts_cache_has_content_with_mutex()) {
+ bool result = tts_cache_send_with_mutex(tts_client);
if (!result) {
- printf("Failed to send cached text: %s\n", tts_cached_text);
return false;
- } else {
- printf("Successfully sent cached text: %s\n", tts_cached_text);
- }
-
- // 清空缓存
- if (tts_cached_text != NULL) {
- memset(tts_cached_text, 0, tts_cached_capacity);
}
- tts_cached_length = 0;
}
// 检查是否有缓存的stop命令需要发送
*/
int uapi_get_cached_text_count(void)
{
- return tts_cached_length;
+ return tts_cache_get_length_with_mutex();
}
/**
*/
void uapi_clear_tts_cache(void)
{
- if (tts_cached_text != NULL) {
- memset(tts_cached_text, 0, tts_cached_capacity);
- }
- tts_cached_length = 0;
- tts_has_stop_cached = false; // 同时清空stop缓存标志
- printf("TTS cache cleared\n");
+ tts_cache_clear_with_mutex();
}
/**
if (msg_str != NULL && strcmp("success", msg_str) == 0) {
event_type = TTS_EVENT_STARTED_SYNTHESIS;
tts_is_ready = TTS_READY_SUCCESS_READY;
-
- // TTS准备就绪,发送缓存的文本(如果有的话)
- if (tts_cached_length > 0) {
- printf("TTS is ready, sending cached text (length: %d): %s\n", tts_cached_length, tts_cached_text);
- if (tts_client != NULL) {
- bool result = uapi_send_single_tts_text(tts_client, tts_cached_text);
- if (result) {
- printf("Successfully sent cached text: %s\n", tts_cached_text);
- // 清空缓存
- memset(tts_cached_text, 0, tts_cached_capacity);
- tts_cached_length = 0;
- } else {
- printf("Failed to send cached text: %s\n", tts_cached_text);
- }
- }
- }
} else {
event_type = TTS_EVENT_SYNTHESIS_ERROR;
}
}
}
+
+
+ // "{ \"header\": { \
+ // \"event\": \"LongTextStream\", \
+ // \"trace_id\": \"3fa6b9e6a30b407ea38ad7ae69e6c291\"\
+ // },\
+ // \"payload\": {\
+ // \"voice\":\"xiaoyun\",\
+ // \"format\":\"mp3\",\
+ // \"sample_rate\":16000,\
+ // \"volume\":80,\
+ // \"speech_rate\":0,\
+ // \"text\":\"%s\"\
+ // } }"
+
+/**
+ * @brief 发送长文本TTS合成请求
+ * @param client WebSocket客户端
+ * @param text 要合成的文本
+ * @param voice 语音类型,默认为"xiaoyun"
+ * @param format 音频格式,默认为"mp3"
+ * @param sample_rate 采样率,默认为16000
+ * @param volume 音量,默认为80
+ * @param speech_rate 语速,默认为0
+ * @param trace_id 跟踪ID,可以为NULL
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_send_long_text_tts(WebSocketClient *client, const char *text,
+ const char *voice, const char *format,
+ int sample_rate, int volume, int speech_rate,
+ const char *trace_id)
+{
+ cJSON *json = NULL;
+ cJSON *header = NULL;
+ cJSON *payload = NULL;
+ char *jsonString = NULL;
+ bool result = false;
+
+ // 参数验证
+ if (client == NULL || text == NULL) {
+ printf("TTS client or text is NULL\n");
+ return false;
+ }
+
+ // 设置默认值
+ if (voice == NULL) voice = "xiaoyun";
+ if (format == NULL) format = "mp3";
+ if (trace_id == NULL) trace_id = "3fa6b9e6a30b407ea38ad7ae69e6c291";
+
+ // 创建根JSON对象
+ json = cJSON_CreateObject();
+ if (json == NULL) {
+ printf("Failed to create JSON object\n");
+ return false;
+ }
+
+ // 创建header对象
+ header = cJSON_CreateObject();
+ if (header == NULL) {
+ printf("Failed to create header object\n");
+ goto cleanup;
+ }
+
+ // 添加header字段
+ if (cJSON_AddStringToObject(header, "event", "LongTextStream") == NULL) {
+ printf("Failed to add event field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddStringToObject(header, "trace_id", trace_id) == NULL) {
+ printf("Failed to add trace_id field\n");
+ goto cleanup;
+ }
+
+ // 将header添加到根对象
+ if (cJSON_AddItemToObject(json, "header", header) == 0) {
+ printf("Failed to add header to root object\n");
+ goto cleanup;
+ }
+ header = NULL; // 防止重复释放
+
+ // 创建payload对象
+ payload = cJSON_CreateObject();
+ if (payload == NULL) {
+ printf("Failed to create payload object\n");
+ goto cleanup;
+ }
+
+ // 添加payload字段
+ if (cJSON_AddStringToObject(payload, "voice", voice) == NULL) {
+ printf("Failed to add voice field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddStringToObject(payload, "format", format) == NULL) {
+ printf("Failed to add format field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddNumberToObject(payload, "sample_rate", sample_rate) == NULL) {
+ printf("Failed to add sample_rate field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddNumberToObject(payload, "volume", volume) == NULL) {
+ printf("Failed to add volume field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddNumberToObject(payload, "speech_rate", speech_rate) == NULL) {
+ printf("Failed to add speech_rate field\n");
+ goto cleanup;
+ }
+
+ if (cJSON_AddStringToObject(payload, "text", text) == NULL) {
+ printf("Failed to add text field\n");
+ goto cleanup;
+ }
+
+ // 将payload添加到根对象
+ if (cJSON_AddItemToObject(json, "payload", payload) == 0) {
+ printf("Failed to add payload to root object\n");
+ goto cleanup;
+ }
+ payload = NULL; // 防止重复释放
+
+ // 生成JSON字符串
+ jsonString = cJSON_Print(json);
+ printf("uapi_send_long_text_tts: %s\r\n", jsonString);
+ if (jsonString == NULL) {
+ printf("Failed to print JSON to string\n");
+ goto cleanup;
+ }
+
+ // 发送WebSocket消息
+ if (send_websocket_message(client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+ printf("Long text TTS message sent successfully\n");
+ result = true;
+ } else {
+ printf("Long text TTS message send failed\n");
+ }
+
+cleanup:
+ // 清理资源
+ if (jsonString != NULL) {
+ free(jsonString);
+ }
+ if (header != NULL) {
+ cJSON_Delete(header);
+ }
+ if (payload != NULL) {
+ cJSON_Delete(payload);
+ }
+ if (json != NULL) {
+ cJSON_Delete(json);
+ }
+
+ return result;
+}
+
+
/*
* 使用示例:
*