AlexaのASR/NLUをコマンドラインでテストする

こんにちは。ハグテク(いとう)です。普段はオランダに巣食いつつフリーランスでデベロッパーをしています。AWSやAlexaの界隈によく顔を出しています。どうも。

この記事は、スマートスピーカーアドベントカレンダー 2021 11日目の記事です。テーマは。「AlexaのASR/NLUをコマンドラインでテストする」です。 公式ドキュメントでは少しわかりづらいかな? という点を実際にコードで補足しながら、見ていきたいと思います。

それでは行ってみましょう!

ASR/NLU Evaluation Tool

asr-nlu-evaluation-console

API Reference

https://developer.amazon.com/en-US/docs/alexa/smapi/nlu-evaluation-tool-api.html#smapi

ASR Evaluation のステップ

公式ドキュメントには、ASR Evaluation の実装方法が記載されています。この手順を追いながら解説していきます。

1. カタログを作って、スキルに関連づける

カタログは、複数のスキルでシェアできるデータソースです。カタログは、developer.amazon.com のアカウントに紐付けられます。カタログは、通常 Alexa Voice Service が提供する AWS S3 バケットでホストされます。ご自身のAWSアカウント上に S3 バケットでカタログをホストすることも可能です。開発者コンソールのGUIで ASR Evaluation のテストを作成する場合、この部分は隠蔽されていて、意識することはありません。

試しに、開発者コンソールでASR Evaluation Tool でテストを作成したあと、 Get the list of catalogs, v0 API でリストした結果がこちらです。“ALEXA_ASR_EVALUATION” というカタログが、“AMAZON.AudioRecording” というタイプで作成されています。そして、”associatedSkillIds” 属性に、このカタログに関連づけられたスキルのIDが確認できます。

-> % curl --location --request GET 'https://api.amazonalexa.com/v0/catalogs?vendorId=xxxxxx' \
--header 'Authorization: Bearer ....' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1040  100  1040    0     0   4279      0 --:--:-- --:--:-- --:--:--  4279
{
  "_links": {
    "self": {
      "href": "/v0/catalogs"
    }
  },
  "catalogs": [
    {
      "associatedSkillIds": [
        ""amzn1.ask.skill.xxxxxxxx"
      ],
      "createdDate": "2021-11-12T13:58:34.189Z",
      "id": "amzn1.ask-catalog.cat.28b2d85a-f34b-419e-8616-17cb30bd6d65",
      "lastUpdatedDate": "2021-11-12T13:58:34.346Z",
      "title": "ALEXA_ASR_EVALUATION",
      "type": "AMAZON.AudioRecording",
      "usage": "AlexaTest.Catalog.AudioRecording"
    }
  ],
  "isTruncated": false
}

独自のカタログを作りたい場合は、Create a catalog APIを利用します。実行結果はこうなります。

curl --location --request POST 'https://api.amazonalexa.com/v0/catalogs' \
--header 'Authorization: Bearer xxxxx' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "title": "hugtech-test-catalog-001",
    "vendorId": "xxxxxx",
    "usage": "AlexaTest.Catalog.AudioRecording",
    "type": "AMAZON.AudioRecording"
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   449  100   286  100   163    758    432 --:--:-- --:--:-- --:--:--  1190
{
  "associatedSkillIds": [],
  "createdDate": "2021-11-28T21:32:33.649Z",
  "id": "amzn1.ask-catalog.cat.xxxxxx",
  "lastUpdatedDate": "2021-11-28T21:32:33.649Z",
  "title": "hugtech-test-catalog-001",
  "type": "AMAZON.AudioRecording",
  "usage": "AlexaTest.Catalog.AudioRecording"
}

カタログの作成ができました。このカタログIDを使い、スキルを紐付けます。Associate a catalog with a skill APIを使います。スキルの紐付けを行い、先程紹介した Get the list of catalogs, v0 API で確認した結果はこうです。

カタログ “hugtech-test-catalog-001” の associatedSkillIds 属性に、スキルIDが関連づけられています。

-> % curl --location --request PUT 'https://api.amazonalexa.com/v0/skills/amzn1.ask.skill.842aa6a7-xxxx/catalogs/amzn1.ask-catalog.cat.b8690b93-xxxx' \
--header 'Authorization: Bearer xxxxxK' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

