Alexa公式の日本語FactサンプルスキルをASK SDK v2対応してTypeScriptで書き直してみた

Alexaの公式Githubリポジトリで公開されているFactサンプルスキル日本語版のASK SDK v2対応とTypeScript化の過程をご紹介します。
2018.05.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Alexaの公式Githubリポジトリで公開されているFactサンプルスキルには、メインの英語版のブランチに加えて、日本語版のブランチがあります。 英語版は先日リリースされたAlexa Skill Kit SDK for Node.js Version 2(以下v2 SDK)に対応したコードに修正が済んでいますが、 残念ながら日本語版はv2 SDK対応がされていません。そこで、日本語版のv2 SDK対応を行い、ついでにスキルのコードをTypeScript化もしてみましたのでその過程をご紹介します。

v2 SDK対応

package.jsonの修正

まずはpackage.jsonのdependenciesでv2 SDKを指定します。

git diff lambda/custom/package.json
diff --git a/lambda/custom/package.json b/lambda/custom/package.json
index 631590d..c36fd9e 100644
--- a/lambda/custom/package.json
+++ b/lambda/custom/package.json
@@ -14,6 +14,7 @@
   "author": "Amazon.com",
   "license": "Apache-2.0",
   "dependencies": {
-    "alexa-sdk": "^1.0.12"
+    "ask-sdk": "^2.0.3"
   }
 }

index.jsの修正

次にindex.jsを修正します。Alexaの発話内容などの日本語固有の箇所を除いて、v2 SDK対応済みのUS版のindex.jsのコードをコピーします。FallbackIntentとか、US版でしか動かない箇所もありますが、残していても問題無さそうなので今回はそのままにしました。

v2 SDK対応したUS版では、cookbookというユーティリティ関数のモジュールが追加されていて、その中の関数が一つ使用されていました。今回はとりあえず当該関数だけをindex.jsにコピーすることにしました。

修正後のindex.jsはこんな感じになります。

デプロイ&動作確認

ここまでで、いったんスキルをデプロイして動作確認します。

cd lambda/custom
npm install --save ask-sdk
cd ../..
ask deploy -p XXXX
-------------------- Create Skill Project --------------------
Profile for the deployment: [XXXX]
Skill Id: XXXXXXXXXXXXXXXX
Skill deployment finished.
Model deployment finished.
Lambda deployment finished.
Lambda function(s) created:
  [URI] XXXXXXXXXXXXXXXX
No in-skill product to be deployed.
Your skill is now deployed and enabled in the development stage.
Try invoking the skill by saying “Alexa, open {your_skill_invocation_name}” or simulate an invocation via the `ask simulate` command.

ask simulateコマンドは以前は日本語スキルでは使えなかったのですが、ask-cli v1.3.1現在日本語スキルでも使えるようになっていました。

 ask simulate -l ja-JP -t "宇宙豆知識をひらいて" -p XXXX

開発者コンソールのテスト画面でも、スキルが問題なく動作することが確認できました。

TypeScript化

無事v2 SDKでスキルが動くようになったので、次はTypeScript化を行います。全体的な作業の流れは以下のブログを参考にしました。

[日本語Alexa] Alexa-SDK Ver2 をTypeScriptで使う

TypeScript開発環境の準備

まずTypeScriptコマンド(tsc)をインストールします。

npm install -g typescript
tsc --version
Version 2.8.3

次にNodeの型情報をインストールします。

npm install -g --save-dev @types/node

index.jsをindex.tsにリネームします。

git mv index.js index.ts

tscコマンドの設定ファイルtsconfig.jsonを生成して最低限必要な部分を編集します。

tsc --init
message TS6071: Successfully created a tsconfig.json file.
cat tsconfig.json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,  
    "esModuleInterop": true,
    "sourceMap": true,
  },
  "files": [
    "index.ts"
  ]
}

index.tsの編集

index.tsをコンパイルが通るように編集していきます。 まず先頭のrequireをimportに変更します。

- const Alexa = require('ask-sdk');
+ import * as Alexa from 'ask-sdk';

関数定義の引数に型情報をつけます。

+    canHandle(handlerInput: Alexa.HandlerInput) {
-    canHandle(handlerInput) {

+    handle(handlerInput: Alexa.HandlerInput) {
-    handle(handlerInput) {

+    handle(handlerInput: Alexa.HandlerInput, error: Error) {
-    handle(handlerInput, error) {

getRandomItem()のオリジナルのJS実装は引数に任意の型の配列もしくはオブジェクト受け付ける仕様になっています。今回はコンパイルを通すことを優先したいので、引数の型をstring[]に限定した実装に単純化することにしました。

+ function getRandomItem(arrayOfItems: string[]) {
+     let i = 0;
+     i = Math.floor(Math.random() * arrayOfItems.length);
+     return (arrayOfItems[i]);
+ }

SessionEndedRequestHandlerではhandlerInput.requestEnvelope.requestのインスタンスがSessionEndedRequest型で返ってくることになっていて、その型にしかreasonというメンバーは定義されていないので、以下のようにキャストします。

+     handle(handlerInput: Alexa.HandlerInput) {
+         const request: SessionEndedRequest = <SessionEndedRequest>handlerInput.requestEnvelope.request;
+         console.log(`Session ended with reason: ${request.reason}`);
+   
+       return handlerInput.responseBuilder.getResponse();
+     },

今回の編集で利用しようとしている型のimportを追加します。

import { RequestEnvelope, ResponseEnvelope, services, SessionEndedRequest } from 'ask-sdk-model';

修正後のindex.tsはこんな感じになります。

最後に、tsconfig.jsonのあるディレクトリでtscコマンドを実行すると、index.tsからindex.jsが生成され、ask deploy等でAWS Lambdaにデプロイすることができるようになります。

おわりに

tscコマンドの使い方で若干とまどいましたが、 JSからTSへの移殖自体は移植元のコードが単純だったこともあり、サクッとできてしまいました。 今回作業した内容は以下で公開してありますので、TS x v2 SDKでスキル開発をする際の参考にしていただけると幸いです。

GitHub - mayosuke/skill-sample-nodejs-fact at ja-JP

参考