初めてのスキル開発
このガイドでは、ASK SDK v2 for Node.jsを使ったスキル開発の手順を説明します。
前提条件
- Amazon開発者アカウント。Alexaスキルの作成と設定に必要です。
- アマゾンウェブサービス(AWS)アカウント。このガイドでは、AWS Lambdaでスキルをホスティングする手順を確認できます。
- インストールされたSDKに依存関係のあるNPMプロジェクト。ASK SDK v2 for Node.jsのセットアップを参照してください。このサンプルスキルには、標準SDK配布パッケージが必要です。依存関係をカスタマイズしている場合は、コアSDKのサポートモジュールをインストールする必要があります。
スキルコードを記述する
以下のセクションでは、ハンドラーごとのスキルコードの記述について説明します。
依存関係をインポートする
index.js
(下記のセクションでTypeScript.Sameを使用する場合は、index.ts
)というファイルを作成し、以下のコードを貼り付けます。
const Alexa = require('ask-sdk-core');
import {
ErrorHandler,
HandlerInput,
RequestHandler,
SkillBuilders,
} from 'ask-sdk-core';
import {
Response,
SessionEndedRequest,
} from 'ask-sdk-model';
リクエストハンドラーの追加
まず、スキルで受信するさまざまなタイプのリクエストを処理するのに必要なリクエストハンドラーを作成します。
LaunchRequestハンドラー
以下は、スキルがLaunchRequest
を受信した時に呼び出されるハンドラーを設定するコードのサンプルです。特定のインテントなしでスキルが呼び出された場合、LaunchRequest
イベントが発生します。
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'ようこそ、アレクサスキルキットへ。こんにちは、と言ってみてください。';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
}
};
const LaunchRequestHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'ようこそ、アレクサスキルキットへ。こんにちは、と言ってみてください。';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
},
};
受信したリクエストがLaunchRequest
の場合、canHandle
関数はtrueを返します。handle
関数は、基本的なあいさつの応答を生成して返します。
HelloWorldIntentハンドラー
以下は、スキルがHelloWorldIntent
を受信した時に呼び出されるハンドラーを設定するコードのサンプルです。
以下のコードをindex.js
ファイルの、前述のハンドラーの後に貼り付けます。
const HelloWorldIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
},
handle(handlerInput) {
const speechText = 'こんにちは';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
}
};
const HelloWorldIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'こんにちは';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
},
};
canHandle
関数は受信するリクエストがIntentRequest
かどうかを検出し、インテント名がHelloWorldIntent
の場合にtrueを返します。handle
関数は、基本的な「こんにちは」という応答を生成して返します。
HelpIntentハンドラー
以下は、スキルがビルトインインテントAMAZON.HelpIntent
を受信した時に呼び出されるハンドラーを設定するコードのサンプルです。
以下のコードをindex.js
ファイルの、前述のハンドラーの後に貼り付けます。
const HelpIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speechText = 'こんにちは、と言ってみてください。';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
}
};
const HelpIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'こんにちは、と言ってみてください。';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('ハローワールド', speechText)
.getResponse();
},
};
さきほどのハンドラー同様、このハンドラーはIntentRequest
を想定されるインテント名と照合します。基本のヘルプ手順が返されます。
CancelAndStopIntentハンドラー
CancelAndStopIntentハンドラーもビルトインインテントによって呼び出されるため、HelpIntentハンドラーに似ています。以下は、1つのハンドラーを使ってAmazon.CancelIntent
とAmazon.StopIntent
という2つのインテントに応答している例です。
以下のコードをindex.js
ファイルの、前述のハンドラーの後に貼り付けます。
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
|| handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speechText = 'さようなら';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('ハローワールド', speechText)
.withShouldEndSession(true)
.getResponse();
}
};
const CancelAndStopIntentHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
|| handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput : HandlerInput) : Response {
const speechText = 'さようなら';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('ハローワールド', speechText)
.withShouldEndSession(true)
.getResponse();
},
};
両方のインテントに対する応答は同じであるため、1つのハンドラーにすることで重複するコードを減らせます。
SessionEndedRequestハンドラー
SessionEndedRequest
を受信した後は音声、カード、ディレクティブを使った応答を返すことはできませんが、クリーンアップロジックを追加するにはSessionEndedRequestHandlerが最適な場所です。
以下のコードをindex.js
ファイルの、前述のハンドラーの後に貼り付けます。
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
//クリーンアップロジックをここに追加します
return handlerInput.responseBuilder.getResponse();
}
};
const SessionEndedRequestHandler : RequestHandler = {
canHandle(handlerInput : HandlerInput) : boolean {
return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
},
handle(handlerInput : HandlerInput) : Response {
console.log(`次の理由でセッションが終了しました。 ${(handlerInput.requestEnvelope.request as SessionEndedRequest).reason}`);
return handlerInput.responseBuilder.getResponse();
},
};
エラーハンドラーの追加
ASK SDK v2 for Node.jsはエラー処理が簡単で、スムーズなユーザーエクスペリエンスを実現するスキルが作成しやすくなります。エラーハンドラーは、未処理のリクエストやAPIサービスのタイムアウトなどのエラー処理ロジックを組み込むのに最適です。以下の例では、catch allエラーハンドラーをスキルに追加して、すべてのエラーに対してスキルが意味のあるメッセージを返すようにしています。
以下のコードをindex.js
ファイルの、前述のハンドラーの後に貼り付けます。
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`処理されたエラー: ${error.message}`);
return handlerInput.responseBuilder
.speak('すみません。コマンドを理解できませんでした。もう一度お願いします。')
.reprompt('すみません。コマンドを理解できませんでした。もう一度お願いします。')
.getResponse();
},
};
const ErrorHandler : ErrorHandler = {
canHandle(handlerInput : HandlerInput, error : Error ) : boolean {
return true;
},
handle(handlerInput : HandlerInput, error : Error) : Response {
console.log(`処理されたエラー:${error.message}`);
return handlerInput.responseBuilder
.speak('すみません。コマンドを理解できませんでした。もう一度お願いします。')
.reprompt('すみません。コマンドを理解できませんでした。もう一度お願いします。')
.getResponse();
},
};
Lambdaハンドラーを作成する
Lambdaハンドラーは、AWS Lambda関数のエントリーポイントとなります。以下は、スキルが受信するすべてのリクエストのルーティングを行うLambdaハンドラー関数のコードサンプルです。Lambdaハンドラー関数は、作成したリクエストハンドラーを使用して設定されたSDKのSkill
インスタンスを作成します。
以下のコードをindex.js
ファイルの、前述のセクションの後に貼り付けます。
let skill;
exports.handler = async function (event, context) {
console.log(`REQUEST++++${JSON.stringify(event)}`);
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
const response = await skill.invoke(event, context);
console.log(`RESPONSE++++${JSON.stringify(response)}`);
return response;
};
let skill;
exports.handler = async (event, context) => {
console.log(`REQUEST++++${JSON.stringify(event)}`);
if (!skill) {
skill = SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
const response = await skill.invoke(event, context);
console.log(`RESPONSE++++${JSON.stringify(response)}`);
return response;
};
関数は、SkillBuilders.custom
ビルダーを使用してSDKインスタンスを作成します。addRequestHandlers
ビルダー関数はリクエストハンドラーを登録します。関数は、Lambdaハンドラー関数としてエクスポートされます。
また、ASK SDK v2 for Node.jsで提供されるlambda
ビルダー関数を使って、Skill
のインスタンスを呼び出して応答を返すLambdaハンドラー関数を簡単に作成することもできます。以下の例を参照してください。
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler)
.addErrorHandlers(ErrorHandler)
.lambda();
exports.handler = SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.lambda();
スキルパッケージを作成する
スキルのコードが完成したら、スキルパッケージを作成できます。スキルをAWS Lambdaにアップロードするには、スキルファイルとnode_modules
フォルダーを含むzipファイルを作成します。すべてのプロジェクトファイルは、プロジェクトフォルダではなく、ファイルを直接圧縮するようにしてください。
スキルをAWS Lambdaにアップロードする
スキルに適切なロールでAWS Lambda関数を作成する手順については、カスタムスキルをAWS Lambda関数としてホスティングするを参照してください。関数作成時には、一から作成オプションを選択し、ランタイムとしてNode.js 10.xを選択します。
AWS Lambda関数を作成し、トリガーとして「Alexa Skills Kit」を設定したら、前のステップで作成した.zipファイルをアップロードします。その際、ハンドラーはデフォルトのindex.handler
のままにします。最後に、AWS Lambda関数のARNをコピーします。このARNはAmazon開発者コンソールでスキルを設定する際に必要となります。
スキルの設定とテストを行う
スキルコードをAWS Lambdaにアップロードしたら、Alexaのスキルを設定できます。新しいスキルを作成するには、
- Alexa Skills Kit開発者コンソールに移動してログインします。
- 右上のスキルの作成ボタンをクリックします。
- スキル名として「HelloWorld」と入力します。
- カスタムスキルを選択してからスキルを作成をクリックします。
次に、スキルの対話モデルを定義します。サイドバーの呼び出し名を選択し、スキルの呼び出し名に「ハローワールド」を入力します。
次に、HelloWorldIntent
というインテントを対話モデルに追加します。対話モデルのインテントセクションにある追加ボタンをクリックします。カスタムインテントを作成を選択した状態で、インテント名として「HelloWorldIntent」を入力し、インテントを作成します。インテントの詳細ページで、ユーザーがこのインテントを呼び出すのに使用できるサンプル発話をいくつか追加します。この例では、以下のサンプル発話を追加しましたが、これ以外でもかまいません。
こんにちはと言って
ハローワールドと言って
こんにちは
ハイと言って
ハイワールドと言って
ハイ
ごきげんいかが
AMAZON.CancelIntent
、AMAZON.HelpIntent
、AMAZON.StopIntent
はAlexaのビルトインインテントのため、サンプル発話を追加する必要はありません。
開発者コンソールでは、スキルモデル全体をJSON形式で編集することもできます。サイドバーでJSONエディターを選択します。この例では、以下のJSONスキーマを使用できます。
{
"interactionModel": {
"languageModel": {
"invocationName": "ハローワールド",
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "HelloWorldIntent",
"slots": [],
"samples": [
"ごきげんいかが",
"ハイ",
"ハイワールドと言って",
"ハイと言って",
"こんにちは",
"ハローワールドと言って",
"こんにちはと言って"
]
}
],
"types": []
}
}
}
対話モデルの編集が完了したら、モデルを保存してビルドします。
次に、スキルのエンドポイントを設定します。エンドポイントでAWS LambdaのARNを選択し、さきほど作成した関数のARNを貼り付けます。残りの設定は、デフォルト値のままで構いません。エンドポイントを保存をクリックします。
この時点で、スキルをテストできるようになります。上部にあるメニューでテストをクリックし、テストページに移動します。このスキルでは、テストは有効になっていますオプションがONになっていることを確認します。テストページを使って、テキストや音声でリクエストをシミュレーションできます。
呼び出し名と、さきほど設定したサンプル発話のうち1つを使います。たとえば、「アレクサ、ハローワールドを開いてこんにちはと言って」と言うと、スキルは「こんにちは」と答えるはずです。また、(スマートフォンやhttps://alexa.amazon.comで)Alexaアプリを開くと、スキル一覧が表示されます。ここから、Alexa搭載デバイスでテストできるように、アカウントでスキルを有効にすることができます。
この時点で、さまざまなインテントや、スキルコードに対応するリクエストハンドラーを試してみてください。一通りのテストが完了したら、スキルの認定を申請して世界中のAlexaユーザーに公開するプロセスに進むことができます。