AI出售比萨饼或Voximplant如何与Dialogflow交朋友

我们最近提供了一种称为Dialogflow连接器业务解决方案:一堆Google的Dialogflow和我们的Voximplant云。 连接器可以代替呼叫中心接线员工作,并接受复杂的订单。 这之所以成为可能,是因为Dialogflow允许您摆脱通常的IVR场景,在这种情况下,客户端被迫从给定的集合中命名单词,交互式菜单可以响应这些单词。 Google平台可以顺序地从客户端接收输入并将它们收集在一起-例如,在在线商店中形成订单。 您可能已经听说过流行语“ 插槽填充 ”,仅此而已。 正如我们为订购比萨饼的机器人一样,细节正在削减中等待您-以此类推,您可以煮类似的东西,并且很高兴电梯和“十一”的时代早已过去了...


电话号码


首先,您应该租用一个虚拟数字,机器人会将其“应答”到该虚拟数字。 为此,请在Voximplant管理面板的“号码”菜单中单击“购买电话号码”。


在新屏幕上,将开关置于“测试号码”位置-这将允许您租用虚拟号码。


虚拟号码非常便宜,可以让您在我们的平台上全面测试任何解决方案。 租一个房间和更多...

...创建一个脚本


现在我们需要一个云方案,这是我们决策的核心。 将由他接听电话,识别语音并将其转移到Dialogflow。 该脚本必须在应用程序内部创建。 在左侧菜单中,选择“应用程序” ,创建一个新的应用程序并为其命名。


然后转到应用程序中的“脚本”选项卡,然后单击加号创建自己的脚本。 记住给它起一个名字,例如dialogflow。


是时候写代码了!

让我们连接AI模块-它包含Dialogflow的方法和事件-以及语音识别模块和player 。 我们将声明变量和棘手的wordend函数,该函数将接收一个输入量(pizza)和一个带有单词('margarita','margaritas','margaritas')的数组,并返回与案例编号匹配的单词。 这是必要的,这样机器人就不会说“ 4 margaritas”,而是正确发出“ 4 margaritas”。

require(Modules.AI); require(Modules.ASR); require(Modules.Player); let mycall = null, voice = Language.Premium.RU_RUSSIAN_YA_FEMALE, account_name = "", dialed_number = "", caller_id = "", flow, lastText = '', player function wordend(num, words) { return words[ ((num=Math.abs(num%100)) > 10 && num < 15 || (num%=10) > 4 || num === 0) + (num !== 1) ]; } 

现在添加传入呼叫的​​处理程序和startASR helper函数:

 VoxEngine.addEventListener(AppEvents.CallAlerting, (e) => { mycall = e.call; mycall.addEventListener(CallEvents.Connected, handleCallConnected); account_name = e.toURI.substring(e.toURI.indexOf('.') + 1); account_name = account_name.substring(0, account_name.indexOf('.')); dialed_number = e.destination; caller_id = e.callerid; mycall.answer(); }); function startASR() { mycall.removeEventListener(CallEvents.PlaybackFinished, startASR); mycall.sendMediaTo(flow); } 

发生Connected事件时,将调用handleCallConnected函数。 实际上,整个填充发生在其中:

  • 创建一个Dialogflow对象;
  • 合成语音向客户打招呼,并提出下订单;
  • 识别开始,客户下订单;
  • 客户词被传送到Dialogflow,出现一个发话槽;
  • 合成语音表示客户的命令和地址;
  • 机器人挂断,会话关闭。

功能清单:

