【Alexaスキル】ダイアログモデルのスロットの検証をLambdaでやる


はじめに

アレクサスキル開発中に受け取ったスロットの検証をしたい場面があり調べました。

このインテントでは{option}スロットが必須の項目となっています。
ユーザーは【水】と【コップ】を頼むか、【水】だけ頼むかの選択肢があります。

{option}なしでインテントが呼び出された場合、アレクサは【コップ】も注文するか聞き返します。

スロットのバリエーションは以下です。
※ここに【コップ】も入っちゃてるのがイケてません。いい方法があればコメントください。。。

alexa developer consoleで検証ルールを設定したが。。。

テストしてみると、、、

2回想定外の回答をするとスキルが強制終了してしまいました。
今回のスキルではユーザーの正しい回答があるまで何度も聞き返してほしかったので困ります。

Lambdaで検証してユーザーに応答を促す

やっと本題です。
Alexa側の検証を外してしまい、Lambda側で検証を行います。

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

    if (slots.option.resolutions["resolutionsPerAuthority"][0]["status"]["code"] != 'ER_SUCCESS_MATCH') {
      return handlerInput.responseBuilder
        .speak('答えは「はい」か「いいえ」でお願いします。キャンセルする場合は「キャンセル」と言ってください。')
        .addElicitSlotDirective('option')
        .getResponse();
    }
    const option = slots.option.resolutions["resolutionsPerAuthority"][0]["values"][0]["value"]["id"];
    // 本来の処理は省略
    return handlerInput.responseBuilder
      .speak('ご注文を承りました。')
      .withShouldEndSession(true)
      .getResponse();
  }
};

まずslots.option.resolutions["resolutionsPerAuthority"][0]["status"]["code"] != 'ER_SUCCESS_MATCH'でスロットに入った単語が想定しているバリエーションの同義語かどうか判定します。
ユーザーに再度発話を促すには.addElicitSlotDirective('option')を呼び出します。
optionはスロット名です。

また、同義語でIDを設定している場合はslots.option.resolutions["resolutionsPerAuthority"][0]["values"][0]["value"]["id"]で一意のIDを取得できるのでいろいろな言い回しが想定される場合は便利です。

これで何度でもユーザーに発話を促すことができました!

おわりに

もっときれいな形がありそうですがとりあえずは実現したいことができました。
これからもっとガンガン触っていこうと思います。