Alexa サンプル発話がスロットのみの場合、発話の認識率を高めることができる

#はじめに

スロット値がめっちゃあるスキル（[:closed_book: 中学一年の英単語](https://alexa-skills.amazon.co.jp/apis/custom/skills/amzn1.ask.skill.3af5caf0-3599-4da9-8983-84b76a211d82/launch)）を作ってスキルストアに公開ところ、Amazonさんから発話の認識率が向上する改善の提案をいただいたのでメモ。

#公開時のインテントとスロットの設定

公開当初は、こんな感じでインテントを作成していた。

```JSON
  {
      "name": "AnswerIntent",
      "slots": [
          {
              "name": "Word",
              "type": "WordsList"
          }
      ],
      "samples": [
          "{Word}",
          "{Word} かな",
          "{Word} です",
          "えっと {Word}"
      ]
  },
```


#認識率を向上させるには

上記のインテント設定に対して、下記のような提案をいただいた。

> サンプル発話がスロットのみの場合、そのスロット独自のインテントを作成することで、発話の認識率を高めることができます。

どうやらサンプル発話がスロットのみのものがある場合は、スロットのみの単独インテントを作成すると認識率が上がるようだ。

ただ、公式ドキュメントにはインテントを分けることは記載されていないっぽい。あ、カスタムスロットとカスタムインテントの場合ということか。どこかに書いてあるのかもしれない。

| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426739/615b0774-3b60-399d-ba21-cbc88af599a2.png)|
|:--|

`JSON` で `{word}` と記述されている部分を別のインテントにするイメージ。

```JSON
  {
      "name": "AnswerIntent",
      "slots": [
          {
              "name": "Word",
              "type": "WordsList"
          }
      ],
      "samples": [
          "{Word}",       ←--- これ　※発話がスロットのみ
          "{Word} かな",
          "{Word} です",
          "えっと {Word}"
      ]
  },
```


または `Alexa Developer Console` で `{word}` と記述されている部分を別のインテントにするイメージ。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426739/96967612-3dee-2b0c-aac6-6cc9fab5a91a.png)|
|:--|


ハンドラーはこんな感じ。

```JavaScript:index.js
const AnswerIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
        && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AnswerIntent';
    },
    async handle(handlerInput) {
      :
      :
```

#どのように変更するのか

スロットのみの単独インテントを作る。そして、もともと作成していたインテントから発話がスロットのみの定義を削除する。これだけ。

`JSON` で記述する場合はこんな感じで設定する。

```JSON:JSON
  {
      "name": "AnswerIntent",
      "slots": [
          {
              "name": "Word",
              "type": "WordsList"
          }
      ],
      "samples": [                 ※{Word}を削除
          "{Word} かな", 
          "{Word} です",
          "えっと {Word}"
      ]
  },
  {
      "name": "AnswerOnlyIntent",
      "slots": [
          {
              "name": "Word",
              "type": "WordsList"
          }
      ],
      "samples": [
          "{Word}"                ※発話がスロットのみのインテントを作る
      ]
  },
```
`Alexa Developer Console` ではこんな感じで設定する。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426739/1671267e-1d89-4e26-5a5c-6cd19b038a9a.png)|
|:--|

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426739/905b7654-40f6-dd72-b3ca-22bed7d97363.png)|
|:--|

ハンドラーはこんな感じで、どっちのインテントも取れるように変更する。

```JavaScript:index.js
const AnswerIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
        && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AnswerIntent'
        || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AnswerOnlyIntent');
    },
    async handle(handlerInput) {
      :
      :
```

#おわりに

気のせいかもしれないが、なんとなく向上したような気がする。
公開したスキルのスロットの中で認識の精度がイマイチだったスロット値がいくつかあったが、高い確率で認識されるようになったように感じたため、試してみる価値ありです。

（2021/5/16 追記）書いてから何ヶ月か経過したが、絶対やった方がいい。やるとやらないとではかなり認識率が違う。