Google Homeを使って4歳児とSlackで会話する方法

*わたあめに捧ぐ(私信)*

私の家では、家族の連絡にSlackを利用しています。

Slackはとても便利なのですが、基本的にテキストベースのコミュニケーションとなるため、
文字入力ができない幼児には使うことができません。

そこで、Google Homeを活用して、文字入力をせずにSlackで会話するシステムを構築してみました。

イメージは以下のとおりです。


![slack-google-home.png](https://qiita-image-store.s3.amazonaws.com/0/40886/a20f28a5-aabb-d3af-e4e1-f18ca85d3136.png)

このシステムは、大まかに以下の2つで構成されています。

1. Slackへの投稿をGoogle Homeがしゃべってくれる仕組み
2. Google Homeに話しかけるとSlackに投稿してくれる仕組み

順を追って説明していきます。

# 1. Slackへの投稿をGoogle Homeで喋らせるBotの作成

以下のソフトウェアを書きました。
https://github.com/ikasamah/go-slack-google-home

Google Homeに任意のテキストを喋らせる方法としては、 `google-home-notifier` が主流ですが、
同じ操作を行える[homecast](https://github.com/ikasamah/homecast)というGoパッケージを作り、[go-slack-google-home](https://github.com/ikasamah/go-slack-google-home)で使用しています。
Slackではなく、LINEやHTTPサーバ経由などでGoogle Homeを喋らせたい場合は、[homecast](https://github.com/ikasamah/homecast)パッケージの使用をオススメします。

- https://github.com/ikasamah/homecast
- [Google Homeに任意の言葉を喋ってもらう方法 Golang編](https://qiita.com/ikasamah/items/48ca06c5a4e0421b8756)

## 1-1. Botの登録
Slackの以下のページからBotを作成します。
https://my.slack.com/apps/A0F7YS25R-bots

Botの名前などは何でもOKです。
作成が終わったら、適当なチャンネルにBotをinviteしてメンションできる状態にしておきます。

## 1-2. Botの起動
一旦、ローカルのMacでBotの動作確認を行います。

```bash
# Goがインストールされていない場合
# $ brew install go

$ go get github.com/ikasamah/go-slack-google-home
$ go/bin/go-slack-google-home -token [1-1. で作成したBotのToken] -lang ja

...(以下、ログが出力される)... 
```

プログラムを起動した状態で、SlackからBotにメンションを送ってみましょう。
`@xxxxx こんにちは`

Google Homeが**「こんにちは」**と喋りだせば成功です。
*※複数台のGoogle Homeがある場合は全てが喋ります*


*Ctrl+C* でBotのプログラムを中断し、次に進みます

## 1-3. Raspberry PiにBotをデプロイする
作成したBotは、ローカルネットワーク内で常に動かしておく必要があります。
このままMacで動かしても問題ありませんが、何かしらの専用マシンを用意するのがよいでしょう。
ここでは、Raspberry PiでBotを動かす例を紹介します。

Raspberry Piの環境が無い場合は、以下などを参考にSSHログインができるところまで設定してください。
[Raspberry Pi 初期設定](https://qiita.com/HeRo/items/c1c30d7267faeb304538)

### Goのインストール
apt-getで取得できるGoはかなり古いバージョンなので、別の方法でインストールします。

```bash
$ wget https://storage.googleapis.com/golang/go1.9.linux-armv6l.tar.gz
$ sudo tar -C /usr/local -vxzf go1.9.linux-armv6l.tar.gz
$ echo 'PATH=$PATH:/usr/local/go/bin' >> ~/.profile
$ source ~/.profile
$ go version
go version go1.9 linux/arm
```

### go-slack-google-home のインストール
```bash
$ go get github.com/ikasamah/go-slack-google-home
# 以下で起動可能
# $ go/bin/go-slack-google-home -token [1-1. で作成したBotのToken] -lang ja
```


### Systemdを使ってサービス登録する
Raspberry Piがリブートしても自動でBotが起動するようにします。

```bash
$ sudo vi /etc/systemd/system/slackgooglehome.service
```

以下の内容を書き込みます。
- `<SLACK_BOT_TOKEN>`は適宜変更してください。
- `<USERNAME>` にはgo-slack-google-homeをインストールしたLinuxのユーザーを入れてください

```
[Unit]
Description=slack-google-home Server
After=syslog.target network-online.target

[Service]
Type=simple
User=root
ExecStart=/home/<USERNAME>/go/bin/go-slack-google-home -token=<SLACK_BOT_TOKEN> -lang=ja
Restart=on-failure
RestartSec=10
KillMode=process
WorkingDirectory=/home/<USERNAME>

[Install]
WantedBy=multi-user.target
```

サービスの有効化と起動

```bash
$ sudo systemctl enable slackgooglehome
$ sudo systemctl start slackgooglehome
```

ステータスの確認

```
$ sudo systemctl status slackgooglehome

# 以下のような表示が出ていればOKです。

● slackgooglehome.service - slack-google-home Server
   Loaded: loaded (/etc/systemd/system/slackgooglehome.service; enabled)
   Active: active (running) since Sun 2018-02-11 03:29:45 JST; 7min ago
 Main PID: 20869 (go-slack-google)
   CGroup: /system.slice/slackgooglehome.service
           └─20869 /home/<USERNAME>/go/bin/go-slack-google-home -token xoxb-xxxxxxxxxxxxxxxxxx -lang ja

Feb 11 03:29:50 pienc2 go-slack-google-home[20869]: 2018/02/11 03:29:50.142535 [INFO] Connected: user_id=UXXXXXXX
...(以下続く)...
```

これで、SlackからGoogle Homeを喋らせることが可能になりました。

実際、この仕組みだけでもそこそこ使える場面は多く、
「急ぎ目で家族に連絡したいけど、スマホを手元に持っていないっぽくて反応がない」
などの場合に家の中のGoogle Homeから呼びかけることができます。


# 2. Google Homeに話しかけるとSlackに投稿するDialogflowの作成
Dialogflowとは「自然言語によるチャットボットを作成するサービス」です。
Googleが買収したサービスで、以前は`API.AI`という名前でした。

今回はDialogflowを使ってGoogle Home=>Slackの連携を実現します。
Dialogflowの細かい説明を書くと長くなってしまうので、必要な設定のみを書いていきます。

### 補足
なお、Google HomeからSlackに連携する方法には、ここで紹介する方法以外にも`IFTTT`を使う方法もあります。
お手軽に連携したい場合はIFTTTとの連携の方がよいかもしれません。

個人的にはDialogflowが進化した時に、より便利に使えだろうと考えているため、この方法を採用しています。


## 2-1. Aegentの作成
まず、新たなAgentを作成します。名前は何でも大丈夫です。

Agentの設定メニューの`Intents`をクリックし、`Default Welcome Intent` を選択してください。
そして、画像のようにText Response を以下に変更します。
「スラックに何とポストしますか？」

他の項目は空で大丈夫です。

<img width="1007" alt="スクリーンショット 2018-02-11 4.40.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/40886/cca66b3b-3253-f58b-790b-8dd80c8cecfb.png">


## 2-2. Intentの追加
次に任意の発言を受け取り、Slackに投稿するIntentを作ります。
今回の核となる部分です。

まず、　`User says`　に「こんにちは」と入力します(何でもよいです)
そして、「こんにちは」のテキストを選択すると、Entityの選択ダイアログが出ます。
ここは `@sys.any` を選択してください。

次に`Action`と書いてある項目のパラメータを以下のように設定します。

```
PARAMTER_NAME: any
ENTITY: @sys.any
VALUE: $any
```

Text responseは「スラックに $any とポストしました」と設定します。

最後に、Fulfillmentの設定で `Use Webhook` にチェックをしておきます。

以下の画像のようになっていればOKです。

![スクリーンショット 2018-02-11 4.51.38.png](https://qiita-image-store.s3.amazonaws.com/0/40886/ce592cb1-33e8-c412-2daf-c7ddd8d83216.png)


## 2-3. Fulfillmentの設定
Fulfillmentとは、IntentのActionを受け取るバックエンドのようなものです。
左のメニューからFulfillmentの設定を開きます。

Fulfilmentは、任意のURLにアクセスする方法と、Inline Editorでコードを書く方法の2通りあります。
インラインのコードはワンクリックでCloud Functionsにデプロイされて動くことになります。

ここでは、手軽なインラインを利用します。

Inline EditorをEnableにして、
package.jsonタブに1行追加します


```
{
  "name": "dialogflowFirebaseFulfillment",
  "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": "~6.0"
  },
  "scripts": {
    "start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
    "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
  },
  "dependencies": {
    "slackbots": "^1.1.0",  # この行を追加
    "actions-on-google": "^1.5.x",
    "firebase-admin": "^4.2.1",
    "firebase-functions": "^0.5.7",
    "apiai": "^4.0.3"
  }
}
```

次に、index.jsを以下のコードに置き換えます。
https://gist.github.com/ikasamah/904e075f46e9418c6df569cfdc6755a2


- `<CHANNEL_TO_POST>` には投稿するチャンネルに置き換えてください。
 - # 抜きのチャンネル名でOKです。(#generalに投稿する場合、`general`)
 - Botが投稿先のチャンネルに入っている必要があります。
- `<SLACK_BOT_TOKEN>` にはbotのトークンを入れてください。


完了したら「DEPLOY」ボタンを押します。すると、Cloud Functionsにアップロードされます。
Google　Cloud Platform(GCP)のアカウントがない場合にはここで引っかかるかもしれません。
引っかかった場合は、GCPのプロジェクトを作る必要があります。

Fulfillmentの設定画面は下のような感じです。

![スクリーンショット 2018-02-11 5.31.35.png](https://qiita-image-store.s3.amazonaws.com/0/40886/0380c57d-da89-5c44-307e-a65101cf9cd5.png)


## 2-4. Google Homeへのインテグレーション
作ったエージェントをGoogle Homeで使えるようにします。
左の`Integration`メニューをクリックして、Google Assistantを選択します。

![スクリーンショット 2018-02-11 5.41.38.png](https://qiita-image-store.s3.amazonaws.com/0/40886/a0385ebc-4798-58de-a98d-d1d5980e80ed.png)

![スクリーンショット 2018-02-11 5.44.37.png](https://qiita-image-store.s3.amazonaws.com/0/40886/941c45a9-1d6f-604b-4dd9-b73888d5ed96.png)

このボタンを押すと　`Actions on Google`に遷移し、
Assistant Appを作る画面になります。適当にアプリを作りましょう

アプリの例:
![スクリーンショット 2018-02-11 5.49.46.png](https://qiita-image-store.s3.amazonaws.com/0/40886/ca85d40f-84a2-8667-b4fe-830cf91a080a.png)

入力がやや面倒ですが、`TEST DRAFT`を押すと実機でアプリが動くようになります。
なお、`SUBMIT DRAFT FOR REVIEW`を押すとGoogleに**公開**アプリとしての審査依頼を出してしまうので気をつけましょう😱

アプリの名前は「お父さん呼んで」としてみました。
これは、アプリを呼び出す際に用いられるので、わかりやすいものがよいでしょう。

> 👧 「お父さん呼んで」
> 🤖 「はい、お父さん呼んでのテストバージョンです。」
> 🤖 「スラックに何とポストしますか」
> 👧 「お餅おいしい」
> 🤖 「スラックにお餅おいしいとポストしました」

のような感じになります。
左メニューにシミュレーターも用意されているので、実機以外での確認も可能です。

なお、詳しくは把握しきれていないのですが、あくまでテストアプリの扱いになるので、以下の制限があるようです。
- Implicit Invocation(明示的に呼び出さずにアプリを使う方法)が動かない
- Sample invocations (アプリの呼び出し方の別名のようなもの)が上手く動かない
- テストアプリを利用できるのはアプリにリンクされたアカウントのオーナーか、ゲストのみ
    - 他の家族がVoiceMatchが設定してあると、上手くアプリを呼び出せなかったりします

Actions on Googleはいまいち理解しきれていないので、もう少し研究してみようと思います。

以上で全ての工程が完了です。
お疲れ様でした！

# さいごに
このシステムによって、実際に子供とも遠隔からSlackで会話できるようになりました。
すごくハッピーだったので、妻に自慢してみたところ...


![IMG_2506.jpeg](https://qiita-image-store.s3.amazonaws.com/0/40886/b746742f-414c-f745-ca27-2a5cd1c18bd8.jpeg)

👉**その発想はなかった**