-> % curl --location --request GET 'https://api.amazonalexa.com/v0/catalogs?vendorId=xxxxxxx' \
--header 'Authorization: Bearer xxxxK' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1668  100  1668    0     0   6270      0 --:--:-- --:--:-- --:--:--  6247
{
  "_links": {
    "self": {
      "href": "/v0/catalogs"
    }
  },
  "catalogs": [
    {
      "associatedSkillIds": [
        "amzn1.ask.skill.842aa6a7-xxxx"
      ],
      "createdDate": "2021-11-28T21:32:33.649Z",
      "id": "amzn1.ask-catalog.cat.b8690b93-xxxx",
      "lastUpdatedDate": "2021-11-28T21:40:21.100Z",
      "title": "hugtech-test-catalog-001",
      "type": "AMAZON.AudioRecording",
      "usage": "AlexaTest.Catalog.AudioRecording"
    },
    {
      "associatedSkillIds": [
        "amzn1.ask.skill.xxxxx9"
      ],
      "createdDate": "2021-11-12T13:58:34.189Z",
      "id": "amzn1.ask-catalog.cat.xxxxxxx",
      "lastUpdatedDate": "2021-11-12T13:58:34.346Z",
      "title": "ALEXA_ASR_EVALUATION",
      "type": "AMAZON.AudioRecording",
      "usage": "AlexaTest.Catalog.AudioRecording"
    }
  ],
  "isTruncated": false
}

2. カタログに音声データをアップロードする

カタログの作成ができたので、ASR Evaluation に利用する音声データをアップロードします。アップロードの方法は、AWS S3のMultipartアップロードの手順を踏むのですが、SMAPIのAPIと連携する関係で少しわかりづらいので、少し詳しく説明します。

2.1 アップロードリクエストをオープンする

AVS に 音声データのアップロードリクエストを送信します。受理されると、リクエストのIDと1つの PresignedUrl (アップロード先を示す有効期限付きのURL)が発行されます。

Create an upload, v0 API を使います。Callしてみましょう。

-> % curl --location --request POST 'https://api.amazonalexa.com/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxx/uploads' \
--header 'Authorization: Bearer xxxxx83t' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "numberOfUploadParts": 1
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1055  100  1023  100    32   3398    106 --:--:-- --:--:-- --:--:--  3504
{
  "catalogId": "amzn1.ask-catalog.cat.72757baa-xxxxxx",
  "createdDate": "2021-11-29T21:29:59.253Z",
  "id": "amzn1.ask-catalog.upl.44e82eb0-xxxxxxxx",
  "ingestionSteps": [
    {
      "errors": [],
      "logUrl": "",
      "name": "INGESTION",
      "status": "PENDING"
    },
    {
      "errors": [],
      "logUrl": "",
      "name": "UPLOAD",
      "status": "PENDING"
    },
    {
      "errors": [],
      "logUrl": "",
      "name": "SCHEMA_VALIDATION",
      "status": "PENDING"
    }
  ],
  "lastUpdatedDate": "2021-11-29T21:29:59.253Z",
  "presignedUploadParts": [
    {
      "partNumber": 1,
      "url": "https://ask-catalog-prod-na-tmp-upload.s3.amazonaws.com/contentAuthorities/AlexaTest/catalogScopes/AlexaTest.Catalog.AudioRecording/catalogs/amzn1.ask-catalog.cat.72757baa-2306-463a-95b9-af1f6447354e/uploads/b0ab46b5-2dea-4094-98b8-62dbd3733f90?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20211129T212959Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKW4E4252YH7ICGJ%2F20211129%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=c15ee06b7e92922e78f44bf2a6fbe73487fbc2ce58ba8ec38aa5ee635e0ce189"
    }
  ],
  "status": "PENDING"
}

Bodyに指定した numberOfUploadParts プロパティは アップロードするファイルのサイズが 5GB を超えない限り、1 を指定します。

レスポンスを見ると、presignedUploadParts プロパティに アップロード先のURLが格納されています。

2.2 ファイルをアップロードする

2.1 で取得したPresignedUrl に ファイルを PUT します。

ファイルは、複数のaudioファイルを固めたzipファイルです。拡張子は含めないようにしてください。アップロードする際に .mp3 が自動的に付与されて保存されます。

