最佳实践
最佳实践
1. 利用普通链路,实现音乐播放和内容播放,以及打断
1.1.典型场景:
如下图所示,用户通过唤醒后,通过说出“播放音乐”的请求,用户完成唤醒响应与同duer SDK的音频交互逻辑,将采集到用户说话的PCM数据不断送入SDK中做识别,SDK会与云端交互,最终将该段音频识别到的ASR结果和NLP结果返回给用户业务层,用户再依据自身需求,对返回的tts和音乐mp3进行播放的动作。
1.2 音乐和内容播放:
媒资相关的播放走协议action的“media.play”,用户参考linux的demo,duerapp_intent.c文件的实现。 通过add_new_action_handle接口注册"media.play"的接收回调函数,在函数内解析处url进行播放。
static int media_play_handle_callback(baidu_json *action)
{
DUER_LOGI("in %s", __func__);
if (action == NULL) {
DUER_LOGE("no valid action list value");
return -1;
}
baidu_json *act_arg = baidu_json_GetObjectItem(action, "arg");
if (!act_arg) {
return -1;
}
baidu_json *arg_domain = baidu_json_GetObjectItem(act_arg, "domain");
baidu_json *arg_type = baidu_json_GetObjectItem(act_arg, "type");
baidu_json *arg_info = baidu_json_GetObjectItem(act_arg, "info");
if (!arg_info) {
return -1;
}
int music_type = URL_TTS;
action_need_resume = 1;
if (arg_domain) {
if (strcmp(arg_domain->valuestring, "other")) { // other之外的domain,都认为是URL_MUSIC
music_type = URL_MUSIC;
action_need_resume = 0;
}
}
baidu_json *track_id = baidu_json_GetObjectItem(arg_info, "trackId");
baidu_json *track_url = baidu_json_GetObjectItem(arg_info, "trackUrl");
if (track_url && track_url->valuestring) {
DUER_LOGI("receive type %d url %s", music_type, track_url->valuestring);
send_music_queue(music_type, track_url->valuestring);
} else {
DUER_LOGE("receive track id");
}
return 0;
}
add_new_action_handle("media.play", media_play_handle_callback);
1.3 打断续播:
1. 打断续播指在播放媒资期间,通过唤醒进行打断,在播放完请求的恢复后,再恢复到之前的媒资进行播放。
2.该功能需要播放器进行适配,可以参考linux-ffmpeg-demo下的播放器实现,包含播放控制和SEEK功能。
1.4 典型场景:
如下图所示,第一次唤醒通过“播放音乐”获取媒资进行播放,在播放音乐mp3期间进行第二次唤醒,此次通过“今天天气”等语句,获取回复的tts进行播放,在该tts播放完成后,恢复到第二次唤醒时正在播放的媒资,并从断点位置续播。
1.5 流程示例:
// 1.进行播放媒资
media_play_handle_callback:
send_music_queue(URL_MUSIC, url));
// 2.播放时进行唤醒,暂停播放媒资,备份url和播放进度
wake_up_action:
duerapp_player_pause();
-->player_pause(); // 进行备份动作
// 3.唤醒的query,返回非媒资的tts进行播放,在播放完后继续播放之前的媒资
media_play_handle_callback:
send_music_queue(URL_TTS, url); // 类型为tts,用于区分可暂停的媒资和不可暂停的tts回复,如果使用URL_MUSIC,则会覆盖掉之前备份的媒资
action_done_callback:
send_music_queue(MUSIC_CTL_CONTINUE, NULL); // 在当前请求的数个tts都加入播放队列后,发送恢复指令,将暂停的媒资数据也加入到播放队列,在tts播放结束后会自动续播
-->player_resume(); // 恢复媒资,将备份的媒资加入到队列尾部
2. 利用startListen功能实现免唤醒对话
可参考唤醒的实现,免唤醒对话只需要在特定触发条件下,走唤醒时的动作,便可上传语音进行识别。参考wake_up_action()。
static void wake_up_action()
{
DUER_LOGI("wake up action");
duerapp_player_pause();
//duerapp_player_i2s_write((void *)wake_up_prompt_tone, sizeof(wake_up_prompt_tone)); // 直接播放 速度比较快
send_music_queue(TONE_MUSIC, TONE_TYPE_WAKEUP); // 播报“我在”的唤醒响应词,免唤醒时根据需求选择是否播放
DUER_LOGI("wake up action done");
event_record_start(); // 开始录音进行上传
}
录音上传流程:
duer_dcs_on_listen_started(); // 录音上传启动
duer_voice_start(16000); // 设置采样率,支持8000,16000
duer_voice_send(buffer, s_index->size); // 持续发送音频,支持16bit 单通道音频
duer_voice_stop() // 停止发送音频
3. 利用普通链路实现简单的设备控制功能
在duerapp_intent.c文件中,用户可以在duerapp_intent_init函数中注册对应协议的处理函数。 协议分为action和intent,action的优先级高于intent,在有action的协议字段时,解析action后将不会再继续解析intent字段。 具体的协议内容参考通用技能协议表。
int duerapp_intent_init()
{
// action
add_new_action_handle("media.play", media_play_handle_callback);
// intent
add_new_intent_handle("failure", "failure", failure_intent_handle_callback);
add_new_intent_handle("sys_command", "stop", music_ctl_stop_handle_callback);
add_new_intent_handle("sys_command", "pause", music_ctl_pause_handle_callback);
add_new_intent_handle("sys_command", "continue", music_ctl_continue_handle_callback);
add_new_intent_handle("media_command", "stop", music_ctl_stop_handle_callback);
add_new_intent_handle("media_command", "pause", music_ctl_pause_handle_callback);
add_new_intent_handle("media_command", "continue", music_ctl_continue_handle_callback);
add_new_intent_handle("media_command", "goto", music_ctl_seek_handle_callback);
add_new_intent_handle("media_command", "fastforward", music_ctl_seek_handle_callback);
add_new_intent_handle("media_command", "backforward", music_ctl_seek_handle_callback);
add_new_intent_handle("sys_parameter", "up_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "down_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "to_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "min_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "mid_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "max_volume", system_ctl_volume_set_callback);
add_new_intent_handle("sys_parameter", "mute", system_ctl_volume_set_callback);
// other
bdvs_set_class_done_cb(BDVS_CLASS_TYPE_ACTION, action_done_callback);
bdvs_set_class_done_cb(BDVS_CLASS_TYPE_INTENT, intent_done_callback);
return 0;
}
4. 利用云云对接链路,实现高级设备控制
4.1. 适用场景
- 客户有自己的语义服务. 希望对现有的语义和协议进行纠正和改造.
- 客户有自己的FAQ和知识问答.希望对百度原有的TTS 答复文本进行替换或关掉.
- 客户有自己的内容需要透传给设备. 或者设备有自定义的内容要透传到客户云端.
- 客户可以根据自己的实际需求,选择哪些领域进行云云对接.
4.2. 流程图
4.3. 协议文档
1. 客户端连接鉴权
百度云建立连接时,会在 header 传递 Timestamp, AccessKey, Authorization 参数。
2. 接口说明
(1) URL
POST https://xxxxx
(2) 请求参数
与 ASR 结果回调接口的参数一致
- Header 参数
参数 | 类型 | 说明 |
---|---|---|
Content-Type | string | application/json |
Timestamp | long | 时间戳(毫秒) |
AccessKey | string | access_key |
Authorization | string | 摘要信息 |
- Body 参数
参数 | 类型 | 说明 |
---|---|---|
logId | string | 日志 ID |
device | obj | 百度三元组数据 |
device.fc | string | |
device.pk | string | |
device.ak | string | |
query | string | ASR 识别结果 |
nluInfos | string | 请求语义 |
extInfo | obj | 扩展信息 |
custom | string | 端上自定义信息 |
- nluInfos 字段说明 //这里只是示例
[{\"domain\":\"clean_bot\",\"intent\":\"start_clean\",\"slots\":{\"location\":[{\"slot_type\":\"STRING\",\"text\":\"卧室\",\"value\":\"卧室\"}]}}]
- extInfo 字段说明 //这里只是示例
{
"memberId": 123456789, // 用户ID
}
(3) 响应参数
参数 | 类型 | 说明 |
---|---|---|
logId | string | 日志 ID |
errCode | int | 错误码,0为成功,其他为失败 |
errMsg | string | 错误信息 |
tts | obj | 播报信息 |
nluInfos | string | 响应语义 |
ctrlParams | obj | 控制参数 |
custom | string | 客户自定义,透传到端上 |
- tts 内容字段说明:
{
"flag": 0, // 0: 正常播报(默认),1:tts 不进行播报(content字段内容不生效)
"content":"tts text" // 用于tts播报的内容, 如果content为空,则会用百度侧的content进行播报
}
- custom字段说明:
类型为string,百度透传结果,客户进行端云协同
原始如json数据需要序列化成 string类型
举例:
"custom": "
{\"otherKey1\":\"otherValue1\",\"otherKey2\":\"otherValue2\"}
". //整个内容是 string,百度透传结果,客户进行端云协同
4.4. 对接过程
- 百度云提供Demo文件. 下载地址xxxx, 用户下载后. 按Demo中代码实现 鉴权. 其中AK/SK 由百度提供. 只允许存储在云端. 切勿泄露
- 客户实现好后. 将有外网权限的接口提供给百度侧,并提供哪些领域需要进行云云对接. 百度侧配置好后. 会将相关的领域的query+语义都推送到客户云. 客户云需要在3s内响应百度云. 否则超时后, 百度云会以原语义信息进行下发.
5. 利用度家平台实现自定义FAQ
5.1 问答管理
机器人对技能统一调度管理,从而为用户提供多项对话服务。技能分发对话流管理(适用于简单的对话流程)。技能分发对话流管理为开发者提供了便捷的对话中控服务,仅需将技能添加到机器人中,机器人即可自动将用户对话分发给对应的技能进行回复。
5.2 如何添加问答?
问答型对话没有需要参数化的内容,往往具有固定的标准答案;这类型的对话逻辑梳理其实就是要对问题进行分类。需要有标准问题和相似问题,相似问题即为标准问题的泛化内容,并且可以设置回复答案。可以添加的问答对有品牌、各种生活资讯、价格对比等