今更の今更ながらプロアクティブイベントAPIを試したけどBOCCO emo Platform APIでいいやと思った話

#はじめに
こんにちは。介護や障害福祉に特化したエンジニアをしている福村といいます。
Alexaは体が不自由な高齢者や障害者にも有効だと考え、初期から注力していますが、ようやく最近 AWS CLFをとったぐらいのよわよわエンジニアです。

この記事は、Alexaのプロアクティブ（通知）について考えてみた、スマートスピーカー Advent Calendar 2021 の12日目の記事です。

https://qiita.com/advent-calendar/2021/smart-speaker

#目次
- プロアクティブ（通知）って使ってますか？
- プロアクティブの詳しいサイトはこの２つ！
- プロアクティブ概要
- プロアクティブの実際の動き
- プロアクティブのユースケース
- プロアクティブで困っていること
- BOCCOならクリアできる
- まとめ

#プロアクティブ（通知）って使ってますか？
介護している/されている人へのAlexa活用を考えている私としては、通知の機能は「すごい使えそう！」って思いました。
ただ、当初あまり参考となる記事も少なく、公式ドキュメントを読み進める余裕と能力がなかったので放置していたのですが、最近調べると色々なサイトが多くなってきたので、取り組んでみました。

#プロアクティブの詳しいサイトはこの２つ！
###Alexa Deep Dive 第5章

https://github.com/aajug/book-alexa-deep-dive/releases

言わずと知れた、日本Alexa開発コミュニティ「AAJUG」メンバーが書いた本。
日本のAlexaチャンピオン全4人、それ以外にもVUI界隈での著名人ばかりのすごい本。
これが無料で公開されているので、感謝しつつ読みましょう。
プロアクティブに関しては、第5章のせーのさんが書かれています。

###kun432's blog

https://kun432.hatenablog.com/entry/proactive-event-api-part-1

Alexa Deep Diveを参考としたブログ記事。
今回のアドベントカレンダー作成者の @kun432 さんのブログですね。
ええ、もうばれたかと思いますが、本記事のタイトルはこのブログ記事をパクってますｗ

本記事はこの２つを参考にしながら、プロアクティブを試した内容となります。

#プロアクティブ概要
詳細は上記2つの内容をご覧いただけると良いですが、プロアクティブを実現させる手順の概要は以下になります。
1.スキルを作成する
2.SMAPIでマニフェストファイルにパーミッションとイベントスキーマを追加する
3.スクリプトでメッセージを送信する

###1.スキルを作成する
適当なスキルをつくります。
hostedスキルでテンプレートのHello World（「スクラッチで作成」）が簡単で良いです。
プロアクティブ自体は、スキルのコードには全く何も書く必要がないため、ビルドさえできるスキルにすれば良いです。

###2.SMAPIでマニフェストファイルにパーミッションとイベントスキーマを追加する
ちょっとめんどくさいですね。
ASK CLIで1で作成したスキルのマニフェストファイルを追記します。
コンソールでいつかできるようになったら良いのになと思います。

一点ハマったのはマニフェストファイルの更新です。
ASK CLIのV2を使っているのですが、参考サイトや公式ドキュメントを見ても以下のように書いてたのですが、なぜか私の環境ではエラーとなりました。

```
ask smapi update-skill-manifest -s amzn.ask.skill.xxxxx-xxxx-xxxx -g development --manifest "$(cat skill.json)"
```

公式ドキュメントをくまなく調べてみて、以下ならうまくいきました。

```
ask smapi update-skill-manifest -s amzn.ask.skill.xxxxx-xxxx-xxxx -g development --manifest "file:skill.json"
```

manifestオプションの書式が違うようにしたのですが、これが正しいのか不明です。
公式ドキュメントの下記あたりを読んだのですが、どれが正しいことをいっているのかがよくわからず。。。

https://developer.amazon.com/ja-JP/docs/alexa/smapi/ask-cli-command-reference.html

https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-known-issues.html

