スキルにカスタムタスクを追加する



スキルにカスタムタスクを追加する

すでにAlexaスキルを開発している場合は、タスクを実行するよう変更できます。ここでは、Alexaスキルにカスタムタスクを作成する方法を紹介します。カスタムタスクを使用すると、Direct Skill Connectionsを通じてほかのスキルから機能を利用できるようになります。Skill Connectionsの詳細については、Skill Connectionsとはを参照してください。

前提条件

ここでは、ASK CLI v2を使用する必要があります。ASK CLI GitHubリポジトリから入手してください。

カスタムタスクをサポートできるようスキルパッケージを変更する

開発者コンソールではなく、ASK CLIでスキルの作成や変更を行っている場合、スキルパッケージを直接編集できます。詳細については、スキルパッケージの形式を参照してください。

スキルパッケージを変更する

  • skill.jsonファイルを保存したskill-packageフォルダに、tasksというサブフォルダを作成します。tasksフォルダには、タスク定義ファイルを格納します。
スキルパッケージフォルダ内のtasksサブフォルダ
スキルパッケージフォルダ内のtasksサブフォルダ

タスク定義ファイルを作成する

タスク定義はOpenAPI V3の仕様に従い、次の制限があります。

  1. タスク定義ファイルの名前は、{TaskName}.{TaskVersion}.jsonの形式にします。{TaskName}にはタスク名、{TaskVersion}にはタスクのバージョン番号を指定します。たとえば、CountDown.1.jsonのようになります。
  2. タスク名は、パスとして表されます。たとえば、タスク名がCountDownの場合、OpenAPIの仕様では/CountDownのように表されます。
  3. タスクのバージョンには正の整数のみ指定できます。
  4. 1つのファイルに含めることができるタスク定義は1つだけです。つまり、ファイルごとに1つのパスのみ指定できます。
  5. 現時点で使用できるのは、インライン参照のみです。
  6. タスクのペイロードは、上記で指定したパスのPOST本文として表されます。指定できるHTTPメソッドはPOSTのみです。
  7. POSTrequestBodyには、application/jsonのみ指定できます。
  8. POSTresponsesには、application/jsonのみ指定できます。
  9. infox-amzn-alexa-access-scopeフィールドは、アクセス制御のカスタム拡張フィールドです。publicおよびvendor-private設定を指定できます。タスク定義にアクセススコープ値が指定されていない場合、デフォルト値のvendor-privateとなります。
  10. infoオブジェクトのx-amzn-display-detailsフィールドは、カスタム拡張フィールドです。ローカライズした言語のタスクタイトルを割り当てることができます。x-amzn-display-details値が指定されない場合、デフォルト値としてinfo.titleフィールドの値が使用されます。
  11. タスクには、少なくとも1つのinputパラメーターが必要です。
  12. タスクコンポーネントのInputプロパティ内のx-amzn-display-detailsフィールドは、カスタム拡張フィールドです。タスクのinputパラメーターに人が読める文字列を追加し、オプションでローカライズした言語のパラメーターを割り当てることができます。x-amzn-display-detailsフィールドが指定されない場合、プロパティ内部のプロパティ名自体が使われます。

以下は、ASK CLI 2.0での応答例です。

$ ask smapi get-task -s <yourSkillId> --task-name amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown --task-version 1
  {
   "openapi": "3.0.0",
   "info": {
     "title": "数字カウントダウンタスク",
     "version": "1",
     "x-amzn-alexa-access-scope": "public",
     "x-amzn-display-details": {
      "ja-JP": {
       "title": "数字カウントダウンタスク"
      },
      "en-US": {
       "title": "A task to count down numbers"
      }
     }
   },
   "tags": [{
     "name": "count down"
   }],
   "paths": {
     "/CountDown": {
       "summary": "カウントダウン",
       "description": "カウントダウンを開始",
       "post": {
         "requestBody": {
           "content": {
             "application/json": {
               "schema": {
                 "$ref": "#/components/schemas/Input"
               }
             }
           }
         },
         "responses": {
           "200": {
             "description": "カウントダウンが正常に完了する場合",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "#/components/schemas/SuccessfulResponse"
                 }
               }
             }
           },
           "400": {
             "description": "指定したパラメーターの検証が失敗する場合 - 例:lowerLimitにupperLimitより大きな数を指定することはできません"
           },
           "500": {
             "description": "カウントダウンが失敗する場合"
           }
         }
       }
     }
   },
   "components": {
     "schemas": {
       "Input": {
         "type": "object",
         "properties": {
           "upperLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1,
             "x-amzn-display-details": {
              "ja-JP": {
               "name": "上限"
              },
              "en-US": {
               "name": "Upper Limit"
              }
             }
           },
           "lowerLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1,
             "x-amzn-display-details": {
              "ja-JP": {
               "name": "下限"
              },
              "en-US": {
               "name": "Lower Limit"
              }
             }
           }
         }
       },
       "SuccessfulResponse": {
         "type": "object",
         "properties": {
           "endTime": {
             "type": "string",
             "format": "date-time"
           }
         }
       }
     }
   }
}

