Google Home で「出でよシェンロン」

先日、IFTTT を使って、ツイッター上にポルンガを呼び出しました。
https://qiita.com/chibi929/items/fb580c21b7fc18411244

やっぱり、シェンロンも呼び出したいよね。ってことで、
今回は Actions on Google を使いつつ、ホログラムでシェンロンを呼び出します。

プロジェクト作成手順等、いくつもの記事で紹介があると思いますが、
自分自身の理解のため書いていきます。他記事と重複すると思いますがご了承下さい。

## システム構成

![20171202222826.png](https://qiita-image-store.s3.amazonaws.com/0/53393/67e0e38c-af9d-9356-c9b5-82a63392493a.png)

本当は、電気も消したいところですが、
ハードウェアが揃ってないため電気は消せず。。。とりあえず今度作ることにします。

### この辺使いました

- Google Home / Mini
- Actions on Google
- Dialogflow
- IBM Cloud (Cloud Foundry アプリ)
- Node.js / Express
- WebScoket
- HTML/CSS/JS ＆ ホログラム用CDケース

## Actions on Google

### プロジェクト作成

![1.png](https://qiita-image-store.s3.amazonaws.com/0/53393/5d1e164a-1071-6cc0-c74a-3173f36493ea.png)

`Add/import project` をクリックします。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/53393/97bc919f-c1d3-9e64-2bef-78a4326eec5c.png)

`Project name` , `Country/region` を入力し、
`CREATE PROJECT` をクリックします。

### Dialogflow と繋げる

プロジェクトが出来ると以下のような画面が表示されます。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/53393/6225b4d8-fdb1-9b92-2643-12d61fd2971b.png)

`Dialogflow` の `BUILD` をクリックします。
初めは、アカウントの設定やらパーミッションの要求やら表示されると思いますので、完了させましょう。

