Chatbot導入検討〜Google actions審査まで

そこそこ苦労したので、備忘録的な物と、これからChatbot導入検討する人に向けて

## ChatBotの導入検討
国内Chatbotのベンチャー何社か会って、導入検討する。

会社の都合上Chatbotに期待する要件として

- 語録の自動学習
- 自社APIと繋げれる事

4社ぐらいと会ってみたが、どこも機械学習を使って語録認識に役立てていなかった。
キーワードに対して、キーワードを返すだけのタイプのchatbotばかりだった。
語録の認識についてだが、
期待する動きとして「ゴールデンウィークの空き状況を教えて」と問い合わせが会った時、
ゴールデンウィークを4月28日〜30日、5月3日〜6日と認識したいとか
日本の地名や、フルーツの名前とか一般辞書的な物が共通であって、そういった物を利用できるというイメージがあったのだが、そういう物は一切なく、全部Chatbotの仕組みを使って自作は可能ですという感じだった。

もう一つの要件として、APIから自社の予約状況等の情報を参照できる仕組みがほしかったが、それもできる所が無かった。（要開発でできるという所もあるにはあったが、基本パッケージでは無い）

## 結局大手クラウドから探す事に
AmazonとGoogleならChatbotぐらいあるだろと思って探したら、すぐに見つかった。
AmazonはLexで
Googleはdialogflowだった

Amazon lexは結局調べないままDialogflowを採用する事に。