タスク定義ファイルを作成する

  • テキストエディターで、/tasksディレクトリにCountDown.1.jsonという名前のタスク定義ファイルを新規作成し、以下のJSONコードをコピーします。
{
   "openapi": "3.0.0",
   "info": {
     "title": "カウントダウンするタスク",
     "version": "1",
     "x-amzn-alexa-access-scope": "public"
   },
   "tags": [{
     "name": "カウントダウン"
   }],
   "paths": {
     "/CountDown": {
       "summary": "カウントダウン",
       "description": "カウントダウンを開始",
       "post": {
         "requestBody": {
           "content": {
             "application/json": {
               "schema": {
                 "$ref": "#/components/schemas/Input"
               }
             }
           }
         },
         "responses": {
           "200": {
             "description": "カウントダウンが正常に完了する場合",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "#/components/schemas/SuccessfulResponse"
                 }
               }
             }
           },
           "400": {
             "description": "指定したパラメーターの検証が失敗する場合 - 例:lowerLimitにupperLimitより大きな数を指定することはできません"
           },
           "500": {
             "description": "カウントダウンが失敗する場合"
           }
         }
       }
     }
   },
   "components": {
     "schemas": {
       "Input": {
         "type": "object",
         "properties": {
           "upperLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1
           },
           "lowerLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1
           }
         }
       },
       "SuccessfulResponse": {
         "type": "object",
         "properties": {
           "endTime": {
             "type": "string",
             "format": "date-time"
           }
         }
       }
     }
   }
}

テスト例を追加して、タスク定義の認定を申請する

スキルをテストして認定を申請すると、カスタムタスクの機能が検証されます。タスク定義ファイルでは、カスタムタスクのテスト例を提供してください。これらのテスト例は、認定前および認定の検証中に、スキルのAWS Lambda関数でカスタムタスクハンドラーを呼び出すための入力の生成に使用されます。

テスト例の定義はOpenAPI V3の仕様に従い、次の制限があります。

  1. カスタムタスクごとに、少なくとも1つのテスト例とカスタムタスク定義を提供する必要があります。カスタムタスクごとに、5つまでテスト例を提供できます。
  2. テスト例が有効であり、スキルのカスタムタスクが呼び出された際に正常な応答を返すことを確認してください。
  3. 各テスト例には、次のフィールドが含まれます。
名前 必須 説明
summary 文字列 テスト例の概要です。
description × 文字列 テスト例の説明です。
value オブジェクト タスク定義に準拠した有効なカスタムタスク入力です。

テスト例をタスク定義ファイルに追加する

  • テキストエディターで、post/requestBody/content/application/json/examplesのパスにあるタスク定義ファイルにテスト例を追加します。以下は、タスク定義リクエスト本文にテスト例を追加する例です。
"requestBody": {
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/Input"
            },
            "examples": {
                "countdownTenToOne": {
                    "summary": "10から1にカウントダウンする入力の例",
                    "description": "入力例はタスクの検証に使用されます",
                    "value": {
                        "upperLimit": 10,
                        "lowerLimit": 1
                    }
                },
                "countdownHundredToNinety": {
                    "summary": "100から90にカウントダウンする入力の例",
                    "description": "入力例はタスクの検証に使用されます",
                    "value": {
                        "upperLimit": 100,
                        "lowerLimit": 90
                    }
                }
            }
        }
    }
}

AWS Lambda関数にタスク機能を実装する

次に、CountDown機能をAWS Lambdaに実装します。ここでは、Pythonを使用します。

class CountDownTaskHandler(AbstractRequestHandler):
  def can_handle(self, handler_input):
    return is_request_type("LaunchRequest")(handler_input)\
      and handler_input.request_envelope.request.task.name == "amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown"
      
  def handle(self, handler_input):
    # カウントダウンしてタスクを完了する
    response_builder = handler_input.response_builder
    
    task = handler_input.request_envelope.request.task

    lower_limit = task.input['lowerLimit']
    upper_limit = task.input['upperLimit']

    count_down_speech = [i + '<break time="1ms" />' for i in range(lower_limit, upper_limit)]
    response_builder.speak("<ssml>" + "".join(count_down_speech) + "</ssml>")
    response_builder.add_directive(CompleteTaskDirective(...))

    return response_builder.response

