LoginSignup
17
10

More than 5 years have passed since last update.

ServerlessFramework+TypeScriptで作るAlexaスキル

Last updated at Posted at 2017-11-20

ついに日本でもAmazonEchoが発売されました!
ということで、ServerlessFrameworkでAlexaスキルを作って見ようと思います。
今回はAlexa Skills Kit for Node.js+TypeScriptで実装してみます。

前提

事前にalexa開発者ポータルに登録しておいてください。 (lambdaをデプロイするだけなら不要ですが
nodeのインストール方法やserverlessの利用方法詳細等は省略します。

環境

  • node v8.9.1
  • yarn v1.3.2
  • serverless v1.24.1

serverlessプロジェクトを作る

まずは、lambda側の実装からやっていきます
適当なディレクトリを作ります

$ mkdir serverless-alexa-sample
$ cd serverless-alexa-sample

serverlessコマンドでプロジェクトを作成します。

$ sls create --template aws-nodejs

TypeScript環境を作る

続いてTypeScriptの環境を作っていきます
package.json作成後、typescript周りのライブラリをインストールします。

$ yarn init -y
$ yarn add typescript tslint tslint-config-standard --dev

必要な型定義を追加します

$ yarn add @types/node @types/alexa-sdk --dev

tsconfig.jsonを追加します

tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es2015",
    "sourceMap": false,
    "outDir": "build",
    "removeComments": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "allowUnreachableCode": true,
    "allowUnusedLabels": true,
    "alwaysStrict": true,
    "noImplicitReturns": true,
    "suppressImplicitAnyIndexErrors": true,
    "lib": [
      "es2017"
    ],
    "types": [
      "node"
    ]
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

tslint.jsonを追加します

tsling.json
{
  "extends": "tslint-config-standard"
}

続いてtsファイル用のディレクトリを生成し、既存のhandler.jsをリネームして配置します。

$ mkdir src
$ mv handler.js src/handler.ts

このままではTypeScriptのビルドエラーとなるためhandler.tsを以下のように修正します。

src/handler.ts
+ module.exports.hello = (event: any, context: any, callback: any) => {
+   const response = {
+     statusCode: 200,
+     body: JSON.stringify({
+       message: 'Go Serverless v1.0! Your function executed successfully!',
+       input: event
+     })
+   }
+ 
+   callback(null, response)
+ 
+   // Use this code if you don't use the http event with the LAMBDA-PROXY integration
+   // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event })
+ }

ビルドが通るか確認してみます。
package.jsonにビルド用のコマンドを追加します。

pakage.json
{
  "name": "serverless-alexa-sample",
  "version": "1.0.0",
  "main": "index.js",
  "author": "YukiYonekura <yuki.yonekura@example.com>",
  "license": "MIT",
+  "scripts": {
+    "build": "tsc"
+  },
  "devDependencies": {
    "@types/alexa-sdk": "^1.0.10",
    "@types/node": "^8.0.53",
    "tslint": "^5.8.0",
    "tslint-config-standard": "^7.0.0",
    "typescript": "^2.6.1"
  }
}

ビルドしてみます。

$ yarn run build
yarn run v1.3.2
$ tsc
Done in 1.06s.

これでTypeScriptでの開発環境が整いました!
ビルドしたファイルは./buildディレクトリに配置されています。(tsconfig.jsonで指定

build
└── handler.js

実装

ここからlambdaの実装に入ります
今回は「開いて」と発話すると「こんにちはアレクサ」、「終了」と発話すると「さようならアレクサ」、
それ以外なら「よく分かりません」と返すだけの簡単なスキルを実装してみます。

Alexa Skills Kit for Node.jsを追加します

$ yarn add alexa-sdk

handler.tsを以下のように修正します

src/handler.ts
import * as Alexa from 'alexa-sdk'

module.exports.hello = (event: Alexa.RequestBody<any>, context: Alexa.Context) => {
  const alexa = Alexa.handler(event, context)
  alexa.registerHandlers({
    'Unhandled': function () {
      this.emit(':tell', 'よく分かりません')
    },
    'LaunchRequest': function () {
      this.emit(':tell', 'こんにちはアレクサ')
    },
    'AMAZON.StopIntent': function () {
      this.emit(':tell', 'さようならアレクサ')
    }
  })
  alexa.execute()
}

実際の実装ではstate毎にhandlerを実装していくことになると思うので、
handlerは別ファイルに分けたほうがいいでしょう

serverless.ymlを以下のように編集します
handlerにビルドしたファイルを指定し、eventsにAlexaスキル用のイベントを追記します

serverless.yml
 functions:
   hello:
+    handler: build/handler.hello
+    events:
+      - alexaSkill

スキルの実装は以上になります
tsファイルをビルド後にslsコマンドでデプロイします

$ yarn run build
$ sls deploy

参考

Alexaスキルの登録

ここからは、開発者コンソールからAlesaスキルの登録を行って行きます

(スキルの登録方法については、公式に詳しくのっているで、雑に説明しています

まずは、ALEXAのホームにアクセスし、
「Alexa Skills Kit」の「始める」ボタンをクリックします

alexa_01.png

登録済みのスキル一覧が表示されます
まだスキルを登録していないので何も表示されていません。
「新しいスキルを追加する」ボタンをクリックします。

alexa_02.png

スキルの作成画面に遷移します。
説明に従って項目を埋めていきます。

alexa_03.png

※ALEXAではなくカナで「アレクサ」の方がいいかも

ちゃんと日本語化されているので特に困ることはないと思います。
全て載せると 面倒くさい 長くなるのでデフォルト値から変更した箇所だけ載せます

スキル情報

言語

もちろん「Japanese」を選択します

スキル名

任意の名前を入力

呼び出し名

画像では「ハローALEXAサンプル」となっていますが、カタカナの方がいい気がします

対話モデル

インテントスキーマ

AMAZON.StopIntentだけ登録します。
LaunchRequestとUnhandleは不要です

{
  "intents": [
    {
      "intent": "AMAZON.StopIntent"
    }
  ]
}

サンプル発話

AMAZON.StopIntentと「終了」、「おわり」という単語を紐づけます
組み込みインテントなので「ストップ」、「停止」等の単語は登録しなくても認識されます

AMAZON.StopIntent 終了
AMAZON.StopIntent おわり

設定

サービスエンドポイントのタイプ

「AWS Lambda の ARN (Amazonリソースネーム)」を選択

デフォルト

デプロイしたlambdaのARNを入力

arn:aws:lambda:ap-northeast-1:123456789012:function:serverless-alexa-sample-dev-hello

テスト

ここまで項目を入力するとテスト実行が可能になります
サービスシミュレーターから以下のように動作を確認できます

LaunchRequest
alexa_04.png

AMAZON.StopIntent
alexa_06.png

Unhandled
alexa_05.png

追記: アプリケーションIDの設定

Alexa SDKではApplicationIDを設定してあげないと、ログに以下のようなWarningが出力されます

Warning: Application ID is not set

ApplicationIDはAlexaの開発者コンソールで確認できます。
「スキルIDの表示」をクリックするとApplicationIDが表示されます。

alexa_07.png

ApplicationIDを確認したらhandler.tsを以下のように編集します
今回はApplicationIDをLambdaの環境変数から取得するようにしています

src/handler.ts
import * as Alexa from 'alexa-sdk'

module.exports.hello = (event: Alexa.RequestBody<any>, context: Alexa.Context) => {
  const alexa = Alexa.handler(event, context)
+  alexa.appId = process.env.APPLICATION_ID
  alexa.registerHandlers({
    'Unhandled': function () {
      this.emit(':tell', 'よく分かりません')
    },
    'LaunchRequest': function () {
      this.emit(':tell', 'こんにちはアレクサ')
    },
    'AMAZON.StopIntent': function () {
      this.emit(':tell', 'さようならアレクサ')
    }
  })
  alexa.execute()
}

続いてserverless.ymlに環境変数の設定を追記します

serverless.yml
functions:
  hello:
    handler: build/handler.hello
+    environment:
+      # 開発者コンソールで取得したApplicationIDを設定
+      APPLICATION_ID: amzn1.ask.skill.12345678-1234-1234-1234-123456789012
    events:
      - alexaSkill

これでWarningは表示されなくなりました

コード

今回作成したコードは以下においています
https://github.com/YukiYonekura/serverless-alexa-sample

まとめ

招待メールはよ

申請までの流れはEchoが届いたら書くかも

17
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
10