Alexa
AlexaSkillsKit

Alexa Skillの管理コンソールから送られる値は実機と異なる件について

More than 1 year has passed since last update.

皆さん、こんにちは。
Amazon Echoの招待は届いたでしょうか?
私は未だに届かず、悶々としている日々を過ごしています。
RaspberryPi上でalexa-avs-sample-appを日本語で実行できることを知り、alexa-avs-sample-appを日本語環境で動かして何とか毎日を過ごしております。

alexa-avs-sample-appを日本語に対応させる

管理コンソールから送られる値

ServiceRequest.json
{
  "session": {
    "new": true,
    "sessionId": "SessionId.hogehoge",
    "application": {
      "applicationId": "amzn.hogehoge"
    },
    "attributes": {},
    "user": {
      "userId": "amzn.hogehoge"
    }
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.hogehoge",
    "intent": {
      "name": "hogehoge",
      "slots": {
        "gohanNames": {
          "name": "gohanNames",
          "value": "カツカレー"
        }
      }
    },
    "locale": "ja-JP",
    "timestamp": "2017-11-20T07:43:46Z"
  },
  "context": {
    "AudioPlayer": {
      "playerActivity": "IDLE"
    },
    "System": {
      "application": {
        "applicationId": "hogehoge"
      },
      "user": {
        "userId": "hogehoge"
      },
      "device": {
        "supportedInterfaces": {}
      }
    }
  },
  "version": "1.0"
}

alexaのスキル開発する際、ユーザーからの問いかけに対して何らかのアクションにするには、発話された内容の文脈からIntentを判別して、Lambdaなどでイベントを切り分けます。

"Stop"など特定の文字列のみであれば、管理コンソールから送られる値のみでも判定は容易です。
ただ、カスタムスロットを使用してかつ、カスタムスロットに登録された語句に一致するか判定した上で処理をする上では、管理コンソールから送られた値では判定出来ません。

ServiceRequest.json
"intent": {
  "name": "hogehoge",
  "slots": {
    "gohanNames": {
      "name": "gohanNames",
      "value": "カツカレー"
   }
}

例えば、「今日の晩御飯 {gohanNames} がいい!」という発話例が登録された「hogehoge」というintentを呼び出すために管理コンソールのサービスシミュレーターに「今日の晩御飯カツカレーがいい!」と入力したとしましょう。
サービスシミュレーターの返答結果は、上記の様になります。
一見、Intentは「hogehoge」が呼び出されていて、カスタムスロットを使ってカツカレーを拾えている様に見えます。

では、カスタムスロットに登録されていないハンバーグカレーを使って「今日の晩御飯ハンバーグカレーがいい!」と入力してみましょう。

ServiceRequest.json
"intent": {
  "name": "hogehoge",
  "slots": {
    "gohanNames": {
      "name": "gohanNames",
      "value": "ハンバーグカレー"
   }
}

あれおかしいですね。ハンバーグカレーはカスタムスロットに登録されていないので、本来であれば出てこないんじゃ...と思うと思います。(少なからず私は思ってハマりました。)

管理コンソールのサービスシミュレーターで入力した文面は、文脈の判定のみ(違ってたらコメントください)のようで、スロット値の解決までは行われていないのです。
なので、同義語の判定もカスタムスロットにいくら設定してもサービスシミュレーターからは確認することが出来ません。

「resolutions」キーが含まれているか否か

ここからは公式のDeveloperサイトのサンプルをお借りします。
スロットタイプ値の同義語とIDを定義する(エンティティ解決)

ServiceRequest.json
{
  "type": "IntentRequest",
  "intent": {
    "name": "GetMediaIntent",
    "slots": {
      "MediaType": {
        "name": "MediaType",
        "value": "track",
        "resolutions": {
          "resolutionsPerAuthority": [
            {
              "authority": "amzn1.er-authority.echo-sdk.<skill_id>.MEDIA_TYPE",
              "status": {
                "code": "ER_SUCCESS_MATCH"
              },
              "values": [
                {
                  "value": {
                    "name": "song",
                    "id": "SONG"
                  }
                }
              ]
            }
          ]
        }
      }
    }
  }
}

結論から言うと、発話した内容とカスタムスロットに定義した値とのマッチング出来ているか見るには現状、Amazon Echoの実機が必要です。
管理コンソールのサービスシミュレーターから送られるServiceRequestと実機から行われるServiceRequestでは、「resolutions」が含まれているかという違いがあります。

逆に裏を返せば、resolutionsがなければデバッグ中の処理扱い、あれば実機環境での実行と処理を切り分けることが可能です。

では、実機環境から送って、スロットの値とのマッチングを見て見ましょう。"resolutions"直下には、"resolutionsPerAuthority"が含まれており、その直下"status"キーの"code"キーの値を見てマッチングしているかしていないかを判別します。
マッチしている時は、"ER_SUCCESS_MATCH"を返却し、マッチしていない時は、"ER_SUCCESS_NO_MATCH"を返却します。
マッチしている時は、valuesも併せて返却されるので、その中のvalueのnameを取得することで、発話した内容からマッチングしたとされるカスタムスロットの値を取得することができます。

実機がまだ手に届かず開発している方も多いと思いますので、スキル開発時カスタムスロットを利用するときはこの点見落としがちなのでお気をつけて下さい。