ほかのスキルでタスクを利用できるようにする

新しいタスクをほかのスキルから利用できるようにするには、スキルパッケージに作成したのと同じカスタムタスクを実装したスキルを登録する必要があります。

タスクを実装したスキルを登録する

  • 次の例のように、skill.jsonファイルを編集します。
{
  ...
  "apis": {
    "custom": {
      ...
      "tasks": [{
        "name": "CountDown",
        "version": "1"
      }]
    }
  }
}

スキルをデプロイする

スキルのタスクをリクエスタースキルから利用できるようにするには、スキルを次のようにデプロイする必要があります。

新しいスキルをデプロイする

  • ASK CLIで、ask deployコマンドを実行します。

カスタムスキルを既存スキルに追加してデプロイする(ASK CLI)

スキルをデプロイしたら、タスクがdevelopmentステージのスキルのプライベート名前空間に作成されます。

カスタムスキルを既存スキルに追加してデプロイする(SMAPI)

SMAPIを使ってプログラムでスキルを管理している場合、次の手順で既存スキルにタスクをデプロイできます。

  1. 後続のステップで使用するアクセストークンを取得するすべてのSMAPIリクエストのAuthorizationヘッダーに、このトークンを指定する必要があります。アクセストークン取得の詳細については、SMAPIで使用するアクセストークンの取得方法を参照してください。
  2. (任意)ローカルにスキルパッケージのコピーがない場合は、次の手順を実行します。
    1. スキルパッケージ形式でスキルパッケージを書き出します。
    2. 書き出しリクエストのステータスを取得します。書き出しリクエストのステータスがSUCCEEDEDの場合、応答のskillフィールドのlocationフィールドには、書き出したスキルのzipアーカイブをダウンロードするURLが含まれます。
  3. ローカルでスキルを編集し、タスク定義に必要な変更を加えます。
  4. スキルパッケージをzip形式に圧縮します。
  5. zip形式のスキルパッケージを公開URLにアップロードするか、Amazon S3へのスキルパッケージのアップロードに使用する署名済みアップロードURLを作成します。
  6. スキルに、アップロードされたスキルパッケージを読み込みます。
  7. 読み込みリクエストのステータスをチェックして、スキルが正常に読み込まれたことを確認します。

タスクハンドラーを呼び出す

  • 次の例のように、ASK CLIのinvoke-skill-end-pointコマンドでタスクハンドラーを呼び出して、タスクロジックが正しく実行されることを確認します。このコマンドはタスクワークフローを実行しません。タスクワークフローを実行するには、スキルが認定され、公開される必要があります。このコマンドの使用方法の詳細については、ASK CLIコマンドリファレンスを参照してください。
$ ask smapi invoke-skill-end-point -s {skillId} --stage {skillStage} --skill-request-body file:./input.json --endpoint-region {endpoint-region}

input.jsonファイルは以下のようになります。

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "amzn1.echo-api.session.aaf7b112-434c-11e7-2563-6bbd1672c748",
        "application": {
            "applicationId": "{YourProviderSkillId}"
        },
        "user": {
            "userId": "amzn1.ask.account.12345ABCDEFGH"
    	}
    },
    "context": {
        "System": {
            "application": {
                "applicationId": "{YourProviderSkillId}"
            },
            "user": {
                "userId": "amzn1.ask.account.12345ABCDEFGH"
            }
        }
    },
    "request": {
        "type": "LaunchRequest",
        "requestId": "amzn1.echo-api.request.da528275-5aa6-4f69-8038-06efc94d1923",
        "timestamp": "2020-01-29T23:11:48Z",
        "locale": "ja-JP",
        "task": {
            "name": "{YourProviderSkillId}.{taskName}",
            "version": "{taskVersion}",
            "input": {
                ...          
            }
        }
    }
}

カスタムスキルへのアクセスを制限する

カスタムスキルへのアクセスを制限することができます。現在、サポートされているアクセスレベルは2つです。

  • 公開: タスクはすべてのスキルに公開されます。
  • ベンダープライベート: タスクは同じベンダーのスキルに対してのみ公開されます。たとえば、このタスクはほかのベンダーのスキル開発者の検索結果には表示されません。

デフォルトでは、すべてのカスタムタスクは、まずベンダープライベートアクセスレベルで作成されます。タスクのアクセスレベルを設定するには、タスク定義ファイルのinfoセクションを変更し、x-amzn-alexa-access-scopeフィールドにpublic(公開アクセスの場合)、vendor-private(ベンダープライベートアクセスの場合)のいずれかを設定する必要があります。

