- 原文地址:Announcing the Alexa Skills Kit for Node.js
- 原文做者:David Isbitski
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Yuhanlolo
- 校对者:yqian1991, DateBro
咱们今天很高兴地宣布,一个新的基于 Node.js,旨在帮助开发者们更加简单和快捷地开发 Alexa skill 的 alexa-sdk 发布了。经过 Alexa Skills Kit、Node.js,和 AWS Lambda 开发 Alexa skill 现在已成为最受欢迎的 skill 开发方式。Node.js 事件驱动,非阻塞的特性,使它很是适合开发 Alexa skill,而且 Node.js 也是世界上最大开源系统之一。除此以外,为每月前一百万个网络请求提供免费服务的亚马逊网络服务系统(AWS)Lambda,可以支持大部分开发者从事 skill 的开发。在使用 AWS Lambda 的同时,你不须要担忧管理任何 SSL 证书的问题(由于 Alexa Skills Kit 是被 AWS 信任的触发器)。html
在使用 AWS Lambda 建立 Alexa skill 的时候,加入 Node.js 和 Alexa Skills Kit 只是一个简单的流程,但你实际上所须要写的代码要比这复杂得多。咱们已经意识到大部分开发 skill 的时间都花费在处理会话(session)的属性、skill 的状态持久化,建立回复以及行为模式上面。所以,Alexa 团队着手于开发一个基于 Node.js 的 Alexa Skills Kit SDK 来帮助你避免这些常见的烦恼,从而专一于你的 skill 自身的逻辑开发而不是样板化编码。前端
有了 alexa-sdk,咱们的目标是帮助你在可以避免没必要要的复杂度的状况下,更快捷地开发 skills。今天咱们要发布的这个最新版本的 SDK 具有如下几个特色:node
alexa-sdk 已经上传到了 github,而且能够以 node 包的形式经过下面的指令在你的 Node.js 环境下安装:android
npm install --save alexa-sdk
复制代码
为了开始使用 alexa-sdk,你须要先导入它的库。你只须要在你的项目里简单地建立一个名为 index.js 的文件而后加入如下代码:ios
var Alexa = require('alexa-sdk');
exports.handler = function(event, context, callback){
var alexa = Alexa.handler(event, context);
};
复制代码
这几行代码将会导入 alexa sdk 而且为咱们建立一个 alexa 对象以便以后使用。接着,咱们须要处理与 skill 交互的️ intent。幸运的是,alexa-sdk 使得在咱们想要的意图(Intent)上激活一个函数变得简单。例如,建立一个为 ‘HelloWorldIntent’ 服务的事件管理器,咱们只须要简单地用如下代码实现:git
var handlers = {
'HelloWorldIntent': function () {
this.emit(':tell', 'Hello World!');
}
};
复制代码
注意上面出现的一个新语法规则 “:tell”? alexa-sdk 遵循 tell/ask 的响应方式来生成你的[语音输出回复对象](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#Response Format)。若是咱们想要问用户问题的话,咱们须要把以上代码改为:github
this.emit(‘:ask’, ’What would you like to do?’, ’Please say that again?’);
复制代码
事实上,你的 skill 生成的许多回复都遵循同样的语法规则。下面是一些常见的 skill 回复生成的例子:web
var speechOutput = 'Hello world!';
var repromptSpeech = 'Hello again!';
this.emit(':tell', speechOutput);
this.emit(':ask', speechOutput, repromptSpeech);
var cardTitle = 'Hello World Card';
var cardContent = 'This text will be displayed in the companion app card.';
var imageObj = {
smallImageUrl: 'https://imgs.xkcd.com/comics/standards.png',
largeImageUrl: 'https://imgs.xkcd.com/comics/standards.png'
};
this.emit(':askWithCard', speechOutput, repromptSpeech, cardTitle, cardContent, imageObj);
this.emit(':tellWithCard', speechOutput, cardTitle, cardContent, imageObj);
this.emit(':tellWithLinkAccountCard', speechOutput);
this.emit(':askWithLinkAccountCard', speechOutput);
this.emit(':responseReady'); // 在回复建立以后,返回 Alexa 服务以前被调用。Calls :saveState。
this.emit(':saveState', false); // 事件管理器将 this.attributes 的内容和当前管理器的状态存储到 DynamoDB,而后将以前内置的回复发送到 Alexa 服务。若是你想用别的方式处理持久化状态,能够重写它。其中的第二个属性是可选的而且能够经过将它设置为 ‘true’ 以强制储存。
this.emit(':saveStateError'); // 在存储状态的过程出错时被调用。若是你想本身处理异常的话,能够重写它。
复制代码
一旦咱们建立好事件管理器,在新的 session(NewSession)场景下,咱们须要用以前建立的 alexa 对象中的 registerHandlers 函数去注册这些管理器。数据库
exports.handler = function(event, context, callback){
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
};
复制代码
你也能够同时注册多个事件管理器。与其建立单个管理器对象,咱们建立了一个新的 session,其中有许多处理不一样事件的不一样管理器,而且咱们能够通下面的代码同时注册它们:npm
alexa.registerHandlers(handlers, handlers2, handlers3, ...);
复制代码
你所定义的事件管理器能够相互调用,从而保证你的 skill 的回复是统一的。下面是 LaunchRequest 和 IntentRequest(在 HelloWorldIntent 中)都返回 “Hello World” 消息的一个例子。
var handlers = {
'LaunchRequest': function () {
this.emit('HelloWorldIntent');
},
'HelloWorldIntent': function () {
this.emit(':tell', 'Hello World!');
};
复制代码
一旦你注册了全部的意图管理器函数,你只须要简单地用 alexa 对象里的执行函数去运行 skill 的逻辑就能够了。最后一行代码是这样的:
exports.handler = function(event, context, callback){
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
复制代码
你能够从 github 上下载完整的示例。咱们还提供了最新的基于 Node.js 和 alexa-sdk 开发的 skill 示例:Fact,HelloWorld,HighLow,HowTo 和 Trivia。
alexa-sdk 会根据当前状态把即将接受的 intent 传送给正确的管理器函数。它其实只是 session 属性中一个简单的字符串,用来表示 skill 的状态。在定义 intent 管理器的时候,你也能够经过将表示状态的字符串添加到 intent 的名称后面来模仿这个内置传送的过程,但事实上 alexa-sdk 已经帮你作到了。
好比说,让咱们根据上一个管理新的 session 事件的例子,建立一个简单的有“开始”和“猜数”两个状态的猜数字游戏。
var states = {
GUESSMODE: '_GUESSMODE', // User is trying to guess the number.
STARTMODE: '_STARTMODE' // Prompt the user to start or restart the game.
};
var newSessionHandlers = {
// 如下代码将会切断任何即将输入的 intent 或者启动请求,而且把它们都传送给这个管理器。
'NewSession': function() {
this.handler.state = states.STARTMODE;
this.emit(':ask', 'Welcome to The Number Game. Would you like to play?.');
}
};
复制代码
注意当一个新的 session 被建立时,咱们简单地经过 this.handler.state 把 skill 的状态设置为 STARTMODE。此时 skill 的状态将会自动被持久化在 session 的属性中,若是你在 DynamoDB 里设置了表格的话,你能够选择将它持久化于各个 session 当中。
值得注意的是,NewSession 是一个很棒的捕捉各类行为的管理器,同时也是一个很好的 skill 入口,但它不是必需的。NewSession 只会在一个以它命名的函数中被唤醒。你所定义的每个状态均可以有它们本身的 NewSession 管理器,在你使用内置留存时被唤醒。在上面的例子中,咱们能够更加灵活地为 states.STARTMODE 和 states.GUESSMODE 定义不一样的 NewSession 行为。
为了定义回复 skill 在不一样状态下的 intents,咱们须要使用 Alexa.CreateStateHandler 函数。任何在这里定义的 intent 管理器将只会在特定状态下工做,这让咱们的开发操做更加灵活!
例如,若是咱们在上面定义的 GUESSMODE 状态下,咱们想要处理用户对一个问题的回复。这能够经过 StateHandlers 实现,就像这样:
var guessModeHandlers = Alexa.CreateStateHandler(states.GUESSMODE, {
'NewSession': function () {
this.handler.state = '';
this.emitWithState('NewSession'); // 等同于 Start Mode 下的 NewSession handler
},
'NumberGuessIntent': function() {
var guessNum = parseInt(this.event.request.intent.slots.number.value);
var targetNum = this.attributes["guessNumber"];
console.log('user guessed: ' + guessNum);
if(guessNum > targetNum){
this.emit('TooHigh', guessNum);
} else if( guessNum < targetNum){
this.emit('TooLow', guessNum);
} else if (guessNum === targetNum){
// 经过一个 callback 函数,用 arrow 函数储存正确的 ‘this’ context
this.emit('JustRight', () => {
this.emit(':ask', guessNum.toString() + 'is correct! Would you like to play a new game?',
'Say yes to start a new game, or no to end the game.');
})
} else {
this.emit('NotANum');
}
},
'AMAZON.HelpIntent': function() {
this.emit(':ask', 'I am thinking of a number between zero and one hundred, try to guess and I will tell you' +
' if it is higher or lower.', 'Try saying a number.');
},
'SessionEndedRequest': function () {
console.log('session ended!');
this.attributes['endedSessionCount'] += 1;
this.emit(':saveState', true);
},
'Unhandled': function() {
this.emit(':ask', 'Sorry, I didn\'t get that. Try saying a number.', 'Try saying a number.'); } }); 复制代码
另外一方面,若是咱们在 STARTMODE 状态下,我能够用如下方式定义 StateHandlers:
var startGameHandlers = Alexa.CreateStateHandler(states.STARTMODE, {
'NewSession': function () {
this.emit('NewSession'); // 在 newSessionHandlers 使用管理器
},
'AMAZON.HelpIntent': function() {
var message = 'I will think of a number between zero and one hundred, try to guess and I will tell you if it' +
' is higher or lower. Do you want to start the game?';
this.emit(':ask', message, message);
},
'AMAZON.YesIntent': function() {
this.attributes["guessNumber"] = Math.floor(Math.random() * 100);
this.handler.state = states.GUESSMODE;
this.emit(':ask', 'Great! ' + 'Try saying a number to start the game.', 'Try saying a number.');
},
'AMAZON.NoIntent': function() {
this.emit(':tell', 'Ok, see you next time!');
},
'SessionEndedRequest': function () {
console.log('session ended!');
this.attributes['endedSessionCount'] += 1;
this.emit(':saveState', true);
},
'Unhandled': function() {
var message = 'Say yes to continue, or no to end the game.';
this.emit(':ask', message, message);
}
复制代码
咱们能够看到 AMAZON.YesIntent 和 AMAZON.NoIntent 在 guessModeHandlers 对象中是没有被定义的,由于对于该状态来讲,“是”或者“不是”的回复是没有意义的。这样的回复将会被 ‘Unhandled’ 管理器捕捉到。
还有就是,注意在 NewSession 和 Unhandled 这两个状态中的不一样行为。在这个游戏中,咱们经过调用 newSessionHandlers 对象中的 NewSession 管理器“重置” skill 的状态。你也能够跳过这一步,而后 alexa-sdk 将会为当前状态调用 intent 管理器。你只须要记住在调用 alexa.execute() 以前去注册你的状态管理器,不然它们将不会被找到。
全部属性将会在你的 skill 结束 session 时自动保存,可是若是用户本身结束了当前的 session,你须要 emit ‘:saveState’ 事件(this.emit(‘:saveState’, true)来强制保存这些属性。你应该在 SessionEndedRequest 管理器中作这件事,由于 SessionEndedRequest 管理器将会在用户经过“退出”或回复超时结束当前 session 的时候被调用。你能够看看以上的代码示例。
咱们将上面的例子写在了一个高/低猜数字游戏中,你能够点击这里下载。
不少人喜欢将 session 属性值储存到数据库中以便往后使用。alexa-sdk 直接结合了 Amazon DynamoDB(一个 NoSQL 的数据库服务)让你只须要几行代码就能够实现属性存储。
简单地在你调用 alexa.execute 以前为 alexa 对象中的 DynamoDB 的表格设置一个名字。
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = appId;
alexa.dynamoDBTableName = ’YourTableName'; // That’s it! alexa.registerHandlers(State1Handlers, State2Handlers); alexa.execute(); }; 复制代码
以后,你只须要调用 alexa 对象的 attributes 为你的属性设置一个值。再也不须要其余输入而获得单独的函数!
this.attributes[”yourAttribute"] = ’value’; 复制代码
你能够提早手动建立一个表格或者为你的 Lambda 函数的 DynamoDB 提供建立表格权限而后一切都会自动生成。不过你要知道,在第一次唤醒 skill 的时候,建立表格可能会花费几分钟的时间。
尝试扩展猜数字游戏:
想要获取更多关于学习使用 Alexa Skills Kit 开发的信息,能够看看下面的连接:
基于 Node.js 的 Alexa Skills Kit
Alexa 开发者播客
Alexa 开发培训
关于 Alexa Skills 的介绍
101 条语音交互设计指南
Alexa Skills Kit (ASK)
Alexa 开发者论坛
-Dave (@TheDaveDev)
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。