阅读本文,你可以了解到以下信息:
host
headers
Content-Type: application/json
url
POST /v1/auth/tokens
请求参数
名称 | 类型 | 说明 | 是否必填 | 默认值 | 备注 |
---|---|---|---|---|---|
productId | string | 产品id | 是 | - | - |
deviceId | string | 设备id | 是 | - | 一个代表你的终端的唯一标识符 |
curtime | number | 请求授权时间 | 是 | - | 当前UTC时间戳,从 1970年1月1日0点0分0秒开始到现在的秒数 |
checksum | string | 令牌 | 是 | - | 计算方法: md5(secret + deviceId + curtime),两个值拼接的字符串,并通过md5进行加密。 |
接口错误码
错误码 | 错误信息 |
---|---|
20101 | 请求参数错误 |
20102 | 授权时间戳有误 |
20103 | productId无效 |
20104 | Checksum鉴权失败 |
20105 | 其他错误(包括deviceId不在设备白名单内/设备配额已耗尽/deviceId为空/deviceId格式有误) |
20199 | 服务异常 |
请求示例
static char * aiui_generate_token(const char *product_id, const char *secret_id, const char *device_id)
{
...
char *origin_product_ntp = csk_calloc(1, strlen(secret_id)+strlen(current_time) + 1);
if (origin_product_ntp == NULL) {
LOG_ERR("malloc failed");
return NULL;
}
strcat(origin_product_ntp, secret_id);
strcat(origin_product_ntp, current_time);
char md5_hex_string[80] = {'\0'};
unsigned char output[16] = {'\0'};
mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx);
mbedtls_md5_starts(&ctx);
mbedtls_md5_update(&ctx, origin_product_ntp, strlen(origin_product_ntp)); // 更新有效数据部分的MD5值
mbedtls_md5_finish(&ctx, output);
mbedtls_md5_free(&ctx);
for (int i = 0; i < 16; ++i) {
sprintf(md5_hex_string + i * 2, "%02x", output[i]);
}
const char *http_req_headers[] = {
"Content-Type: application/json\r\n",
}
...
req.method = HTTP_POST;
req.url = AIUI_TOKEN_URL;
req.host = AIUI_HOST;
req.protocol = "HTTP/1.1";
req.header_fields = http_req_headers;
req.payload = req_body;
req.payload_len = strlen(req.payload);
req.response = response_cb;
req.recv_buf = recv_buf_ipv4;
req.recv_buf_len = sizeof(recv_buf_ipv4);
ret = http_client_req(sock4, &req, timeout, "IPv4 GET");
close(sock4);
csk_free(origin_product_ntp);
char *aiui_token = NULL;
ret = k_msgq_get(&token_msgq, &aiui_token, K_SECONDS(5));
if (ret != 0) {
LOG_ERR("get token timeout");
return NULL;
}
return aiui_token;
}
postman请求示例
聆思大模型应用设备端授权.postman_collection.json
示例代码
详细内容请参考CSK6接入大模型示例代码:
duomotai_ap\components\aiui_inter_conn\aiui_conn.c
响应示例
{
"token": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJVQUp3dE9hdXRoU2VydmljZS***",
"expireAt": 1716378329574
}
请联系聆思首席大模型FAE 覃工(xqqin@listenai.com) 获取产品productid和secretid。
本接口是基于 WebSocket 协议实现数据的传输的。接口提供两个版本:
gateway
ws[s]://api.listenai.com/v1/interaction
dispatch
ws[s]://api.listenai.com/v1/dispatch
请求时headers带上
Authorization: Bearer token
其中token
为步骤一获取的授权结果。
请求参数
参数格式:
param=value1&token=value2
请求参数需要urlencode(Base64 编码)
请求参数说明:
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
param | string | 是 | Base64 编码后的字符串,详见 param 字段说明 | eyJhdXRoX2lkIjogIkxTMjAyNDAzMjYwMDMifQ== |
token | string | 否 | 大模型设备端接入token,详见 token 字段说明,该字段为字段,其作用等同于headers带入token值,两种方式选其一即可 | eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9*** |
param参数说明:
{
"auth_id": "LS20240326003",
"llm_app": "9ebe7088"
}
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
auth_id | string | 是 | 用户唯一ID(即步骤一所述deviceId) | 4d0c4412769b |
llm_app | string | 否 | 由客户端指定的大模型应用ID,如“儿童闲聊”应用对应一个ID,"口语私教"应用对应另一个ID | 9ebe7088 |
token参数说明:
token值为步骤一获取的鉴权信息,已经过base64编码,直接带入即可。websocket连接支持token值作为参数信息上传云端,示例:
eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJVQUp3dE9hdXRoU2VydmljZSIsI***
请求示例:
ws[s]://api.listenai.com/v1/interaction?param=xxxx&token=xxx
websocket请求示例代码
aiui_handle_t aiui_conn_init(void)
{
...
char *url = aiui_generate_url();
csk_ws_client_config_t config = {
.host = AIUI_HOST,
.scheme = AIUI_SCHEME,
.path = url,
.optional_headers = extra_headers,
};
//
csk_ws_client_create(&aiui_handle->ws_handle, &config);
csk_free(url);
csk_ws_client_eventcb_config_t cb_config = {
.connected_handler = ws_connected_cb,
.connected_arg = aiui_handle,
.disconnected_handler = ws_disconnected_cb,
.disconnected_arg = aiui_handle,
.message_handler = ws_data_cb,
.message_arg = aiui_handle,
};
// 注册websocket回调
csk_ws_client_config_event_cb(aiui_handle->ws_handle, &cb_config);
// 建立websocket
csk_ws_client_connect(aiui_handle->ws_handle);
k_sem_take(&ws_connected_sem, K_FOREVER);
return aiui_handle;
...
}
详细内容请参考CSK6接入大模型示例代码:
duomotai_ap\components\csk_websocket_client\csk_websocket_client.c
csk_websocket_client.c
csk_websocket_client.h
返回信息
{
"action":"connected",
"cid":"cidf415ba9c@dx8d0d18b0d6dd3eef00",
"code":"0",
"data":"",
"desc":"success"
}
{
"action": "error",
"cid": "3def61d96bdd",
"code": "400",
"data": "",
"desc": "设备在其他地方上线"
}
Websocket连接建立之后,进入实时通信阶段,可以进行会话的创建、数据的上传、结果的接收等。
整体的交互协议分为指令和数据,分别对应TEXT消息和BINARY消息。
连接建立之后,就可以开始创建会话,创建会话是为了在长连接中标识一次会话请求的起点,定义BINARY消息类型(如文本数据和音频数据)、需要的结果类型和各类型的参数。创建会话之后,在会话结束之前,所有请求的数据和指令均属于该会话。
{
"action":"start",
"params":{
"data_type":"audio",
"aue":"raw",
"features":[
"nlu",
"tts"
],
"asr_properties":{
"ent":"home-va"
},
"tts_properties":{
"vcn":"x4_lingxiaoqi_oral"
},
"nlu_properties":{
"sn":"xxxxxxxx"
},
"translate_properties":{
"from":"xxx",
"to": "xxx"
},
"evaluate_properties":{
"business": {
"category": "read_sentence",
"text": "[content]I don't know why",
"ent": "en_vip"
}
}
}
}
参数说明
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
action | string | 是 | 指令类型 | start |
params | object | 是 | 业务参数 | |
params.fullduplex | string | 否 | 是否开启全双工:"1"(开启)、"2"(关闭),默认关闭 | "1" |
params.data_type | string | 是 | 数据类型:audio、text | audio |
params.aue | string | 是 | 数据类型为audio时必填,指定音频格式: 【默认】raw: pcm格式(16khz 16bit LE, 单声道) opus-wb: opus-wb格式 speex-wb: speex-wb格式 ico: ico格式 |
raw |
params.speex_size | int | 否 | 音频数据格式为speex-wb时必填 | 70 |
features | array | 否 | 自定义结果类型功能,默认为["nlu"、"tts"]: nlu: 语义理解与回复(aiui或llm) tts: 下发tts音频链接 translate: 下发翻译结果 如不需要使用nlp功能,传空数组 |
["nlu", "tts"] |
params.asr_properties | object | 否 | 设备端指定的asr参数,详见asr_properties参数说明 | |
params.tts_properties | object | 否 | 设备端指定的tts参数,详见tts_properties参数说明 | |
params.nlu_properties | object | 否 | 设备端指定的nlu参数,nlu_properties参数说明 | |
params.translate_properties | object | 否 | 设备端指定的翻译参数,translate_properties参数说明 | |
params.evaluate_properties | object | 否 | 设备端指定的评测参数,evaluate_properties参数说明 |
asr_properties参数说明
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
asr_appid | string | 否 | 自定义appid,一般不使用 | |
asr_apikey | string | 否 | 自定义apikey,一般不使用 | |
asr_apisecret | string | 否 | 自定义apisecret,一般不使用 | |
evad | string | 否 | 是否开启LS Gateway提供的vad "1": 开启 "0": 关闭 |
"1" |
vad_eos | int | 否 | vad后端点 | 800 |
ent | string | 否 | 设备端指定的识别引擎 | sms-aiui16k |
pd | string | 否 | ||
svad | int | 否 | 由于云端有3个vad:语义vad、普通引擎vad、聆思vad,如需关闭vad,可将eos拉到4000,或者增加上传"svad"=0 |
tts_properties
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
tts_appid | string | 否 | 自定义appid,一般不使用 | |
tts_apikey | string | 否 | 自定义apikey,一般不使用 | |
tts_apisecret | string | 否 | 自定义apisecret,一般不使用 | |
vcn | string | 否 | 发音人 | "x4_lingxiaoyue_oral" |
ent | string | 否 | 引擎 | "xtts" |
volume | int | 否 | 音量:1-100 | 50 |
speed | int | 否 | 语速:1-100 | 50 |
pitch | int | 否 | 声调:1-100 | 50 |
nlu_properties
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
aiui_appid | string | 否 | 自定义appid,一般不使用 | |
aiui_apikey | string | 否 | 自定义apikey,一般不使用 | |
nlp_mode | string | 否 | nlp类型: aiui llm |
"aiui" |
scene | string | 否 | 自定义scene,默认main | "main" |
sn | string | 否 | 设备sn | "xxxxxx" |
lat | string | 否 | 纬度 | |
lng | string | 否 | 经度 | |
auth_id | string | 否 | ||
clean_dialog_history | string | 否 | "user" | |
abilities | object | 否 | 设备支持的能力列表 |
translate_properties
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
translate_appid | string | 否 | 自定义appid,一般不使用 | |
translate_apikey | string | 否 | 自定义apikey,一般不使用 | |
translate_apisecret | string | 否 | 自定义apisecret,一般不使用 | |
from | string | 是 | 翻译源语种 | "cn" |
to | string | 是 | 翻译目标语种 | "en" |
evaluate_properties
参数 | 类型 | 必须 | 说明 | 示例 |
---|---|---|---|---|
evaluate_appid | string | 否 | 自定义appid,一般不使用 | |
evaluate_apikey | string | 否 | 自定义apikey,一般不使用 | |
evaluate_apisecret | string | 否 | 自定义apisecret,一般不使用 | |
business | object | 是 | 评测自定义参数 | |
business.ent | string | 否 | 中文:cn_vip(默认) 英文:en_vip |
|
business.category | string | 是 | 中文题型: read_syllable(单字朗读,汉语专有) read_word(词语朗读) read_sentence(句子朗读) read_chapter(篇章朗读) 英文题型: read_word(词语朗读) read_sentence(句子朗读) read_chapter(篇章朗读) simple_expression(英文情景反应) read_choice(英文选择题) topic(英文自由题) retell(英文复述题) picture_talk(英文看图说话) oral_translation(英文口头翻译) |
|
business.text | string | 是 | 待评测文本 | |
business.group | string | 否 | 针对群体不同,相同试卷音频评分结果不同 (仅中文字、词、句、篇章题型支持),此参数会影响准确度得分 adult(成人群体,不设置群体参数时默认为成人) youth(中学群体) pupil(小学群体,中文句、篇题型设置此参数值会有accuracy_score得分的返回) |
|
business.check_type | string | 否 | 设置评测的打分及检错松严门限(仅中文引擎支持) easy:容易 common:普通 hard:困难 |
|
business.grade | string | 否 | 设置评测的学段参数 (仅中文题型:中小学的句子、篇章题型支持) junior(1,2年级) middle(3,4年级) senior(5,6年级) |
|
business.rst | string | 否 | 评测返回结果与分制控制(评测返回结果与分制控制也会受到ise_unite与plev参数的影响) 完整:entirety(默认值) 中文百分制推荐传参(rst="entirety"且ise_unite="1"且配合extra_ability参数使用) 英文百分制推荐传参(rst="entirety"且ise_unite="1"且配合extra_ability参数使用) 精简:plain(评测返回结果将只有总分) |
|
business.ise_unite | string | 否 | 返回结果控制 0:不控制(默认值) 1:控制(extra_ability参数将影响全维度等信息的返回) |
|
business.plev | string | 否 | 在rst="entirety"(默认值)且ise_unite="0"(默认值)的情况下plev的取值不同对返回结果有影响。 plev:0(给出全部信息,汉语包含rec_node_type、perr_msg、fluency_score、phone_score信息的返回;英文包含accuracy_score、serr_msg、 syll_accent、fluency_score、standard_score、pitch信息的返回) |
|
business.extra_ability | object | 否 | 拓展能力(生效条件ise_unite="1", rst="entirety") 多维度分信息显示(准确度分、流畅度分、完整度打分) extra_ability值为multi_dimension(字词句篇均适用,如选多个能力,用分号;隔开。例如:add("extra_ability"," syll_phone_err_msg;pitch;multi_dimension")) 单词基频信息显示(基频开始值、结束值) extra_ability值为pitch ,仅适用于单词和句子题型 音素错误信息显示(声韵、调型是否正确) extra_ability值为syll_phone_err_msg(字词句篇均适用,如选多个能力,用分号;隔开。例如:add("extra_ability"," syll_phone_err_msg;pitch;multi_dimension")) |
abilities示例
// 设备支持闹钟能力,创建和删除
{
"params":{
"nlu_properties":{
"abilities": [
{
"name": "alarm",
"intents": ["create", "delete"]
},
// ...
]
}
}
}
会话创建帧响应
会话创建成功后,云端会返回以下响应:
{
'action':'started',
'cid': 'ee60b72f0ec7',
'code':'0',
'data':'',
'desc':'success',
'fid': 'f79a8ef4307d',
'sid':'33737e7ce2f74497baa2ee51b344df8a'
}
设备端上传数据有两种方式,文本数据和音频数据。在交互过程中,设备端不断构造 binary message 发送到服务端,内容是音频或文本的二进制数据。一个会话中,二进制文本数据只需要发送一次。
发送数据示例:
python:
CHUNK_SIZE = 512
SAMPLE_RATE = 16000 # 采样率
CHANNELS = 1
stream = audio.open(format=pyaudio.paInt16,
channels=CHANNELS,
rate=SAMPLE_RATE,
input=True,
frames_per_buffer=CHUNK_SIZE)
audio_data = stream.read(CHUNK_SIZE)
ws.send(audio_data, opcode=websocket.ABNF.OPCODE_BINARY)
rtos示例:
enum websocket_opcode {
WEBSOCKET_OPCODE_CONTINUE = 0x00,
WEBSOCKET_OPCODE_DATA_TEXT = 0x01,
WEBSOCKET_OPCODE_DATA_BINARY = 0x02,
WEBSOCKET_OPCODE_CLOSE = 0x08,
WEBSOCKET_OPCODE_PING = 0x09,
WEBSOCKET_OPCODE_PONG = 0x0A,
};
int csk_ws_client_send_bin(csk_ws_client_handle_t ws_handle, uint8_t *data, int data_len)
{
uint32_t free_num = k_msgq_num_free_get(&csk_ws_send_msgq);
if(free_num <= 3){
LOG_WRN("send bin no more free space: %d", free_num);
return -1;
}
uint8_t *send_data = (uint8_t *)csk_malloc(data_len);
if(send_data == NULL){
LOG_ERR("%s %d", __FUNCTION__, __LINE__);
return -ENOMEM;
}
memcpy(send_data, data, data_len);
csk_ws_send_msg_t msg = {
.opcode = WEBSOCKET_OPCODE_DATA_BINARY,
.data = send_data,
.len = data_len,
};
int ret = k_msgq_put(&csk_ws_send_msgq, &msg, K_NO_WAIT);
if(ret < 0){
LOG_WRN("send bin k_msgq_put ret = %d", ret);
csk_free(send_data);
return ret;
}
return 0;
}
客户端可以主动结束音频发送,云端会结束识别并进行对应的处理。指令内容如下:
{
"action": "end"
}
参数说明
参数 | 类型 | 说明 | 必须 |
---|---|---|---|
action | string | 状态标识(类型详见action参数说明) | 是 |
code | string | 云端返回编码 | 是 |
cid | string | 云端当前长连接id | 否 |
fid | string | 云端单次全双工交互id | 否 |
sid | string | 云端单次交互id(可用于查询交互记录) | 是 |
action参数说明
参数 | 类型 | 说明 | 必须 |
---|---|---|---|
started | string | 会话创建状态标识 | 是 |
result | string | 识别结果返回状态标识 | 是 |
finish | string | 会话结束状态标识 | 是 |
data参数说明
参数 | 类型 | 说明 | 必须 |
---|---|---|---|
sub | string | 详见sub状态结果 | 是 |
is_last | bool | 是否是最后识别结果(详见is_last参数说明) | 是 |
code | string | 云端返回编码 | 是 |
auth_id | string | 是 | |
result_id | int | 是 |
sub参数说明
参数 | 类型 | 说明 | 必须 |
---|---|---|---|
iat | string | 识别结果 | 是 |
vad | string | vad结果(注:vad结果可能会在最终识别结果前下发) | 是 |
tts | string | tts结果 | 是 |
nlp | string | 语义结果 | 是 |
is_last参数说明
参数 | 类型 | 说明 | 必须 |
---|---|---|---|
True | string | 是最后识别结果 | 是 |
False | string | 非最后识别结果 | 是 |
识别结果(流式)
{
'code': '0',
'data': {
'sub': 'iat',
'is_last': True,
'auth_id': 'd9ec6e29f379cf919d9daed0d2459612',
'result_id': 5,
'text': '今天广州的天气怎么样?需要带伞吗??'
},
'action': 'result',
'desc': 'success',
'sid': '5404f85784014c068bdc8a90a66d3d4a',
'fid': '10f3eca6a9c5',
'cid': 'ee60b72f0ec7'
}
vad结果(注:vad结果可能会在最终识别结果前下发,表示静音段超过eos,请设备端停止录音)
{
'code': '0',
'data': {
'sub': 'vad',
'result_id': 0,
'info': 'end'
},
'action': 'result',
'desc': 'success',
'sid': '5404f85784014c068bdc8a90a66d3d4a',
'fid': '10f3eca6a9c5',
'cid': 'ee60b72f0ec7'
}
语义结果
{
"code":"0",
"data":{
"sub":"nlp",
"auth_id":"4d0c4412769b62f0f44134ce9f2db11f",
"result_id":1,
"intent":{
"semantic":[
{
"slots":[
{
"name":"location.city",
"value":"广州市",
"normValue":"广州市"
},
{
"name":"location.cityAddr",
"value":"广州",
"normValue":"广州"
},
{
"name":"location.type",
"value":"LOC_BASIC",
"normValue":"LOC_BASIC"
},
{
"name":"queryType",
"value":"确认"
},
{
"name":"questionWord",
"value":"需要"
},
{
"name":"subfocus",
"value":"伞"
},
{
"name":"datetime",
"value":"今天",
"normValue":"{\"datetime\":\"2023-11-16\",\"suggestDatetime\":\"2023-11-16\"}"
}
],
"intent":"QUERY"
}
],
"shouldEndSession":"true",
"dialog_stat":"DataValid",
"data":{
"result":[
]
},
"save_history":true,
"uuid":"ara3d116b3a@dx000118b0e1c0a10b00",
"version":"171.0",
"sid":"ara3d116b3a@dx000118b0e1c0a10b00",
"rc":0,
"answer":{
"text":"不用带伞,今天广州阴",
"type":"T"
},
"used_state":{
"state_key":"fg::weather::default::default",
"state":"default"
},
"service":"weather",
"state":{
"fg::weather::default::default":{
"state":"default"
}
},
"text":"今天广州的天气怎么样?需要带伞吗?",
"category":"IFLYTEK.weather"
}
},
"action":"result",
"desc":"success",
"sid":"ebd611e1-f4ec-4d3c-be4d-ed8c122ea96d"
}
tts结果
请注意content需要base64解码后方可访问。
{
"code":"0",
"data":{
"sub":"tts",
"is_last":true,
"auth_id":"3fdc7e97c0d351991975662bd425e999",
"result_id":0,
"content":"aHR0cDovL2ludGVncmF0aW9uLXR0cy5pZmx5b3MuY24vbGl2ZS9kNjVkYzUyNDJhNGRhMGY4NWFjZDZhMTY3YmM0OWMyOWNlOTdkNGI1Lm1wMw=="
},
"action":"result",
"desc":"success",
"sid":"9470b468-ab3b-44de-ba95-24ab9dc60770"
}
翻译结果
{
"code": "0",
"data": {
"nlp_origin": "translate",
"sub": "nlp",
"payload": {
"code": 0,
"data": {
"result": {
"trans_result": {
"dst": "Sing a song.",
"src": "唱一首。"
},
"from": "cn",
"to": "en"
}
},
"message": "success",
"sid": "its000dc8b5@dx1961441a6a7a11d902"
}
},
"action": "result",
"desc": "success",
"sid": "bc178d7c-e561-46b2-b0d8-9035f5f4f2f8"
}
评测结果
{
"code": "0",
"data": {
"nlp_origin": "evaluate",
"sub": "nlp",
"payload": {
"read_sentence": {
"rec_paper": {
"read_chapter": {
"sentence": {
"fluency_score": 3.672485,
"word_count": 4,
"standard_score": 2.794051,
"end_pos": 178,
"accuracy_score": 2.956864,
"index": 0,
"total_score": 3.155269,
"beg_pos": 0,
"word": [
{
"syll": {
"phone": {
"gwpp": -0.000443,
"end_pos": 62,
"beg_pos": 46,
"content": "ay",
"dp_message": 0
},
"end_pos": 62,
"syll_accent": 0,
"serr_msg": 0,
"syll_score": 4.999741,
"beg_pos": 46,
"content": "ay"
},
"pitch_beg": 55,
"end_pos": 62,
"pitch_end": 62,
"property": 0,
"index": 0,
"total_score": 5,
"pitch": " 139.23 139.23 140.99 143.43 145.23 142.63 135.24",
"global_index": 0,
"beg_pos": 46,
"content": "i",
"dp_message": 0
},
{
"syll": {
"phone": [
{
"gwpp": -0.009648,
"end_pos": 70,
"beg_pos": 62,
"content": "d",
"dp_message": 0
},
{
"gwpp": -0.013372,
"end_pos": 78,
"beg_pos": 70,
"content": "ow",
"dp_message": 0
},
{
"gwpp": -0.000125,
"end_pos": 81,
"beg_pos": 78,
"content": "n",
"dp_message": 0
},
{
"gwpp": -0.0004,
"end_pos": 85,
"beg_pos": 81,
"content": "t",
"dp_message": 0
}
],
"end_pos": 85,
"syll_accent": 0,
"serr_msg": 0,
"syll_score": 4.995635,
"beg_pos": 62,
"content": "d ow n t"
},
"pitch_beg": 70,
"end_pos": 85,
"pitch_end": 85,
"property": 0,
"index": 1,
"total_score": 4.999567,
"pitch": " 142.86 142.86 141.61 141.21 141.82 142.93 144.08 144.61 144.46 143.53 142.31 141.29 140.79 140.40 139.95",
"global_index": 1,
"beg_pos": 62,
"content": "don't",
"dp_message": 0
},
{
"syll": {
"phone": [
{
"gwpp": -0.003223,
"end_pos": 92,
"beg_pos": 85,
"content": "n",
"dp_message": 0
},
{
"gwpp": -0.042028,
"end_pos": 120,
"beg_pos": 92,
"content": "ow",
"dp_message": 0
}
],
"end_pos": 120,
"syll_accent": 0,
"serr_msg": 0,
"syll_score": 4.985162,
"beg_pos": 85,
"content": "n ow"
},
"pitch_beg": 85,
"end_pos": 120,
"pitch_end": 113,
"property": 0,
"index": 2,
"total_score": 4.996269,
"pitch": " 138.30 138.30 137.74 136.98 135.55 133.99 132.85 132.31 131.42 130.07 127.76 125.03 122.41 120.35 118.65 116.84 114.78 112.80 110.77 108.60 106.32 104.27 103.17 103.04 104.12 105.54 109.12 114.40",
"global_index": 2,
"beg_pos": 85,
"content": "know",
"dp_message": 0
},
{
"syll": {
"phone": [
{
"end_pos": 120,
"beg_pos": 120,
"content": "w",
"dp_message": 16
},
{
"end_pos": 120,
"beg_pos": 120,
"content": "ay",
"dp_message": 16
}
],
"end_pos": 120,
"syll_accent": 0,
"serr_msg": 1,
"syll_score": 0,
"beg_pos": 120,
"content": "w ay"
},
"end_pos": 120,
"property": 0,
"index": 3,
"total_score": 0,
"global_index": 3,
"beg_pos": 120,
"content": "why",
"dp_message": 16
},
{
"end_pos": 156,
"beg_pos": 120,
"content": "sil"
}
],
"content": "i don't know why"
},
"integrity_score": 3.75,
"end_pos": 178,
"beg_pos": 0,
"content": "I don't know why",
"reject_type": 0,
"fluency_score": 5,
"word_count": 4,
"score_pattern": "loose",
"standard_score": 3.725402,
"is_rejected": false,
"accuracy_score": 4.134972,
"except_info": 0,
"total_score": 3.265142
}
},
"lan": "en",
"type": "study",
"version": "7.0.0.1020"
}
}
},
"action": "result",
"desc": "success",
"sid": "a44ccf3d-1b81-46c8-b102-cf92f819b386"
}
在会话所有结果均已下发,则会下发一个结束指令消息,表示该会话已经结束。
{
'code': '0',
'data': '',
'action': 'finish',
'desc': 'success',
'sid': '279e517195ab47d496d0fd4925e959d9',
'fid': '874e07bceeb9',
'cid': 'ee60b72f0ec7'
}
创建会话
{
"action": "start",
"params": {
"data_type": "audio",
"aue": "raw",
"features": [
"nlu",
"tts"
],
"asr_properties": {
"ent": "home-va",
"evad":0,
"vad_eos":800,
},
"tts_properties": {
"vcn": "x4_lingxiaoqi_oral"
},
"nlu_properties": {
"sn": auth_info.device_id,
}
}
}
发送音频数据
int aiui_audio_send_start(aiui_handle_t handle)
{
#define ONESHOT_START_FORMAT "{\"action\": \"start\", \"params\": {\"eos\": \"250\", \"ent\": \"sms-haier-test\", \"evad\": \"1\", \"data_type\": \"audio\", \"result_level\": \"plain\", \"clean_dialog_history\": \"user\", \"aue\": \"raw\"}, \"tts_properties\": {\"vcn\": \"x4_lingxiaoqi_oral\"}}"
#define CONTINUE_START_FORMAT "{\"action\":\"start\",\"params\":{\"fullduplex\": \"1\", \"eos\": \"250\", \"ent\":\"sms-haier-test\", \"evad\":\"1\", \"data_type\":\"audio\",\"result_level\":\"plain\",\"clean_dialog_history\":\"user\",\"aue\":\"raw\",\"dwa\":\"\"}}"
LOG_INF("func: %s, line: %d", __FUNCTION__, __LINE__);
int ret = 0;
aiui_inter_handle_t *aiui_handle = handle;
char *start_format = (aiui_get_interactive_mode() == AIUI_INTER_ONESHOT) ?
ONESHOT_START_FORMAT : CONTINUE_START_FORMAT;
ret = csk_ws_client_send_text(aiui_handle->ws_handle, start_format);
if (ret < 0) {
LOG_ERR("%s: %d, ret = %d", __FUNCTION__, __LINE__, ret);
}
return ret;
}
int aiui_audio_send_data(aiui_handle_t handle, const void *audio, int len)
{
aiui_inter_handle_t *aiui_handle = handle;
int ret = csk_ws_client_send_bin(aiui_handle->ws_handle, (void *)audio, len);
if (ret < 0) {
LOG_ERR("%s: %d, ret = %d", __FUNCTION__, __LINE__, ret);
}
return ret;
}
发送end指令
int aiui_audio_send_end(aiui_handle_t handle)
{
aiui_inter_handle_t *aiui_handle = handle;
const char *end_tag = "{\"action\":\"end\"}";
int ret = csk_ws_client_send_text(aiui_handle->ws_handle, (void *)end_tag);
if (ret != 0) {
return ret;
}
LOG_INF("func: %s, line: %d", __FUNCTION__, __LINE__);
return 0;
}
云端响应
音频请求返回过程数据示例.json
创建会话
{
"action": "start",
"params": {
"data_type": "text",
"features": [
"nlu",
"tts"
],
"tts_properties": {
"vcn": "x4_lingxiaoqi_oral"
},
"nlu_properties": {
"sn": auth_info.device_id,
}
}
}
发送文本数据
int csk_ws_client_send_text(csk_ws_client_handle_t ws_handle, char *text_msg)
{
char *send_data = (char *)csk_malloc(strlen(text_msg) + 1);
if(send_data == NULL){
LOG_ERR("%s %d", __FUNCTION__, __LINE__);
return -ENOMEM;
}
strcpy(send_data, text_msg);
csk_ws_send_msg_t msg = {
.opcode = WEBSOCKET_OPCODE_DATA_TEXT,
.data = send_data,
.len = strlen(text_msg),
};
int ret = k_msgq_put(&csk_ws_send_msgq, &msg, K_NO_WAIT);
if(ret < 0){
LOG_WRN("send text k_msgq_put ret = %d", ret);
csk_free(send_data);
return ret;
}
return 0;
}
详细内容请参考CSK6接入大模型示例代码:
duomotai_ap\components\aiui_inter_conn\aiui_conn.c
示例代码获取:
git clone --branch release https://cloud.listenai.com/CSKG962172/duomotai_ap.git
示例应用目录:apps\LLM_pic
更详细文档请参考:大模型语音交互与识图快速体验
示例代码获取:
https://cloud.listenai.com/listenai_xqqin/aitalk.git
python示例用于快速体验聆思大模型交互,开发者可以先体验整个交互流程后,再去实现设备端接入的开发,效率更高,python示例运行详见根目录readme文档说明。