STATIC VOID __on_ai_toy_audio_trigger_pin(UINT_T port, PUSH_KEY_TYPE_E type, INT_T cnt)
{
TAL_PR_DEBUG("ai toy -> audio trigger pin pressed %d", type);
/** Exit lowpower status when key press and device was in lowpower status */
__on_ai_toy_key_press_exit_lowpower();
if (LONG_KEY == type) {
TAL_PR_INFO("[%s] swimming get bind role avatar", __func__);
CHAR_T avatar_url[256] = {0};
OPERATE_RET rt = swimming_get_bind_role_avatar(avatar_url, sizeof(avatar_url));
if (OPRT_OK == rt && avatar_url[0] != '\0')
{
TAL_PR_INFO("[%s] swimming role avatar url: %s", __func__, avatar_url);
/* TODO: use avatar_url to download/display the role avatar image */
}
return;
}
}
STATIC OPERATE_RET swimming_get_bind_role_avatar(CHAR_T *url_buf, INT_T buf_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
CHAR_T post_content[] = "{}";
TUYA_CHECK_NULL_RETURN(url_buf, OPRT_INVALID_PARM);
rt = iot_httpc_common_post_simple("thing.ai.agent.role.get-bind-role", "1.0",
post_content, NULL, &result);
if (OPRT_OK != rt) {
TAL_PR_ERR("swimming_get_bind_role_avatar request failed: %d", rt);
return rt;
}
TUYA_CHECK_NULL_RETURN(result, OPRT_MID_HTTP_GET_RESP_ERROR);
ty_cJSON *role_img = ty_cJSON_GetObjectItem(result, "roleImgUrl");
if (role_img && role_img->valuestring) {
snprintf(url_buf, buf_len, "%s", role_img->valuestring);
TAL_PR_INFO("swimming_get_bind_role_avatar: %s", url_buf);
} else {
TAL_PR_WARN("swimming_get_bind_role_avatar: roleImgUrl not found");
rt = OPRT_COM_ERROR;
}
ty_cJSON_Delete(result);
return rt;
}