実際にPUTしてファイルをアップロードした結果がこちらです。ETagの値は、次のステップで使うため、覚えておく必要があります。

Get the list of uploads, v0 APIで、アップロードの状態を確認してみます。

-> % curl --location --request GET 'https://api.amazonalexa.com/v0/catalogs/amzn1.ask-catalog.cat.72757baa-2306-463a-95b9-af1f6447354e/uploads' \
--header 'Authorization: Bearer xxxxx3t' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8070  100  8070    0     0  20906      0 --:--:-- --:--:-- --:--:-- 20906
{
  "_links": {
    "self": {
      "href": "/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxxxx/uploads"
    }
  },
  "isTruncated": false,
  "uploads": [
  :
    {
      "catalogId": "amzn1.ask-catalog.cat.72757baa-xxxx",
      "createdDate": "2021-11-29T21:29:59.253Z",
      "id": "amzn1.ask-catalog.upl.44e82eb0-xxxxx",
      "lastUpdatedDate": "2021-11-29T21:29:59.253Z",
      "status": "PENDING"
    },
    :
  ]
}

Upload は依然として”PENDING” のままです。

2.3 アップロードリクエストをクローズする

アップロードが完了したら、AVSに完了を通知します。

Complete an upload, v0 APIを使います。Callしてみます。結果を 先ほどと同様に Get the list of uploads, v0 APIで確認してみます。

-> % curl --location --request POST 'https://api.amazonalexa.com/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxxxx/uploads/amzn1.ask-catalog.upl.44e82eb0-xxxxxxx' \
--header 'Authorization: Bearer xxxxxx' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "partETags": [
        {
            "eTag": "47xxxxxxx",
            "partNumber": 1
        }
    ]
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   132    0     0  100   132      0    287 --:--:-- --:--:-- --:--:--   287


-> % curl --location --request GET 'https://api.amazonalexa.com/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxxx/uploads' \                                                            
--header 'Authorization: Bearer xxxxxxx' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8072  100  8072    0     0  22360      0 --:--:-- --:--:-- --:--:-- 22360
{
  "_links": {
    "self": {
      "href": "/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxx/uploads"
    }
  },
  "isTruncated": false,
  "uploads": [
    :
    {
      "catalogId": "amzn1.ask-catalog.cat.72757baa-xxxx",
      "createdDate": "2021-11-29T21:29:59.253Z",
      "id": "amzn1.ask-catalog.upl.44e82eb0-xxxx",
      "lastUpdatedDate": "2021-11-29T22:03:24.883Z",
      "status": "SUCCEEDED"
    },
     :
  ]
}

ステータスが “SUCCEEDED” に変わっています。

ファイルは正しくアップロードできているでしょうか? Get information about a specified upload, v0 APIで確認します。

-> % curl --location --request GET 'https://api.amazonalexa.com/v0/catalogs/amzn1.ask-catalog.cat.72757baa-xxxxxx/uploads/amzn1.ask-catalog.upl.44e82eb0-xxxxxx' \
--header 'Authorization: Bearer xxxxx' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1615  100  1615    0     0   2515      0 --:--:-- --:--:-- --:--:--  2515
{
  "catalogId": "amzn1.ask-catalog.cat.72757baa-xxxxxx",
  "createdDate": "2021-11-29T21:29:59.253Z",
  "file": {
    "presignedDownloadUrl": "https://ask-catalog-prod-na-content-upload.s3.amazonaws.com/xxxxxx",
    "status": "AVAILABLE"
  },
  "id": "amzn1.ask-catalog.upl.44e82eb0-xxxxxxxx",
  "ingestionSteps": [
    {
      "errors": [],
      "logUrl": "https://ask-catalog-prod-na-error-logs.s3.amazonaws.com/xxxxxx",
      "name": "INGESTION",
      "status": "SUCCEEDED"
    },
    {
      "errors": [],
      "logUrl": "",
      "name": "UPLOAD",
      "status": "SUCCEEDED"
    },
    {
      "errors": [],
      "logUrl": "",
      "name": "SCHEMA_VALIDATION",
      "status": "SUCCEEDED"
    }
  ],
  "lastUpdatedDate": "2021-11-29T22:03:24.883Z",
  "status": "SUCCEEDED"
}