handleCallConnected
function handleCallConnected(e) {
flow = AI.createDialogflow({
lang: "ru"
});
if (AI.Events.DialogflowResponse !== undefined)
flow.addEventListener(AI.Events.DialogflowResponse, (event) => {
if (event.response.queryResult !== undefined) {
let result = event.response.queryResult
if (result.queryText === undefined) {
if (result.languageCode !== undefined) startASR();
return
}
if (result.fulfillmentText !== undefined) {
try {
player = VoxEngine.createTTSPlayer(result.fulfillmentText, voice)
player.addMarker(-500)
player.addEventListener(PlayerEvents.PlaybackMarkerReached, startASR)
player.sendMediaTo(mycall)
} catch (err) {}
if (result.allRequiredParamsPresent == true &&
result.outputContexts !== undefined &&
result.parameters.PizzaType != undefined) {
let msg = " ";
for (let k = 0; k < result.parameters.PizzaType.length; k++) {
let count = result.parameters.count[k] !== undefined ? result.parameters.count[k] : 1
switch (count) {
case 1:
msg += " ";
break;
case 2:
msg += " ";
break;
default:
msg += count + " ";
break;
}
if (result.parameters.PizzaSize[k] !== undefined) {
switch (result.parameters.PizzaSize[k]) {
case "small":
msg += wordend(count, ['', '', '']);
break;
case "medium":
msg += wordend(count, ['', '', '']);
break;
case "large":
msg += wordend(count, ['', '', '']);
break;
}
}
msg += " "
switch (result.parameters.PizzaType[k]) {
case "margarita":
msg += wordend(count, ['', '', '']);
break;
case "fourcheese":
msg += wordend(count, ['', '', '']) + " ";
break;
case "vegetarian":
msg += wordend(count, [' ', ' ', ' ']);
break;
case "pepperoni":
msg += wordend(count, ['', '', '']) + " ";
break;
case "cheese":
msg += wordend(count, [' ', ' ', ' ']);
break;
case "chicken":
msg += wordend(count, ['', '', '']) + " ";
break;
}
if (k == result.parameters.PizzaType.length - 1) msg += " , "
else msg += " ";
}
msg = msg.slice(0, msg.length - 2);
if (result.parameters.time !== undefined && result.parameters.time != "") {
let time = new Date(result.parameters.time),
local = time.toTimeString()
local = local.split(":")
time = local[0] + ":" + local[1]
msg += ". " + time
}
if (result.parameters.deliveryaddress !== undefined) msg += ". " + result.parameters.deliveryaddress
msg += ". ?";
player.stop()
player = VoxEngine.createTTSPlayer(msg, voice)
player.addMarker(-500)
player.addEventListener(PlayerEvents.PlaybackMarkerReached, startASR)
player.sendMediaTo(e.call)
} else {
player.stop()
lastText = result.fulfillmentText
player = VoxEngine.createTTSPlayer(result.fulfillmentText, voice)
if (result.action == "pizzaorder.pizzaorder-yes") {
player.addEventListener(PlayerEvents.PlaybackFinished, () => mycall.hangup())
player.sendMediaTo(e.call)
} else {
player.addMarker(-500)
player.addEventListener(PlayerEvents.PlaybackMarkerReached, startASR)
player.sendMediaTo(e.call)
}
}
}
}
})
player = VoxEngine.createTTSPlayer("! , !", voice);
player.addMarker(-500);
player.addEventListener(PlayerEvents.PlaybackMarkerReached, startASR);
player.sendMediaTo(e.call);
mycall.record();
mycall.addEventListener(CallEvents.Disconnected, (event) => {
VoxEngine.terminate();
})
}


剩下的很少了。 转到“路由”选项卡->“创建”。 带有表格的模态窗口将会出现。 可以通过类比来指定名称-dialogflow-rule。 保留默认掩码,最重要的是附加dialogflow脚本。 单击“创建规则”,模式窗口将关闭。


现在,您需要将购买的号码附加到应用程序。 为此,请转到应用程序内的“数字”部分,单击“可用”,然后单击选定数字旁边的“附加”。 将打开一个模式窗口,仅在此处选择所需的规则并单击“附加”。


点击“保存”。 现在,脚本知道需要什么来响应您租用的任何拨号号码。 鉴于我们只有一个号码,这就是我们所需要的。

太好了,现在一切都连接在一起,应该可以正常工作!

对话流程代理


就Dialogflow而言,代理是机器人。 我们已经详细描述了如何创建代理以及如何与他通信,但是这次我们建议使用我们的工件。

您需要在dialogflow.com上注册并创建一个新代理。 不要忘记指定俄语:


默认情况下,代理不知道单个语句(意图),并且通常不执行任何操作。 下载我们代理商的资产并将其上传到您的资产 :为此,在代理商的设置中,转到“导出和导入”标签->“从ZIP导入”。


现在,您有一套订购披萨的俗语! 您可以在“意图”部分中进行研究; 请注意,代理具有辅助语句pizza.sizehelppizza.typehelp 。 多亏了他们,在打下比萨饼店之后,客户可以问“您有哪种披萨”,然后机器人会告诉您菜单上的内容。

验证是否在“常规”选项卡上的设置中选择了第二版API。


最后, 点击几下即可下载您的Google服务帐户的JSON。

绑定代理到Voximplant应用程序


在Voximplant应用程序左侧的菜单中,选择“ Dialogflow连接器”,单击“添加”,以出现的模式形式加载JSON,然后再次单击“添加”。


您将看到JSON文件出现在列表中,这意味着它已附加到应用程序。

做完了! 配置了Dialoglow + Voximplant束,链的所有链接都组装在一起。

如果您懒得做所有这些步骤,则可以感觉到我们的比萨店演示:

  • 转到http://demos05.voximplant.com/pizza/ ;
  • 输入电话号码(在俄罗斯为7900 ...),然后单击“下一步”;
  • 从指定的号码拨打+74999384952;
  • 享受奇迹的机器人:)

Source: https://habr.com/ru/post/zh-CN412663/


All Articles