Amazon Echo Spot の画面をリッチに作る

Amazon Echo Spot を購入し、更に Amazon Echo Show も12月に発売されるので、いいタイミングかな？と思い、ディスプレイ付き Alexa デバイスのリッチな画面の作り方を確認して、記事にまとめてみました。

最終的に「公式ドキュメントにめちゃめちゃ書いてあるじゃん！」と気づくんですが、気づく前に「結局どないすりゃええん？」って感覚がすごかったので、みんなが同じ悩みを持たないように何か助けになればと思って書きますた。

Card に表示していた分をそのまま画面に表示させられる、ということがあるので、画面付き Alexa 用の画面作成方法というのをスルーしがちですが、やっぱり画面付き Alexa で表示させると見た目が…… という感じなので、画面用の画面を作る！ということで記載しています。

具体的には、下図のように Card そのままで表示していた内容を、、、

![UNADJUSTEDNONRAW_thumb_1062.jpg](https://qiita-image-store.s3.amazonaws.com/0/92506/4993a75a-6cce-6fd8-010c-3be5e7476c3e.jpeg)

更に下図のように、見た目の綺麗な画面用の画面を表示させる方法になります。

![UNADJUSTEDNONRAW_thumb_1059.jpg](https://qiita-image-store.s3.amazonaws.com/0/92506/9dbd6b67-c7f9-e1a7-bdea-825991f31d4c.jpeg)

タイトルの”リッチ”という言葉は、マークアップが使ってあって、見やすい！おしゃれ！という意味で使っています。

一応、Alexa Skill を作ったことがある人向けの内容で、エンドポイントの AWS Lambda は、Node.js 6.10 を使って書いています。

# 画面なしの Alexa Skill と違うとこ

基本的な作り方は、普通の Alexa Skill 作りと変わりません。それにちょっと項目・操作を付け足すことで実装できます。

画面なしの Alexa Skill では、レスポンスに下記の内容を入れて返していました。

- 話す内容（outputSpeech）
- カードの内容（card）
- 聞き取れなかった時の内容（reprompt）

画面有りの Alexa Skill で画面をリッチに返すには、上記項目に加え、下記項目を返す必要があります。

- 画面の内容（directives（type:"Display.RenderTemplate"））

”画面の内容”を追加するには、AWS Lambda でのレスポンスの項目追加だけでなく、Alexa Skill の設定も変更する必要があります。

# Alexa Skill の設定

下図が Alexa Skill のインターフェース項目になります。

<img width="983" alt="Screen Shot 2018-11-26 at 19.53.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/92506/84478183-6660-7184-ded7-b951b5987a1c.png">

Alexa Skill でカスタムスキルを作成する際、”インターフェース”タブを選択すると上図の画面が表示されます。ここに表示されているインターフェースの内容は、レスポンスの”Directive”項目に紐づくものになっています。（例：type:"AudioPlayer.Play"、type:"VideoApp.Launch"など）

Displayインターフェースのトグルを有効にすることで Alexa Skill 側の設定はOKです。

Displayインターフェースの詳細は公式ドキュメントの [Displayインターフェースのリファレンス](https://developer.amazon.com/ja/docs/custom-skills/display-interface-reference.html) を参照してみてください。正直に言うとこのリンクに全てが載っています。。

# Displayテンプレートとは

Displayインターフェースには、テンプレートが存在し、用途にあった内容を選択、使用することができます。テンプレートの内容については下記のサイトがひと目で見てわかるようになっているのでおすすめです。

[[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示](https://dev.classmethod.jp/cloud/alexa-sdk-v2-seventh/)

さすがクラスメソッドさん。。

Displayテンプレートの”BodyTemplate1”の構文は下図のようになっています。

<img width="777" alt="Screen Shot 2018-11-27 at 9.34.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/92506/b37b47fd-6623-8d08-5c19-74edc812ed56.png">

各項目は全て埋めなくても表示されます。

textContent では、”type”を指定することでマークアップを使用できます。
textContent の各フィールド（”primaryText”、”secondaryText”、”tertiaryText”）の”type”を”RichText”とすることで、マークアップの記載が反映されます。
テンプレートそのままの設定を使用するのもよいですが、Amazon Echo Spot では、表示できる範囲が狭いということもあり、Font size 変更のマークアップなどは重宝します。

他のテンプレートや詳しい”BodyTemplate1”の内容については、公式ドキュメントの　[Displayテンプレートのリファレンス](https://developer.amazon.com/ja/docs/custom-skills/display-template-reference.html)　に詳しく記載してあるので参照してみてください。

# ソースコード

AWS Lambda で、Alexa Skill のテンプレート（alexa-skills-kit-color-expert）を元にソースコードを変更していきます。元のソースコードのレスポンス部は下記のようになっています。

```javascript:index.js
function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: `SessionSpeechlet - ${title}`,
            content: `SessionSpeechlet - ${output}`,
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
        shouldEndSession,
    };
}
```

上記ソースコードを変更していきます。

```javascript:index.js(修正後)
/* 引数にcontenttext追加 */
function buildSpeechletResponse(title, output, contenttext, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: `${title}`,
            content: `${output}`,
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
        /* Add Start */
        directives: [
            {
                type: "Display.RenderTemplate",
                template: {
                    type: "BodyTemplate1",
                    title: title,
                    textContent: {
                        primaryText: {
                            type: 'RichText',
                            text: contenttext,
                        }
                    }
                }
            }
        ],
        /* Add End */
        shouldEndSession,
    };
}
```

話す内容と画面に表示する内容は同じではないので、関数の引数を増やします。
インターフェース項目を指す、”Directive”を追加し、その配下の”type”項目に Displayインターフェースを示す”Display.RenderTemplate”を指定します。
textContent、primaryText の”type”を”RichText”とすることでマークアップが使用できるようになります。

```javascript
var title = '検索結果';
var contenttext = '<font size="2">' + cnt + '冊見つかりました。<br />' + booklist + 'のような本があります。</font>';
```

上記コードのようなマークダウンが書けます。
font size を"2"にすることで、カードだとデフォルトで最大で11文字しか入らなかったところにそれ以上のものが収まるようになりました。

マークアップを駆使したり、”BodyTemplate1”のテキスト以外の他の項目をきちんと設定することで、もっといいものを作れたりしますのでやってみてください。

# 小ネタ
Alexa Skill のテストのところで画面右側をスクロールして、デバイスを指定すれば、どんな画面になるか見ることができます。

<img width="829" alt="Screen Shot 2018-11-27 at 13.50.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/92506/e62fa1ef-6edc-48b4-0eca-24e64e99be08.png">


# まとめ

わざわざ Displayインターフェースを使わずとも、Card を調整すれば、ある程度見れる画面は作成できます。しかし、デバイスに合わせるために作った凸凹な表示画面が、普通の Card の方にも表示されてダサいという点や、Displayインターフェースを使うことでマークアップが使用でき、よりリッチな画面作りができるという点などがメリット・デメリットとして存在します。

Displayインターフェースを使うことで、話すこと、カード、ディスプレイと三拍子そろったAlexa Skill が作成できるので、積極的に Displayインターフェースを使っていくべきかなと思います！