Skill Connectionsでカスタムタスクを利用できるようにする方法

タスクをほかのスキルに公開するには、プロバイダースキルが認定され、公開されている必要があります。 スキルの認定と公開の説明に従い、スキル認定の申請と公開を行ってください。認定と公開が完了したら、スキルはliveステージに移行します。タスクはタスクカタログに追加され、Skill Connectionsを通じて別のスキルから利用できるようになります。

開発者は、ASK CLIのsearch-taskコマンドやget-taskコマンドを使ってタスクを検索できます。

-hオプションを使うと、CLIコマンドのコマンドラインヘルプを表示できます。ask smapi search-task -hのように使います。

以下は、ASK CLI 2.0で、すべてのオプションを指定してask smapi search-taskコマンドを実行した例です。(skillIdのみが必須です。開発者アカウントの任意のskillIdを使用できます。provider-skill-idは任意です。プロバイダースキルのIDが指定された場合、結果には開発者アカウントがアクセスできる、プロバイダースキルのカスタムタスクがすべて表示されます)。

ask smapi search-task -s <skillId> --keywords <keywords> --provider-skill-id <providerSkillId> --max-results <max-results> —-next-token <nextToken>

以下は、ASK CLI 2.0の出力例です。

$ ask smapi search-task -s {skillId} --keywords "カウントダウン"

{
  "taskSummaryList": [
    {
      "description": "数字カウントダウンタスク",
      "name": "amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown",
      "version": "1"
    },
    {
      "description": "100から1までの数字をカウントダウン",
      name": "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef.CountDown",
      "version": "1"
    }
  ]
}

$ ask smapi search-task -s <yourSkillId> --provider-skill-id "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef"
    
    {
      "taskSummaryList": [
        {
          "description": "100から1までの数字をカウントダウン",
          "name": "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef.CountDown",
          "version": "1"
        }
      ]
    }
   

以下は、ASK CLI 2.0で、すべてのオプションを指定してask smapi get-taskコマンドを実行した例です(すべてのオプションが必須です)。

ask smapi get-task -s <yourSkillId> --task-name <providerSkillID>.<name> --task-version <task-version>

以下は、ASK CLI 2.0での応答例です。

コマンドは次のとおりです。

$ ask smapi get-task -s <yourSkillId> --task-name amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown --task-version 1

出力結果は次のとおりです。

{
   "openapi": "3.0.0",
   "info": {
     "title": "数字カウントダウンタスク",
     "version": "1",
     "x-amzn-alexa-access-scope": "public"
   },
   "tags": [{
     "name": "カウントダウン"
   }],
   "paths": {
     "/CountDown": {
       "summary": "カウントダウン",
       "description": "カウントダウンを開始",
       "post": {
         "requestBody": {
           "content": {
             "application/json": {
               "schema": {
                 "$ref": "#/components/schemas/Input"
               }
             }
           }
         },
         "responses": {
           "200": {
             "description": "カウントダウンが正常に完了する場合",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "#/components/schemas/SuccessfulResponse"
                 }
               }
             }
           },
           "400": {
             "description": "指定したパラメーターの検証が失敗する場合 - 例:lowerLimitにupperLimitより大きな数を指定することはできません"
           },
           "500": {
             "description": "カウントダウンが失敗する場合"
           }
         }
       }
     }
   },
   "components": {
     "schemas": {
       "Input": {
         "type": "object",
         "properties": {
           "upperLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1
           },
           "lowerLimit": {
             "type": "number",
             "maximum": 100,
             "minimum": 1
           }
         }
       },
       "SuccessfulResponse": {
         "type": "object",
         "properties": {
           "endTime": {
             "type": "string",
             "format": "date-time"
           }
         }
       }
     }
   }
}

Skill Connectionsを通じてタスクが呼び出されるしくみ

タスクの認定と公開が完了してliveステージに移行すると、ほかのスキルからタスクの標準IDを使ってタスクをリクエストできるようになります。標準IDは、skillIdとタスク名を連結したIDで、{ProviderSkillId}.CountDownのように表記します。

リクエスタースキルがタスクに接続するには、スキルが応答で次のディレクティブを返す必要があります。カスタムタスクをリクエストするには、リクエスタースキルが、URIにプロバイダースキルIDを指定して、Direct Skill Connectionsを送信する必要があります。

{
  "type": "Connections.StartConnection",
  "uri": "connection://{ProviderSkillId}.CountDown/1?provider={ProviderSkillId}",
  "input": {
    "lowerLimit": 1,
    "upperLimit": 10
  }
}

タスクのリクエスト方法の詳細については、プロバイダースキルのタスクをリクエストするを参照してください。