Alexaのスキルを開発する ~その2~ 処理の作成(AWS Lambda)
2019/09/07 |
|
2018/05/20 |
|
2018/01/19 |
|
前回Amazon Developer ConsoleでAlexaのスキルを作成しました。Amazon Developer Consoleではどういう言葉を言ったときにスキルが起動するのか(呼び出し名)、どういう文章(発話サンプル)で特定の機能(インテント)を呼び出すのか、どういうパラメータ(スロット)を渡すのか、を定義しました。
今度は実際にそのデータを受け取って処理を行う部分を作成してみます。
処理はAWS LambdaかHTTPSを呼び出して行います。今回はLambdaで作ってみます。
AWSを使うにはあらかじめアカウントを作成しておく必要があります。アカウント作成の説明は省略しますが、アカウント作成してIAMでユーザー作成して…といったお決まりの約束をあらかじめ済ましておきます。
AWS Lambda
関数の作成
ここからLambdaで処理を作成していきます。AWSにログインし、検索窓に”lambda”と入力、リストからLambdaを選びます。
初めて関数を作る場合は以下の画面が表示されるので、”関数の作成”を押します。
既に何か関数が存在する場合は一覧画面が表示されるので、”関数の作成”を押します。
”関数の作成”画面が表示されたら、”Serverless Application Repositoryの参照”を選択、フィルターに”alexa-skills-kit-nodejs-skillfact”と入力、出てきた一覧から”alexa-skills-kit-nodejs-skillfact”を選択します。
画面が変わるので、画面下の方にある”アプリケーション名”を入力します。
名前は”omikuji”にしました。入力したら画面右下の”デプロイ”を押します。
しばらく待つと…関数が作成されました。クリックして関数の画面に行きます。
関数の画面の下の方に、コードを入力するところがあります。
既にコードが入力されていますが、消して以下のソースを貼り付けます。そして画面右上にある”保存”ボタンを押して保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
/* eslint-disable func-names */ /* eslint-disable no-console */ const Alexa = require('ask-sdk'); const LaunchHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'LaunchRequest' }, handle(handlerInput) { const request = handlerInput.requestEnvelope.request; var day = "今日"; const factArr = data; const factIndex = Math.floor(Math.random() * factArr.length); const randomFact = factArr[factIndex]; const speechOutput = GET_FACT_MESSAGE + day + "の運勢は" + randomFact; return handlerInput.responseBuilder .speak(speechOutput) .withSimpleCard(SKILL_NAME, day + "は" + randomFact) .getResponse(); }, }; const IntentHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; console.log(request.intent.name) return true; return (request.type === 'IntentRequest' && request.intent.name === 'fate'); }, handle(handlerInput) { const request = handlerInput.requestEnvelope.request; var day = request.intent.slots["day"].value; const factArr = data; const factIndex = Math.floor(Math.random() * factArr.length); const randomFact = factArr[factIndex]; const speechOutput = GET_FACT_MESSAGE + day + "の運勢は" + randomFact; return handlerInput.responseBuilder .speak(speechOutput) .withSimpleCard(SKILL_NAME, day + "は" + randomFact) .getResponse(); }, }; const HelpHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent'; }, handle(handlerInput) { return handlerInput.responseBuilder .speak(HELP_MESSAGE) .reprompt(HELP_REPROMPT) .getResponse(); }, }; const ExitHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'IntentRequest' && (request.intent.name === 'AMAZON.CancelIntent' || request.intent.name === 'AMAZON.StopIntent'); }, handle(handlerInput) { return handlerInput.responseBuilder .speak(STOP_MESSAGE) .getResponse(); }, }; const SessionEndedRequestHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'SessionEndedRequest'; }, handle(handlerInput) { console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`); return handlerInput.responseBuilder.getResponse(); }, }; const ErrorHandler = { canHandle() { return true; }, handle(handlerInput, error) { console.log(`Error handled: ${error.message}`); return handlerInput.responseBuilder .speak(ERROR_MESSAGE) .reprompt(ERROR_MESSAGE) .getResponse(); }, }; const SKILL_NAME = 'おみくじ'; const GET_FACT_MESSAGE = '運勢をお教えします。'; const HELP_MESSAGE = '運勢をお教えします。'; const HELP_REPROMPT = 'どうしました?'; const STOP_MESSAGE = 'さようなら!'; const ERROR_MESSAGE = 'エラーが発生しました!'; const data = [ '大吉', '中吉', '小吉', ]; const skillBuilder = Alexa.SkillBuilders.standard(); exports.handler = skillBuilder .addRequestHandlers( LaunchHandler, IntentHandler, HelpHandler, ExitHandler, SessionEndedRequestHandler ) .addErrorHandlers(ErrorHandler) .lambda(); |
コードの説明
このソースはサンプルソースを元に修正しました。可能な限り元のサンプルに近づけています。
先頭でAlexa Skills Kitを読み込んだ後、最初に実行されるのは以下の個所になります。
1 2 3 4 5 6 7 8 9 10 11 12 |
const skillBuilder = Alexa.SkillBuilders.standard(); exports.handler = skillBuilder .addRequestHandlers( LaunchHandler, IntentHandler, HelpHandler, ExitHandler, SessionEndedRequestHandler ) .addErrorHandlers(ErrorHandler) .lambda(); |
Alexa Skills Kitで用意されているSkillBuilderに、各リクエストに応じたハンドラを登録し、最後にlambda()関数を呼び出すという形になります。
ハンドラの選択
登録するハンドラ、今回はLaunchHandler, IntentHandler, HelpHandler, ExitHandler, SessionEndedRequestHandler、をあらかじめ用意しておき、SkillBuilderにaddRequestHandlers()で登録します。エラー処理はaddErrorHandlers()で別途登録します。
リクエストが来ると、登録された順番に各ハンドラのcanHandle()関数が呼び出されます。その関数ではリクエストの内容を見て、自分の担当する処理かどうかをTrue/Falseで返します。自分の担当ならTrueを返し、処理を行います。その場合以降のハンドラは呼び出されません。
実際の処理は各ハンドラのhandle()関数に記述します。canHandle()でTrueを返した場合に呼び出されます。
リクエストタイプ
リクエストの種類にはいくつかあり、今回は以下の3つに対応します。
- LaunchRequest … ”○○を開いて”いったように、具体的なコマンドが指定されてないときのリクエストです。ちなみに今回のサンプルでは”今日”の運勢を教えます。
- IntentRequest…定義したインテントが呼び出された場合のリクエストです。今回のサンプルでは”明日の運勢は”と言った時に、このリクエストが送られます。
- SessionEndedRequest…ユーザーがスキルを終了した、ユーザーがスキルに理解できない応答を返した、エラーが発生した、いずれかの場合のリクエストです。
handle()関数の中からは、handlerInput.requestEnvelope.request.typeでリクエストの種類を取得できます。
インテント
特定のコマンドが呼び出されたときに、どのコマンド(インテント)なのかを示します。
前回はAmazon Developer Consoleで”fate”というインテントを”{day} の運勢は”という発話サンプルで定義したので、”今日の運勢は”と話すと、リクエストタイプに”IntentRequest”、インテントに”fate”がセットされたリクエストがやってきます。
”AMAZON.HelpIntent”、”AMAZON.StopIntent”はどのスキルでも自動的に定義されるインテントで、それぞれヘルプ、ストップ時の処理を記述します。
handlerInput.requestEnvelope.request.intent.nameでインテント名が取得できます。
スロット
コマンドに対するパラメータがスロットです。
スロットはhandlerInput.requestEnvelope.request.intent.slots[“day”].value”という形で取得できます”day”がスロット名です。こちらも前回Amazon Developer Consoleで定義しました。
今回のサンプルでは、このスロットに”いつ”かを表すパラメータが入っています。取得した日付は何も加工せずそのまま返します。
Response
各ハンドラのhandle()関数では、最後にResponseBuilderを使って作成したResponseを返します。speak()で読み上げる文章を指定し、withSimpleCard()では画面に表示する文字を指定します。そして、getResponse()で生成したレスポンスを取得し、それをreturnします。
以下のページにリクエストからレスポンスまでの一連の流れの説明があります。
スキルにLambdaのARNをセットする
あとは前回Amazon Developer Consoleで作成したAlexaスキルに、このLambdaのARNをセットしてあげます。
画面右上の”arn:”で始まる、ARNをコピーします。
Amazon Developer Consoleに戻り、左の”エンドポイント”をクリックし、”AWS LambdaのARN”を選択します。”デフォルトの地域”にLambdaのARNを貼り付け、”エンドポイントを保存”ボタンを押します。
これでAlexaからおみくじスキルを使うと、このLambda関数が呼び出されて運勢を教えてくれるはずです。
次はテストしてみます。