[日本語Alexa] Alexa SDK for Node.js Ver2入門(その1)はじめの一歩

本記事では、入門用という位置付けで、Alexa SDK for Node.js の使い方を、順を追って紹介して行きたいと思います。 初回は、もっとも簡単なサンプル・会話の継続と終了・複数のハンドラー定義などです。
2018.04.24

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

1 はじめに

Alexaのスキル開発のためにNode.js用として Alexa Skills Kit for Node.js (以下、Alexa SDK) が提供されていますが、今月18日、大きく進化を遂げ、Version 2 となりました。

GitHub alexa/alexa-skills-kit-sdk-for-nodejs

こちらは、先月発表されたASK SDK v2 for Javaと同じコア機能セットとなっており、これにより、Amazonから提供されるスキル開発用のSDKは、JavaとNode.jsの2本だてとなりました。

Alexa Skills Kit SDKs

本記事では、入門用という位置付けで、Alexa SDKの使い方を、順を追って紹介して行きたいと思います。(対象は、Node.js用のみです。Java用には触れておりません)

なお、以前に紹介した下記の記事は、初期バージョン(Ver1.x)のものであり、これらの焼き直しともなっています。

2 Alexa SDK とは

Alexaのスキル開発では、「データの永続性」「レスポンスの組み立て」「動作のモデリング」などに多大な労力が必要ですが、Alexa SDKを利用することで、その殆どを任せることができます。これにより開発者は、ロジックに集中することが可能になります。

Alexa SDKの特徴は、次のように列挙できます。

  • NPMパッケージとして提供される
  • コア機能のみのパッケージも利用可能 (Ver2)
  • 各種のリクエストをハンドラとして定義できる
  • ハンドラは、柔軟にグループ化や共通処理が可能(Ver2)
  • セッションごとやセッションを跨ぐデータの永続化が可能 (Ver2)
  • DynamoDB等のDBが使用可能(Ver2)
  • すべての音声出力は、SSMLでラップされる
  • 全てのLambdaイベントとコンテキストにアクセスが可能
  • デバイスアドレスなどのAlexaサービスをラップし、簡単に利用可能 (Ver2)
  • すべてのSDKツールが、handInputオブジェクトに用意され単体テストが可能 (Ver2)
  • TypeScript定義ファイルと、.d.tsファイルの読み取りが可能 (Ver2)
  • async/awaitが利用可能 (Ver2)

3 インストール

インストールは、npmコマンドで可能です。

$ npm install --save ask-sdk

node_modulesの下に、必要なモジュールが展開されますので、Lambdaへアップロードする際にzipに含まれるようにします。

ask-sdkは、依存関係を含めると概ね40Mbyteです。

$ du -k ./node_modules/
38852 ./node_modules/

コア機能のみを利用する場合は、下記のように600KByte程度で利用することも可能です。

$ npm install --save ask-sdk-model
$ npm install --save ask-sdk-core
$ du -k ./node_modules/
624 ./node_modules/

4 最初のサンプル

Alexa SDKを使用した最小限のスキルを書いてみました。

const Alexa = require('ask-sdk');

let skill;
exports.handler = async function (event, context) {
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(MyHandler)
.create();
}
return skill.invoke(event);
}

const MyHandler = {
canHandle(handlerInput) {
return true;
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('こんにちは')
.getResponse();
}
};

Alexa SDKでは、SkillBuildersでスキルオブジェクトを生成し、ハンドラ(MyHandler)を追加していきます。そして、Lambdaのパラメータ(event)を指定したinvoke()により、Lambdaの戻り値を返しています。

ここで追加したハンドラ(MyHandler)では、canHandle()true(常に処理する)を返しているため、このハンドラが、すべての処理を担うことになります。

MyHandlerのhandle()では、responseBuilderを使用してレスポンスを組みたて、最後にgetResponse()でレスポンスを返します。

上記のサンプルは、何を話しかけても "こんにちは" と返ってくる(だけの)スキルです。

LaunchRequestリクエストで起動している状況

IntentRequest(HelloWorldIntent)リクエストで起動している状況

5 会話の継続と終了

アレクサからの発話には、会話を継続するものと、終了させるものの2種類があります。Alexa SDKのVer1.xでは、:tell:ask で簡単に記述できるようになっていましたが、残念ながら、Ver2では提供されていません。

