DialogflowのWebhookでカルーセル型リストのレスポンスを返す

@radiocat さんの記事を参考にして今後発売されるスマートディスプレイに重宝しそうな
カルーセル型リスト表示をJsonレスポンス作って返してみました。

参考URL: https://qiita.com/radiocat/items/8def1d9ba0eb38b8a04e

#環境
IBMクラウドにNode-REDを構築してそちらからJsonレスポンスを返すようにしました。
IBMクラウドの環境構築はこちらの資料を参考にしてください。

https://drive.google.com/open?id=1iGnYvdZpHYuuMySn-GYo-80SrxvRN1KM

#完成動画
スマートディスプレイが手元に無いのでAndroid携帯で試しています。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">actions on googleとDialogflow使ってカルーセル型リスト表示してみた。 <a href="https://twitter.com/hashtag/actionsongoogle?src=hash&amp;ref_src=twsrc%5Etfw">#actionsongoogle</a> <a href="https://twitter.com/hashtag/dialogflow?src=hash&amp;ref_src=twsrc%5Etfw">#dialogflow</a> <a href="https://t.co/ZgYEWD85nS">pic.twitter.com/ZgYEWD85nS</a></p>&mdash; がおまる@スマートスピーカー・HoloLens研究者 (@gaomar) <a href="https://twitter.com/gaomar/status/1001697423356518401?ref_src=twsrc%5Etfw">2018年5月30日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#1. Dialogflowの設定
まずはDialogflowの設定を行います。

### 1-1. リスト表示用Intent作成
適当にIntentを作成します。
Training phrasesに「リストみせて」と入力します。最後に一番下のwebhookを有効にしています。

