kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

今更ながらプロアクティブイベントAPIを試してみる② そう、Voiceflowでもね!

周回遅れネタでしたが、前回は前フリで、今日が本題です。

Voiceflowでプロジェクトを開いて、右上の歯車アイコンをクリック、「設定メニュー」を開いてみましょう。

f:id:kun432:20200802080339p:plain

プロジェクト名や呼び出し名を設定できますね。ここで”Advanced”タブをクリックします。

f:id:kun432:20200802080512p:plain

ん?

f:id:kun432:20200802080619p:plain

f:id:kun432:20200802080753p:plain

そう、Voiceflowではスキルイベントを設定できるのですね。前回のエントリを見ていただいた方ならわかると思いますが、

VoiceflowでもプロアクティブイベントAPIはできます!

ということでプロアクティブイベントAPI やってみるPart2はVoiceflow編です。

目次

プロアクティブイベントAPI対応スキルの作成

スキルの新規作成

まずはスキルを新規に作成します。「プロアクティブイベント通知のサンプル」というスキルを作成しました。

f:id:kun432:20200802082346p:plain

ブロックを並べるのは後でやりましょう。

スキルマニフェストの修正

前回同様、スキルマニフェストの修正を行います。Voiceflowの場合、ask-cliを使う必要はなく、冒頭にご紹介した「設定メニュー」でマニフェストの修正を行います。設定メニューの"Advanced"を再度開いてください。

f:id:kun432:20200802080619p:plain

でこのテキストエリアにスキルマニフェストを追記すれば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"というエントリが必要なようです。まあこのへんはお約束的に考えてもらえればいいかと思います。それ以外は前回と一緒ですね。

f:id:kun432:20200802083714p:plain

スキルで通知を許可させる

で、少しブロックを追加します。以下のようなフローを作成してください。

f:id:kun432:20200802084526p:plain

少し解説します。

スキルが起動したら、まずUser Info Blockで「通知(Notification)」が許可されているかをチェックします。許可されている場合は"Success"へ。許可されていない場合は"No Access"に分岐します。

f:id:kun432:20200802084709p:plain

許可されていない場合は、Permission Blockで「通知(Notification)」の権限許可を促すカードを送信するとともに、Speak Blockでその旨を伝えます。

f:id:kun432:20200802084955p:plain

許可されている場合はスキルのメインとなるフローを作ればよいです。今回はテストなのでSpeak Blockでメッセージを発話するだけにしてあります。

f:id:kun432:20200802085236p:plain

はい、これでアップロードしてください。

前回ask-cliで実施した際には、スキルマニフェストを更新するだけでクライアントIDやクライアントシークレットが確認できるようになっていましたが、Voiceflowではその権限を必要とするUser Info Blockをフローに入れた形でアップロードしないとこの情報は表示されません。

アップロードが完了したらAlexa開発者コンソールにアクセスして、クライアントIDやクライアントシークレットを確認しましょう。メニューから「ツール」→「アクセス権限」を開きます。

f:id:kun432:20200802084042p:plain

クライアントIDとクライアントシークレットが表示されていればOKです。メッセージ送信時に必要になるので、控えておいてください。

あと、テストシミュレータで一度スキルを実行するとカードが送信されるので、アクセス権の変更も行いましょう。

f:id:kun432:20200802090339p:plain

Alexaアプリの「アクティビティ」にカードが飛んでますね。(そういえばアプリがアップデートされてからホームカードが見当たらない気がする・・・)

f:id:kun432:20200802090620p:plain

通知権限を許可しておきます。

f:id:kun432:20200802090711p:plain

再度テストしてみました。きちんと許可されていますね。

f:id:kun432:20200802090758p:plain

これで準備は完了です。

送信用スキルの作成

送信は前回のスクリプトをそのまま使えばよいのですが、せっかくなのでこれもVoiceflowでやっちゃいましょう!最初に作ったスキルとは別のスキルを新規作成します。このスキルは最初のスキルに対して通知を行うだけのスキルなので、公開する必要はありません。

こんなフローを作ります。

f:id:kun432:20200802102650p:plain

順に見ていきましょう。

スキル起動後

まず、スキル起動後です。ここは単に、起動後のメッセージをAlexaが発話して、ユーザが「通知して」と発話したら次に進むインテントがあるだけなので、詳細は割愛します。

