- 原文地址: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、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。