はじめに
いつの間にか SMAPIに get-task
、search-task
などのタスクを操作するコマンドが追加されていたので使ってみようと思った。現状では、一般開発者がカスタムタスクを作っても、特に何かができるというわけではないので、今回は単純にスキルにタスクを追加してSMAPIで操作してみたというもの。
カスタムタスクでできること。
No. | できること | 概要 |
---|---|---|
1. | Alexa定型アクション | 予め指定した値を使ってスキルを起動することができる。 |
2. | Direct Skill Connections | 他のスキルと連携する。 |
3. | Quick Links for Alexa | スキル起動時に外部から値を渡すことができる。 |
4. | Timer API(LAUNCH_TASK) | タイマーが鳴った後にスキルを再開する。 |
前提
- ASK CLI v2(ASK CLI v1ではデプロイできない)
- スキルの公開(カスタムタスクの動作をEchoデバイスで確認する場合)
現在、ASK CLI v1を使用している方は、Alexa ASK CLI を v2 にバージョンアップして、スキルプロジェクトを v2 用にマイグレーション する必要があります。
手順
-
ask new
する。 -
skill-package/
フォルダ配下にtasks/
フォルダを手動で作成する。 - タスク定義ファイルを手動で作成する。
-
skill.json
にタスク情報を追加する。 - Lambda関数にカスタムタスクを判別するコードを追加する。
-
ask deploy
する。 - カスタムタスクの動作を確認する。
- SMAPIコマンドでタスクを確認する。
ask new する
まずスキルを作成する。
任意のフォルダを作成して、ask new
する。
ask new
tasksフォルダを作成する
作成したスキルの skill-package/
フォルダ配下に移動し、tasks
(※固定)という名称のフォルダを手動で新規作成をする。
CustomTask:
│ ask-resources.json
│
├─.ask
│ ask-states.json
│
├─lambda
│ index.js
│ package.json
│ util.js
│
└─skill-package
│ skill.json
│
├─assets
│ ja-JP_largeIcon.png
│ ja-JP_smallIcon.png
│
├─interactionModels
│ └─custom
│ ja-JP.json
│
└─tasks ←‐‐‐ フォルダを作成する
CountDown.1.json ←‐‐‐ タスク定義ファイルを作成する
タスク定義ファイルを作成する
tasks/
フォルダ配下にタスク定義ファイル
を手動で新規作成する。
※タスクの定義ファイルはOpenAPI V3
仕様に準拠
制限事項(抜粋)
- タスク定義ファイルのファイル名は
{TaskName}.{TaskVersion}.json
の形式となる。 - タスク名がパスとなる。例)タスク名が
CountDown
の場合、/CountDown
になる。 - 1タスク定義ファイルにつき1タスクとなる。
詳しくは、公式ドキュメントを参照
タスク定義ファイル
CountDown
というタスク名称で、バージョンが 1
の場合、ファイル名は CountDown.1.json
となる。 以下のJSONをコピーするだけ。
{
"openapi": "3.0.0",
"info": {
"title": "Task to perform a count down",
"version": "1",
"x-amzn-alexa-access-scope": "vendor-private"
},
"tags": [{
"name": "count down"
}],
"paths": {
"/CountDown": {
"summary": "Count Down",
"description": "To start a count down",
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Input"
}
}
}
},
"responses": {
"200": {
"description": "When the count down finishes successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuccessfulResponse"
}
}
}
},
"400": {
"description": "When the given parameters fail validations - e.g. lowerLimit cannot be higher than upperLimit"
},
"500": {
"description": "When the count down fails"
}
}
}
}
},
"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.json にタスク情報を追加する
タスクを実装するスキルを作成するには、以下のようにskill.json
にタスク情報を追加する必要がある。
{
...
"apis": {
"custom": {
...
"tasks": [{
"name": "CountDown",
"version": "1"
}]
}
}
}
Lambda関数にカスタムタスクを判別するコードを追加する
カスタムタスクから起動された場合 handlerInput.requestEnvelope.request.task
に値が格納される。
タスク名で判別させて目的の処理を実行させる。タスク起動でない場合、task は undefined
となる。
task = handlerInput.requestEnvelope.request.task;
if (task.name === 'amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1.CountDown') {
let campaignsCode = task.input.CampaignsCode;
console.log(`LaunhcRequestHandler campaignsCode: ${campaignsCode}`);
}
ask deploy する
ASK CLI v2で、ask deployコマンドを実行する。
ask deploy
カスタムタスクの動作を確認する
カスタムタスクはスキルを公開していないとEchoデバイスで確認することができない。
そのため、invoke-skill-end-point
を使用して動作確認をする。
ask smapi invoke-skill-end-point -s amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1 --stage development --skill-request-body file:./input.json --endpoint-region FE
※skill.jsonのregionsにエンドポイントが設定されていないとエラーになる。
"regions": {
"FE": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:023972248338:function:ask-custom-SosuDice-default"
}
}
},
input.json のサンプル を参考に input.json を作成してください。自分のスキルを実行したときに CloudWatchログに表示されるRequsetを使っても "message": "Session object of the skill request body does not contain a skill id that matches that of the request path."というメッセージが表示され、実行できなかった。なぜか公式の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": "1",
"input": {
"upperLimit": 10,
"lowerLimit": 2
}
}
}
結果が戻ってくればOK。
"invocationResponse": {
"body": {
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>タスク起動です。</speak>"
}
},
"userAgent": "ask-node/2.10.1 Node/v12.18.4",
"sessionAttributes": {}
}
},
SMAPIコマンドでタスクを確認する
スキルが公開されていることが前提。
ASK CLI が v2 になったばかりの頃は、SMAPIにタスクを確認するコマンドはなかったので、v2でタスクを作成して、v1で確認するという、わけのわからない状況だったが、やっと改善され get-task
、search-task
という2つのコマンドが追加された。
(注意)スキルの公開前に、search-task
コマンドや get-task
コマンドを使っても、そのタスク情報は返却されない。
get-task
指定されたタスク名とバージョン
の組合せでタスク定義の詳細を取得する。
--task-name
はCountDown
だけでは検索できず、以下のようにamzn1....で始まる名前を指定する必要がある。--task-name
はsearch-task
コマンドを実行することで確認できる。
get-task
コマンドを実行すると、上記で作成したタスクが画面に表示される。
ask smapi get-task --skill-id amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1 --task-name amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1.CountDown --task-version 1
search-task
スキルのタスク情報を取得する。キーワードとプロバイダースキルIDで検索できる。キーワードとプロバイダースキルIDの両方を省略すると、そのスキルのすべてのタスクが返されます。
ask smapi search-task --skill-id amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1
{
"nextToken": "AAIAAUQUjdUvlTskvOjFe6MRnJzD5jfhxC2aN3cuMXVhZq_WiANmN4f8x4a45EF4Bbp5sRfdOUm3T===",
"taskSummaryList": [
:
:
{
"description": "To start a count down",
"name": "amzn1.ask.skill.f40f1525-e285-481a-xxxx-4a4665be4fb1.CountDown",
"version": "1"
},
:
:
],
"totalCount": 47
}
おわりに
現在、一般開発者は、カスタムタスクを作成したとしても何もできない状態であるため、はやくSkill Connections
などタスクを使える仕組みを一般開発者にも解放して欲しいと思う。
※記事を書いてから3年ぐらい経過した。カスタムタスクでできることが増えてスキル開発の幅も広がってきたと思う。個人的には、タイマー鳴ったあとにもう一度スキルを起動できる仕組みが気に入っている。