[Dialogflow v2]Google Homeで国名コード検索

# BELってどこの国…？
ワールドカップ2018、とうとう終わってしまいました。個人的にはベルギー優勝！という予想でしたが、皆様の予想はいかがでしたでしょうか。

こういった国際大会を見ていると、国名がアルファベットの略記で表示されます。日本であればJPNのような。ワールドカップくらいの参加国数であれば推測できるのですが、他の大会、オリンピックともなると参加国も多数となり、「これどこの国だっけ？」とわからなくなります。
これは…Google Homeに「BELってどこの国？」と聞くと教えてくれる機能があれば便利そうだ！

というのが建前で、Dialogflowを使ってGoogle Homeの機能拡張をやったことがなかったので、ちょうどいい題材見つけた！という次第です。なので中身はほぼチュートリアル。

2018/07/19現在、少し前にDialogflowのv2が正式リリースされたからか、UIが変わって、いろいろな記事を見ても微妙に言葉遣いが違っておりました。そういった苦労をしたこともあり、今回の投稿のモチベーションにもなっています…。

# 大まかな流れ
Actions on GoogleとDialogflowの２つのサービスで構築します。
1. [Actions on Google] Actions on Googleにプロジェクト作成
2. [Actions on Google] Actionを作成
3. [Dialogflow] Intentで問い合わせの文言を定義
4. [Dialogflow] Entityで対応する国名コードを定義
5. [Dialogflow] Fulfillmentで国名コードに対応する国名を検索して返信
6. [Dialogflow] テスト
7. 完成！Google Homeに遊んでもらう

リリースまではしてないです。あくまで個人利用。

