Help us understand the problem. What is going on with this article?

【Hackathonやってみた】飲食店検索Slack Chatbotを作ったよ

[前置き]
閲覧ありがとうございます!エンジニア歴10ヶ月のひよっこwebでべろぱーです。
本投稿はエンジニア歴3年未満程度の初学者向け投稿になります。
個人で何か作りたいけど、丁度いい規模感のアイデアが思い付かない...
そんなあなたに!お手軽なChatbotの制作をオススメします!
というわけで作ってみましたー!↓↓

作ったもの -What I made-

🎉🎉地域の飲食店検索Slackチャットボット「GourmetNav」 🎉🎉

Slack上で動作するチャットボット。
「駅名」+ 「空白」 + 「店名に関わるキーワード」を入力すると、その地域の飲食店名とお店のURLを飛ばしてくれる(σ・ω・)σ
gourmetnav.gif

おもしろいところ

  • 地図を見ずに、駅名なんとなくの店名だけで検索できる。Slackで!!
  • チェーン店も、もちろん対象。目指せ、地域のスタバマスター!٩(。˃ ᵕ ˂ )وイェーィ♪

なにができるの

  • 「GourmetNav」の検索結果から、ワンクリックで各飲食店のサイトに飛べる。
  • わざわざブラウザで色んなページを見に行ったりしなくていい。
  • 検索結果にたまーに混じっている別の地域のお店、とかがない(←ここ重要!)

技術的な話

TL;DR (大まかなデータの流れ)

Slack × GAS × 駅情報取得API × ぐるなびAPI を使用しています。

  1. Slackのチャンネル「GourmetNav」から、「駅名」+ 「半角(または全角)空白」 + 「店名に関わるキーワード」を入力、送信。
  2. Slackから受け取った入力情報をGAS上で参照。
  3. 駅情報取得APIを用いて、入力情報内の「駅名」から緯度・経度を取得。
  4. ぐるなびAPIを用いて、上記の緯度・経度からその地域の飲食店を検索、一覧にしてGoogle Spreadsheetに出力(2度目以降はシートを初期化して更新するのでデータは保持しない)
  5. 生成されたSpreadsheet内の飲食店一覧から、「店名に関わるキーワード」と部分一致する「飲食店名」とその「サイトURL」を取得。
  6. 取得した「飲食店名」とその「サイトURL」をSlack側に出力。
  7. Slackのデータ容量圧迫しないように投稿を毎日自動削除するようにトリガーを設定(任意)

具体的な面倒くさいところ

1. まず、ローカルでの開発環境構築(任意)

ある程度のコード量/ロジックを書くならば、GASをブラウザ上のスクリプトエディタでベタ書きするのは、間違いなくNonsenseなんじゃないかと思います。(知らんけど)
(参考): Google Apps Script をローカル環境で快適に開発するためのテンプレートを作りました
(著者): @howdy39

※型定義ないとデバックしづらいのでTypeScriptも入れました(任意)

今回デバッグしていて初めて気付いたんですけど、Javascriptって配列にtypeofかけても「object」って返されるんですね。なんて暗黒言語!!
競技プログラミング(Atcoder)でC#愛好家の私には拒絶反応が出たので、typescript導入しました。
(参考): clasp + TypeScriptで課題改善botを作った
(著者): @mochisuna
(参考): JavaScriptの型などの判定いろいろ
(著者): @amamamaou

2. GASでSlackからの入力情報を受け取り、参照し、出力する(必須)

開発環境を整備したら、まずはSlackとBotによる簡単な入出力を実装する。
下記の記事を参考にすると、以下のようなことができる。
✔️GASでPOSTリクエストを受け取る
✔️SlackでOutgoing WebHookの設定を行う
✔️GASでSlackから渡された値を参照する
(参考): Slack上のメッセージをGoogleAppsScriptで受け取ってよしなに使う
(著者): @kyo_nanba

※このとき、SlackAppというライブラリを使用することで設定が少し楽になる

世の中のSlack愛好家の皆さんに圧倒的感謝!
SlackApp作成者@soundTricker さんに三跪九叩頭しましょう。
(参考): Slack BotをGASでいい感じで書くためのライブラリを作った

3. 駅情報取得API, ぐるなびAPIを上記の中に組み込んで出力内容を工夫する

この部分に関しては、記事読んで実践するだけですんなり実装できました。
(参考): GoogleAppsScriptでぐるなびAPIから取得した駅周辺のお店をスプレッドシートに書き出す
(著者): @kouheidev

4. 上記参考記事を悪魔合体させながら論理構造を調整

今回は社内Slack上で作成したこともあり、一旦ソースコードは開示しません。
(まだまだ生後10ヶ月のエンジニア、トークンの扱いとかGASの仕様とか、セキュリティ面に関しては完璧に理解してるわけじゃないので!)
ただまあ、ベテランの皆さんなら多分苦もなく実装できると思います。(・ω・。)


苦労したところ

無限ループ🌀🌀

GAS上でのテストでは問題ないのに、
Slackで実際に入出力をテストすると無限ループが頻繁に発生しました。(恐ろしい...)
暫くして気付いたのですが、下記のロジックによるものでした。
ユーザの「A」という検索ワードに対して、「GourmetNav」は該当する検索結果を見つけてきます。
そして、「Aが見つかりました!」とSlackに出力してくれるわけです。
この出力を、GAS側は「ユーザによる新しい入力」として検知し、再び検索/出力処理を繰り返すわけです。
なるほど〜〜それはそうだわ! ということで、
doPost内の記述に下記を加えることで無限ループは解消します!

  if (e.parameter.user_name == "slackbot"){
    throw new Error("this is bot."); //入力者がbotだった場合、エラーを返します
  }

まとめ

Slackからのデータ入力をSpreadsheetに出力だとか、
Spreadsheet側の入力をSlackに出力するだとか、
こうした一方通行なBotならQiita上にも数多くあります

ただ、今回作成したのはInteractiveなChatBot。
ユーザ入力に対して、GAS側で入力を検知、
各API内を検索、Spleadsheetに検索結果を出力、
そして、ユーザの求めている情報にマッチする情報のみをユーザに提供する。

こうしたInteractiveなSlackチャットボット制作記事は、決して多くはないかと思います。
GASでSlack向けに開発している方にとって、何かの一助となれば幸いです。

ついったフォローしてね。(・ω・。)
@NadjaHarold

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした