Giter VIP home page Giter VIP logo

bot-sdk's Introduction

度秘BOT SDK for PHP

这是一个帮助开发Bot的SDK,我们强烈建议您使用这个SDK开发度秘的Bot。当然,您可以完全自己来处理DuerOS的协议,自己完成session、nlu、result的处理,但是度秘的DuerOS对BOT的协议会经常进行升级,这样会给您带来一些麻烦。这个SDK会与DuerOS的协议一起升级,会最大限度减少对您开发bot的影响。

通过bot-sdk可以快速的开发bot

我们的目标是通过使用bot-sdk,可以迅速的开发一个bot,而不必过多去关注DuerOS对Bot的复杂协议。我们提供如下功能:

  • 封装了DuerOS的request和response
  • 提供了session简化接口
  • 提供了nlu简化接口
    • slot 操作
    • nlu理解交互接口(ask)
  • 提供了多轮对话开发接口
  • 提供了事件监听接口

安装、使用BOT SDK进行开发

度秘BOT SDK采用PSR-4规范自动加载 , PHP版本确保在5.4.0及以上。要验证请求参数来自DuerOS,php还得支持openssl扩展。使用composer执行如下命令进行安装:

composer require dueros/bot-sdk

为了开始使用BOT SDK,你需要先新建一个php文件,比如文件名是Bot.php。你先需要require autoload.php文件,这个文件一般在vendor目录,如果没有这个目录,请先执行composer dump-autoload。

require 'vendor/autoload.php';

class Bot extends Baidu\Duer\Botsdk\Bot{
    /**
     * $postData可以不传,由于DuerOS对bot是post请求,sdk默认自动获取
     */
    public function __construct($postData = []) {
       parent::__construct($postData); 

       // 开启校验请求参数签名
       // php 得支持open ssl扩展
       $this->certificate->enableVerifyRequestSign();
    }
}

需要继承Baidu\Duer\Botsdk\Bot。 下一步,我们处理意图。Bot-sdk提供了一个函数来handle这些意图。比如,为新建闹钟,创建一个handler,在构造函数中添加:

use \Baidu\Duer\Botsdk\Card\TextCard;

$this->addIntentHandler('remind', function(){
    $remindTime = $this->getSlot('remind_time');
   
    if($remindTime) {
        $card = new TextCard('创建中');
        return [
            'card' => $card,
        ];
    }
});

/**
 * 或者,可以不通过匿名函数,还支持传入成员函数名
 */

$this->addIntentHandler('remind', 'create');

//定义一个成员函数
public function create(){
    $remindTime = $this->getSlot('remind_time');
    return [...];
}

这里addHandler可以用来建立(intent) => handler的映射,第一个参数是条件,如果满足则执行对应的回调函数(第二个参数)。 其中,$this指向当前的Bot,getSlot继承自父类Bot,通过slot名字来获取对应的值。回调函数返回值是一个数组,可以包含多个字段,比如:carddirectivesoutputSpeechreprompt

template展现模版 为了更好的在有屏设备端上展现技能,DuerOS提供了多种展现模板供开发者使用。展现模板分body template和list template两种类型。其中body template由图片和文字组成,list template由一系列list item组成,每个list item由图片和文字组成。不同的展现模板适合不同的场景,开发者可以根据技能展现的需求选择合适的模板。关于模板的详细功能和展现效果可以参考DuerOS模板文档,https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-custom/display-template_markdown。

文本展现模板

BodyTemplate1

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate1;

$bodyTemplate = new BodyTemplate1();
//设置模版token
$bodyTemplate->setToken('token');
//设置模版背景图片
$bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$bodyTemplate->setTitle('托尔斯泰的格言');
//设置模版plain类型的文本
$bodyTemplate->setPlainTextContent('拖尔斯泰-理想的书籍是智慧的钥匙'); 
//定义RenderTemplate指令
$directive = new RenderTemplate($bodyTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是BodyTemplate1模板',
];

上图下文模版

BodyTemplate2

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate2;

$bodyTemplate = new BodyTemplate2();
//设置模版token
$bodyTemplate->setToken('token');
//设置模版展示图片
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//or 图片设置宽和高
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg', 200, 200);
//设置模版背景图片
$bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$bodyTemplate->setTitle('托尔斯泰的格言');
//设置模版plain类型的文本结构
$bodyTemplate->setPlainContent('拖尔斯泰-理想的书籍是智慧的钥匙'); 
//定义RenderTemplate指令
$directive = new RenderTemplate($bodyTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是BodyTemplate2模板',
];