[dialogflowでの見え方]
![dialog.png](https://qiita-image-store.s3.amazonaws.com/0/269117/0a11bced-a5e8-3905-2595-4574f9b2fe4b.png)
[Assistantでの見え方]
![assistant.png](https://qiita-image-store.s3.amazonaws.com/0/269117/7a408a4a-34c4-73c8-9e74-758454363b36.png)


## Dialogflowを採用した理由
- 拡張性が高い chatbotのみならず、Google assistant, Google home, Facebook messenger, Line, slack, 対抗馬と思われるAmazon Alexa等も使えると判ったから。
- 音声認識が優秀　
- WebhookとしてAPIに繋いで自社サーバーとやり取りできるのを確認したから

## DialogFlow Fullfillment webhook
ここまでは引っかかる所がなかったが、ここで難儀した。
APIを使って応答する方法は2種類存在

- 自前webhookサーバーを立てて通信させる方法
- Firebase functionsを使って即席の応答プログラムを開発する方法。

結論を先に述べると後者のfunctionsを使った方が良いです。

ちょうど、Dockerでrest api django環境を持っていたので、AWSでそれを建てて、webhookサーバーの機能を実装していく。APIのJSONフォーマットはそこそこ判りやすく、問題はなかったが、いざ繋ごうとしたらhttpsを強要されたので、SSL設定を施した。(つまずき1）

dialog flowの応答設定をそのままAction on Googleで使えるので、Google Assistantで同じ様に動くか確認する。表示形式Card型で候補の店舗をいくつか表示する形がDialogFlowでは確認できていた。
Assistantのシミュレーターで試すと、Dialog flow APIのqueryResult.fulfillmentTextの方が表示されていて、Card表示されない。　（つまずき２）

いろいろ調べていくと、DialogFlowと、Actions on GoogleのCardのJson仕様が異なっており、Textだけの表示という残念な結果に。
結局DialogFlowと、Actions on Googleで同じCard表示をするにはFirebase functionsを使った方が良いという結論になり、Firebase functionsを使ってみる事に。

##Firebase functionsに触れてみる
店舗の情報をjsonにまとめてあったのをFirebase realtime databaseに入れて使ってみる。
firebase functionsから、realtime databaseを参照するドキュメントが少なくて難儀したが、繋いでみると今度は部分一致が無い事に気づく。(つまずき３）
<PRE>
shop:[
  {
   name:'池袋の店舗名',
   station:'池袋駅',
   address:'豊島区池袋',
   ....
  }
]
</PRE>
というデータ構造をしていた。

全文一致、前方一致、後方一致、前方Like一致はあるみたいだが、「池袋」というキーワードを３項目全てに部分一致で探さないといけないという状態だったので、realtime database 向けでは無いというあきらめをして。functionsで一緒にデプロイされるフォルダーに置いてファイル参照が出来たのでそれでやった。
尚DialogflowのinlineEditorを使ってfirebase functionsのコードを編集できるが、コード書きにく過ぎるのと、たまにdeployにコケるので、Firebase CLIを使う。
<img width="600" alt="スクリーンショット 2018-09-06 12.59.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/269117/a93de85f-89f6-47da-3ebc-f2707925b347.png">
一度でもCLIからdeployするとこうなる↓　こちらのソースをコピーしてFirebase CLIのindex.jsにコピペして使う function名が変わらなければ問題はない。
またCLIではdialog flow のパッケージが入ってないので、いろいろnpmからインストールしないと駄目。
![スクリーンショット 2018-09-06 13.06.26.png](https://qiita-image-store.s3.amazonaws.com/0/269117/54feafc3-dd97-e1d6-29be-b837da92acd9.png)

注意点というかこうすりゃよかったと思った点。
deploy - テストが非常に手間がかかる。　deployに20秒ぐらいかかり、実行して結果のログ(Firebase function ログから見る)を得るのにトータルで１分ぐらいかかる。
(愚痴ると、普段Flutterでhot reloading,hot restartで開発しているせいかもしれんが、Javaのクソ長コンパイルとどっちがマシだレベルでとてもストレスフル。 jsなのに..）
ローカルの実行環境でテスト出来るが、DialogFlowが動いてくれるかという心配もあり、かなりのイテレーションが発生した、経験が無いとあたりをつけられないのでしょうがない気もするが、DialogFlowのはくDiagnostic infoをバリエーション揃えておけば手間省けたなとかは思ったり。

さらに難儀した話としてはこのWebhook用functions のnode.js apiが結局見つけられなかった。
（dialog flowそのものやFirebase functionsのは見つかるが）
https://github.com/dialogflow/fulfillment-webhook-nodejs
ここを参考に作ったので、各関数の仕様とかよくわかっていない。

##Actions on Google審査
dialogflowそのものは誰の断りもなく、リリースさせられるが、アプリは審査を受ける。
予備知識ほぼゼロだったので当然の様にリジェクト。　主な原因はこんな感じ。

- AFF App violates Apps for Families policy
- Not supported language
- App does not quit on request
- Mic is open without prompt
- Sample triggers do not work Sample Invocations

(つまずき何度か)

### AFF App violates Apps for Families policy
Directory Information > Addtional Informationで
For FamiliesでYesにチェックを入れてた為。
つまるところ子供向けコンテンツじゃないと駄目らしい。
別にアダルティーな内容ではないので、全年齢対象だったが、子供向コンテンツでもないとチェックを入れとくと駄目みたい
### Not supported language
日本語のみ対応なのに、英語でところどころ聞いてしまうシーンがあったので弾かれた。
心当たりがまったくなかったのだが、
Intent の Action and Parameterで必須項目（チェックの入っている）変数が埋まっていない場合、Promptsが空だと、英語でwhere? と返ってきてしまう為。

![スクリーンショット 2018-09-06 13.29.05.png](https://qiita-image-store.s3.amazonaws.com/0/269117/15a6bc6f-72a0-23be-42c4-57377eab8f2b.png)
Promptに日本語で「場所はどちらでしょうか？」と入れる事で、必須項目漏れの際、「場所はどちらでしょうか？」と聞いてくる様になる。
### App does not quit on request
終了用のintentがないという内容。
「終了」「止めて」「中止」等のキーワードの反応するIntentを作って、アプリから離脱ができればok

### Mic is open without prompt
ちゃんとした解決策が今の所まだ見つけてないが、Google Home や Assistantではマイクを使ってコマンド受付するのだが、ユーザが何を回答すればわからないとか、終わった気になって放置してしまった場合の処置が無いという内容。
Node.jsでWebhookClientにwaitとかがあるのだが、使い方がわからない。
結局対処として、リクエストに対する回答文の後ろに、「続ける場合は更に質問を、終わる場合は終了と言ってください」という一文を載せて、ユーザーが能動的に「終了」と言ってもらう様にしむける。
サイトのURLを踏んでもらう場合の回答は、そのままWebを見に行くと、終了しなくなりそうなので、回答したらアプリ終了する様にしておいた。

### Sample triggers do not work Sample Invocations
![スクリーンショット 2018-09-10 17.58.06.png](https://qiita-image-store.s3.amazonaws.com/0/269117/a57d2d59-ef03-0516-e68c-e7742c01c000.png)


見たとおりAssistantやHomeにどういうフレーズを言ったらアプリ起動してくれるかなのだが、会社名を認識してくれなくて、難儀した。
会社名 OR サービス名はシンプルに限る。


これらの他にも当然、Webhookから応答が無い場合や、回答が無いとリジェクトの原因になるだろう。
あと審査している内容はdialog flowのHistoryに残るので対策は割とできると思われる。
「ヘルプ」とか試して見ているので、使い方Intentとして作っておいた方が良いかもしれない。

## 承認　Deploying
<img width="701" alt="スクリーンショット 2018-09-11 10.39.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/269117/ff0ddd77-6b72-f055-a9d7-e1159dd19947.png">
こんな文面の承認メールが届いた。
デプロイに時間がかかる模様


## まとめ
- 下手なchatbotに手を出すぐらいならDialogflow使いましょう。
- Assistantを使わない場合でも認識が良いのでおすすめ出来る。
- Webhook作る時は、素直にFirebase functions 使おう。
- Functions 開発がFullfillmentこみでやると結構しんどいので、なるべくロジックは先にnodejsでしっかり出来てから繋ぎ込みをした方が良い。あるいは別サーバーに飛ばして処理をするだけのコードにしておくとか。
- chatbotだけではなくGoogle Assistantで起動出来るアプリにしたい場合は、Actions on Goolgeの審査を受けましょう。そこそこ厳しいです。

## 今後の展望というかやりたい事
google Assistantを使う場合、google アカウントが必須なので、そのアカウントとソーシャルログイン等で紐付きさえできていれば、自社サービスのログインした状態で、予約をしたり、物を買ったり、前回行ったお店の混み具合を確認したり、ユーザーの識別ができるのでよりターゲットマーケティングが出来たりすると思われる。
そこまで需要があるかどうかは今後のGoogle先生の注目度次第な感じ

google duplex とか電話を使っ応対ができる日もそのうち来るらしい。
https://www.lifehacker.jp/2018/07/google-ai-assistant.html
音声認識を除けば、dialogflowで設定していく事になると思う。
FAQや電話問い合わせも出来る日も近そうだ。