![s100.png](https://qiita-image-store.s3.amazonaws.com/0/154355/55e77c39-c4fc-547e-ec31-986fe414ba64.png)

### 1-2. リストタップ応答用Intent作成
表示されたリストをタップしたときに反応させるIntentを作成します。

![s101.png](https://qiita-image-store.s3.amazonaws.com/0/154355/24282d59-dc24-a3b1-c3a9-2fb7ea1743d7.png)

**Contexts**

| 設定項目       |       値 |
|:-----------------:|:------------------:|
| Add input Context             | actions_intent_OPTION |
| Add output Context             | actions_intent_OPTION |

**Events**

| 設定項目       |       値 |
|:-----------------:|:------------------:|
| Add event             | actions_intent_OPTION |

**Action and parameters**

| 設定項目       |       値 |
|:-----------------:|:------------------:|
| Enter action name             | send.action |
| PARAMETER NAME             | myVal |
| ENTITY             | @sys.any |
| VALUE             | #actions_intent_OPTION.OPTION |

#2. Node-REDの設定
Node-REDはこんな感じにノードを作りました。

![s200.png](https://qiita-image-store.s3.amazonaws.com/0/154355/19324580-36f4-c469-7dd1-a3b1bb24ad56.png)

ノードのソースコードは以下の通り

```javascript:ソースコード
[
    {
        "id": "94a2d39c.75582",
        "type": "http in",
        "z": "10d2bba3.1d0484",
        "name": "",
        "url": "/api/hello",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 120,
        "y": 540,
        "wires": [
            [
                "d80fb5f0.3d1778"
            ]
        ]
    },
    {
        "id": "7380d152.0e70c",
        "type": "template",
        "z": "10d2bba3.1d0484",
        "name": "くだもの検索",
        "field": "payload",
        "fieldType": "msg",
        "format": "json",
        "syntax": "mustache",
        "template": "{\n    \"fulfillmentText\": \"てすと\",\n    \"payload\": {\n        \"google\": {\n            \"expectUserResponse\": true,\n            \"richResponse\": {\n                \"items\": [\n                {\n                    \"simpleResponse\" : {\n                        \"textToSpeech\": \"果物一覧\"\n                    }\n                }]\n            },\n            \"systemIntent\": \n            {\n                \"intent\": \"actions.intent.OPTION\",\n                \"data\": {\n                    \"@type\": \"type.googleapis.com/google.actions.v2.OptionValueSpec\",\n                    \"carouselSelect\": {\n                        \"items\": [\n                        {\n                            \"optionInfo\": {\n                                \"key\": \"リンゴ\"\n                            },\n                            \"description\": \"リンゴ（林檎、学名：Malus pumila）は、バラ科リンゴ属の落葉高木樹。またはその果実のこと。植物学上はセイヨウリンゴと呼ぶ。春、白または薄紅の花が咲く。果実は食用にされ、球形で甘酸っぱい。\",\n                            \"image\": {\n                                \"url\": \"https://2.bp.blogspot.com/-oTqVMb3zbQ4/UgSMNNLY2wI/AAAAAAAAW-o/4nxDWnz7YsQ/s800/fruit_apple.png\",\n                                \"accessibilityText\": \"リンゴ画像\"\n                            },\n                            \"title\": \"リンゴ\"\n                        },\n                        {\n                            \"optionInfo\": {\n                                \"key\": \"オレンジ\"\n                            },\n                            \"description\": \"オレンジ（英名: orange、学名: Citrus sinensis）はミカン科ミカン属の常緑小高木、またはその果実のこと。 (syn. C. aurantium)、柑橘類に属する。\",\n                            \"image\": {\n                                \"url\": \"https://1.bp.blogspot.com/-l61TqzrDRz8/UnyGAHKhxBI/AAAAAAAAaYs/MI7pnI28hSI/s800/cut_fruit_orange.png\",\n                                \"accessibilityText\": \"オレンジ画像\"\n                            },\n                            \"title\": \"オレンジ\"\n                        },\n                        {\n                            \"optionInfo\": {\n                                \"key\": \"バナナ\"\n                            },\n                            \"description\": \"バナナ（甘蕉、実芭蕉、英: banana [bəˈnænə, bəˈnɑːnə]、学名 Musa spp.）はバショウ科バショウ属のうち、果実を食用とする品種群の総称。また、その果実のこと。いくつかの原種から育種された多年性植物。種によっては熟すまでは毒を持つものもある。\",\n                            \"image\": {\n                                \"url\": \"https://4.bp.blogspot.com/-t3Fr_Y_xuc0/VNH6f0IGMjI/AAAAAAAArSY/Q0f6FXo84uc/s800/banana_kawa_muke.png\",\n                                \"accessibilityText\": \"バナナ画像\"\n                            },\n                            \"title\": \"バナナ\"\n                        }]\n                    }\n                }\n            }\n      \n        }\n    }\n}",
        "output": "json",
        "x": 380,
        "y": 540,
        "wires": [
            [
                "61f817a5.071628"
            ]
        ]
    },
    {
        "id": "61f817a5.071628",
        "type": "http response",
        "z": "10d2bba3.1d0484",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 610,
        "y": 540,
        "wires": []
    },
    {
        "id": "d80fb5f0.3d1778",
        "type": "switch",
        "z": "10d2bba3.1d0484",
        "name": "actionチェック",
        "property": "payload.queryResult.action",
        "propertyType": "msg",
        "rules": [
            {
                "t": "null"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 120,
        "y": 600,
        "wires": [
            [
                "7380d152.0e70c"
            ],
            [
                "f933355a.9f15b8"
            ]
        ]
    },
    {
        "id": "f933355a.9f15b8",
        "type": "function",
        "z": "10d2bba3.1d0484",
        "name": "くだもの選択処理",
        "func": "const myVal = msg.payload.queryResult.parameters.myVal;\n\nmsg.ret = {\n    \"val\":myVal\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 390,
        "y": 600,
        "wires": [
            [
                "c93a1f69.04e0a"
            ]
        ]
    },
    {
        "id": "c93a1f69.04e0a",
        "type": "template",
        "z": "10d2bba3.1d0484",
        "name": "テキスト返す",
        "field": "payload",
        "fieldType": "msg",
        "format": "json",
        "syntax": "mustache",
        "template": "{\n    \"fulfillmentText\":\"{{ret.val}} を選択しました\"\n}",
        "output": "json",
        "x": 400,
        "y": 660,
        "wires": [
            [
                "61f817a5.071628"
            ]
        ]
    }
]
```
###2-1. レスポンス解説
レスポンスはどのように返しているのか見ていきましょう。
果物検索のノードはtemplateノードで設定しています。中身はこんな感じです。

ポイントは`carouselSelect`で、カルーセル型のリストを設定しているところです。
他のリストにしたいって人はコチラに様々な形式がありますので参照してください。

https://github.com/dialogflow/fulfillment-webhook-json/tree/005bd669687f5252c860978aea72b0ff4397ae98/responses/v2/ActionsOnGoogle/RichResponses

```javascript:果物検索templateノード

{
    "fulfillmentText": "てすと",
    "payload": {
        "google": {
            "expectUserResponse": true,
            "richResponse": {
                "items": [
                {
                    "simpleResponse" : {
                        "textToSpeech": "果物一覧"
                    }
                }]
            },
            "systemIntent": 
            {
                "intent": "actions.intent.OPTION",
                "data": {
                    "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
                    "carouselSelect": {
                        "items": [
                        {
                            "optionInfo": {
                                "key": "リンゴ"
                            },
                            "description": "リンゴ（林檎、学名：Malus pumila）は、バラ科リンゴ属の落葉高木樹。またはその果実のこと。植物学上はセイヨウリンゴと呼ぶ。春、白または薄紅の花が咲く。果実は食用にされ、球形で甘酸っぱい。",
                            "image": {
                                "url": "https://2.bp.blogspot.com/-oTqVMb3zbQ4/UgSMNNLY2wI/AAAAAAAAW-o/4nxDWnz7YsQ/s800/fruit_apple.png",
                                "accessibilityText": "リンゴ画像"
                            },
                            "title": "リンゴ"
                        },
                        {
                            "optionInfo": {
                                "key": "オレンジ"
                            },
                            "description": "オレンジ（英名: orange、学名: Citrus sinensis）はミカン科ミカン属の常緑小高木、またはその果実のこと。 (syn. C. aurantium)、柑橘類に属する。",
                            "image": {
                                "url": "https://1.bp.blogspot.com/-l61TqzrDRz8/UnyGAHKhxBI/AAAAAAAAaYs/MI7pnI28hSI/s800/cut_fruit_orange.png",
                                "accessibilityText": "オレンジ画像"
                            },
                            "title": "オレンジ"
                        },
                        {
                            "optionInfo": {
                                "key": "バナナ"
                            },
                            "description": "バナナ（甘蕉、実芭蕉、英: banana [bəˈnænə, bəˈnɑːnə]、学名 Musa spp.）はバショウ科バショウ属のうち、果実を食用とする品種群の総称。また、その果実のこと。いくつかの原種から育種された多年性植物。種によっては熟すまでは毒を持つものもある。",
                            "image": {
                                "url": "https://4.bp.blogspot.com/-t3Fr_Y_xuc0/VNH6f0IGMjI/AAAAAAAArSY/Q0f6FXo84uc/s800/banana_kawa_muke.png",
                                "accessibilityText": "バナナ画像"
                            },
                            "title": "バナナ"
                        }]
                    }
                }
            }
      
        }
    }
}
```

![s201.jpeg](https://qiita-image-store.s3.amazonaws.com/0/154355/5008815b-3ce8-b306-1141-d3a1debcd7cc.jpeg)
表示はこのようにされます。

###2-2.選択処理
画像をタップすると`actions_intent_OPTION`のイベントがDialogflowに飛んでいきます。
Contextsも同時に格納されているので、その中にあるOPTIONという部分の値をパラメータとして受け取っています。

Node-REDではfunctionノードでDialogflowからくるパラメータを取得しています。

```javascript:くだもの選択処理function
const myVal = msg.payload.queryResult.parameters.myVal;

msg.ret = {
    "val":myVal
}
return msg;
```

最後にtemplateノードで選択した値を表示しています。

```javascript:テキスト返すtemplate
{
    "fulfillmentText":"{{ret.val}} を選択しました"
}
```

#まとめ
今後増えてくるスマートディスプレイはAndroidでいうJavaやKotlinといった専用言語での開発ではなく、
Node.jsやPythonを使ってレスポンスをJsonで返して表示する開発になります。
他にもいろんな表示形式があるので、是非試してみてください！

システム化のご検討やご相談は弊社までお問い合わせください。
https://i-enter.co.jp/contact/