f:id:kun432:20200802102847p:plain

アクセストークンの取得

次、2段目のところですが、ここではプロアクティブイベントAPIへのリクエストに必要な「アクセストークン」を、クライアントID/シークレットを使って取得していまます。

f:id:kun432:20200802103143p:plain

最初に作成したスキル側で取得したクライアントID/シークレットをSet Blockで変数にセットしておきます。

f:id:kun432:20200802104043p:plain

クライアントID/シークレットを使って、API Blockでアクセストークンを取得します。

  • リクエスト先URLは https://api.amazon.com/auth/o2/token、メソッドはPOSTにします。
  • Headersタブで、Content-Type: application/x-www-form-urlencodedをHTTPヘッダーとして指定します。

f:id:kun432:20200802104427p:plain

  • BodyタブでHTTPボディを設定します。以下のパラメータをURL Encoded形式で設定します。
    • grant_type: client_credentials
    • client_id はさきほど設定した変数{client_id}を使います。
    • client_secret も同様に変数{client_secret}を使います。
    • scope: alexa::proactive_events

f:id:kun432:20200802104439p:plain

Transform Into Variablesでリクエストの結果を変数に入れます。リクエストの結果はresponseというオブジェクトで返ってきます。リクエストが成功していればresponseの中にaccess_tokenというキーがありますの、これをビルトインで用意されている{access_token}変数に入れます。ちなみに、Transform Into VariablesはHeaders/Body/Paramsどのタブで設定しても同じです。

f:id:kun432:20200802105400p:plain

成功すれば次に進みますが、失敗したときのためにSpeak Blockをつなげておきましょう。

f:id:kun432:20200802105531p:plain

イベントスキーマ作成のために必要な時刻情報の生成

アクセストークンが取得できたら、次はプロアクティブイベント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を使ってコードでこれらを生成します。

f:id:kun432:20200802110114p:plain

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内で変数を設定してもそのままでは他のブロックから見えません。他のブロックでもこの変数を利用したい場合は、対話モデルマネージャ(左下の""アイコン)で同じ名前の変数を作成しておくことを忘れないでください。

f:id:kun432:20200802110908p:plain

プロアクティブイベントAPIへのリクエス

アクセストークンおよびイベントスキーマに必要なパラメータの生成ができれば、あとはイベントスキーマ文字列を作成して送るだけです。

f:id:kun432:20200802111121p:plain

API Blockの設定はこんな感じです。

  • リクエストURLは、https://api.fe.amazonalexa.com/v1/proactiveEvents/stages/developmentにメソッドPOSTで送信します。公開スキルへの通知の場合とURLが変わることに注意してください。
  • Headersに以下を設定します。
    • Content-Type: application/json
    • Authorization: Bearer {access_token}。これが認証になります。

f:id:kun432:20200802111335p:plain

  • 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": {}
   }
}

f:id:kun432:20200802111602p:plain

はい、これでおしまいです。

通知の送信

テストシミュレータで送信用スキルを起動します。

f:id:kun432:20200802111800p:plain

送信が成功して、Echoデバイスに通知が来ていればOKです。

f:id:kun432:20200802112231j:plain

まとめ

ということで、VoiceflowでプロアクティブイベントAPIによる通知をやってみました。スキルマニフェストの更新にask-cli使う必要がなく、ブラウザだけで完結するのでとてもお手軽ですねー。

一応補足しておくと、スキルイベントが使えるといっても、これ実質プロアクティブイベントAPI専用といってもよいです。というのもの、スキルイベント、本来は発生したイベントの通知がスキル側に飛んでくるので、それを受けるためのハンドラを用意してあげれば音声以外での処理みたいなことが行えるのですが、Voicwflowでは音声入力以外のハンドラ(Choice Block/Intent Blockがそれですね)を作ることができません。例えばAPLのTouchイベントとかは今でも対応できないわけですね。将来的にこのあたりの機能がついてくると非常に面白いのではないかなーと思いますので期待して待ちたいと思います。

前回もお伝えしていますが、ユーザにダイレクトにリアルタイムにリーチできる機能なので、ぜひ活用してみてください!

参考

公式フォーラムに上がっているNicolasさんのエントリを参考にさせていただきました。Thanks Always! Nico!

forum.voiceflow.com