Alexa Gadgets Toolkitを使ってAlexaスキルのセッションを永続化させる

最近会社で「Alexaおじさん」という肩書を勝手にいい広めながらiOSエンジニアをしている私です。
この記事は、「AAJUG京都 スキル企画・開発アドバンスド」にて発表した内容を再構築したものとなっています。

# Alexa Gadgets Toolkitとは何か
>Alexa Gadgets Toolkitを使用すると、ユーザー独自のAlexa Gadgetを開発できます。Alexa Gadgetは、Alexaに接続されたアクセサリで、Bluetooth経由で互換性のあるAmazon Echoデバイスとやり取りします。

[amazon alexa - Alexa Gadgets Toolkitとは より引用](https://developer.amazon.com/ja/docs/alexa-gadgets-toolkit/understand-alexa-gadgets-toolkit.html)

そもそもAlexa Gadgetとは何かという話になりますが、USで発売されているEcho ButtonのようなEchoデバイスと接続し利活用することができるEchoデバイスのアクセサリーのことを指します。
<img width="1020" alt="スクリーンショット 2019-11-21 8.51.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/4599fc9a-16e0-7f86-603d-a103d3cb0cff.png">
[US Amazon - Echo Buttons (2 buttons per pack) より](https://www.amazon.com/dp/B072C4KCQH/)

日本未発売のEcho Buttonは、イントロゲームの早押しに使ったり、○xゲームの入力デバイスとして活用することができます。最近だと定形アクションにも対応し、ウェイクワードなしでも定形アクションの実行が可能になったりしています。
そんなもAlexa Gadgetsを開発者が自由に作ることができるようになるツールが**Alexa Gadgets Toolkit**になります。

# Alexa Gadgets Toolkitを用いると何ができるの？
先の内容と重複しますが、一言で言うと**EchoデバイスやAlexaスキルと連動したGadget開発ができます。**
実際に開放されて利活用できる機能は、大きく分けて2つです。

- カスタムスキルと連動して、ガジェットを制御する
- Alexaネイティブ機能と連動してガジェットを制御する

## カスタムスキルと連動して、ガジェットを制御する
こちらは文字通り、開発者が開発したカスタムスキルからガジェットを操作したり、ガジェットからのEventに反応させてAlexa側で何らかのイベントを発火させることが可能になります。

## Alexaネイティブ機能と連動してガジェットを制御する
カスタムスキル以外にもAlexaのネイティブ機能と連動したガジェットの開発も可能です。
スキルとは別に下記の項目が用意されています。

> - スピーチマークデータ – ガジェットとAlexaの読み上げ機能とのリアルタイムな同期を可能にします。この情報は、SpeechDataインターフェースから提供されます。
> - 通知 – Alexaドメインまたは有効なAlexaスキルから新しいコンテンツが提供されていることを、ガジェットからユーザーに知らせることができます。この情報には、Notificationsインターフェースからアクセスできます。
> - タイマー、アラーム、リマインダー – Echoデバイスのタイマー、アラーム、リマインダーが設定されたことや解除されたことをガジェットに知らせることができます。この情報は、Alertsインターフェース（ベータ）とStateListenerインターフェースを組み合わせて提供されます。
> - ウェイクワードの検出 – ユーザーがEchoデバイスのウェイクワードを口にしたことをガジェットに知らせます。ガジェットは、この情報をStateListenerインターフェースから取得します。
現在の時刻 – Echoデバイスの現在の時刻をガジェットに提供します。この時刻情報（ベータ）は、StateListenerインターフェースから提供されます。
> - Amazon Musicの曲のテンポデータ – Echoデバイスが再生しているAmazon Musicのテンポデータをガジェットに送信します。この情報には、MusicDataインターフェース（ベータ）からアクセスします。

[amazon alexa - Alexa Gadgets Toolkitとは より引用](https://developer.amazon.com/ja/docs/alexa-gadgets-toolkit/understand-alexa-gadgets-toolkit.html)

例えば、Alexaで流しているAmazon musicのテンポデータを利用して踊る人形を作ったり、日本で発売されていないEcho Wall Clock的なものを作ったりなども可能です。
Alexa Gadgetからは上記のネイティブ機能にアクセスすることは可能ですが、カスタムスキルからアクセスすることはできません。

## スキル開発者は何ができるのか？
基本的にスキル開発者にとって恩恵があるのは、**カスタムスキルと連動して、ガジェットを制御する**ということが可能になったことです。
ゲームスキルであれば、スコア表示であったりゲームの世界観を生み出すためのツールとして活用することが可能になりましたが、ガジェットと言われると天気予報スキルや交通情報系のスキルなどゲームのような体験がないスキルには使い所がないと思いがちです。
何よりもAlexa Gadgets Toolkitによって変わったことは、使い方によってはカスタムスキルを使っているときにAlexaを能動的に話させることが可能になり、使い方次第によってはカスタムスキルのセッション持続時間を永続化することが可能になったということです。

# Alexaのセッション持続時間
スキル開発者にとって避けて通ることができない問題です。どんなにリッチでより良い体験を作ろうとしてもセッション持続時間の壁に当たってしまい提供したい音声体験を創り出せなかった方も多いのではないかと思います。改めて、そんなセッション持続時間を振り返ってみたいと思います。

- 通常：8秒
- Audio Tagを活用：240秒(4分)
- Alexa Gadgets Toolkit：90秒(1分30秒)

普通にスキルを作った場合は、8秒でタイムアウトしてしまいます。リプロンプトで、再度呼びかけても8秒後にスキルが自動的に閉じられ今までのセッション情報は破棄されます。
そこでセッション時間を伸ばそう！と試行錯誤した結果、Audio Tagを活用し最大4分までセッションの持続時間を伸ばすテクニックがよく利用されていました。Alexaを使ったボードゲームなどもAudioTagを活用してユーザーの思考時間を稼いでいます。有名所だとアタリの創業者が開発した**St.Noire**などがよく考えられた利用例です。
![スクリーンショット 2019-11-23 23.00.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/429dd726-dc03-a50c-d3ab-d75b2ad83df3.png)
[St.NOIREより](https://www.st-noire.com)
もちろん、ユーザーが4分以上思考してしまった場合はスキルが閉じられ、セッション情報は破棄されてしまいます。なので、AudioTagを利用する場合はスキルがクローズされるときにDynamoDBにゲームの進行情報を保持させ再度スキルを呼び出せば再開できるような作りとしていることが多いです。
しかし、どんなに頑張っても従来の仕組みではスキルが特定の時間でクローズされてしまい、セッションの永続化ということはできませんでした。
そんな夢のようなカスタムスキルのセッションを永続化させるAlexa Gadgets Toolkitですが、しっかりと持続時間は存在します。90秒とAudio Tagよりも持続時間が短いのです。
持続時間があるのにセッションの永続化が可能になったのにはGadgetからのイベントでAlexaを発話させることが可能になったことが関連しています。

# 実際にスキルを永続化させる
Gadgetからのイベントを監視するには下記のjsonをレスポンスに対してaddDirectiveすることで、監視することが可能になります。

```javascript

function sessionPersistenceResponse (handlerInput) {
    // セッショントークン
    let sessionToken = gadgetUtil.sessionToken(handlerInput);
    // 永続化用のディレクティブ
    let persistenceDirective = gadgetDirective.sessionPersistence(sessionToken, null);
    // Echoから発話させる内容
    return handlerInput.responseBuilder
        .speak("")
        .addDirective(persistenceDirective)
        .getResponse();
}
```

```json
{
	"type": "CustomInterfaceController.StartEventHandler",
	"token": "【アクセストークン】",
	"eventFilter": {
		"filterExpression": {
			"and": [
				{
					"==": [
						{
							"var": "header.name"
						},
						"【監視するイベント名】"
					]
				},
				{
					"==": [
						{
							"var": "header.namespace"
						},
						"Custom.【namespace】"
					]
				}
			]
		},
		"filterMatchAction": "SEND_AND_TERMINATE"
	},
	"expiration": {
		"durationInMilliseconds": 90000,
		"expirationPayload": {}
	}
}
```

上記の内容では、``durationInMilliseconds``に90000ms付与してるので90秒後にはスキルが終了されます。
ここで、キーになるのはAlexa Gadgets Toolkitを使うとGadgetからのイベントで発話させることが可能になったということです。
Gadgetからのイベントで発話させる方法は普通のカスタムスキルと同じなので再度``addDirective``でGadgetの監視するイベントを指定することが可能です。再度監視するイベントを指定することが可能なので、Gadgetから定期的に永続化用のイベントをEchoデバイスに送付することで擬似的にカスタムスキルのセッションを永続化することが可能になるのです。

## もう少しわかりやすく
※イベント当日は、勉強会のセッションタイムキーパースキルを作っていたので時間を取り扱っています。

まず、スキルからGadgetに対してイベントを送付します。このとき送付するイベントは、セッションが開始されたイベントかつPayloadにセッション終了時刻を含めています。
Gadget側ではStartイベントを検知して、セッション終了時刻の監視を開始します。
![スクリーンショット 2019-11-23 23.28.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/04c93d7d-72e3-7bd9-10f1-97c0578a647a.png)

Gadget側では、セッション終了時刻の監視と同時にAlexa Gadgets Toolkitのセッション持続時間の90秒を監視しています。
セッション持続時間のリミットが近くなったタイミングで、GadgetからEchoデバイスにイベントを送付し、Alexaが発話するようにします。
![スクリーンショット 2019-11-23 23.31.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/3818db54-5ed2-d1e6-e503-7c666d590fd8.png)

Gadgetから受け取ったイベントを元にAlexaは無言の発話を行い、再度Gadgetのイベントを監視するイベントハンドラーを付与させます。
このタイミングで、Alexa Gadgets Toolkitの90秒ルールは0秒から再カウントされるので、これを無限に行うことでセッションを永続化させることが可能です。
![スクリーンショット 2019-11-23 23.33.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/74386ba6-12e9-ec0b-e9f0-9726f9634c56.png)

# Alexa Gadgets Toolkit 辛いとこ
## エラーの切り分けが複雑になる
従来であれば、スキルの不具合といえばCloudWatchのログを確認して対応すれば良かったですが、Gadgetが絡んでくるとエラーの切り分けが複雑になります。実機でしかデバッグができないので、よりその辛さが際立ってきます。

- Cloud watchで捕捉できるエラーなら「SkillのScript」
- Gadget側で捕捉できるエラーなら「GadgetのScript」
- 上記２つでなければ、gadgetとskillでやり取りするDirectiveのフォーマット

今回開発したときに切り分ける基準として上記の3つで大体切り分けることができました。Directiveに付与するjsonのフォーマットに誤りがあるとそもそもエラーログも出なかったり、発話もしないので一番特定が面倒かもしれません。

## スキル公開の前例がないらしい
Alexa Gadgets Toolkitを使ったスキル公開例がないので、審査をどうするかなどまだ見えない部分が多いそうです。
プライベーターがデバイスを量産することも難しいので、Gadget側のスクリプトをオープンソースにしてユーザーに手作りしてもらうとかの方法も考えることができますが、見えない部分が多いです。
かつ、スキルの永続化を行うとそもそものAlexaの審査基準に当てはまらない可能性が高いので、そのままでは審査に通らない可能性が高いです。

# 最後に
Alexa Gadgets Toolkitはカスタムスキルと連動するガジェットを開発することができるので音声以外の側面からスキルの体験をより高めることが可能になりました。一方で、ガジェットをうまくつかうことで、Alexaを能動的に発話させることができるようになったので、使い方次第では人対人の会話に近い対話も生み出せるのではないかと感じています。これによってスキルが持つ世界観にユーザーを引き込むことがより可能になったことがAlexa Gadgets Toolkitの大きな利点と感じています。

声で操作するGadgetが作れるようになっただけではないということを1つ感じていただき、よりAlexaの体験を広げることのきっかけになれば良いなと思っています。

# 当日のデモスキルのソースはこちらから
[Github - alexa-chin-bell-gadget](https://github.com/MasamiYamate/alexa-chin-bell-gadget)