lixiaote / AndroidBotSdkDemo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Demo使用指引

编译安装源代码到小度设备,通过语音指令"小度小度,打开单肩包",调起app。app内部有支付接口示例,UIControl示例。可以参考示例代码实现自己的功能.如果有疑问可以参考FAQ

需求背景

有些情况下 ,开发者需要以客户端app的型式,实现一个bot,包括但不限于以下情况:

  • app(可能是电视、手机、pad上的)已经存在,需要和dcs语音交互的主控程序去打通
  • bot的功能,需要在端上有比较复杂的界面、交互、功能实现(只用view + tts 的简单交互满足不了)

所以,需要实现一个安卓系统的sdk,辅助开发以安卓app形式存在的bot。

开发出来的app可以用在在电视、show等基于安卓的DuerOS设备上

android bot sdk的基本功能:

  • 被调起
  • 被探测
  • 接收语音解析出来的指令
  • 主动上报ui状态(供语音解析使用)
  • 在适当的时候发起语音请求

DBP平台上的前期准备

流程图

流程1: 打开bot app

open_bot_app

流程2: 云端定义的intent

可以在dbp平台上定义intent,也可以是云端预定义的ScreenNavigator等指令

cloud_based_intent

流程3: 客户端custom_user_interaction

custom_user_interaction

API

BotSdk的初始化

建议在application启动的时候完成BotSdk的初始化

BotSdk.getInstance().init(application);

注册过程

如果启动后不能正确注册,将无法收到解析出来的指令

public void register(){
    if (!BotSdk.getInstance().isRegister()) {
        String rand1="hongyang"+Math.random();
        String rand2= "yanghong"+Math.random();
        String botId="3fcc17e3-7e97-b9ec-84cd-5211f6271394"; //来自DBP平台
        BotSdk.getInstance().register(
            messageListener,
            botId,
            rand1,
            sign(rand1),
            rand2,
            sign(rand2)
        );
    }
}

public String sign(String rand){
    String key = "abcdefghijk12345";  //来自DBP平台
    return getMD5(rand+key);
}

响应云端请求

onHandleIntent 响应DBP平台上定义的intent。onHandleScreenNavigatorEvent响应内置的屏幕导航请求

new IBotMessageListener() {
    @Override
    public void onHandleIntent(String token, BotIdentity identity, BotIntent intent,
                               String customData) {
        Log.d("BotSdk", "onHandleIntent:" + token + "|" + identity
                .accessToken + "|" + intent.name + "|" + intent.slots + "|" +
                customData);

        if ("light_on".equals(intent.name )) {
            if (intent.slots!=null  && intent.slots.size() > 0 && intent.slots.get(0).value.equals("黄灯")) {
                mLight.setImageDrawable(getResources().getDrawable(R.drawable.light2));
            } else {
                mLight.setImageDrawable(getResources().getDrawable(R.drawable.light3));
            }
        } else if ("light_off".equals(intent.name)) {
            mLight.setImageDrawable(getResources().getDrawable(R.drawable.light));
        }

    }


    //内置的屏幕导航请求
    @Override
    public void onHandleScreenNavigatorEvent(int event) {

        String msg = "";

        switch (event) {
            case IBotMessageListener.NAV_SCROLL_LEFT: //“向左滚动”
                msg = "NAV_SCROLL_LEFT";
                break;
            case IBotMessageListener.NAV_SCROLL_RIGHT: //“向右滚动”
                msg = "NAV_SCROLL_RIGHT";
                break;
            case IBotMessageListener.NAV_SCROLL_UP: //“向上滚动”
                msg = "NAV_SCROLL_UP";
                break;
            case IBotMessageListener.NAV_SCROLL_DOWN: //“向下滚动”
                msg = "NAV_SCROLL_DOWN";
                break;
            case IBotMessageListener.NAV_NEXT_PAGE: //“下一页”
                msg = "NAV_NEXT_PAGE";
                break;
            case IBotMessageListener.NAV_PREVIOUS_PAGE: //“上一页”
                msg = "NAV_PREVIOUS_PAGE";
                break;
            case IBotMessageListener.NAV_GO_HOMEPAGE: //“回到首页”
                msg = "NAV_GO_HOMEPAGE";
                break;
            case IBotMessageListener.NAV_GO_BACK: //“返回”
                msg = "NAV_GO_BACK";
                break;
            default:
                break;
        }
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }

};

客户端自定义交互

//定义自定义交互
private void updateUiContext() {
    UiContextPayload payload = new UiContextPayload();
    HashMap<String, String> params;
    
    params = new HashMap<>();
    params.put("name", "地址");
    params.put("type", "city");
    payload.addHyperUtterance(
            "sdkdemo://input",  //url
            null,  //words,自定义的query列表
            "input", //type
            params);  //其他参数

    String[] words = {"试一试", "点击试一试"};
    params = new HashMap<>();
    params.put("name", "试一试");
    payload.addHyperUtterance("sdkdemo://clicktest",
            words,
            "link",
            params);

    BotSdk.getInstance().updateUiContext(payload);
}


