/**
* Copyright (c) 2017 Baidu, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const extend = require('node.extend');
/**
* 封装DuerOS 对query的解析结果
* 只有IntentRequest 才有Nlu结构
**/
class Nlu{
/**
* 构造函数
*
* @param {array} intents IntentRequest 中的intents
**/
constructor (intents) {
this._data = extend(true, intents);
this.requestIntents = intents;
/**
* 记录返回的指令
**/
this._directive = null;
}
/**
* 通过槽位名设置一个槽位的值,如果没有此槽位,新增一个
*
* @param {string} field 槽位名
* @param {string} value 值
* @param {Integer} index 第几个intent,默认第一个
* @public
**/
setSlot (field, value, index = 0) {
if (!field || !this._data[index]) {
return;
}
let slots = this._data[index].slots;
if(!slots) {
return;
}
if (slots[field]) {
slots[field].value = value;
}
//add a new field
slots[field] = {
name: field,
value: value
}
}
/**
* 通过槽位名获取一个槽位的值
*
* @param {string} field 槽位名
* @param {Integer} index 第几个intent,默认第一个
* @return {null|string}
* @public
**/
getSlot (field, index = 0) {
if (!field || !this._data[index]) {
return;
}
let slots = this._data[index].slots;
if(!slots || !slots[field]) {
return;
}
return slots[field].value;
}
/**
* 获取DuerOS请求中的意图名
*
* @return {string|null}
* @public
**/
getIntentName () {
if(this._data[0]) {
return this._data[0].name;
}
}
/**
* Bot是否在询问用户,等待用户的回复
*
* @return {Boolean}
**/
hasAsked () {
return !!this._directive;
}
/**
* Bot主动发起对一个槽位的询问。比如:打车时询问用户目的地
*
* @example
* this.ask('destination');
*
* @param {string} slot 槽位名
* @return {null}
* @public
**/
ask (slot) {
if (!slot) {
return;
}
this._directive = {
type: 'Dialog.ElicitSlot',
slotToElicit: slot,
updatedIntent: this._getUpdateIntent()
};
}
/**
* @return {array}
**/
toDirective () {
return this._directive;
}
/**
* @return {Object}
**/
toUpdateIntent () {
return {
intent: this._data[0]
};
}
/**
* @return {array}
* @private
**/
_getUpdateIntent () {
return {
name: this.getIntentName(),
slots: this._data[0].slots,
};
}
/**
* 设置将对话的处理代理给Dialog Management(DM)。
* 按事先配置的顺序,包括对缺失槽位的询问,槽位值的确认(如果设置了槽位需要确认,以及确认的话术)
* 和整个意图的确认(如果设置了意图需要确认,以及确认的话术。比如可以将收集的槽位依次列出,等待用户确认)
*
* @public
**/
setDelegate () {
this._directive = {
type: 'Dialog.Delegate',
updatedIntent: this._getUpdateIntent()
};
}
/**
* 主动发起对一个槽位的确认,此时还需同时返回询问的outputSpeach。
* 主动发起的确认,DM不会使用默认配置的话术。
*
* @example
* this.setConfirmSlot('destination');
*
* @param {string} field 槽位名
* @public
**/
setConfirmSlot (field) {
let slots = this._data[0].slots;
if(!slots) {
return;
}
if(slots[field]) {
this._directive = {
type: 'Dialog.ConfirmSlot',
slotToConfirm: field,
updatedIntent: this._getUpdateIntent()
};
}
}
/**
* 主动发起对一个意图的确认,此时还需同时返回询问的outputSpeach。
* 主动发起的确认,DM不会使用默认配置的话术。
* 一般当槽位填槽完毕,在进行下一步操作之前,一次性的询问各个槽位,是否符合用户预期。
*
* @example
* this.setConfirmIntent();
*
* @public
**/
setConfirmIntent () {
this._directive = {
type: 'Dialog.ConfirmIntent',
updatedIntent: this._getUpdateIntent()
};
}
/**
* 获取槽位的确认状态
* @desc 获取一个slot对应的confirmationStatus
* @param {string} field 槽位名
* @return {string} 槽位的confirmationStatus
*/
getSlotConfirmationStatus(field, index = 0) {
if(!field){
return;
}
let slots = this._data[index].slots;
return slots[field].confirmationStatus;
}
/**
* 获取意图的确认状态
* @desc 获取一个intent对应的confirmationStatus
* @return {string 意图的confirmationStatus
**/
getIntentConfirmationStatus(index = 0) {
return this._data[index].confirmationStatus;
}
}
Nlu.SLOT_NOT_UNDERSTAND = 'da_system_not_understand';
module.exports = Nlu;