集成Alexa与Voiceflow – CodesCode
如何将Alexa和Voiceflow集成,将注意力放在对话设计而非编码上这将帮助你提升对话品质!
Alexa有很多功能,但是创建复杂对话并不容易。Voiceflow是一个无需编写代码就能创建复杂对话的工具。该集成允许您在Voiceflow中创建对话,然后部署到Alexa。
因此,在这个仓库中,你将找到一个使用Alexa Skills Kit SDK for Node.js和调用Voiceflow的对话管理器API集成Alexa和Voiceflow的简单示例。
先决条件
- 您需要在Voiceflow上拥有一个账户
- 您需要在Alexa Developer上拥有一个账户
- 您的计算机上需要安装Node.js和npm/yarn
Voiceflow项目
在Voiceflow上,您需要创建一个项目并创建一段对话。您可以按照Voiceflow快速入门创建一段简单的对话。在Voiceflow中,您唯一需要关心的是设计对话。
在这个示例中,我们将创建一段简单的对话,询问用户关于Pokemon的信息。对话将会是这样的:
NLU
Voiceflow拥有一个内置的NLU,由于我们将使用对话管理器API调用Voiceflow,因此我们需要在Voiceflow和Alexa上设计我们的NLU。
按照示例,我们将创建一个名为info_intent
的意图和一个名为pokemon
的插槽,该插槽将被用户要了解的Pokemon的名称填充:
对话管理器API
对话管理器API是一个REST API,可以让您与Voiceflow进行交互。您可以在这里找到文档。
DM API会自动创建和管理对话状态。对DM API的相同请求可能会产生不同的响应,这取决于您的图表逻辑和API之前收到的请求。
DM API的终端是:https://general-runtime.voiceflow.com/state/user/%7BuserID%7D/interact
可以发送不同类型的请求。要查看所有请求类型的列表,请查看下面的action字段的文档。
要启动对话,您应该发送一个启动请求。然后,要传递给您的用户响应,您应该发送一个文本请求。如果您拥有自己的NLU匹配,那么您可能想直接发送一个意图请求。
这里有一个请求的示例:
curl --request POST \ --url 'https://general-runtime.voiceflow.com/state/user/{userID}/interact?logs=off' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --header 'Authorization: VF.DM.96ds3423ds9423fs87492fds79792gf343' \ --data '{ "action": { "type": "launch" }, "config": { "tts": false, "stripSSML": true, "stopAll": true, "excludeTypes": [ "block", "debug", "flow" ] }}'
如您所见,您需要传递userID
和Authorization
头。该userID
是您想与之交互的用户ID。Authorization
头是您可以在Voiceflow项目设置中找到的API密钥。
您可以在voiceflow/project.vf
中找到我在本示例中使用的Voiceflow项目。
Alexa技能
要创建一个Alexa技能,您需要前往Alexa Developer并创建一个新的技能。请按照Alexa Developer控制台快速入门创建一个简单的技能。
NLU
我们需要在我们的Alexa Skill中复制Voiceflow NLU(意图和实体)。
正如您所看到的,我们正在使用SearchQuery
类型。此类型用于获取用户输入并直接发送到Voiceflow。您可以在这里找到有关该类型的更多信息。
Lambda代码
Alexa Skill代码将是通用的,这意味着该Alexa Skill代码可以与任何Voiceflow项目一起使用。为此,我们将实现一个Lambda函数,该函数将调用Voiceflow对话管理器API。我们将使用Alexa Skills Kit SDK for Node.js和Axios来调用API。
我们只需要调整两个处理程序,即LaunchRequestHandler
和ListenerIntentHandler
。 LaunchRequestHandler
用于启动对话,而ListenerIntentHandler
用于将用户输入发送到Voiceflow。
让我们从LaunchRequestHandler
开始:
const LaunchRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; }, async handle(handlerInput) { let chatID = Alexa.getUserId(handlerInput.requestEnvelope).substring(0, 8); const messages = await utils.interact(chatID, {type: "launch"}); return handlerInput.responseBuilder .speak(messages.join(" ")) .reprompt(messages.join(" ")) .getResponse(); }};
当技能启动时,将调用此处理程序。我们将获取用户ID并使用launch
操作调用Voiceflow对话管理器API。然后,我们将返回响应。
以下交互将由ListenerIntentHandler
处理:
const ListenerIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' }, async handle(handlerInput) { let chatID = Alexa.getUserId(handlerInput.requestEnvelope).substring(0, 8); const intent = Alexa.getIntentName(handlerInput.requestEnvelope); const entitiesDetected = utils.alexaDetectedEntities(handlerInput.requestEnvelope); const request = { type: "intent", payload: { intent: { name: intent }, entities: entitiesDetected } }; const messages = await utils.interact(chatID, request); return handlerInput.responseBuilder .speak(messages.join(" ")) .reprompt(messages.join(" ")) .getResponse(); }};
当用户说出某个内容时,将调用此处理程序。我们将获取用户输入,并使用intent
操作调用Voiceflow对话管理器API。由于NLU推理由Alexa完成,我们需要获取检测到的实体和检测到的意图,并将它们发送到Voiceflow。然后,我们将返回响应。
为了获取检测到的实体,我们将使用以下函数:
module.exports.alexaDetectedEntities = function alexaDetectedEntities(alexaRequest) { let entities = []; const entitiesDetected = alexaRequest.request.intent.slots; for ( const entity of Object.values(entitiesDetected)) { entities.push({ name: entity.name, value: entity.value }); } return entities;}
您可以在lambda/utils.js
中找到此函数的代码。
最后,我们必须确保将这些处理程序添加到skill中:
exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, ListenerIntentHandler, HelpIntentHandler, CancelAndStopIntentHandler, FallbackIntentHandler, SessionEndedRequestHandler, IntentReflectorHandler) .addErrorHandlers( ErrorHandler) .withCustomUserAgent('sample/hello-world/v1.2')
在上述处理程序中,您可以看到我们使用了名为utils.interact
的函数。此函数将调用Voiceflow对话管理器API。您可以在lambda/utils.js
中找到该函数的代码:
const axios = require('axios');const VF_API_KEY = "VF.DM.96ds3423ds9423fs87492fds79792gf343";module.exports.interact = async function interact(chatID, request) { let messages = []; console.log(`request: `+JSON.stringify(request)); const response = await axios({ method: "POST", url: `https://general-runtime.voiceflow.com/state/user/${chatID}/interact`, headers: { Authorization: VF_API_KEY }, data: { request } }); for (const trace of response.data) { switch (trace.type) { case "text": case "speak": { // remove break lines messages.push(this.filter(trace.payload.message)); break; } case "end": { messages.push("再见!"); break; } } } console.log(`response: `+messages.join(",")); return messages;};
这个函数将返回一个消息数组。我们将使用这个数组来构建回应。我们还添加了一些代码来移除换行和奇怪的字符:
module.exports.filter = function filter(string) { string = string.replace(/\'/g, '\'') string = string.replace(/(<([^>]+)>)/ig, "") string = string.replace(/\&/g, ' and ') string = string.replace(/[&\\#,+()$~%*?<>{}]/g, '') string = string.replace(/\s+/g, ' ').trim() string = string.replace(/ +(?= )/g,'') return string;};
通过这段代码,我们已经完成了 Alexa 技能。你可以在 lambda/index.js
中找到 Lambda 函数的代码。
测试
一旦你创建了 Alexa 技能和 Voiceflow 项目,你就可以进行测试。你可以使用 Alexa 模拟器进行测试,也可以使用真实设备进行测试。
按照我们使用的例子,你可以使用以下句子来请求有关 Pokemon 的信息,以测试 Alexa 技能:
结论
正如你所见,将 Alexa 与 Voiceflow 集成非常简单。你可以在 Voiceflow 中创建复杂的对话,然后将其部署到 Alexa 上。这样,你的重点将放在对话上,而不是代码上!
希望你喜欢这个教程。
你可以在这里找到这个教程的代码。
愉快编码!
Leave a Reply