![4.png](https://qiita-image-store.s3.amazonaws.com/0/53393/17a4ce54-69a0-2e01-1925-6b7c86c51efb.png)

`CREATE ACTIONS ON DIALOGFLOW` を選択して Dialogflow を作成します。

## Dialogflow (Step 1)

https://dialogflow.com/docs/agents

### Agent 作成

Dialogflow の Project? の作成です。

![7.png](https://qiita-image-store.s3.amazonaws.com/0/53393/448f93ce-58e4-7dfb-7447-822b0d2fbd02.png)

各種設定を入力したら `CREATE` をクリック。

### Intents 作成

ここで IN と OUT を作成していきます。

![8.png](https://qiita-image-store.s3.amazonaws.com/0/53393/c7bc521a-fee3-66a2-056d-c7f1cf5f67c7.png)

初期状態で何かありますが、とりあえず気にしないことにして、
`CREATE INTENT` をクリックします。

![9.png](https://qiita-image-store.s3.amazonaws.com/0/53393/ab2cf6c3-2848-6a43-113e-93e83558429c.png)

`User says` がトリガーとなり `Response` を返します。
入力したら `SAVE` をクリックします。

ここで `End conversation` にチェックを入れておくことで、
Google Home のやりとりはこの Intent で終了となります。
※ 終了しない場合は Google Home さんは聞き耳を立て続けてくれるのかな・・・？

### Integrations

Intent が完成したら Actions on Google から使えるように Integration します。

![10.png](https://qiita-image-store.s3.amazonaws.com/0/53393/082b76ff-bc99-71ed-7f6c-b6b699170a5d.png)

`Integrations` から `Google Assistant` をクリックします。

![11.png](https://qiita-image-store.s3.amazonaws.com/0/53393/12361a15-214a-b16b-d05c-30c0e2282072.png)

ここで、初期状態から居た `Default Welcome Intent` がいらっしゃった。
(まだ良くわかってない)

とりあえず下側の `Select intent` からさっき作った Intent を選択して、
`UPDATE DRAFT` をクリック！

### 動作確認(Actions on Google)

とりあえずここまでで Hello World です。
シミュレーターで確認できます。

![12.png](https://qiita-image-store.s3.amazonaws.com/0/53393/2ea36fad-c5bb-ae5e-bae0-a3a609928300.png)

`VISIT CONSOLE` をクリックして `Actions on Google` の画面に遷移し、

![12_5.png](https://qiita-image-store.s3.amazonaws.com/0/53393/7b698c63-7b36-99bc-991b-6714e753a389.png)

`TEST DRAFT` をクリックするとシミュレーター画面に移動します。

![13_simu.png](https://qiita-image-store.s3.amazonaws.com/0/53393/d9e451d1-a399-547f-e62b-5c6c28eb87ef.png)

こんな感じです。
「こんにちは！」は `Default Welcome Intent` ですね。

## Dialogflow (Step 2)

Step 1 で作成した Intent を作り込みます。

### Intent で変数的なものを使う

シェンロン以外も呼び出せるようにします。

![14.png](https://qiita-image-store.s3.amazonaws.com/0/53393/fcf7100f-e1b6-7314-9fc8-3de2e5ec15d4.png)

User says を `出でよTarget` のように変更し `Target` の部分をドラッグすると何か出てきます。
とりあえず `@sys.any` を選択しておきます。

![15.png](https://qiita-image-store.s3.amazonaws.com/0/53393/5f5ad714-8cb2-b9d1-4f61-a408eadd1773.png)

すると何やらパラメーターが追加されます。
試しに Response で `$any` を使うと変数として扱われるようです。
`@sys.any` は、そのとき言った言葉が格納されるようです。

### Entities 作成

パラメーター ( `Target` ) に使われる言葉を定義します。

![16.png](https://qiita-image-store.s3.amazonaws.com/0/53393/0549ae84-005a-bdca-a005-fa728414ba65.png)

`シェンロン` と `しぇんろん` は `shenron` として扱われ、
`キノコ` , `きのこ` , `茸` , `木野子` は `kinoko` として扱われるようになります。

### Intent に Entity を設定

![17.png](https://qiita-image-store.s3.amazonaws.com/0/53393/7e060c5e-d41c-decf-6296-4839f757e080.png)

一旦、×ボタンを押してパラメーターを消しちゃいます。

![18.png](https://qiita-image-store.s3.amazonaws.com/0/53393/9c2cdde7-9d14-838d-919d-1dccee53b227.png)

再びドラッグすると先ほど作った `Target` が生まれているはず。

## サーバーに Webhook する

さて、ここから音声入力をトリガーにサーバーを叩いてシェンロンを呼び出します。

### Fulfillment を設定

![19.png](https://qiita-image-store.s3.amazonaws.com/0/53393/f07d16fe-67c9-35e1-6bcc-08998b1e73f9.png)

ENABLED を ON にして、サーバーのURLを入れて完了。
shenrons API を叩きます。

### Intent で Webhook を使う設定

![20.png](https://qiita-image-store.s3.amazonaws.com/0/53393/e783af9e-b023-8b4c-b3f4-b2d160547174.png)

今回レスポンスは Webhook に任せちゃうので消しておきます。
`slot-filling` は良くわかりませんが。。。とりあえず `Use Webhook` にチェックを入れます。

## サーバー側の実装

Node.js で Express を使って実装しました。

### Request

https://dialogflow.com/docs/fulfillment#request

```js:request
{
  "result": {
    "parameters": {
      "Target": "shenron" // ← ここの Key にあたる部分は Entity で作った名前
    }
  }
}
```

この辺を POST メソッドでハンドリングすれば良いようです。
ハンドリングしたらそれを Websocket を使ってブラウザ側へ通知します。

### Response

https://dialogflow.com/docs/fulfillment#response

```js:request
{
  "speech": "レスポンス",
  "displayText": "レスポンス"
}
```

この辺を詰めて返せばよいようです。
今回は要らないので空文字列・・・と思ったら空だと「応答がありません」とか言われてしまったので
試しに `.` を入れたら無音になってくれた

- `speech` は音声のレスポンス
- `displayText` は文字列のレスポンス

## ブラウザ側

Websocket を使ってサーバーとコネクションを張っておき、
通知が来るのを待ち続けます。

## 動作確認

「OK Google, テスト用アプリにつないで」
Google Home「わかりました。テストバージョンのテスト用アプリです。」
Google Home「こんにちは！」
「出でよシェンロン」

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/4049ab00-4f9f-e37c-2aff-6c14f41fb0c8.jpeg" width="512" alt=""/>

ついでに、
「出でよキノコ」

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/63ada86c-ca18-2ab5-3c84-23461f390f5d.jpeg" width="512" alt=""/>

## 最後に

全然上手くいかないなーと思ったら、
「ideo きのこ」「医療 きのこ」「ビデオきのこ」
なぜか「塩きのこ」まで認識されました。

きっと自分の滑舌が悪いせいです。きっと。

確認の仕方は、スマホ版 Google Assitant をインストールしてきて、そいつに話しかけてみました。
文字起こししてくれるのでそれで確認できました。

なので `Intent` 作成時の `User says` には「ideo Target」とかも追加しました。

## わからないこと/今後調べること

- `End conversation` にチェックを入れない場合
- 「テスト用アプリにつないで」を無しにしたい
    - publish しないとダメなのか？
- `Integration` の上側 (Welcome Intent の方)
- 「テスト用アプリにつないで」の場合、プロジェクトを２個作った場合は最後に Integration したほうが起動するのか？

## 参考

- [Actions on Googleでapi.aiを使ってGoogle Homeに何か言わせてみる](https://qiita.com/syarihu/items/53ea1a65f481f8121109)
- https://kotodama.today/?p=45