アップロードにはどうやら、INGESTION, UPLOAD, SCHEMA_VALIDATION の3つのステップがあったようですねw とにかくアップロードはいずれのステップも SUCCEEDED となっており、成功はしているようです。

レスポンスの file.presignedDownloadUrl にアップロードしたファイルが格納されています。ダウンロードしてみます。

-> % curl https://ask-catalog-prod-na-content-upload.s3.amazonaws.com/contentAuthorities/AlexaTest/catalogScopes/AlexaTest.Catalog.AudioRecording/catalogs/amzn1.ask-catalog.cat.72757baa-xxxxxxxxxx/uploads/amzn1.ask-catalog.upl.44exxxxxxx --output audio_dl.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 14102  100 14102    0     0  22708      0 --:--:-- --:--:-- --:--:-- 22672

-> % unzip audio_dl.zip                                  
Archive:  audio_dl.zip
  inflating: konbanha                
  inflating: ohayougozaimasu         
  inflating: konnichiha              
[23時16分56秒] [~/tinms/tradfit/alexa-utterance-test-tool] [development *]
-> % 

正しくファイルがアップロードされていることが確認できました。

AnnotationSetを作る

ファイルがアップロードできたところで、次はこれらのファイルをつかってAnnotationSetを作りましょう。ASR、NLU用のテスト仕様書のようなものです。

まずは、ASRのAnnotationSetを作ります。

Create an Annotation Set API を使います。テスト仕様書の雛形を作成するAPIです。Callしてみます。スキルは言語単位で作りますが、ASRのAnnotationSetには現状ロケールで分けるという概念はないようです。 アノテーションセットの名前にロケールをつけるてアノテーションの言語を識別しやすいようにしておくのがよい方法です。

-> % curl --location --request POST 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-5591-476f-8f58-ae94f43d41b9/asrAnnotationSets' \
--header 'Authorization: Bearer Atza|IwEBID_8f98r359AvawBuPnYsHuU87ZrHSbfe0M-d3uJSeszwR9Eam_klmr12PSwiFBDcMMVTMoAPyXNB-cRKQD5-ImNOQku4ljSE5Rz9duNUs3E8Y-dscv2ROaQJXQkMAioTmXzsXkv6ZXuR3zAtT-e8okrEjxxMoq-JaT5H7smPRC2fhCwW0udIdecaz_qy0-IZIaobi4oOb8CcC43CYuWyp3KSCQRvmPGFpJNhwLaj_LqxWZ1x3j1Z_JWyn6iOc9bP9KIC7vL7L5z00BulHE47yGe82rdp6IfrGIATptJyTWdKwG1w-1czEVWBSyRWWUlcQDL79Fkuc_C6b0aKk8V1gjhWgk6s18PkSaY0x52FSp3fIJlNwChgvRzQRXYswuwhA07B1Km_CJE0daBvgR3FX4n_fim2-dzwEtB_ziR8Z_x2g10k-tpP4UBaM907uTJBuPx-Gv3PSg9BK0WycwmVIUyMZI2jLbzhnU0LkAitWs0J7ktnr5SyNqTckwg7UuZrJ1cyirjmo1wJkmNTxoZ5K-4kcgHXklxW_pVO3G4tVzzf4ON9IN7I8fns2T3kOPDwHPAzpYuxktGh8kjMuSfpKKM_Ki1DdMJNstoPNxOmbF2GtK5HrQLac_PNZ4ItiBh_R9-c6vgI84fdcv1hiIEo39Cd9aR2lquzlhW95CAtJ8qRFxnR8FNBTHNLHx6fS_rfn7XUjGaT74s_OC5d777kT5mn-WRjpzIW_nIl0f6NGp9vQ' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "name": "sample-annotation-set-jp"
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   113  100    74  100    39    141     74 --:--:-- --:--:-- --:--:--   215
{
  "id": "amzn1.ask.asr-annotation-set.a84e6c2e-xxxxxxxx"
}

テストの雛形ができたので、AnnotationSetにテストを追加します。Update Annotation Set Annotations API を使います。Callしてみます。