会話の継続と終了は、ResponseBuilderreprompt()を追加するかどうかで決まります。

(1) 会話(セッション)を終了させる場合

ResponseBuilderspeak()だけを追加すると、会話は終了します。

return handlerInput.responseBuilder
.speak('こんにちは')
.getResponse();

レスポンスには、shouldEndSessionキーが含まれていないため、デフォル値であるtrueとなり、アレクサの発話の後、直ちにセッションは終了します。

(2) 会話(セッション)を継続する場合

一方、会話を継続したい場合は、speak()にプラスしてreprompt()を追加します。

return handlerInput.responseBuilder
.speak('何になさいますか')
.reprompt('ご注文をお願いします')
.getResponse();

こうすることで、レスポンスでは、shouldEndSessionキーがfalseとなり、会話は継続となります。

会話継続にした場合は、アレクサの発話の後、ユーザーからの返答を待つようになります。 もし、このタイミングでユーザーからの返事がない場合、今度は、催促するようにreprompt()で指定した内容が発話されます。(それでも、ユーザーからの返事がない場合は、セッションは終了します)

Alexa:「何になさいますか」
ユーザー:......
Alexa:「ご注文をお願いします」

6 複数のハンドラー定義

ハンドラーは、addRequestHandlersによって幾つでも追加することができます。

skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
Handler1,
Handler2,
Handler3)
.create();

そして、どのリクエストをどのハンドラで処理するかは、canHandle()の戻り値で区別します。最初のサンプルでは、ここでtrueを返していたので、すべてのリクエストを処理するようになっていました。

const MyHandler = {
canHandle(handlerInput) {
return true;
},
handle(handlerInput) {
// ハンドラーの処理
}
};

canHandle()で、対象となるリクエストを絞ることで、複数のハンドラを定義できます。以下の例では、LauchRequestとIntentRequestのOrderIntentを処理するハンドラを定義しています。

const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
// LaunchRequestの処理
}
};

const OrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'OrderIntent';
},
handle(handlerInput) {
// OrderIntentの処理
}
};

7 一連の流れを書いてみる

それでは、一連の流れを Alexa SDK で記述してみることにします。

サンプルは、簡単なコーヒーショップのスキルです。スキルを起動すると「ようこそ・・・」というようなウエルカムメッセージを返し、注文を聞きます。 コーヒーを注文をすると、スキルは終了します。

定義されているインテントは、以下のOrderIntentだけです。

呼び出し名は、「コーヒーショップ」になっています。

コードは、下記の通りです。

const Alexa = require('ask-sdk');

let skill;
exports.handler = async function (event, context) {
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(LaunchRequestHandler,OrderIntentHandler)
.create();
}
return skill.invoke(event);
}

const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('ようこそ、クラスメソッド・コーヒーショップへ、ご注文をどうぞ')
.reprompt('ご注文をお伺いします')
.getResponse();
}
};

const OrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'OrderIntent';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('ご注文ありがとうございました')
.getResponse();
}
};

動作している様子です。

8 最後に

Ver1.xにあった、ステートごとのハンドラ定義、また、リソースを定義してthis.t(キー文字列) で使用するような手法は、標準機能からは無くなっています。(同等の記述は可能)

今回紹介したサンプルは、必須のハンドラであるAMAZON.HelpIntent、StopIntent、CancelIntentの処理や、エラー処理などは、まったく行なっておりません。これらについては次回以降、逐次紹介させて頂きたいと考えております。

9 参考リンク

Alexa Skills Kit SDK for Node.js

Now Available: Version 2 of the ASK Software Development Kit for Node.js

GitHub repository for the SDK v2 for Node.js

[日本語Alexa] Alexa SDK for Node.js Ver2入門(その1)はじめの一歩

[日本語Alexa] Alexa SDK for Node.js Ver2入門(その2)ハンドラの登録

[日本語Alexa] Alexa SDK for Node.js Ver2入門(その3)レスポンスの作成

[日本語Alexa] Alexa-SDK Ver2(その4)スキル属性

[日本語Alexa] Alexa-SDK Ver2(その5)ダイアログモード

[日本語Alexa] Alexa-SDK Ver2(その6) 所在地情報

[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示