左图右文模版

BodyTemplate3

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate3;

$bodyTemplate = new BodyTemplate3();
//设置模版token
$bodyTemplate->setToken('token');
//设置模版展示图片
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//or 图片设置宽和高
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg', 200, 200);

//设置模版背景图片
$bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$bodyTemplate->setTitle('托尔斯泰的格言');
//设置模版plain类型的文本结构
$bodyTemplate->setPlainContent('拖尔斯泰-理想的书籍是智慧的钥匙');  
//定义RenderTemplate指令
$directive = new RenderTemplate($bodyTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是BodyTemplate3模板',
];

右图左文

BodyTemplate4

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate4;

$bodyTemplate = new BodyTemplate4();
//设置模版token
$bodyTemplate->setToken('token');
//设置模版展示图片
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//or 图片设置宽和高
$bodyTemplate->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg', 200, 200);

//设置模版背景图片
$bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$bodyTemplate->setTitle('托尔斯泰的格言');
//设置模版plain类型的文本结构
$bodyTemplate->setPlainContent('拖尔斯泰-理想的书籍是智慧的钥匙'); 
//定义RenderTemplate指令
$directive = new RenderTemplate($bodyTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是BodyTemplate4模板',
];

图片模板

BodyTemplate5

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate5;

$bodyTemplate = new BodyTemplate5();
//设置模版token
$bodyTemplate->setToken('token');
//模版图片数组添加一张图片
$bodyTemplate->addImages('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版背景图片
$bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
/设置模版标题
$bodyTemplate->setTitle('托尔斯泰的格言');
//定义RenderTemplate指令
$directive = new RenderTemplate($bodyTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是BodyTemplate5模板',
];

横向列表模板

ListTemplate1

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\ListTemplate1;
use \Baidu\Duer\Botsdk\Directive\Display\Template\ListTemplateItem;

$listTemplate = new ListTemplate1();
//设置模板token
$listTemplate->setToken('token');
//设置模板背景图
$listTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$listTemplate->setTitle('托尔斯泰的格言');

//设置模版列表数组listItems其中一项,即列表的一个元素
$listTemplateItem = new ListTemplateItem();
$listTemplateItem->setToken('token');
$listTemplateItem->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//or 图片设置宽和高
$listTemplateItem->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg', 200, 200);

$listTemplateItem->setPlainPrimaryText('一级标题');
$listTemplateItem->setPlainSecondaryText('二级标题');

//把listTemplateItem添加到模版listItems
$listTemplate->addItem($listTemplateItem);
//定义RenderTemplate指令
$directive = new RenderTemplate($listTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是ListTemplate1模板',
];

纵向列表模板

ListTemplate2

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\ListTemplate2;
use \Baidu\Duer\Botsdk\Directive\Display\Template\ListTemplateItem;

$listTemplate = new ListTemplate2();
//设置模板token
$listTemplate->setToken('token');
//设置模板背景图
$listTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
//设置模版标题
$listTemplate->setTitle('托尔斯泰的格言');

//设置列表数组listItems其中一项,即列表的一个元素
$listTemplateItem = new ListTemplateItem();
$listTemplateItem->setToken('token');
$listTemplateItem->setImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
$listTemplateItem->setPlainPrimaryText('一级标题');  
$listTemplateItem->setPlainSecondaryText('二级标题'); 
$listTemplateItem->setPlainTertiaryText('三级标题');

//把listTemplateItem添加到模版listItems
$listTemplate->addItem($listTemplateItem);
//定义RenderTemplate指令
$directive = new RenderTemplate($listTemplate);
return [
    'directives' => [$directive],
    'outputSpeech' => '这是ListTemplate2模板',
];

Display.ElementSelected事件

当点击模板列表中的卡片时,DuerOS会向技能发送Display.ElementSelected事件,请求技能进行相应的处理。

use \Baidu\Duer\Botsdk\Directive\Display\RenderTemplate;
use \Baidu\Duer\Botsdk\Directive\Display\Template\BodyTemplate1;

$this->addEventListener('Display.ElementSelected', function($event){
    $token = $event['token'];
    $bodyTemplate = new BodyTemplate1();
    //设置模版token
    $bodyTemplate->setToken('token');
    //设置模版背景图片
    $bodyTemplate->setBackGroundImage('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg');
    //设置模版标题
    $bodyTemplate->setTitle('托尔斯泰的格言');
    //设置模版plain类型的文本
    $bodyTemplate->setPlainTextContent('拖尔斯泰-理想的书籍是智慧的钥匙'); 
    //定义RenderTemplate指令
    $directive = new RenderTemplate($bodyTemplate);
    return [
        'directives' => [$directive],
        'outputSpeech' => '点击后展现',
    ];
});

card展现卡片 在有屏设备上,您的技能在回复用户时,可以通过使用卡片展现更生动、丰富的内容。常用的展现卡片类型有文本卡片、标准卡片、标准列表卡片、图片卡片。展现卡片随Response消息一起发送给DuerOS。具体展现卡片的功能和展示效果可以参考DuerOS展现卡片文档,https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-custom/cards_markdown。

文本卡片

TextCard

use \Baidu\Duer\Botsdk\Card\TextCard;
$card = new TextCard('content');

//or
$card = new TextCard();
//设置content
$card->setContent('Content');
//设置链接
$card->setAnchor('http://www.baidu.com');
$card->setAnchor('http://www.baidu.com', 'showtext');
//设置cueWords
$card->addCueWords('hint1');
$card->addCueWords(['hint1', 'hint2']);

return [
    'card' => $card,
];

标准卡片

StandardCard

use \Baidu\Duer\Botsdk\Card\StandardCard;
$card = new StandardCard();

$card->setTitle('title');
$card->setContent('content');
$card->setImage('http://www...');
$card->setAnchor('http://www.baidu.com');

return [
    'card' => $card,
];

列表卡片

ListCard

use \Baidu\Duer\Botsdk\Card\ListCard;
use \Baidu\Duer\Botsdk\Card\ListCardItem;

$card = new ListCard();
$item = new ListCardItem();
$item->setTitle('title')
    ->setContent('content')
    ->setUrl('http://www')
    ->setImage('http://www.png');

$card->addItem($item);
$card->addItem($item);

return [
    'card' => $card,
];

列表卡片点击事件处理

Screen.LinkClicked 如果卡片或者卡片列表配置了URL地址,当用户点击卡片或者卡片列表时,DuerOS会向技能发送Screen.LinkClicked事件,技能收到该事件后会返回需要展现的内容。

use \Baidu\Duer\Botsdk\Card\StandardCard;
$this->addEventListener('Screen.LinkClicked', function($event){
    $url = $event['url'];
    $token = $event['token'];

    $card = new StandardCard();
    $card->setTitle('title');
    $card->setContent('content');

    return [
        'card' => $card,
    ];
});

图片卡片

ImageCard

$card = new ImageCard();
$card->addItem('http://src.image', 'http://thumbnail.image');

directive返回指令

音乐播放指令

AudioPlayer.Play

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Play;

$directive = new Play('http://www.music', Play::REPLACE_ALL); 
return [
    'directives' => [$directive],
    'outputSpeech' => '正在为你播放歌曲',
];

渲染音频播放器的主界面

AudioPlayer.Play指令中增加playerInfo信息

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Play;
use \Baidu\Duer\Botsdk\Directive\AudioPlayer\PlayerInfo;
use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Control\PlayPauseButton;
use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Control\NextButoon;
use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Control\PreviousButton;
//创建音频播放指令
$directive = new Play('http://www.music', Play::REPLACE_ALL);

//音频播放器的主界面
$playerInfo = new PlayerInfo();

//创建暂停按钮
$playpause = new PlayPauseButton();
$previous = new PreviousButton();
$controls = array(
    $playpause, 
    $previous
);

//设置PlayerInfo的Controls内容
$playerInfo->setControls($controls);

//也可以使用addControl,增加一个control
$playerInfo->addControl(new NextButoon());

$playerInfo->setTitle('周杰伦');
$playerInfo->setTitleSubtext1('七里香');

//设置Play指令的PlayerInfo
$directive->setPlayerInfo($playerInfo);
return [
    'directives' => [$directive],
    'outputSpeech' => '周杰伦,七里香',
];

停止端上的播放音频

AudioPlayer.Stop

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Stop;

$directive = new Stop(); 
return [
    'directives' => [$directive],
    'outputSpeech' => '已经停止播放',
];

音频事件处理

Bot可以通过addEventListener接口来监听音频播放的时的事件,下面以AudioPlayer.PlaybackNearlyFinished事件举例。

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Play;

$this->addEventListener('AudioPlayer.PlaybackNearlyFinished', function($event){
    $token = $event['token'];
    $directive = new Play('http://www.audio', Play::ENQUEUE); 
    return [
        'directives' => [$directive],
    ];
});

视频播放

VideoPlayer视频播放提供了VideoPlayer指令接口和VideoPlayer事件接口。VideoPlayer指令是技能向DuerOS发送的,对视频进行控制的指令,如播放指令、停止播放指令等。DuerOS收到指令后会转化成端上能识别的播放指令,对视频进行相应的控制。VideoPlayer事件是指在视频播放过程中触发一系列事件,DuerOS会将这些事件上报给技能,请求技能进行处理。具体协议内容可以参考视频协议文档,https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-custom/videoplayer_markdown。

视频播放指令

VideoPlayer.Play

use \Baidu\Duer\Botsdk\Directive\VideoPlayer\Play;

$directive = new Play('http://www.video', Play::REPLACE_ALL); 
return [
    'directives' => [$directive],
    'outputSpeech' => '正在为你播放视频',
];

停止端上播放的视频

VideoPlayer.Stop

use \Baidu\Duer\Botsdk\Directive\VideoPlayer\Stop;

$directive = new Stop(); 
return [
    'directives' => [$directive],
    'outputSpeech' => '已经停止播放',
];

视频事件处理

Bot可以通过addEventListener接口来监听视频播放的时的事件,下面以VideoPlayer.PlaybackNearlyFinished事件举例。

use \Baidu\Duer\Botsdk\Directive\VideoPlayer\Play;

$this->addEventListener('VideoPlayer.PlaybackNearlyFinished', function($event){
    $token = $event['token'];
    $offsetInMilliseconds = $event['offsetInMilliseconds'];
    $directive = new Play('http://www.video', Play::ENQUEUE); 
    return [
        'directives' => [$directive],
    ];

});

获取端屏幕展现状态

$screenContext = $this->request->getScreenContext();

渲染引导词

使用Hint指令渲染引导词

use \Baidu\Duer\Botsdk\Directive\Display\Hint;
use \Baidu\Duer\Botsdk\Card\TextCard;

$directive = new Hint(['hint1', 'hint2']);
return [
    'card' => new TextCard('测试Hint指令'),
    'directives' => [$directive],
];

设置好handler之后,就可以实例化刚刚定义的Bot,在webserver中接受DuerOS来的请求。比如,新建一个文件index.php,拷贝如下代码:

$bot = new Bot();

header("Content-Type: application/json");
print $bot->run();

利用php内建的webserver,运行如下命令:

php -S 0.0.0.0:8000 index.php

返回speech

outputSpeech

上面例子,除了返回card之外,还可以返回outputSpeech,让客户端播报tts:

return [
    'outputSpeech' => '请问你要干啥呢',
    //或者ssml
    'outputSpeech' => '<speak>请问你要干啥呢</speak>',
];

reprompt

当客户端响应用户后,用户可能会一段时间不说话,如果你返回了reprompt,客户端会提示用户输入

return [
    'reprompt' => 'hello,请问你要干啥呢',
    //或者ssml
    'reprompt' => '<speak>hello,请问你要干啥呢</speak>',
];

Lanuch & SessionEnd

bot开始服务

当bot被@(通过bot唤醒名打开时),DuerOS会发送LanuchRequest给bot,此时,bot可以返回欢迎语或者操作提示:

$this->addLaunchHandler(function(){
    return [
        'outputSpeech' => '<speak>欢迎光临</speak>' 
    ];

});

bot 结束服务

当用户表达退出bot时,DuerOS会发送SessionEndedRequest

$this->addSessionEndedHandler(function(){
    // clear status
    // 清空状态,结束会话。 
    return null; 
});

使多轮对话管理更加简单

往往用户一次表达的需求,信息不一定完整,比如:'给我创建一个闹钟',由于query中没有提醒的时间,一个好的bot实现会问用户:'我应该什么时候提醒你呢?',这时用户说明天上午8点,这样bot就能获取设置时间,可以为用户创建一个闹钟。比如,你可以这样来实现:

//提醒意图而且有提醒时间slot
$this->addIntentHandler('remind', function(){
    $remindTime = $this->getSlot('remind_time');
    if($remindTime) {
        return [/*设置闹钟指令*/];
    }

    //当前面条件不满足(没有提醒时间),会执行这个handler
    $this->nlu->ask('remind_time');
    $card = new TextCard('要几点的闹钟呢?');
    return [
        'card' => $card,
        'outputSpeech' => '要几点的闹钟呢?',
    ];
});

//监听events
$this->addEventListener('Alerts.SetAlertSucceeded', function($event){
    //do sth. eg. set alert status 
    $card = new TextCard('闹钟创建成功');
    return [
        'card' => $card
    ];
});

$this->addEventListener('AudioPlayer.PlaybackNearlyFinished', function($event){
    $offset = $event['offsetInMilliSeconds'];
    //todo sth,比如:返回一个播放enqueue
    //
    $directive = new Play('ENQUEUE'); 
    $directive->setUrl('http://wwww');
    return [
        'directives' => [$directive],
	];
});

Bot-sdk会根据通过addIntentHandler添加handler的顺序来遍历所有的检查条件,寻找条件满足的handler来执行回调,并且当回调函数返回值不是null时结束遍历,将这个不为null的值返回。

NLU会维护slot的值,merge每次对话解析出的slot,你可以不用自己来处理,DuerOS每次请求Bot时会将merge的slot都下发。session内的数据完全由你来维护,你可以用来存储一些状态,比如打车Bot会用来存储当前的订单状态。你可以通过如下接口来使用slotsession

//slot
getSlot('slot name');
setSlot('slot name', 'slot value');// 如果没有找到对应的slot,会自动新增一个slot

//session
getSessionAttribute('key');
setSessionAttribute('key', 'value');
//or
setSessionAttribute('key.key1', 'value');
getSessionAttribute('key.key1');

//清空session
clearSession();

你的Bot可以订阅端上触发的事件,通过接口addEventListener实现,比如端上设置闹钟成功后,会下发SetAlertSucceeded的事件,Bot通过注册事件处理函数,进行相关的操作。如果不想每个事件都进行处理可以通过接口addDefaultEventListener来统一处理,没有通过addEventListener订阅的事件。

$this->addDefaultEventListener(function($event){
    $this->waitAnswer();  //不结束回话,即shouldEndSession为false。
    $this->setExpectSpeech(false);  //端关闭麦克风,不继续监听
});

NLU交互协议

在DuerOS Bot Platform平台,可以通过nlu工具,添加了针对槽位询问的配置,包括:

  • 是否必选,对应询问的默认话术
  • 是否需要用户确认槽位内容,以及对应的话术
  • 是否需要用户在执行动作前,对所有的槽位确认一遍,以及对应的话术

针对填槽多轮,Bot发起对用户收集、确认槽位(如果针对特定槽位有设置确认选项,就进行确认)、确认意图(如果有设置确认选项)的询问,bot-sdk提供了方便的快捷函数支持:

注意:一次返回的对话directive,只有一个,如果多次设置,只有最后一次的生效

ask

多轮对话的bot,会通过询问用户来收集完成任务所需要的槽位信息,询问用户的特点总结为3点,ask:问一个特定的槽位。比如,打车服务收到用户的打车意图的时候,发现没有提供目的地,就可以ask destination(目的地的槽位名):

//打车意图,但是没有提供目的地
$this->addIntentHandler('rent_car.book', function(){
    $endPoint = $this->getSlot('destination');
    if(!$this->endPoint) {
        //询问slot: destination
        $this->nlu->ask('destination');
    
        $card = new TextCard('打车去哪呢');
        return [
            'card' => $card
        ];
    }
});

delegate

将处理交给DuerOS的对话管理模块DM(Dialog Management),按事先配置的顺序,包括对缺失槽位的询问,槽位值的确认(如果设置了槽位需要确认,以及确认的话术),整个意图的确认(如果设置了意图需要确认,以及确认的话术。比如可以将收集的槽位依次列出,等待用户确认)

$this->addIntentHandler('your intent name', function(){
    if(!$this->request->isDialogStateCompleted()) {
        // 如果使用了delegate 就不再需要使用setConfirmSlot/setConfirmIntent,否则返回的directive会被后set的覆盖。
        return $this->setDelegate();
    }

    //do sth else
});

confirm slot

主动发起对一个槽位的确认,此时还需同时返回询问的outputSpeach。主动发起的确认,DM不会使用默认配置的话术。

$this->addIntentHandler('your intent name', function(){
    if($this->getSlot('money') > 10000000000) {
        $this->setConfirmSlot('money');
        return [
            'outputSpeech' => '你确认充话费:10000000000',
        ];
    }

    //do sth else
});

confirm intent

主动发起对一个意图的确认,此时还需同时返回询问的outputSpeach。主动发起的确认,DM不会使用默认配置的话术。

一般当槽位填槽完毕,在进行下一步操作之前,一次性的询问各个槽位,是否符合用户预期。

$this->addIntentHandler('your intent name', function(){
    $money = $this->getSlot('money');
    $phone = $this->getSlot('phone');
    if($money && $phone) {
        $this->setConfirmIntent();
        return [
            'outputSpeech' => "你确认充话费:$money,充值手机:$phone",
        ];
    }

    //do sth else
});

插件

你还可以写插件(拦截器Intercept),干预对话流程、干预返回结果。比如,用户没有通过百度帐号登录,bot直接让用户去登录,不响应意图,可以使用LoginIntercept

public function __construct($postData = []) {
    parent::__construct($postData);
    $this->addIntercept(new Baidu\Duer\Botsdk\Plugins\LoginIntercept());
    //...
}

开发自己的拦截器,继承\Baidu\Duer\Botsdk\Intercept,通过重载preprocess,能够在处理通过addHandleraddEventListener添加的回调之前,定义一些逻辑。通过重载postprocess能够对回调函数的返回值,进行统一的处理:

class YourIntercept extends \Baidu\Duer\Botsdk\Intercept{
    public function preprocess($bot) {
        //$bot: 你的bot实例化对象
    }

    public function postprocess($bot, $result) {
        //maybe format $result
        return $result;
    }
}

intercept可以定义多个,执行顺序,以调用addIntercept的顺序来执行

如何调试

本地测试

bot-sdk提供了一个简单的工具,方便用户在没有接入DuerOS时调试自己的bot。 首先你需要通过PHP内置的webserver,将你的bot运行起来,这里假设是监听的8000端口。然后,构造你的NLUsession等数据,如个人所得税计算器bot构造的数据结构,具体可以参考samples/personal_income_tax中part目录的例子,比如:./post-part.sh part/create.php

<?php
return [
    'nlu' => [
        'name' => 'personal_income_tax.inquiry',
        'slots' => [
            [
                'name' => 'monthlysalary',
                'value' => '121212',
            ],
            [
                'name' => 'compute_type',
                'value' => '个税',
            ],
        ]
    ],
    'session' => [],
];

如何打印日志

bot-sdk提供了日志打印的工具,开发者可以直接使用,当然也可以用自己习惯的日志工具。一次请求只打印一条NOTICE日志;FATALWARN日志可以打印多条。

日志按小时切分,fatal,warn日志存储到一个文件,notice日志存储到一个文件。日志输出路径可以在构造函数中通过path参数指定。比如log/表示是Bot.php同级的log目录。

可以参考samples/personal_income_tax的例子

定义日志

//可以在构造函数中执行
$this->log = new Baidu\Duer\Botsdk\Log([
    //日志存储路径
    'path' => 'log/', 
    //日志打印最低输出级别
    'level' => Baidu\Duer\Botsdk\Log::NOTICE,
]);

统计耗时

//标记开始,search_t 是对应的字段名
$this->log->markStart('search_t');
$res = \Utils::curl(['url'=>$url, 'timeout'=>2000]);
//标记结束
$this->log->markEnd('search_t');

记录某个字段

//记录这次请求的query
$this->log->setField('query', $this->request->getQuery());

//获取某个字段的值,比如,获取统计的时间
$this->log->getField('search_t');

打印日志

最后将NOTICE日志打印出来

$bot->log->notice('remind');

打印fatal、warn

//test fatal log
$this->log->fatal("this is a fatal log");

数据统计

BotMonitor是什么

它可以帮助您收集和分析您开发的bot运行中产生的数据,帮助您实时查看应用运行状态,及时发现应用中存在的问题,提升>用户体验。目前,BotMonitor提供应用性能分析、用户行为统计。使用BotMonitor,您可以方便的在自己的DBP平台查看Bot的用户量、会话量、请求量、QPS以及Session的相关统计数据指标。

bot-sdk如何使用BotMonitor数据统计

在construct中使用如下方法

//$privateKey为私钥内容,0代表你的Bot在DBP平台debug环境,1或者其他整数代表online环境
$this->botMonitor->setEnvironmentInfo($privateKey, 0);
//环境信息配置完成后,你需要打开BotMonitor数据采集上报开关(默认是开启的,你可以根据自己需求打开或者关闭),true代表打开,false代表关闭
$this->botMonitor->setMonitorEnabled(true);

具体数据统计的说明和使用可以参考BotMonitor文档 https://packagist.org/packages/monitor/bot-monitor

bot-sdk's People

Contributors

wang79120846 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bot-sdk's Issues

【教程】如何使用Laravel 开发Dueros 技能

基础环境搭建

第一步

自行安装PHP 7.1.* 和 Nginx
相关教程: https://github.com/mmjjb/Centos7-PHP7.1-Nginx
为了开发简单,可以关闭SElinux
按照这个教程安装完成之后,还需要安装一下后面会用到的依赖

yum --enablerepo=remi-safe -y install php71-php-zip

第二步

安装composer, 方便安装相关PHP 开发依赖包,具体链接参考此处: https://pkg.phpcomposer.com/#how-to-install-composer
composer 建议全局安装

php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composer

修改composer服务 修改之后,可以有效加速相关依赖包的安装

composer config -g repo.packagist composer https://packagist.phpcomposer.com

第三步

安装Laravel 命令

composer global require "laravel/installer"

这个命令会安装一个laravel 命令,如果是最新的composer,命令应该会在$HOME/.config/composer/vendor/bin 文件夹下面,所以最好是把$HOME/.config/composer/vendor/bin 加入到PATH中去

第四步

创建一个Laravel 项目
我们可以创建一个/www/sites的目录来放网站源码【如果开启了SElinux,可以直接在/var/www 目录下面创建项目】

cd /www/sites/
laravel new dueros.bot

第五步

配置laravel 项目程序目录,很重要 不然会报错的;
给这两个文件配置读写权限:storage 目录和 bootstrap/cache 目录应该允许 Web 服务器写入,否则 Laravel 将无法运行。

cd /www/sites/dueros.bot
chmod -R 777 storage
chmod -R 777 bootstrap/cache

第六步

配置Nginx Server

server {
    listen 80;
    server_name www.domain.com;
    
    #charset koi8-r;
    #access_log  /www/logs/www.domain.com.access.log  main;
    #error_log  /www/logs/www.domain.com-error.log error;
    root /www/sites/dueros.bot/public/;
    index index.php;
    location / {
            try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
            # With php5-cgi alone:
            fastcgi_pass 127.0.0.1:9000;
            # With php5-fpm:
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SERVER_NAME $host;
    }
}

重新启动一下nginx服务,这样laravel的基础项目我们就创建好了

sudo service nginx reload

重启之后,访问nginx server 里面配置域名,应该就可以访问到一个默认如下的网页了
image

现在就可以开始做和Dueros 相关的工作了

请你可以先在Dueros的DBP平台创建好一个测试技能待用,
现在所有的工作都在基于上面的/www/sites/dueros.bot 目录下完成了。
我们先查看一下这个目录都包含那些文件

drwxrwxr-x  6 somebody somebody   4096 Oct 11 09:57 app
-rw-rw-r--  1 somebody somebody   1686 Oct 11 09:57 artisan
drwxrwxr-x  3 somebody somebody   4096 Oct 11 09:57 bootstrap
-rw-rw-r--  1 somebody somebody   1380 Oct 11 09:57 composer.json
-rw-rw-r--  1 somebody somebody 138803 Oct 11 09:57 composer.lock
drwxrwxr-x  2 somebody somebody   4096 Oct 11 09:57 config
drwxrwxr-x  5 somebody somebody   4096 Oct 11 09:57 database
-rw-rw-r--  1 somebody somebody   1129 Oct 11 09:57 package.json
-rw-rw-r--  1 somebody somebody   1040 Oct 11 09:57 phpunit.xml
drwxrwxr-x  4 somebody somebody   4096 Oct 11 09:57 public
drwxrwxr-x  5 somebody somebody   4096 Oct 11 09:57 resources
drwxrwxr-x  2 somebody somebody   4096 Oct 11 09:57 routes
-rw-rw-r--  1 somebody somebody    563 Oct 11 09:57 server.php
drwxrwxrwx  5 somebody somebody   4096 Oct 11 09:57 storage
drwxrwxr-x  4 somebody somebody   4096 Oct 11 09:57 tests
drwxrwxr-x 36 somebody somebody   4096 Oct 11 09:57 vendor
-rw-rw-r--  1 somebody somebody    549 Oct 11 09:57 webpack.mix.js
-rw-rw-r--  1 somebody somebody 219070 Oct 11 09:57 yarn.lock

第七步

执行以下命令安装dueros的bot-sdk

composer require dueros/bot-sdk

第八步

现在我们就来开发dueros的程序
我们先创建一个放Dueros 程序的目录, 执行下面的命令

cd /www/sites/dueros.bot/app/Http/Controllers
mkdir Dueros

我们把程序都放在Dueros这个目录中
进入Dueros 目录

cd Dueros

新建一个文件Bot.php 内容如下

<?php

namespace App\Http\Controllers\Dueros;

use Baidu\Duer\Botsdk\Bot as DuerosBot;

class Bot extends DuerosBot
{
    public function __construct($postData = [])
    {
        parent::__construct($postData);
        $this->addLaunchHandler(function () {
            return [
                    'card'         => null,
                    'outputSpeech' => 'Hi!',
                    'directives'   => [],
                    'resource'     => null,
                    'reprompt'     => null,
                ];
        });
        $this->addSessionEndedHandler(function () {
            return [
                    'card'         => null,
                    'outputSpeech' => 'Bye!',
                    'directives'   => [],
                    'resource'     => null,
                    'reprompt'     => null,
                ];
        });
        $this->addIntentHandler('say_hello', function () {
            return [
                'card'         => null,
                'outputSpeech' => 'Hello Word!',
                'directives'   => [],
                'resource'     => null,
                'reprompt'     => null,
            ];
        });
    }
}

继续在这个目录新建一个文件BotController.php, 这个文件将用来接收相关的网络请求,程序如下

<?php

namespace App\Http\Controllers\Dueros;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class BotController extends Controller
{

    public function post(Request $request)
    {
        $postData = file_get_contents('php://input');
        Log::info($postData);
        $bot = new Bot();

        return $bot->run();
    }
}

然后修改Laravel的路由配置,来接收post 请求
首先进入这个目录

cd /www/sites/dueros.bot/routes/

然后修改里面的api.php, 添加以下路由

Route::group([
        'namespace' => 'Dueros',
], function () {
    Route::post('/hi', 'BotController@post');
});

至此我们已经开发完成

第九步

现在我们就可以开始测试了,把路径填入到Dueros DBP开发平台的webhook 服务里面。路径地址型如: http://www.domain.com/api/hi
你也可以使用Postman 直接发送POST 请求到此地址http://www.domain.com/api/hi进行测试

Incorrect call ?

bot-sdk/src/Bot.php

Lines 651 to 662 in 98eb71f

public function addExpectTextResponse($text){
$this->response->addExpectTextResponse($text);
}
/**
* 技能所期待的用户回复,技能将该信息反馈给DuerOS,有助于DuerOS在语音识别以及识别纠错时向该信息提权。
* 槽位类型
* @param string $slot 槽位类型回复表达的槽位名称。
*/
public function addExpectSlotResponse($slot){
$this->response->addExpectTextResponse($slot);
}

这两个函数都调用了 $this->response->addExpectTextResponse($slot);
addExpectSlotResponse 貌似应该调用 $this->response->addExpectSlotResponse才对吧?

No access right to write file

This is the exception:

file_put_contents(/www/sites/*******/vendor/dueros/bot-sdk/src/f4354d10b358b0e176fbd65699535113): 
failed to open stream: Permission denied {"exception":"[object] (ErrorException(code: 0): file_put_contents(/www/sites/*******/vendor/dueros/bot-sdk/src/f4354d10b358b0e176fbd65699535113): 
failed to open stream: Permission denied at /www/sites/*******/vendor/dueros/bot-sdk/src/Certificate.php:62)

In my tech stack, the vendor directory is not writeable, I think there should a method to change the directory where to write the RSA key.

My dueros/bot-sdk version is: v2.1.8

Directives can't play multiple audio file

Example:

音乐播放指令
AudioPlayer.Play

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Play;

$directive = new Play('http://www.music', Play::REPLACE_ALL); 
return [
    'directives' => [$directive],
    'outputSpeech' => '正在为你播放歌曲',
];

My code:

use \Baidu\Duer\Botsdk\Directive\AudioPlayer\Play;

$directive = new Play('http://www.music1', Play::ENQUEUE); 
$directive2 = new Play('http://www.music2', Play::ENQUEUE); 
return [
    'directives' => [$directive, $directive2],
    'outputSpeech' => '正在为你播放歌曲',
];

As in my code, Dueros just play the first one music.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.