https://developer.amazon.com/ja-JP/docs/alexa/smapi/add-events-to-your-skill-with-smapi.html

###3.スクリプトでメッセージを送信する
トークンを取得して、メッセージを送信するスクリプトをつくって実行します。
「Alexa Deep Dive 第5章」ではAMAZON.TrashCollectionAlert.Activated（ごみ収集のリマインダー）、「kun432's blog」ではAMAZON.MediaContent.Available（メディアコンテンツの利用状況通知）となっていたので、今回はAMAZON.MessageAlert.Activated（メッセージのリマインダー）にしました。

```
const rp = require('request-promise');

const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;


notify(); 

async function notify() {
    const token = await getToken(clientId, clientSecret);
    console.log(`[DEBUG] access_token: ${token}`);
    await sendEvent(token);
}

async function getToken(clientId, clientSecret) {
    const uri = 'https://api.amazon.com/auth/o2/token'

    let body = 'grant_type=client_credentials';
    body += '&client_id=' + clientId;
    body += '&client_secret=' + clientSecret;
    body += '&scope=alexa::proactive_events';

    const options = {
        method: 'POST',
        uri: uri,
        timeout: 30 * 1000,
        body: body,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    };
    const data = await rp(options);
    return JSON.parse(data).access_token;
}

async function sendEvent(token) {

    const body = JSON.stringify(messageAlertActivatedEvent());
    const uri = 'https://api.fe.amazonalexa.com/v1/proactiveEvents/stages/development'
    //const uri = 'https://api.fe.amazonalexa.com/v1/proactiveEvents/' // 公開スキルでは、こちら

    const options = {
        method: 'POST',
        uri: uri,
        timeout: 30 * 1000,
        body: body,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': body.length,
            'Authorization' : 'Bearer ' + token
        }
    };
    await rp(options);
}

function messageAlertActivatedEvent() {

    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.MessageAlert.Activated',
           'payload': {
              'state': {
                 'status': 'UNREAD',
                 'freshness': 'NEW'
              },
              'messageGroup': {
                 'creator': {
                     'name': 'fukumura tsuuchi...'
                 },
              'count': 1,
              'urgency': 'URGENT'
              }
           }
        },
        'localizedAttributes': [
            {
                'locale': 'ja-JP',
            }
        ],
        'relevantAudience': {
            "type": "Unicast",
            "payload": {
                "user": "amzn1.ask.account.XXX...XXXX"
            }
        }
    }
}
```

#プロアクティブの実際の動き
私もアイコン設定の部分（？）でハマり、最初うまく動かなかったのですが、再設定後正常に動きました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">アイコン設定がなぜか外れてて、再設定。アレクサアプリでスキルを無効＆有効にしたら正常に通知されるようになったっぽい。<a href="https://twitter.com/hashtag/alexa?src=hash&amp;ref_src=twsrc%5Etfw">#alexa</a> <a href="https://t.co/CHt4Vp2PQ5">pic.twitter.com/CHt4Vp2PQ5</a></p>&mdash; 福村浩治＠介護福祉エンジニア (@fukumura_kaigo) <a href="https://twitter.com/fukumura_kaigo/status/1469552727995076609?ref_src=twsrc%5Etfw">December 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#プロアクティブのユースケース
タクシー予約スキルのような、予約して、その後タクシーが近くまで来た時に通知がくるようなユースケースが通知として有効なんだろーなと。
つまり、**なにか操作をして、その操作が完了するまでに時間がかかり、それが完了したタイミングで通知をするようなユースケース**だと考えます。

不特定多数ではなく、特定のひとりに何かを伝えたいなら、単純にAlexaの標準機能で、メッセージを送るなり、ビデオ通話をすれば良いわけで、プロアクティブを使う必要性がありません。

#プロアクティブで困っていること
タイトルでわかるように、試した結果、私は現状のプロアクティブだと使えないなーと思っています。
その理由は以下です。