-> % curl --location --request PUT 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxx/asrAnnotationSets/amzn1.ask.asr-annotation-set.a84e6c2e-xxxxx/annotations' \ 
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer xxxxxxx9vQ' \
--data-raw '{
    "annotations": [{
        "uploadId": "amzn1.ask-catalog.upl.59dbd3db-xxxxxx",
        "filePathInUpload": "konnichiha",
        "evaluationWeight": 1,
        "expectedTranscription": "こんにちは"
    }]
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   238    0     0  100   238      0    217  0:00:01  0:00:01 --:--:--   217

登録したAnnotationSet を確認します。Get Annotation Set Contents API を使います。Accept Header は、 application/json または text/csv のみ受け付けますので、忘れずにどちらかを指定します。

-> % curl --location --request GET 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxxx/asrAnnotationSets/amzn1.ask.asr-annotation-set.a84e6c2e-xxxxxxx/annotations' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer xxxxxxGp9vQ' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   724  100   724    0     0   2445      0 --:--:-- --:--:-- --:--:--  2445
{
  "annotations": [
    {
      "evaluationWeight": 1,
      "expectedTranscription": "こんにちは",
      "filePathInUpload": "konnichiha",
      "uploadId": "amzn1.ask-catalog.upl.xxxxxx",
      "audioAsset": {
        "downloadUrl": "https://audio-transcoded-prod.s3.amazonaws.com/M2AUSLW6GQRMGE/amzn1.ask-catalog.cat.xxxxxxxx/amzn1.ask-catalog.upl.xxxxxx/MP3/konnichiha.mp3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20211202T213445Z&X-Amz-SignedHeaders=host&X-Amz-Expires=10800&X-Amz-Credential=AKIAYWH6WUJBVHBXC6M2%2F20211202%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=a9a6e7bb428793c26b097fdc770b6f34f5226155e487d976a0f5dae977388bb1",
        "expiryTime": "2021-12-03T00:34:45.484Z"
      }
    }
  ]
}

downloadUrl のところにS3のURLが返ってきているのがわかります。拡張子に注目してください。mp3がついていますね。先程の章でアップロードしたのは、拡張子をつけていませんでしたが、ここでは拡張子が付与されています。

"downloadUrl": "https://audio-transcoded-prod.s3.amazonaws.com/M2AUSLW6GQRMGE/amzn1.ask-catalog.cat.xxxxxxxx/amzn1.ask-catalog.upl.xxxxxx/MP3/konnichiha.mp3?X-Amz-Algorithmxxxxxxxx1"

Note: Alexaの開発者コンソールで音声ファイルだけ録音して、

ASR の AnnotationSetができました。次は、NLU の AnnotationSetを作ります。

Create a new annotation set API を使います。手順はASRのときとほぼ同じです。Callします。ASRのときとは異なり、ロケールの指定が必要です。

-> % curl --location --request POST 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxx/nluAnnotationSets' \
--header 'Authorization: Bearer Atza|xxxxxxxxM' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "name": "sample-annotation-set",
    "locale": "ja-JP"
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   107  100    45  100    62     44     61  0:00:01  0:00:01 --:--:--   106
{
  "id": "d52feae5-xxxxx"
}

NLUのテスト雛形ができたので、アノテーションを追加します。Upload or update an annotation set API を使います。Callしてみます。

-> % curl --location --request POST 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxx/nluAnnotationSets/d52feae5-xxxxx/annotations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer xxxxxxx9M' \
--data-raw '{
  "data": [
    {
      "inputs": {
        "utterance": "こんにちは"
      },
      "expected": [
        {
          "intent": {
            "name": "AMAZON.CancelIntent",
            "slots": {}
            }
        }
      ]
    }
  ]
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   248    0     0  100   248      0    450 --:--:-- --:--:-- --:--:--   449

AnnotationSets を追加したので確認しましょう。公式ドキュメントにはAnnotationを確認する方法の記載がありませんが、先程実行した Create Annotation の HTTPメソッドをGETに変更することで動きます。Acceptヘッダーだけ注意してください。

-> % curl --location --request GET 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxxx/nluAnnotationSets/d52feae5-xxxxxxx/annotations' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer Atza|xxxxxxxxxB9M' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   119  100   119    0     0    231      0 --:--:-- --:--:-- --:--:--   231
{
  "data": [
    {
      "inputs": {
        "utterance": "こんにちは"
      },
      "expected": [
        {
          "intent": {
            "name": "AMAZON.CancelIntent",
            "slots": {}
          }
        }
      ]
    }
  ]
}

追加されています。

テストを実行する

テストの用意が整ったので、実行してみます。Post ASR Evaluation API を実行します。結果を取得するためのIDが発行されます。

-> % curl --location --request POST 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxxx/asrEvaluations' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer Atzaxxxxxx' \
--data-raw '{
    "skill": {
        "stage": "development",
        "locale": "ja-JP"
    },
    "annotationSetId": "amzn1.ask.asr-annotation-set.a84e6c2e-xxxxxxx"
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   244  100    70  100   174     71    177 --:--:-- --:--:-- --:--:--   249
{
  "id": "amzn1.ask.asr-evaluation.a8a4a0c0-xxxxxxxx"
}

つづいて、NLU のテストも実行します。 Start an evaluation API を使います。呼び出しかたは ASR のときとほぼ同じですね。

-> % curl --location --request POST 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxxx/nluEvaluations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Atza|xxxxxx' \
--data-raw '{
  "stage": "development",
  "locale": "ja-JP",
  "source": {
    "annotationId": "d52feae5-a410-4f95-badf-5675fed8ae34"
  }
}' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   172  100    45  100   127     43    123  0:00:01  0:00:01 --:--:--   166
{
  "id": "f204cb5f-xxxxxx"
}

テスト結果を取得する

AnnotationSetのEvaluationは、非同期に実行されます。Evaluationの開始時に取得したIDをキーに、結果を取得します。まず、ASR Annotation Sets の評価結果を取得します。Get ASR Evaluation Results API を使います。音声ファイルは、期待したとおりに、”こんにちは”と STT(Speech To Text) されて、試験にパスしたことがわかります。

-> % curl --location --request GET 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxxxxx/asrEvaluations/amzn1.ask.asr-evaluation.a8a4a0c0-4570-xxxxxxx/results' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer Atza|xxxxxx' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   798  100   798    0     0   1842      0 --:--:-- --:--:-- --:--:--  1842
{
  "results": [
    {
      "annotation": {
        "audioAsset": {
          "downloadUrl": "https://audio-xxxxx-prod.s3.amazonaws.com/M2Axxxxxxx",
          "expiryTime": "2021-12-03T19:21:12.072Z"
        },
        "evaluationWeight": 1,
        "expectedTranscription": "こんにちは",
        "filePathInUpload": "konnichiha",
        "uploadId": "amzn1.ask-catalog.upl.59dbd3db-xxxxxxx"
      },
      "output": {
        "transcription": "こんにちは"
      },
      "status": "PASSED"
    }
  ]
}

つづいて、NLUの評価結果を確認します。Get the results of an evaluation API を使います。評価結果は、期待したIntentに入らなかったことが確認できます。

-> % curl --location --request GET 'https://api.amazonalexa.com/v1/skills/amzn1.ask.skill.842aa6a7-xxxxx/nluEvaluations/f204cb5f-xxxxxxx/results' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer Atza|xxxxxxxx' | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   440  100   440    0     0   1349      0 --:--:-- --:--:-- --:--:--  1345
{
  "_links": {
    "self": {
      "href": "/v1/skills/amzn1.ask.skill.842aa6a7-xxxxx/results"
    }
  },
  "paginationContext": {
    "totalCount": 1
  },
  "testCases": [
    {
      "actual": {
        "intent": {
          "confirmationStatus": "NONE",
          "name": "AMAZON.FallbackIntent",
          "slots": {}
        }
      },
      "expected": [
        {
          "intent": {
            "name": "AMAZON.CancelIntent",
            "slots": {}
          }
        }
      ],
      "inputs": {
        "utterance": "こんにちは"
      },
      "status": "FAILED"
    }
  ],
  "totalFailed": 1
}

まとめ

正直かなりめんどくさい作業ではありますが、アレクサスキルの認識率を継続的に高めていくためには、ASRとNLUを統合的に評価できるしくみがあるとよいことは間違いないです。現在は、ASRとNLUの評価が完全に分かれている状態のため、ユーザーの音声ファイルから期待するTranscriptionとそのTranscriptionから期待するIntentまでをこれらのAPIを組み合わせることによって、シームレスな評価サイクルが作れたりするとよいですね。