//响应自定义交互
new IBotMessageListener() {
    @Override
    public void onClickLink(String url, HashMap<String, String> paramMap) {
        Log.d(TAG, "onClickLink: " + url + " , " + paramMap);
        if("sdkdemo://clicktest".equals(url)){
            findViewById(R.id.test).performClick();
        }

        if("sdkdemo://input".equals(url)){
            ((TextView)findViewById(R.id.input)).setText(paramMap.get("content"));
        }

        Toast.makeText(MainActivity.this, "url = " + url, Toast.LENGTH_SHORT).show();
    }
}

自定义交互支持的type列表

type
request params
response slots
(除了默认的url之外)
example
input
name:
(optional) value:
(optional) type:
  date
  car_number
  cityxpress_number
  city
(optional) prefix(暂不支持)
content
“输入地址北京”
request params
{
  name:地址,
  type:city
}
response params
{
  content:北京
}
button
name
(optional) index
(optional) index_x
(optional) index_y
-
“点击确认”、“选择确认”、“选择第一个”
request params
{
  name: 确认,
  index: 1,
}
link
name
(optional) index
(optional) index_x
(optional) index_y
(optional) prefix(暂不支持)
-
“点击确认”、“选择确认”、“选择第一个”
request params
{
  name: 确认,
  index: 1,
}
select
name
(optional) selected
(optional) index
(optional) index_x
(optional) index_y
-
“选择确认”、“选择第一个”
request params
{
  name: 确认,
  index: 1,
}
video
name
(optional) index
(optional) index_x
(optional) index_y
(optional) actors(screen_e)
(optional) director
(optional) prefix(暂不支持)
//后续增加的字段要与structures/search-video-structure-private.md 保持一致
-
"播放琅琊榜"
request params
{
  name: 琅琊榜
}
music
name
(optional) index
(optional) index_x
(optional) index_y
(optional) singers
(optional) album
(optional) prefix(暂不支持)
-
"播放青花瓷"
request params
{
  name: 青花瓷
}
tab
name
(optional) selected
(optional) index
(optional) index_x
(optional) index_y
(optional) prefix(暂不支持)
-
“切换到电视剧”
request params
{
name: 电视剧
}
scroll
(optional) name:
(optional) type:
vertical
horizontal
page
direction 方向,取值{left/right/up/down}
by 滚动的相对值,可以有正负
to 滚动的绝对值,-1代表滚到底
"把电影列表向下滚动"
request params
{
name:电影列表
}
response params
{
direction:{left/right/up/down}
  by: {{LONG}},
  to: {{LONG}}, //to ==-1的时候,表示“滚到底”
  //by和to的单位,暂时都是 屏幕/页,以后有需求再加别的unit
}
pager
(optional) name:
(optional) cur_page:
(optional) min
(optional) max
by 页码的相对值,可以有正负
to 页码的绝对值,-1代表最后一页(如果没有max的话, 才会返回-1;否则应该返回max-1)
"把电影列表翻到最后一页"
request params
{
  name:电影列表
}
response params
{
  to: {{LONG}},
}
step
(optional) name:
(optional) cur_page:
(optional) min
(optional) max
by 页码的相对值,可以有正负
to 页码的绝对值,-1代表最后一页(如果没有max的话, 才会返回-1;否则应该返回max-1)
"下一步"
request params
{
}
response params
{
  by: {{LONG}},
}
call_phone
name
(optional) index
-
"电话第一个"
request params
{
index:1
}
response params
{
call_phone_type:(normal/voice/video)
}
send_message
name
(optional) index
-
"发消息给第一个"
request params
{
index:1
}
read_message
(optional) index
-
"阅读第一条留言"
request params
{
index:1
}
view_photo
(optional) index
-
"查看第一张照片"
request params
{
index:1
}

真机调试过程

完成开发的app,可以在小度设备上完成测试

  • 在小度设备上安装开发完成的android app
  • 在Dbp上打开真机调试 真机调试
  • “打开技能调试模式”,听完设置成功的tts不要打断
  • “打开【调用名称】”,android app会被启动

新的安卓项目集成

在项目build.gradle中新增 maven库依赖

maven{ url 'https://dueros.baidu.com/maven/repository/maven-releases/'}

在app/build.gradle加入依赖

implementation 'com.alibaba:fastjson:1.1.71.android'
implementation 'com.baidu.duer.botsdk:bot-sdk-android:1.32.0@aar'

然后参考以上代码示例进行集成

导入demo dbp技能

为便于开发这尽快在本地跑通流程,在DBP创建技能可以直接选则导入技能分享链接,填入:“https://dueros.baidu.com/dbp/main/console?shareCode=FXXs” 可以快速导入demo app对应的BDP技能。

About


Languages

Language:Java 100.0%