STATIC VOID __on_ai_toy_audio_trigger_pin(UINT_T port, PUSH_KEY_TYPE_E type, INT_T cnt)
{
TAL_PR_DEBUG("ai toy -> audio trigger pin pressed %d", type);
/** Exit lowpower status when key press and device was in lowpower status */
__on_ai_toy_key_press_exit_lowpower();
if (LONG_KEY == type) {
CHAR_T lang_code[64] = {0};
CHAR_T timbre_id[128] = {0};
CHAR_T role_id[128] = {0};
swimming_get_languages_list(lang_code, sizeof(lang_code));
swimming_get_timbre_market_all_pages(lang_code, timbre_id, sizeof(timbre_id));
swimming_get_custom_role_page(role_id, sizeof(role_id));
swimming_update_custom_role(role_id, lang_code, timbre_id);
return;
}
}
STATIC VOID swimming_get_languages_list(CHAR_T *out_lang_code, INT_T out_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
TAL_PR_NOTICE("swimming: >>> get languages list");
rt = iot_httpc_common_post_simple("thing.ai.agent.config.languages.list", "1.0", "{}", NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get languages list failed, rt=%d", rt);
return;
}
if (!ty_cJSON_IsArray(result)) {
TAL_PR_ERR("swimming: languages result is not array");
ty_cJSON_Delete(result);
return;
}
INT_T count = ty_cJSON_GetArraySize(result);
TAL_PR_NOTICE("swimming: languages count=%d", count);
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(result, i);
if (NULL == item) continue;
ty_cJSON *lang_code = ty_cJSON_GetObjectItem(item, "langCode");
ty_cJSON *lang_name = ty_cJSON_GetObjectItem(item, "langName");
ty_cJSON *has_default = ty_cJSON_GetObjectItem(item, "hasDefault");
TAL_PR_NOTICE("swimming: [%d] langCode=%s, langName=%s, hasDefault=%s",
i,
lang_code ? lang_code->valuestring : "null",
lang_name ? lang_name->valuestring : "null",
has_default ? (has_default->type == 1 ? "true" : "false") : "null");
if (lang_code && lang_code->valuestring && out_lang_code) {
if (0 == strcmp(lang_code->valuestring, "en")) {
snprintf(out_lang_code, out_len, "%s", lang_code->valuestring);
} else if (out_lang_code[0] == '\0') {
snprintf(out_lang_code, out_len, "%s", lang_code->valuestring);
}
}
}
ty_cJSON_Delete(result);
TAL_PR_NOTICE("swimming: <<< get languages list done, first langCode=%s", out_lang_code ? out_lang_code : "null");
}
STATIC VOID swimming_get_timbre_market_all_pages(CHAR_T *lang, CHAR_T *out_voice_id, INT_T out_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
INT_T page_no = 1;
INT_T page_size = 20;
INT_T total_printed = 0;
BOOL_T first_saved = FALSE;
CHAR_T post_content[256] = {0};
TAL_PR_NOTICE("swimming: >>> get timbre market all pages, lang=%s", lang ? lang : "null");
while (1) {
if (lang && lang[0] != '\0') {
snprintf(post_content, sizeof(post_content),
"{\"pageNo\":%d,\"pageSize\":%d,\"lang\":\"%s\"}",
page_no, page_size, lang);
} else {
snprintf(post_content, sizeof(post_content),
"{\"pageNo\":%d,\"pageSize\":%d}",
page_no, page_size);
}
bk_printf("swimming content = %s \r\n",post_content);
result = NULL;
rt = iot_httpc_common_post_simple("thing.ai.timbre.market.page", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get timbre market page %d failed, rt=%d", page_no, rt);
break;
}
bk_printf("11111111111111111 \r\n");
CHAR_T *result_str = ty_cJSON_PrintUnformatted(result);
if (result_str) {
TAL_PR_NOTICE("swimming: timbre market page %d raw result: %s", page_no, result_str);
ty_cJSON_FreeBuffer(result_str);
}
ty_cJSON *list = NULL;
INT_T total_page = 0;
if (ty_cJSON_IsArray(result)) {
list = result;
} else {
list = ty_cJSON_GetObjectItem(result, "list");
ty_cJSON *tp = ty_cJSON_GetObjectItem(result, "totalPage");
if (tp) total_page = tp->valueint;
}
if (NULL == list || !ty_cJSON_IsArray(list)) {
TAL_PR_ERR("swimming: timbre market page %d list is null or not array", page_no);
ty_cJSON_Delete(result);
break;
}
INT_T count = ty_cJSON_GetArraySize(list);
TAL_PR_NOTICE("swimming: timbre market page %d, count=%d, totalPage=%d", page_no, count, total_page);
if (count == 0) {
ty_cJSON_Delete(result);
break;
}
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(list, i);
if (NULL == item) continue;
ty_cJSON *voice_id = ty_cJSON_GetObjectItem(item, "voiceId");
ty_cJSON *voice_name = ty_cJSON_GetObjectItem(item, "voiceName");
ty_cJSON *speed = ty_cJSON_GetObjectItem(item, "speed");
ty_cJSON *tone = ty_cJSON_GetObjectItem(item, "tone");
ty_cJSON *demo_url = ty_cJSON_GetObjectItem(item, "demoUrl");
ty_cJSON *desc_tags = ty_cJSON_GetObjectItem(item, "descTags");
ty_cJSON *support_langs = ty_cJSON_GetObjectItem(item, "supportLangs");
TAL_PR_NOTICE("swimming: timbre[%d] voiceId=%s, voiceName=%s",
total_printed,
voice_id ? voice_id->valuestring : "null",
voice_name ? voice_name->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] speed=%s, tone=%s",
total_printed,
speed ? speed->valuestring : "null",
tone ? tone->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] demoUrl=%s",
total_printed,
demo_url ? demo_url->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] descTags count=%d, supportLangs count=%d",
total_printed,
desc_tags && ty_cJSON_IsArray(desc_tags) ? ty_cJSON_GetArraySize(desc_tags) : 0,
support_langs && ty_cJSON_IsArray(support_langs) ? ty_cJSON_GetArraySize(support_langs) : 0);
if (!first_saved && voice_id && voice_id->valuestring && out_voice_id) {
snprintf(out_voice_id, out_len, "%s", voice_id->valuestring);
first_saved = TRUE;
}
total_printed++;
}
ty_cJSON_Delete(result);
if (total_page > 0 && page_no >= total_page) break;
if (count < page_size) break;
page_no++;
}
TAL_PR_NOTICE("swimming: <<< get timbre market done, total=%d, first voiceId=%s",
total_printed, out_voice_id ? out_voice_id : "null");
}
STATIC VOID swimming_get_custom_role_page(CHAR_T *out_role_id, INT_T out_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
INT_T page_no = 1;
INT_T page_size = 20;
BOOL_T first_saved = FALSE;
CHAR_T post_content[128] = {0};
TAL_PR_NOTICE("swimming: >>> get custom role page");
while (1) {
snprintf(post_content, sizeof(post_content), "{\"pageNo\":%d,\"pageSize\":%d}", page_no, page_size);
result = NULL;
rt = iot_httpc_common_post_simple("thing.ai.agent.role.custom-role.page", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get custom role page %d failed, rt=%d", page_no, rt);
break;
}
ty_cJSON *list = NULL;
INT_T total_page = 0;
if (ty_cJSON_IsArray(result)) {
list = result;
} else {
list = ty_cJSON_GetObjectItem(result, "list");
ty_cJSON *tp = ty_cJSON_GetObjectItem(result, "totalPage");
if (tp) total_page = tp->valueint;
}
if (NULL == list || !ty_cJSON_IsArray(list)) {
TAL_PR_ERR("swimming: custom role page %d list is null or not array", page_no);
ty_cJSON_Delete(result);
break;
}
INT_T count = ty_cJSON_GetArraySize(list);
TAL_PR_NOTICE("swimming: custom role page %d, count=%d, totalPage=%d", page_no, count, total_page);
if (count == 0) {
ty_cJSON_Delete(result);
break;
}
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(list, i);
if (NULL == item) continue;
ty_cJSON *role_id = ty_cJSON_GetObjectItem(item, "roleId");
ty_cJSON *role_name = ty_cJSON_GetObjectItem(item, "roleName");
ty_cJSON *use_timbre_id = ty_cJSON_GetObjectItem(item, "useTimbreId");
ty_cJSON *use_timbre_name = ty_cJSON_GetObjectItem(item, "useTimbreName");
ty_cJSON *use_lang_code = ty_cJSON_GetObjectItem(item, "useLangCode");
ty_cJSON *use_lang_name = ty_cJSON_GetObjectItem(item, "useLangName");
ty_cJSON *use_llm_name = ty_cJSON_GetObjectItem(item, "useLlmName");
ty_cJSON *template_id = ty_cJSON_GetObjectItem(item, "templateId");
TAL_PR_NOTICE("swimming: role[%d] roleId=%s, roleName=%s",
i,
role_id ? role_id->valuestring : "null",
role_name ? role_name->valuestring : "null");
TAL_PR_NOTICE("swimming: role[%d] useTimbreId=%s, useTimbreName=%s",
i,
use_timbre_id ? use_timbre_id->valuestring : "null",
use_timbre_name ? use_timbre_name->valuestring : "null");
TAL_PR_NOTICE("swimming: role[%d] useLangCode=%s, useLangName=%s",
i,
use_lang_code ? use_lang_code->valuestring : "null",
use_lang_name ? use_lang_name->valuestring : "null");
TAL_PR_NOTICE("swimming: role[%d] useLlmName=%s, templateId=%s",
i,
use_llm_name ? use_llm_name->valuestring : "null",
template_id ? template_id->valuestring : "null");
if (!first_saved && role_id && role_id->valuestring && out_role_id) {
snprintf(out_role_id, out_len, "%s", role_id->valuestring);
first_saved = TRUE;
}
}
ty_cJSON_Delete(result);
if (total_page > 0 && page_no >= total_page) break;
if (count < page_size) break;
page_no++;
}
TAL_PR_NOTICE("swimming: <<< get custom role done, first roleId=%s", out_role_id ? out_role_id : "null");
}
STATIC VOID swimming_update_custom_role(CHAR_T *role_id, CHAR_T *lang_code, CHAR_T *timbre_id)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
CHAR_T post_content[512] = {0};
if (NULL == role_id || role_id[0] == '\0') {
TAL_PR_ERR("swimming: update custom role failed, roleId is empty");
return;
}
TAL_PR_NOTICE("swimming: >>> update custom role, roleId=%s, langCode=%s, timbreId=%s",
role_id, lang_code ? lang_code : "null", timbre_id ? timbre_id : "null");
snprintf(post_content, sizeof(post_content),
"{\"roleId\":\"%s\",\"useLangCode\":\"%s\",\"useTimbreId\":\"%s\"}",
role_id,
lang_code ? lang_code : "",
timbre_id ? timbre_id : "");
rt = iot_httpc_common_post_simple("thing.ai.agent.role.custom-role.update", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt) {
TAL_PR_ERR("swimming: update custom role failed, rt=%d", rt);
if (result) ty_cJSON_Delete(result);
return;
}
TAL_PR_NOTICE("swimming: <<< update custom role success");
if (result) ty_cJSON_Delete(result);
}
设备侧交互流程比如:
1、进入角色列表:设备侧一次性查询模板角色列表(thing.ai.agent.role.role-template.list),查询所有的自定义角色列表(thing.ai.agent.role.custom-role.page)
2、如果某个模板角色存在已经创建好的自定义角色则隐藏;否则显示。对应屏幕上会有些许自定义角色和些许模板角色
3、点击角色修改语言逻辑:
切语种的话还要注意如果音色不支持切的语种还要切音色
STATIC VOID __on_ai_toy_audio_trigger_pin(UINT_T port, PUSH_KEY_TYPE_E type, INT_T cnt)
{
TAL_PR_DEBUG("ai toy -> audio trigger pin pressed %d", type);
/** Exit lowpower status when key press and device was in lowpower status */
__on_ai_toy_key_press_exit_lowpower();
if (LONG_KEY == type)
{
tal_workq_schedule(WORKQ_SYSTEM, swimming_role_config_task, NULL);
return;
}
if (SEQ_KEY == type) {
TAL_PR_DEBUG("[%s] trigger mode:%d, device mode:%d", __func__, s_ai_toy->cfg.trigger_mode, s_ai_toy->cfg.device_mode);
if (s_ai_toy->cfg.device_mode != AI_DEVICE_MODE_CHAT) {
TAL_PR_INFO("[%s] current device mode %d ====> %d", __func__, s_ai_toy->cfg.device_mode, AI_DEVICE_MODE_CHAT);
wukong_audio_player_stop(AI_PLAYER_ALL);
wukong_ai_agent_chat_break(NULL);
wukong_ai_device_mode_switch(AI_DEVICE_MODE_CHAT);
return;
}
/* Double press: stop all playback, send chat break, cycle trigger mode, play mode alert.
* sub_mode_cycle -> tuya_ai_toy_trigger_mode_set persists the new sub-mode. */
wukong_audio_player_stop(AI_PLAYER_ALL);
wukong_ai_agent_chat_break(NULL);
wukong_ai_chat_sub_mode_cycle();
wukong_audio_player_alert(AI_TOY_ALERT_TYPE_LONG_KEY_TALK + s_ai_toy->cfg.trigger_mode, TRUE);
return;
}
/* Single/long press: pass to wukong key handler (e.g. hold to talk). */
wukong_ai_mode_dispatch(AI_MODE_OP_KEY, &type, 0);
}
STATIC VOID swimming_get_languages_list(CHAR_T *out_lang_code, INT_T out_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
TAL_PR_NOTICE("swimming: >>> get languages list");
rt = iot_httpc_common_post_simple("thing.ai.agent.config.languages.list", "1.0", "{}", NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get languages list failed, rt=%d", rt);
return;
}
if (!ty_cJSON_IsArray(result)) {
TAL_PR_ERR("swimming: languages result is not array");
ty_cJSON_Delete(result);
return;
}
INT_T count = ty_cJSON_GetArraySize(result);
TAL_PR_NOTICE("swimming: languages count=%d", count);
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(result, i);
if (NULL == item) continue;
ty_cJSON *lang_code = ty_cJSON_GetObjectItem(item, "langCode");
ty_cJSON *lang_name = ty_cJSON_GetObjectItem(item, "langName");
ty_cJSON *has_default = ty_cJSON_GetObjectItem(item, "hasDefault");
TAL_PR_NOTICE("swimming: [%d] langCode=%s, langName=%s, hasDefault=%s",
i,
lang_code ? lang_code->valuestring : "null",
lang_name ? lang_name->valuestring : "null",
has_default ? (has_default->type == 1 ? "true" : "false") : "null");
if (lang_code && lang_code->valuestring && out_lang_code) {
if (0 == strcmp(lang_code->valuestring, "en")) {
snprintf(out_lang_code, out_len, "%s", lang_code->valuestring);
} else if (out_lang_code[0] == '\0') {
snprintf(out_lang_code, out_len, "%s", lang_code->valuestring);
}
}
}
ty_cJSON_Delete(result);
TAL_PR_NOTICE("swimming: <<< get languages list done, first langCode=%s", out_lang_code ? out_lang_code : "null");
}
STATIC ty_cJSON *swimming_get_role_template_list(VOID)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
CHAR_T post_content[128] = {0};
TAL_PR_NOTICE("swimming: >>> get role template list");
snprintf(post_content, sizeof(post_content), "{}");
rt = iot_httpc_common_post_simple("thing.ai.agent.role.role-template.list", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get role template list failed, rt=%d", rt);
if (result) ty_cJSON_Delete(result);
return NULL;
}
if (!ty_cJSON_IsArray(result)) {
CHAR_T *result_str = ty_cJSON_PrintUnformatted(result);
if (result_str) {
TAL_PR_NOTICE("swimming: role template list raw: %s", result_str);
ty_cJSON_FreeBuffer(result_str);
}
ty_cJSON_Delete(result);
return NULL;
}
INT_T count = ty_cJSON_GetArraySize(result);
TAL_PR_NOTICE("swimming: role template list count=%d", count);
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(result, i);
if (NULL == item) continue;
ty_cJSON *template_id = ty_cJSON_GetObjectItem(item, "templateId");
ty_cJSON *role_id = ty_cJSON_GetObjectItem(item, "roleId");
ty_cJSON *role_name = ty_cJSON_GetObjectItem(item, "roleName");
ty_cJSON *use_lang_code = ty_cJSON_GetObjectItem(item, "useLangCode");
ty_cJSON *use_timbre_id = ty_cJSON_GetObjectItem(item, "useTimbreId");
ty_cJSON *default_flag = ty_cJSON_GetObjectItem(item, "defaultFlag");
TAL_PR_NOTICE("swimming: template[%d] roleId=%s, roleName=%s, useLangCode=%s, useTimbreId=%s, defaultFlag=%d",
i,
role_id ? role_id->valuestring : "null",
role_name ? role_name->valuestring : "null",
use_lang_code ? use_lang_code->valuestring : "null",
use_timbre_id ? use_timbre_id->valuestring : "null",
default_flag ? default_flag->valueint : 0);
}
TAL_PR_NOTICE("swimming: <<< get role template list done, count=%d", count);
return result;
}
STATIC VOID swimming_get_timbre_market_all_pages(CHAR_T *lang, CHAR_T *out_voice_id, INT_T out_len)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
INT_T page_no = 1;
INT_T page_size = 20;
INT_T total_printed = 0;
BOOL_T first_saved = FALSE;
CHAR_T post_content[256] = {0};
TAL_PR_NOTICE("swimming: >>> get timbre market all pages, lang=%s", lang ? lang : "null");
while (1) {
if (lang && lang[0] != '\0') {
snprintf(post_content, sizeof(post_content),
"{\"pageNo\":%d,\"pageSize\":%d,\"lang\":\"%s\"}",
page_no, page_size, lang);
} else {
snprintf(post_content, sizeof(post_content),
"{\"pageNo\":%d,\"pageSize\":%d}",
page_no, page_size);
}
bk_printf("swimming content = %s \r\n",post_content);
result = NULL;
rt = iot_httpc_common_post_simple("thing.ai.timbre.market.page", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get timbre market page %d failed, rt=%d", page_no, rt);
break;
}
bk_printf("11111111111111111 \r\n");
CHAR_T *result_str = ty_cJSON_PrintUnformatted(result);
if (result_str) {
TAL_PR_NOTICE("swimming: timbre market page %d raw result: %s", page_no, result_str);
ty_cJSON_FreeBuffer(result_str);
}
ty_cJSON *list = NULL;
INT_T total_page = 0;
if (ty_cJSON_IsArray(result)) {
list = result;
} else {
list = ty_cJSON_GetObjectItem(result, "list");
ty_cJSON *tp = ty_cJSON_GetObjectItem(result, "totalPage");
if (tp) total_page = tp->valueint;
}
if (NULL == list || !ty_cJSON_IsArray(list)) {
TAL_PR_ERR("swimming: timbre market page %d list is null or not array", page_no);
ty_cJSON_Delete(result);
break;
}
INT_T count = ty_cJSON_GetArraySize(list);
TAL_PR_NOTICE("swimming: timbre market page %d, count=%d, totalPage=%d", page_no, count, total_page);
if (count == 0) {
ty_cJSON_Delete(result);
break;
}
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(list, i);
if (NULL == item) continue;
ty_cJSON *voice_id = ty_cJSON_GetObjectItem(item, "voiceId");
ty_cJSON *voice_name = ty_cJSON_GetObjectItem(item, "voiceName");
ty_cJSON *speed = ty_cJSON_GetObjectItem(item, "speed");
ty_cJSON *tone = ty_cJSON_GetObjectItem(item, "tone");
ty_cJSON *demo_url = ty_cJSON_GetObjectItem(item, "demoUrl");
ty_cJSON *desc_tags = ty_cJSON_GetObjectItem(item, "descTags");
ty_cJSON *support_langs = ty_cJSON_GetObjectItem(item, "supportLangs");
TAL_PR_NOTICE("swimming: timbre[%d] voiceId=%s, voiceName=%s",
total_printed,
voice_id ? voice_id->valuestring : "null",
voice_name ? voice_name->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] speed=%s, tone=%s",
total_printed,
speed ? speed->valuestring : "null",
tone ? tone->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] demoUrl=%s",
total_printed,
demo_url ? demo_url->valuestring : "null");
TAL_PR_NOTICE("swimming: timbre[%d] descTags count=%d, supportLangs count=%d",
total_printed,
desc_tags && ty_cJSON_IsArray(desc_tags) ? ty_cJSON_GetArraySize(desc_tags) : 0,
support_langs && ty_cJSON_IsArray(support_langs) ? ty_cJSON_GetArraySize(support_langs) : 0);
if (!first_saved && voice_id && voice_id->valuestring && out_voice_id) {
snprintf(out_voice_id, out_len, "%s", voice_id->valuestring);
first_saved = TRUE;
}
total_printed++;
}
ty_cJSON_Delete(result);
if (total_page > 0 && page_no >= total_page) break;
if (count < page_size) break;
page_no++;
}
TAL_PR_NOTICE("swimming: <<< get timbre market done, total=%d, first voiceId=%s",
total_printed, out_voice_id ? out_voice_id : "null");
}
STATIC ty_cJSON *swimming_get_custom_role_page(VOID)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
INT_T page_no = 1;
INT_T page_size = 20;
CHAR_T post_content[128] = {0};
ty_cJSON *all_roles = ty_cJSON_CreateArray();
if (NULL == all_roles) {
TAL_PR_ERR("swimming: create custom role array failed");
return NULL;
}
TAL_PR_NOTICE("swimming: >>> get custom role page");
while (1) {
snprintf(post_content, sizeof(post_content), "{\"pageNo\":%d,\"pageSize\":%d}", page_no, page_size);
result = NULL;
rt = iot_httpc_common_post_simple("thing.ai.agent.role.custom-role.page", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt || NULL == result) {
TAL_PR_ERR("swimming: get custom role page %d failed, rt=%d", page_no, rt);
break;
}
ty_cJSON *list = NULL;
INT_T total_page = 0;
if (ty_cJSON_IsArray(result)) {
list = result;
} else {
list = ty_cJSON_GetObjectItem(result, "list");
ty_cJSON *tp = ty_cJSON_GetObjectItem(result, "totalPage");
if (tp) total_page = tp->valueint;
}
if (NULL == list || !ty_cJSON_IsArray(list)) {
TAL_PR_ERR("swimming: custom role page %d list is null or not array", page_no);
ty_cJSON_Delete(result);
break;
}
INT_T count = ty_cJSON_GetArraySize(list);
TAL_PR_NOTICE("swimming: custom role page %d, count=%d, totalPage=%d", page_no, count, total_page);
if (count == 0) {
ty_cJSON_Delete(result);
break;
}
INT_T i;
for (i = 0; i < count; i++) {
ty_cJSON *item = ty_cJSON_GetArrayItem(list, i);
if (NULL == item) continue;
ty_cJSON *role_id = ty_cJSON_GetObjectItem(item, "roleId");
ty_cJSON *role_name = ty_cJSON_GetObjectItem(item, "roleName");
ty_cJSON *use_timbre_id = ty_cJSON_GetObjectItem(item, "useTimbreId");
ty_cJSON *use_lang_code = ty_cJSON_GetObjectItem(item, "useLangCode");
ty_cJSON *template_id = ty_cJSON_GetObjectItem(item, "templateId");
TAL_PR_NOTICE("swimming: role[%d] roleId=%s, roleName=%s, useLangCode=%s, useTimbreId=%s, templateId=%s",
i,
role_id ? role_id->valuestring : "null",
role_name ? role_name->valuestring : "null",
use_lang_code ? use_lang_code->valuestring : "null",
use_timbre_id ? use_timbre_id->valuestring : "null",
template_id ? template_id->valuestring : "null");
ty_cJSON *dup = ty_cJSON_Duplicate(item, 1);
if (dup) {
ty_cJSON_AddItemToArray(all_roles, dup);
}
}
ty_cJSON_Delete(result);
if (total_page > 0 && page_no >= total_page) break;
if (count < page_size) break;
page_no++;
}
INT_T total = ty_cJSON_GetArraySize(all_roles);
TAL_PR_NOTICE("swimming: <<< get custom role done, total=%d", total);
if (total == 0) {
ty_cJSON_Delete(all_roles);
return NULL;
}
return all_roles;
}
STATIC VOID swimming_create_custom_role_from_template(CHAR_T *role_id, CHAR_T *lang_code, CHAR_T *timbre_id)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
CHAR_T post_content[512] = {0};
if (NULL == role_id || role_id[0] == '\0') {
TAL_PR_ERR("swimming: create from template failed, roleId is empty");
return;
}
TAL_PR_NOTICE("swimming: >>> create custom role from template, roleId=%s, langCode=%s, timbreId=%s",
role_id, lang_code ? lang_code : "null", timbre_id ? timbre_id : "null");
snprintf(post_content, sizeof(post_content),
"{\"roleId\":\"%s\",\"useLangCode\":\"%s\",\"useTimbreId\":\"%s\",\"needBind\":true}",
role_id,
lang_code ? lang_code : "",
timbre_id ? timbre_id : "");
rt = iot_httpc_common_post_simple("thing.ai.agent.role.custom-role.create-from-template", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt) {
TAL_PR_ERR("swimming: create from template failed, rt=%d", rt);
if (result) ty_cJSON_Delete(result);
return;
}
if (result) {
CHAR_T *result_str = ty_cJSON_PrintUnformatted(result);
if (result_str) {
TAL_PR_NOTICE("swimming: create from template result: %s", result_str);
ty_cJSON_FreeBuffer(result_str);
}
ty_cJSON_Delete(result);
}
TAL_PR_NOTICE("swimming: <<< create custom role from template success");
}
STATIC VOID swimming_update_custom_role(CHAR_T *role_id, CHAR_T *lang_code, CHAR_T *timbre_id)
{
OPERATE_RET rt = OPRT_OK;
ty_cJSON *result = NULL;
CHAR_T post_content[512] = {0};
if (NULL == role_id || role_id[0] == '\0') {
TAL_PR_ERR("swimming: update custom role failed, roleId is empty");
return;
}
TAL_PR_NOTICE("swimming: >>> update custom role, roleId=%s, langCode=%s, timbreId=%s",
role_id, lang_code ? lang_code : "null", timbre_id ? timbre_id : "null");
snprintf(post_content, sizeof(post_content),
"{\"roleId\":\"%s\",\"useLangCode\":\"%s\",\"useTimbreId\":\"%s\"}",
role_id,
lang_code ? lang_code : "",
timbre_id ? timbre_id : "");
rt = iot_httpc_common_post_simple("thing.ai.agent.role.custom-role.update", "1.0", post_content, NULL, &result);
if (OPRT_OK != rt) {
TAL_PR_ERR("swimming: update custom role failed, rt=%d", rt);
if (result) ty_cJSON_Delete(result);
return;
}
TAL_PR_NOTICE("swimming: <<< update custom role success");
if (result) ty_cJSON_Delete(result);
}
STATIC VOID swimming_role_config_task(VOID *data)
{
CHAR_T lang_code[64] = {0};
CHAR_T timbre_id[128] = {0};
CHAR_T model_role[128] = {0};//模版角色
CHAR_T custum_role[128] = {0};//自定义角色
//查询模板角色列表,返回完整JSON数组,调用方自行选择角色
ty_cJSON *template_list = swimming_get_role_template_list();
if (template_list) {
// TODO: 由外部逻辑(如APP下发DP指令)决定选哪个角色,这里示例取第一个
ty_cJSON *selected = ty_cJSON_GetArrayItem(template_list, 3);
if (selected) {
ty_cJSON *rid = ty_cJSON_GetObjectItem(selected, "roleId");
if (rid && rid->valuestring) {
snprintf(model_role, sizeof(model_role), "%s", rid->valuestring);
}
}
ty_cJSON_Delete(template_list);
}
//查询所有的自定义角色列表,返回完整JSON数组,调用方自行选择角色
ty_cJSON *custom_list = swimming_get_custom_role_page();
if (custom_list) {
// TODO: 由外部逻辑(如APP下发DP指令)决定选哪个角色,这里示例取第一个
ty_cJSON *selected = ty_cJSON_GetArrayItem(custom_list, 0);
if (selected) {
ty_cJSON *rid = ty_cJSON_GetObjectItem(selected, "roleId");
if (rid && rid->valuestring) {
snprintf(custum_role, sizeof(custum_role), "%s", rid->valuestring);
}
}
ty_cJSON_Delete(custom_list);
}
// 点击角色弹出语种选择(客户可以不从云端查,客户自己在设备侧配置也行)
swimming_get_languages_list(lang_code, sizeof(lang_code));
//查询支持该语种的音色列表(客户可以不从云端查,客户自己在设备侧配置也行)
swimming_get_timbre_market_all_pages(lang_code, timbre_id, sizeof(timbre_id));
//这个地方客户自行判断好逻辑,到底是自定义角色还是模版角色
//如果是修改模板角色,调用根据模板角色创建自定义角色接口把语种带进去
bk_printf("swimming model_role = %s,custum_role = %s \r\n",model_role,custum_role);
swimming_create_custom_role_from_template(model_role, lang_code, timbre_id);
//自定义角色则直接修改
//swimming_update_custom_role(role_id, lang_code, timbre_id);
}
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