バチェロレッテの人気であの人が忘れられそうだったのでテコ入れしてみた話

# 導入

[MDC Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mdc)も最終日になりました。
最後はエンタメ感満載で締め括りたいと思います。

昨年、[バチェラー・ジャパン シーズン３を題材にアプリを開発した](https://qiita.com/bamiyanapp/items/2b326e5f270fe89d876b)私ですが、今年もバチェロレッテを題材に何を作ろうかと楽しみに観ていました。しかし、とうとうネタが見つからないまま見終わってしまいました。

とはいえ、[Qiitaでトレンドの湯婆婆](https://qiita.com/search?q=%E6%B9%AF%E5%A9%86%E5%A9%86)に流されるのも気が乗らないので、昨年のリバイバルとして皆さんにあの人を思い出してもらう機会としたいと思います。
[結婚](https://www.excite.co.jp/news/article/E1600410867090/)への祝辞も込めて、このアプリを贈ります。

# なにを作るか

早い話が、昨年のWebアプリをChatBotで再現してみようと思います。
もしスマートスピーカーと繋げれば、Googleアシスタントのボイスで友永さんになりきってもらう選択肢も出てきます。

ガートナーが「ChatBotがWebアプリを駆逐する」などと言いだしてから久しいものの、Webアプリ全盛な状況は変わらずな気もしますが、特定の用途では徐々にシェアを広げて来ている様子もあって、伸び代はまだまだ期待できる分野かなと思います。
身近な例だと、[Pascoのキャンペーン](https://www.pasconet.co.jp/oishii_cp/)は面白いと思いました。
購入のエビデンスを、QRコードのシールなどでなく、レシートの画像をBotに送る仕掛けを作ってます。
他にも、地元の小さい肉屋さんでもLINEアカウントを作って集客しているのはDXの一端を感じました。

で、出来上がったアプリが[これ](https://line.me/R/ti/p/%40988zasxb)です。
お友達登録すれば誰でも使えるので遊んでください。

# どう作るか

利用するサービスなどの基本構成は、[先日挙げた記事](https://qiita.com/bamiyanapp/items/cb1df0b14d3df2a7c32c)と同様にしています。
インテントの構成は、4分岐としました。

- 一問一答で作る
Web版で一問一答と名付けてた機能を、チャット形式の対話でエンティティを埋める形で実装しました。
これはDialogflowで完結します。

- 文章から作る
Web版では「文章から作る」としていた機能ですが、ほぼそのまま再利用します。
文章をそのまま[gooラボ固有表現抽出API](https://labs.goo.ne.jp/api/jp/named-entity-extraction/)に投げて、人名、地名、時刻などなどパラメータを取り出し、文章を作ります。
外部APIが登場するのでfulfillmentが必要です。

- 単語から作る
Web版では「文章から作る」のエラーハンドリング用に実装していた機能です。
入力の文章に情報が少なく、goo APIに投げてもパラメータがあまり埋まらない場合、何か取れた単語を使って[Google検索のサジェスト](https://so-zou.jp/web-app/tech/web-api/google/suggest/)から別の単語を連想させて、文章を作るように実装していました。
（バチェロレッテ→福田、みたいな）
ChatBot（Dialogflow）の制約上、文章でも単語でも同じインテントに割り振るのが難しかったため、単語専用として別出ししました。

- 写真から作る
Web版そのままで、画像URLを[Azure Computer Vision API](https://azure.microsoft.com/ja-jp/services/cognitive-services/computer-vision/)に投げて、キーワードを取り出し、文章を生成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/fc2ba875-188f-21f4-16f8-497d7fee16bd.png)

次の章から、一つずつ詳しく解説します。

# 一問一答で

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/f85ffb98-5b2b-500b-0c1e-b5a9df6c3658.png)

インテントのフレーズには文章形式で入力してもパラメータを拾えるような設定を入れています。
しかしパラメータが多すぎるのか、文章が長すぎるのか、このまま入力しても該当のインテントには進めますが、パラメータは色と金額の2つが取得できませんでした。Dialogflowの限界のようです。
しかもユーザーのフリー入力はこの文章とは全く違ったものであるはずで、うまくこのインテントだと判別するのは不可能なので、基本は「一問一答」のキーワードでこのインテントに分岐することになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/882e8090-fd4d-ce09-ac7b-04734408732b.png)

パラメータについてご覧の設定をしており、一部必須入力にしているため、不足する場合はプロンプトに記載の質問でユーザーから聞き出すようになっています。
「@sys.color」など、エンティティとして特定の条件、選択肢のなかで自動的に取り込んでくれるので、お任せでいい感じにしてくれます。例えば@sys.dateに対して「昨日」と入力すれば、昨日の日付をyyyy-mm-ddの形で取り込んでくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/e8851f93-e855-d92a-d57e-e86cd69450b4.png)

パラメータが取得できれば、あとはレスポンスするだけです。

# 文章から

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/a6eccf0a-6499-5bf8-0cee-e291e0363056.png)

一問一答と同様、「入力としたい文章をインテントのフレーズにすることはできない」ため、「文章で作る」などのキーワードによって分岐します。
そして肝心の入力文章は、アクション＆パラメータの設定によって分岐後にユーザーから聞き出します。
必須入力としているのと、「@sys.any:何を入力しようとこの変数に当てはめる」のがポイントです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/dfbafe8a-7912-02a4-99f9-32ce2438a2e0.png)

FulfillmentでGASのAPIを呼び、文章を[gooラボ固有表現抽出API](https://labs.goo.ne.jp/api/jp/named-entity-extraction/)に投げて解析します。

# 単語から

こちらも同様に、「単語から作る」といったワードから分岐します。
単語のピックアップは、文章と同じくアクション＆パラメータで取ることもできますが、レスポンスで「Card」を利用するとユーザー操作をいい感じにアテンドできるので、インテントを2段構えにして受け取ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/744b3a58-dbd5-6e59-f157-ce2b37cbf542.png)

最初のインテントは、特にそれ以上の入力は受け取らずこのCardだけ返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/4bc1c978-28b2-f916-a9e0-7ac3306a09dc.png)

子のインテントをぶら下げ、「@sys.any」でキーワードを受け取り、[Googleサジェスト](https://so-zou.jp/web-app/tech/web-api/google/suggest/)に投げ、文章を生成して返します。

# 写真から

とても残念なことに、LINEで画像を入力しても、Dialogflowはどのインテントでもフックしてくれませんでした。
仕方なく、画像はURL形式で、テキストメッセージとしてのみ受け取ることにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/fba334cd-ab88-e9ba-c7da-e9eb7561a1c0.png)

ユーザーがいきなりURLを投げるのも不自然ですので、これも「写真から作る」などのキーワードをトリガーに分岐します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/38f7bd39-605b-6fae-7782-71b9d935d3db.png)

こちらも「単語から」と同様にCardを返してユーザーの入力をアテンドします。
Cardのサンプルから選択するとサンプルのURLが入力されるし、ユーザーが別のURLを貼り付けてもOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/5dd6b10c-ecb0-db38-1b17-1dea7bf56958.png)

子のインテントでURLを受け取り、fulfillmentでGASに投げます。
GASでは[Azure Computer Vision API](https://azure.microsoft.com/ja-jp/services/cognitive-services/computer-vision/)により画像からタグ情報を取り出し、文章に反映します。
ついでに、文章だけなのも殺風景なのでURLも画像の形でレスポンスしてあげます。（リプライでなくプッシュメッセージ）

# さいごに

またしてもくだらないアプリをこの世に生み出してしまいましたが、今回も楽しかったです。
構成を考えていたときは、「スマートスピーカーにも転用できる構成」とか考えてましたが結局、画像を返したりCardを使ったり、すっかりLINE依存のコンテンツになってしまいました。
Botは、アプリに血が通ってる感じがするし、血を通わせるための作り込みを考える必要があって、開発体験として新鮮ですね。
皆さんもBotアプリ開発、楽しみながら界隈を盛り上げていきましょう。
![IMG_5417D5323201-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259832/f481d7f6-92ae-a373-23bc-6ee019335ef1.jpeg)