###自由なメッセージ内容を送れない
さんざん言われていると思いますが、これが最大のネックです。
8つのイベントカタログと呼ばれる、テンプレートに沿ったメッセージしか送れません。
文字数だとか、よろしくない言葉がつかえないとかならまだわかるのですが、これはないぜーと。

https://developer.amazon.com/ja-JP/docs/alexa/smapi/schemas-for-proactive-events.html#

###メッセージ内容をすぐさま発話してくれない
動きを見てもらえばわかるように、メッセージ送信をしても、内容を発話するのではなく、お知らせがあることがわかるようになる（黄色に光ったり、showだとお知らせのアイコンが表示されたり）だけです。
この状態で「アレクサ、お知らせある？」と言えば、メッセージ内容を発話してくれますが、このひと手間必要なのかなと。

もちろんいきなり発話されたりしたら困る人もいるので、設定で変えれるようにしてほしいです。
ちなみに、最近母のスマホを新調したのですが、Sharp製だったため、「エモパー」というアプリがあり、このアプリはいきなりすごいいっぱいしゃべります。

https://k-tai.sharp.co.jp/dash/emopa/

もちろん、しゃべらないようにしたりや、家のみしゃべるようにするなどの設定はあるので、これと同じようにAlexaもなってほしいです。
母は面白いから家ではしゃべるようにしてほしいとのことで、新調して1か月以上経ちますが、今のところエモパーを楽しんでいるようです。
**いきなりしゃべりだすくらいじゃないと、生活に浸透しないんじゃないのかなと思います。**

###Alexaで複雑な操作はしたくない
有効なユースケースの例として、「**なにか操作をして、その操作が完了するまでに時間がかかり、それが完了したタイミングで通知をするようなユースケース**」と言いましたが、**複雑な**「なにか操作」をAlexaでするのは厳しいものがあります。
（個人的には、Alexaスキルは起動だけ、もしくは起動後1回だけの操作ではないと実用的じゃないと考えています。）

Alexaをお持ちの方ならわかると思うのですが、まだまだ誤認識も多いですし、APLでタップ（showでのタップ操作）するにしてもそれならスマホで良いんじゃないとなるわけで。

スマホやPCで操作するなら、そのままスマホのプッシュ通知なりでいいわけで、Alexaで通知してもらう必要性が薄れます。

ただ、今後発売予定のEcho Show 15のように大きな画面で壁掛けてあってすぐ操作できるようなデバイスなら、これに関してはクリアできるのかなとも思います。

https://www.amazon.co.jp/Echo-Show-15-%E3%82%A8%E3%82%B3%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%BC15-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4-with-Alexa/dp/B08MQNJC9Z

#BOCCOならクリアできる
「自由なメッセージ内容を送れない」「メッセージ内容をすぐさま発話してくれない」に関しては、BOCCOならクリアできます。
ただし、不特定多数ではなく、自分のBOCCOのみに通知するケースとなります。

BOCCOはコミュニケーションロボットで、BOCCOと新しいバージョンのBOCCO emoがあります。特にemoに関してはスマートスピーカーのように呼び掛けて答える機能もあります。

https://www.bocco.me/

https://www.youtube.com/watch?v=sTbZI10OwoU

APIも公開されているので、開発が可能です。

http://api-docs.bocco.me/reference.html

https://platform-api.bocco.me/api-docs/#put-/v1/webhook/events

実際にAPIで発話させてみました。

https://www.youtube.com/watch?v=pDwBQDzhV1I

**Alexaもこんな感じで、自由な内容をすぐさま発話できるようにしてほしいぃぃぃ！！！**

#まとめ
現状は通知に関しては、（不特定多数ではなく、特定のひとりに何かを伝えたい場合に限り）Alexaのプロアクティブより、BOCCOの方が使い勝手が良いかなと思ってますが、Alexaはどんどん進化していっているので（最近久しぶりにコンソールみたら、結構変わっててビビりましたｗ）、改善を期待していますー！