周回遅れネタでしたが、前回は前フリで、今日が本題です。
Voiceflowでプロジェクトを開いて、右上の歯車アイコンをクリック、「設定メニュー」を開いてみましょう。
プロジェクト名や呼び出し名を設定できますね。ここで”Advanced”タブをクリックします。
ん?
そう、Voiceflowではスキルイベントを設定できるのですね。前回のエントリを見ていただいた方ならわかると思いますが、
VoiceflowでもプロアクティブイベントAPIはできます!
ということでプロアクティブイベントAPI やってみるPart2はVoiceflow編です。
目次
プロアクティブイベントAPI対応スキルの作成
スキルの新規作成
まずはスキルを新規に作成します。「プロアクティブイベント通知のサンプル」というスキルを作成しました。
ブロックを並べるのは後でやりましょう。
スキルマニフェストの修正
前回同様、スキルマニフェストの修正を行います。Voiceflowの場合、ask-cliを使う必要はなく、冒頭にご紹介した「設定メニュー」でマニフェストの修正を行います。設定メニューの"Advanced"を再度開いてください。
でこのテキストエリアにスキルマニフェストを追記すればOKです。スキルマニフェストにはプロアクティブイベント通知に関連するもの以外にも、各エンドポイントやスキルの申請に関する情報も含まれていますが、プロアクティブイベント通知に関連する"publications"、"endpoint"、"subscriptions"だけを記載すればよいです。前回と同じAMAZON.MediaContent.Available
スキーマだとこんな感じです。
{ "publications": [ { "eventName": "AMAZON.MediaContent.Available" } ], "endpoint": { "uri": "https://voiceflow.app/state/skill/{version}", "sslCertificateType": "Wildcard" }, "subscriptions": [ { "eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED" } ] }
エンドポイントはARNではなくhttps://voiceflow.app/state/skill/{version}
というVoiceflow独自のエンドポイントで決め打ちになるようです。{version}
はVoiceflowが内部的に使っている変数でアップロードされるたびに更新されるようです。あとおそらくワイルドカード証明書を使っているのでしょう、"sslCertificateType": "Wildcard"
というエントリが必要なようです。まあこのへんはお約束的に考えてもらえればいいかと思います。それ以外は前回と一緒ですね。
スキルで通知を許可させる
で、少しブロックを追加します。以下のようなフローを作成してください。
少し解説します。
スキルが起動したら、まずUser Info Blockで「通知(Notification)」が許可されているかをチェックします。許可されている場合は"Success"へ。許可されていない場合は"No Access"に分岐します。
許可されていない場合は、Permission Blockで「通知(Notification)」の権限許可を促すカードを送信するとともに、Speak Blockでその旨を伝えます。
許可されている場合はスキルのメインとなるフローを作ればよいです。今回はテストなのでSpeak Blockでメッセージを発話するだけにしてあります。
はい、これでアップロードしてください。
前回ask-cliで実施した際には、スキルマニフェストを更新するだけでクライアントIDやクライアントシークレットが確認できるようになっていましたが、Voiceflowではその権限を必要とするUser Info Blockをフローに入れた形でアップロードしないとこの情報は表示されません。
アップロードが完了したらAlexa開発者コンソールにアクセスして、クライアントIDやクライアントシークレットを確認しましょう。メニューから「ツール」→「アクセス権限」を開きます。
クライアントIDとクライアントシークレットが表示されていればOKです。メッセージ送信時に必要になるので、控えておいてください。
あと、テストシミュレータで一度スキルを実行するとカードが送信されるので、アクセス権の変更も行いましょう。
Alexaアプリの「アクティビティ」にカードが飛んでますね。(そういえばアプリがアップデートされてからホームカードが見当たらない気がする・・・)
通知権限を許可しておきます。
再度テストしてみました。きちんと許可されていますね。
これで準備は完了です。
送信用スキルの作成
送信は前回のスクリプトをそのまま使えばよいのですが、せっかくなのでこれもVoiceflowでやっちゃいましょう!最初に作ったスキルとは別のスキルを新規作成します。このスキルは最初のスキルに対して通知を行うだけのスキルなので、公開する必要はありません。
こんなフローを作ります。
順に見ていきましょう。
スキル起動後
まず、スキル起動後です。ここは単に、起動後のメッセージをAlexaが発話して、ユーザが「通知して」と発話したら次に進むインテントがあるだけなので、詳細は割愛します。
アクセストークンの取得
次、2段目のところですが、ここではプロアクティブイベントAPIへのリクエストに必要な「アクセストークン」を、クライアントID/シークレットを使って取得していまます。
最初に作成したスキル側で取得したクライアントID/シークレットをSet Blockで変数にセットしておきます。
クライアントID/シークレットを使って、API Blockでアクセストークンを取得します。
- リクエスト先URLは
https://api.amazon.com/auth/o2/token
、メソッドはPOST
にします。 - Headersタブで、
Content-Type: application/x-www-form-urlencoded
をHTTPヘッダーとして指定します。
- BodyタブでHTTPボディを設定します。以下のパラメータを
URL Encoded
形式で設定します。grant_type: client_credentials
client_id
はさきほど設定した変数{client_id}
を使います。client_secret
も同様に変数{client_secret}
を使います。scope: alexa::proactive_events
Transform Into Variables
でリクエストの結果を変数に入れます。リクエストの結果はresponse
というオブジェクトで返ってきます。リクエストが成功していればresponse
の中にaccess_token
というキーがありますの、これをビルトインで用意されている{access_token}
変数に入れます。ちなみに、Transform Into Variables
はHeaders/Body/Paramsどのタブで設定しても同じです。
成功すれば次に進みますが、失敗したときのためにSpeak Blockをつなげておきましょう。
イベントスキーマ作成のために必要な時刻情報の生成
アクセストークンが取得できたら、次はプロアクティブイベントAPIに送信するイベントスキーマを作成します。ここで前回のスクリプトのイベントスキーマ生成部分を再掲します。
...snip... let timestamp = new Date(); let expiryTime = new Date(); expiryTime.setMinutes(expiryTime.getMinutes() + 60); return { 'timestamp': timestamp.toISOString(), 'referenceId': 'id-'+ new Date().getTime(), 'expiryTime': expiryTime.toISOString(), 'event': { 'name': 'AMAZON.MediaContent.Available', 'payload': { 'availability': { 'startTime': timestamp.toISOString(), 'provider': { ...snip...
イベントスキーマの中にいくつか日時情報とそれと元にしたパラメータをDateなどを使って生成していますね。同様にVoiceflowでもCustom Code Blockを使ってコードでこれらを生成します。
Custom Code Blockのコードはこんな感じです。これにより必要な日時情報がreferenceId, now, expiryTime, startTimeという変数に結果が入ります。
var now = new Date(); var expiryTime = new Date(); expiryTime.setMinutes(expiryTime.getMinutes() + 60) var startTime = new Date(); var referenceId = 'id-'+ new Date().getTime(); now = now.toISOString(); expiryTime = expiryTime.toISOString(); startTime = startTime.toISOString();
ただしCustom Code Block内で変数を設定してもそのままでは他のブロックから見えません。他のブロックでもこの変数を利用したい場合は、対話モデルマネージャ(左下の""アイコン)で同じ名前の変数を作成しておくことを忘れないでください。
プロアクティブイベントAPIへのリクエスト
アクセストークンおよびイベントスキーマに必要なパラメータの生成ができれば、あとはイベントスキーマ文字列を作成して送るだけです。
API Blockの設定はこんな感じです。
- リクエストURLは、
https://api.fe.amazonalexa.com/v1/proactiveEvents/stages/development
にメソッドPOSTで送信します。公開スキルへの通知の場合とURLが変わることに注意してください。 - Headersに以下を設定します。
Content-Type: application/json
Authorization: Bearer {access_token}
。これが認証になります。
- BodyはRaw形式で以下のデータを指定します。ところどころ変数が含まれている箇所が前処理で生成してたところですね。
{ "timestamp": "{now}", "referenceId": "{referenceId}", "expiryTime": "{expiryTime}", "event": { "name": "AMAZON.MediaContent.Available", "payload": { "availability": { "startTime": "{now}", "provider": { "name": "localizedattribute:providerName" }, "method": "RELEASE" }, "content": { "name": "localizedattribute:contentName", "contentType": "EPISODE" } } }, "localizedAttributes": [ { "locale": "ja-JP", "providerName": "proactive event api sample", "contentName": "push notification test" } ], "relevantAudience": { "type": "Multicast", "payload": {} } }
はい、これでおしまいです。
通知の送信
テストシミュレータで送信用スキルを起動します。
送信が成功して、Echoデバイスに通知が来ていればOKです。
まとめ
ということで、VoiceflowでプロアクティブイベントAPIによる通知をやってみました。スキルマニフェストの更新にask-cli使う必要がなく、ブラウザだけで完結するのでとてもお手軽ですねー。
一応補足しておくと、スキルイベントが使えるといっても、これ実質プロアクティブイベントAPI専用といってもよいです。というのもの、スキルイベント、本来は発生したイベントの通知がスキル側に飛んでくるので、それを受けるためのハンドラを用意してあげれば音声以外での処理みたいなことが行えるのですが、Voicwflowでは音声入力以外のハンドラ(Choice Block/Intent Blockがそれですね)を作ることができません。例えばAPLのTouchイベントとかは今でも対応できないわけですね。将来的にこのあたりの機能がついてくると非常に面白いのではないかなーと思いますので期待して待ちたいと思います。
前回もお伝えしていますが、ユーザにダイレクトにリアルタイムにリーチできる機能なので、ぜひ活用してみてください!
参考
公式フォーラムに上がっているNicolasさんのエントリを参考にさせていただきました。Thanks Always! Nico!