対話を続けるときと終了するときで、どのような違いがあるでしょうか。 コーヒーショップの例では、「コーヒーショップを開いて」という形でスキルを呼び出すと「ようこそ。何を注文しますか?」と問いかけて発話を待ちます。 ここで「コーヒーをお願い」と発話すると応答メッセージを話して対話が終了します。
下がそれぞれのコードになります。
const LaunchRequestHandler = {
//~中略~
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
const OrderIntentHandler = {
//~中略~
return handlerInput.responseBuilder
.speak(speechText)
.getResponse();
}
};
お気づきだと思いますが、フレーズなしでスキルが起動したときの LaunchRequestHandler
では .reprompt()
というメソッド呼び出しが追加されています。 次はそれぞれのJSON出力(一部を抜粋)の違いです。
[LaunchRequestHandlerの場合]
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>ようこそ。何を注文しますか?</speak>"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>ようこそ。何を注文しますか?</speak>"
}
},
"shouldEndSession": false
},
[OrderIntentHandlerの場合]
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>コーヒーを1杯承りました</speak>"
}
},
.reprompt
メソッドによりJSON出力に2つ追加されていることが分かると思います。
"shouldEndSession": false
が追加されている。これにより応答メッセージのあとすぐにセッションを終わらせず、8秒間ユーザーの応答を待つようになります。 shouldEndSesssion
が定義されていない場合の挙動はデバイスに依存しますが、Alexaシミュレータではすぐにセッションを終了します。画面付きのデバイスでは 30秒セッションを保持します。
"reprompt": { … }
が追加されている。 通常、8秒間ユーザーの発話がなかった場合、セッションを終了します。ただし reprompt
が指定されている場合、最初の8秒のあと指定したメッセージを流し、もう8秒間ユーザーの発話を待ちます。 コーヒーショップの例では同じ文言ですが、.reprompt()
の引数で別のメッセージにすることもできます。
詳しくは こちら を参照ください。
PCやモバイルアプリと異なり、インテントは独立したRESTリクエストになります。 そのため、バックエンドサービスは、たとえセッション中であっても、変数等ではそれまでのやり取りを保持できません。 Alexa と ASK SDK は、セッション中の情報を持続するための セッションアトリビュート という仕組みを提供します。バックエンドサービスは、応答プロンプトにセッションアトリビュートを追加することで、Alexaサービスが次回のリクエスト時にアトリビュートを渡してきます。 SDKでの使い方は簡単です。 管理したいアトリビュートを含んだオブジェクトを、setSessionAtribute() と getSessionAttribuite() メソッドで設定・取得してください。
参照する例
let attributes = handlerInput.attributesManager.getSessionAttributes();
var menu = attributes.menu;
設定する例
let attributes = handlerInput.attributesManager.getSessionAttributes();
attributes.menu = menu;
handlerInput.attributesManager.setSessionAttributes(attributes);
前項でセッションアトリビュートについて説明しましたが、今度はセッションにまたがるアトリビュートの管理について説明します。
方法はいろいろありますが、Alexa開発者コンソールによるホストサービスは、AWS S3をサポートしていますので、ここでは S3PersistenceAdapter を使った方法を紹介します。
コードエディタ左側の、「package.json」をダブルクリックしてください。
依存パッケージを定義した "dependencies"に、次の一行を追加します。
"dependencies": {
...
"ask-sdk-s3-persistence-adapter": "^2.0.0"
}
今度は、"index.js" に戻って、ハンドラの登録の周辺に、以下[追加]とコメントされたコードを追加します。
// [**追加**]
// S3PersistenceAdapterを用意
const persistenceAdapter = require('ask-sdk-s3-persistence-adapter');
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
~中略~
)
.addErrorHandlers(
ErrorHandler)
// [**追加**]
// S3PersistentAdapter を PersistentAdapter に設定
.withPersistenceAdapter(
new persistenceAdapter.S3PersistenceAdapter(
{bucketName:process.env.S3_PERSISTENCE_BUCKET}))
.lambda();
これで永続アトリビュートを使う用意ができました。 それでは、注文の際に、注文の品を覚えるコードを追加してみましょう。 まず、OrderIntentHandler.handle() で非同期処理を扱うために "async" を追加します。 次に、永続アトリビュートから現在のアトリビュートを取得、注文を .lastOrder に上書き、アトリビュートを保存・永続化させるコードを追加します。
const OrderIntentHandler = {
~中略~
// [**追加**] 非同期処理のため async を追加する
async handle(handlerInput) {
var menu = handlerInput.requestEnvelope.request.intent.slots.menu.value;
var amount = handlerInput.requestEnvelope.request.intent.slots.amount.value;
if (amount === undefined) {
amount = 1;
}
// [**追加**]
const attr = await handlerInput.attributesManager.getPersistentAttributes();
attr.lastOrder = menu;
handlerInput.attributesManager.setPersistentAttributes(attr);
await handlerInput.attributesManager.savePersistentAttributes();
const speechText = `${menu}を${amount}杯承りました`;
return handlerInput.responseBuilder
.speak(speechText)
.getResponse();
}
};
最後に、フレーズなしでコーヒーショップスキルが呼び出されたとき、最後の注文があれば発話するように、LaunchRequestHandler を変更します。
const LaunchRequestHandler = {
~中略~
// [**追加**] 非同期処理のため async を追加する
async handle(handlerInput) {
// [**追加/変更**]
const attr = await handlerInput.attributesManager.getPersistentAttributes();
const lastOrder = attr.lastOrder;
var speechText = `ようこそ。`;
if (lastOrder !== undefined) {
speechText += `前回は ${lastOrder}を注文しましたね。`;
}
speechText += `今日は何を注文しますか?`;
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
ご自身の AWS アカウントでコードをホストする場合は、 DynamoDbPersistenceAdapter を使うこともできます。 永続アトリビュートを使うと、セッションアトリビュートと同様の手続きでアトリビュートの管理ができるのと、実際の保存先を PersistentAdapter という形で抽象化できるメリットがあります。
以上、今回はダイアログについて説明しました。