## [Actions on Google] Actions on Googleにプロジェクト作成
### プロジェクトを作成
Actions on Googleの[ACTIONS CONSOLE](https://console.actions.google.com/)が全てのスタートです。

![スクリーンショット 2018-07-19 20.20.18.png](https://qiita-image-store.s3.amazonaws.com/0/23715/810ce607-2e93-a314-3686-8bd8c50dabf1.png)

Add/import projectからプロジェクトを作成します。言語、国とかお好きなものを。見かけた記事だと、以前は、言語とか国はもうちょっと後っぽかったんですが、今はこの段階で設定できます。

### カテゴリの決定
このプロジェクトはどんなカテゴリか決めるらしいです。お好きなものを。スキップも可。リリースしないなら何選んでも問題ないと思ってます。
![スクリーンショット 2018-07-19 20.24.56.png](https://qiita-image-store.s3.amazonaws.com/0/23715/994a469d-6034-71d1-3cbd-0b5850fb4f00.png)


### Displaynameの決定
次にこのサービスを起動するためのDisplay name（＝起動ワードって理解です）を設定します。
![スクリーンショット 2018-07-19 20.26.29.png](https://qiita-image-store.s3.amazonaws.com/0/23715/aa6033a3-8679-bef9-c187-deed70d10ada.png)

「Decide〜」をクリックすると設定画面に飛びます。
![スクリーンショット 2018-07-19 20.28.37.png](https://qiita-image-store.s3.amazonaws.com/0/23715/90618bd8-164b-6db1-358f-2e8c94d084d1.png)

声も決められます。MaleとFemale、それぞれ1,2。Display nameは発音を確認できるのに、Assistantの声は確認できず…

## [Actions on Google] Actionを作成
次にActionを作成するらしいです。このあたりもUIが変わったみたいですね。

左のBuildの下のActionsから...
![スクリーンショット 2018-07-19 20.32.56.png](https://qiita-image-store.s3.amazonaws.com/0/23715/2052e163-4deb-521c-f394-0b2b503839ca.png)

ADD YOUR FIRST ACTION。
![スクリーンショット 2018-07-19 20.33.30.png](https://qiita-image-store.s3.amazonaws.com/0/23715/d5825319-c78b-9823-5306-7197ab87b94d.png)

そしてCustom intentを選んでBUILD！
![スクリーンショット 2018-07-19 20.34.12.png](https://qiita-image-store.s3.amazonaws.com/0/23715/4a31de48-3e46-bf88-5f45-6e829b0fa972.png)

これでこのプロジェクトに紐付いたDialogflowのagentの作成画面に移動します。
次からはDialogflowでの作業になります。

## [Dialogflow] Intentで問い合わせの文言を定義
最初に言語してagentを生成。
![スクリーンショット 2018-07-19 20.38.07.png](https://qiita-image-store.s3.amazonaws.com/0/23715/0651c90b-54dd-2be1-763b-08617a87cb3f.png)

今回作成するIntentは全部で4種類。

* Welcome Intent：起動したときにしゃべるメッセージ等
* Fallback Intent：合致するIntentが見つからない場合の処理
* 本体：実施したい処理。今回はここに国名コードを検索して国を返すロジックを組みます。名前は「searchcode」にしました。この名前自体に意味はないですが、以降の説明でsearchcodeと出てきたら本体のIntentと読み替えてください。
* 終了：接続を切る処理。

1,3,4は2ができれば簡単なので、説明は2にしぼります。

ちなみにIntentは[ドキュメント](https://dialogflow.com/docs/intents)によると↓。
> An intent represents a mapping between what a user says and what action should be taken by your software.

### Intentの作成
左のメニューからIntentsを選んでCREATE INTENT。
![スクリーンショット 2018-07-19 22.17.47.png](https://qiita-image-store.s3.amazonaws.com/0/23715/49d1b89d-4fbd-0142-a1ea-3a3519d0bf9e.png)

画面の一番上にIntentの名前を設定できる箇所があるのでsearchcodeと設定。個人的にはちょっとわかりにくかった…SAVEボタンも上にあって少し探したりしました。

### Training phrases
Google Homeへの問い合わせに使う文言を定義します。
これがUIが変わってつまづいたところです。見かけた記事によると「USER SAYS」って前は言ってたみたいですね。
![スクリーンショット 2018-07-19 20.49.52.png](https://qiita-image-store.s3.amazonaws.com/0/23715/c5a85d86-a2aa-02d7-1fd1-f621e0ea4908.png)

Add user expressionに文言を入力してENTER。
![スクリーンショット 2018-07-19 20.51.47.png](https://qiita-image-store.s3.amazonaws.com/0/23715/83bf4d8c-cbf7-37d6-edda-0d1095f9c7b7.png)

そうすると、本体動作（Fulfillment）への入力となるパラメータが、その文言のどこかを定義するところが表示されます。今回はJPの部分。ここのJPはただの例みたいなものらしく、別になんでもよさそうです。ここに入る値はEntityで定義するようです。

問い合わせの文言は複数登録できますのでお好みで。

### Action and parameters
Training phrasesのすぐ下。Fulfillmentへの入力となるパラメータの定義です。といっても上で定義したら自動で追加されてます。必要に応じてRequireとか設定するとよさそうです。
ちなみにここでもひっかかりました。ActionというのがActions on GoogleのActionと混同して、説明がどっちを指してるのか混乱しました。
![スクリーンショット 2018-07-19 20.55.49.png](https://qiita-image-store.s3.amazonaws.com/0/23715/ff2eecd8-444a-ce96-ff74-81971659bca9.png)

### ResponsesとFulfillment
このIntentの動作とその結果を定義します。Fulfillmentの中身を定義するわけではなく、このIntentが動くとFulfillmentを起動しますよ〜という設定です。通常処理はFulfillmentで完結するため、Responseは基本使われない模様。Fulfillmentがコケたときにこのメッセージが読まれるみたいです。
![スクリーンショット 2018-07-19 20.58.41.png](https://qiita-image-store.s3.amazonaws.com/0/23715/4a63314e-ae79-2e2a-3451-1c0e0ef0376a.png)

ちなみにWelcome、FalloutのIntentはコメントを返すだけならTraining等々はいらず、Responseだけ設定すれば動きます。
終了のIntentは、Training Phraseに終了するためのキーワード（例えばありがとう）と、その応答Response（例えばyour welcome）を登録して、Resonsesの下の「Set this intent as end of conversation」を有効にするだけです。

## [Dialogflow] Entityで対応する国名コードを定義
Entityは[ドキュメント](https://dialogflow.com/docs/entities)によると↓。
> Entities are powerful tools used for extracting parameter values from natural language inputs. Any important data you want to get from a user's request, will have a corresponding entity.

パラメータに入る可能性のあるものを定義して、言い回しの違いを吸収するための設定と理解してます。今回、パラメータに入るのは国名コード。しかし、それを全部手打ちするのはつらい。CSVのアップロードで一括登録できるらしいので、[Wikipedia](https://ja.wikipedia.org/wiki/ISO_3166-1)の表をちょちょいとCSVに加工。国名コードってISOらしいんですよ、ご存知でした？？？

ファイル名がそのままEntityが対応するパラメータの名前になりますので、今回はcountrycode.csvとして↓のようなファイルを作成。1列目がパラメータにわたす値、2,3列目が言い回しの種類。今回は2文字、3文字に対応してみました。
<img width="323" alt="スクリーンショット 2018-07-19 21.08.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/23715/b364fd00-a1f8-d403-7666-797e9d9d1a4f.png">

これを右上のメニュー「Upload Entity」からアップロードすると…
![スクリーンショット 2018-07-19 21.09.33.png](https://qiita-image-store.s3.amazonaws.com/0/23715/18d54b98-c660-f116-0746-d3c4eaa39b95.png)

こんな感じに一括登録できます。楽ちん。
![スクリーンショット 2018-07-19 21.10.19.png](https://qiita-image-store.s3.amazonaws.com/0/23715/86edec57-831e-6df9-119a-c9aa6f72a76c.png)


## [Dialogflow] Fulfillmentで国名コードに対応する国名を検索して返信
ここまでの設定で、Google Homeから「JPNってどこ？」と問い合わせると、JPNが本体動作：Fulfillmentに届くようになりました。次は本体動作の作成です。

左のメニューからFulfillmentを選んで、今回はInline Editor（JavaScript）を使いました。
![スクリーンショット 2018-07-19 21.13.06.png](https://qiita-image-store.s3.amazonaws.com/0/23715/ea32c9eb-81db-e382-3e78-1955fbea9627.png)

ちなみにInline Editorで作成したコードは、FirebaseのFunctionsに自動登録されます。便利。

Inline Editorにはデフォルトの処理が既に入っているので、大枠はそれをそのまま利用します。

今回書き換えるのはyourFunctionHandler（~~処理は一つだけですし、めんどくさいので名前はデフォルトのまま...~~）。

今回は国名コード→国の名前を調べることですので、国名コードの連想配列にしてみました。
これまたWikipediaの表をちょちょいと加工してこんな記述に。地域もついでに。

![スクリーンショット 2018-07-19 21.19.35.png](https://qiita-image-store.s3.amazonaws.com/0/23715/2156db45-d686-0abe-705d-7bc8daca5541.png)

そして連想配列から国名と地域を抜き出して、Google Homeに送り返す処理です。
![スクリーンショット 2018-07-19 21.21.48.png](https://qiita-image-store.s3.amazonaws.com/0/23715/fa6c7b9f-b3f1-9c22-9021-79a9127f04d9.png)

なんか小賢しいことをいろいろやっていますが重要なのはagent.add()でGoogle Homeを喋らせられるということだけです。

```javascript

agent.add(vcode + "は" + db[code].name + "、" + db[code].area + "です。");
```

最後にこの関数とIntentを結びつければおしまいです。yourFunctionHandlerのところをコメントアウトして、第一引数に本体処理のIntentの名前を書けばOKです。

![スクリーンショット 2018-07-19 21.24.43.png](https://qiita-image-store.s3.amazonaws.com/0/23715/deeba3a0-e896-ff65-c88f-2fab4c253340.png)

最後にDEPLOY。結構時間がかかるので、慎重にやったほうがいいです。
![スクリーンショット 2018-07-19 21.38.31.png](https://qiita-image-store.s3.amazonaws.com/0/23715/475dbe2e-309b-51ed-a00a-e3d489573694.png)


## [Dialogflow] テスト
これで設定はおしまいなのであとは挙動確認。
Dialogflowの右上の「Try it now」に「JPNってどこ？」と放り込んでやると...

![スクリーンショット 2018-07-19 21.28.16.png](https://qiita-image-store.s3.amazonaws.com/0/23715/2bec4e2f-3a8e-0c28-f925-6765dffb9ccb.png)

JPNは日本、東アジアです。おお、そのとおり。INTENTを見ると、意図通り紐づけたINTENTが起動しています。
アマゾン川がどこにあるかわからず、中学時代に社会科の先生に笑われた地理雑魚勢なので地域も重要。今回のワールドカップもセネガルとセルビアは一瞬ウン？となりました。
![スクリーンショット 2018-07-19 21.30.40.png](https://qiita-image-store.s3.amazonaws.com/0/23715/29cf7008-6b11-e8d9-82f1-d38e0efda8cd.png)

ちなみにJPNが少し横にふくらんでいるのは、スペース入れて文字と文字を区切っているからです。ひっついていると英単語として読まれてしまった…

なお、プログラムがコケるとResponseに設定した文言が返されます。
その原因を探るには、このFulfillmentが動作しているFirebaseに出力されているログが役立ちます
DEPLOYの左にある「View execution logs〜」からその画面にジャンプできます。
![スクリーンショット 2018-07-19 21.42.07.png](https://qiita-image-store.s3.amazonaws.com/0/23715/2525f656-aa9c-8658-797e-19c0f427acce.png)

エラーだとこんなの。このときはタイポ。お恥ずかしい限り。
![スクリーンショット 2018-07-19 21.41.40.png](https://qiita-image-store.s3.amazonaws.com/0/23715/13ec6d1f-a326-6602-5948-4daad0434037.png)

ちなみにFulfillment自体見つからないときはFalloutのintentが動作します。Fallout Intentと、本体動作IntentのResponseで別の文言を指定しておくと、どっちでミスってるのかわかりやすくなります。

このログ、Request bodyというところでFulfillmentで使えるrequestの中身を見ることができたりします。便利。
![スクリーンショット 2018-07-19 21.43.42.png](https://qiita-image-store.s3.amazonaws.com/0/23715/fdc92dd9-6d7d-b8be-9cb7-b1feeabc15f5.png)

## 完成！Google Homeに遊んでもらう
これで準備OK。あとは、このActions on Googleを作ったアカウントに紐づけたGoogle Homeに、
1. ねぇ Google
2. カントリーコードにつないで　→　Welcom Intentが起動
3. BELってどこ？ →　本体のIntentが起動
   ※問い合わせは連続で実行可能。ここがGoogle Home単体よりいいところ。
4. ありがとう　→　終了のIntentが起動

という感じで遊べます。

Google on Actionsにシミュレータがありますので、そちらでも遊べます。左のSimulatorからどうぞ。2文字でもちゃんと答えてくれます。RとLですごい違い…という例にしようと思いましたが、わりと近かった。
![スクリーンショット 2018-07-19 21.52.17.png](https://qiita-image-store.s3.amazonaws.com/0/23715/d7d653d6-5487-25f9-7886-c023ff423abe.png)

# おわりに
ここまでで、Google Homeで問いかけ →　自分で作ったプログラムで処理　→　結果をGoogle Homeに返す、というサービスの基本形ができました。Fulfillmentは直接APIを叩くこともできるみたいです。そこまでこれば通常のAPI開発になりますので、一気にできることが増えそうです。振り返ってみればほとんどコード書いてない。すごいな〜

アイデア一発の国名コード検索でしたが、Actions on Google、Dialogflowのチュートリアルとしては楽しい題材という感想でした。

なお、この記事は、2018/07/19現在のUIを基に作成しています。今後の更新でUIは変わっていくはずですのでご注意を…

ちなみにオリンピックで使われるのはIOCが定義した[IOCコード](https://ja.wikipedia.org/wiki/IOC%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7)なのでISOの国名コードでは見つからない国もあります。
ドイツはDEU…これはわからない。 [Deutschlandが由来](https://lister.tokyo/kuni/country_code.php?doko=%E3%83%89%E3%82%A4%E3%83%84&a3=DEU&a2=DE)らしいですが。
![スクリーンショット 2018-07-19 21.59.55.png](https://qiita-image-store.s3.amazonaws.com/0/23715/9d64adde-7c8c-d0ab-cbcf-9d7fc89225f3.png)
たしか日本の「ドイツ」って呼び方はこっち由来なんでしたっけ？

IOCのコードは3文字の一種類しかないため、あたかもEntityの説明用にわざわざISOのコードを使ったみたいですが、素で気づいてなかったです。ドイツが見つからないなー　→　もしかしてオリンピックってISOコード使ってない？と検索したら発覚したという。結果オーライ。

…CSVと連想配列作り直さなきゃ。