LoginSignup
14
14

More than 5 years have passed since last update.

LINE Messaging APIで飲み会提案botを作った

Last updated at Posted at 2018-09-30

(2018/10/23追記)LINE developers communityのBot一覧に掲載されました https://www.line-community.me/bots

作ったもの

グループチャットに追加された状態で、「(地区名)へ飲みに行くぞ!」と誰かが発言すると、その地区に存在する居酒屋のうち1軒を、ぐるなびの紹介ページのURLとともに提案してくれるbotをハッカソンで作りました。
Screenshot_20180930-122815_LINE.jpg
以下のQRコードから登録できます。
スクリーンショット 2018-09-29 17.58.03.png
ただし2018/9/29現在で、対応している地区名は"四条"、"河原町"、"京都駅"のみとなっています。
(2018/10/5追記)コードを見直し、日本全国の小地区名に対応しました!

実装

環境

  • macOS High Sierra 10.13.6
  • Python 3.6.5 (built in Anaconda 3-5.2.0)
  • Heroku 7.16.0

使ったもの一覧

  • LINE Messaging API
    • botへの指示
  • line-bot-sdk-python
    • サンプルコードを利用
  • Python
  • Flask
    • サーバーサイドで動くプログラムの記述
  • Heroku
    • サーバーサイドのプラットフォーム
  • ぐるなびAPI
    • 飲み屋情報の取得

チャネルを作成

Messaging APIのページでbotのアカウント(「チャネル」という名前で、見た目はLINE@)を作ったり、基本設定ができたりします。

サーバーサイドでbotを動かす

とりあえずオウム返しbotを実装してサーバーサイドで動かすには、こちらの記事が参考になります。
ポイントは次の点です。

  • main.pyif __name__ == "__main__":部分を書き換える(Herokuで動かすための措置)
  • Herokuの環境変数設定にChannel Secretとともに必要なアクセストークンはチャネル基本設定上で発行
  • Webhook送信のURLはhttps://(アプリ名).herokuapp.com/callbackとして登録 これをデプロイするととりあえずbotとしては動作するようになりますが、グループチャットで適切に応答してもらうために、
  • 「Botのグループトーク参加」を「利用する」にする
  • 「自動応答メッセージ」を「利用しない」にする

などの変更もチャネル基本設定上でしておきます。

メッセージ送信部分の書き換え

元のコードを眺めていると、次の箇所がbotにメッセージを送信させている記述だとわかる。

main.py
@handler.add(MessageEvent, message=TextMessage)
def message_text(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text)
    )

グループチャット内における誰かの発言はeventという変数に格納され、そこからevent.message.textで発言内容を得ることができる。
つまり、event.message.text"へ飲みに行くぞ!"という文字が含まれる場合のみ、その直前にあるはずの地区名を取り出してAPIに投げ、得られた情報をTextSendMessage(text=の先に指定すればよい。
そのために、

  • if条件文でevent.message.text"へ飲みに行くぞ"が含まれていなければreturn None(早期return)
  • event.message.text.split("へ")でメッセージを分割、text_splitに格納
  • その前側をtext_split[0]で得、placeに格納 という処理を行うよう、次のように書き換えました。
main.py
def message_text(event):
    if not 'へ飲みに行くぞ' in event.message.text:
        return None
    text_split = event.message.text.split("へ")
    place = text_split[0]
    line_get_data(place)
    nomiyas = line_answer()
    nomiya = random.choice(nomiyas)
    TEXT="{}へ飲みに行くぞ! {}".format(nomiya[0], nomiya[1])
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=TEXT) #event.message.text がメッセージの本文
    )

APIによる飲み屋情報の取得

ここからは僕ではなくハッカソンでの共同開発者が書いているのですが、APIを叩いて居酒屋のデータをcsv形式にダンプする処理をline_get_data(place)で、そのcsv形式のリストからデータを読み込む処理をline_answerで実現し、import行の下にそれらの関数を定義しているようです。
APIにはぐるなびのレストラン検索APIを用いており、無料でアカウントを発行して利用することができます。で、共同開発者が「地区はエリアコードでないと指定できない」と言っていて、そのため取り急ぎ3地区のみ一致条件で拾うという形になってしまったのですが、エリアSマスタ取得APIを併用することでこれは解決できそうです。ただし、ぐるなびの地区分類は最小単位のエリアSでも結構広域なので、実際に一致させるにはもう少し工夫が必要かもしれません。

main.py
def line_get_data(place):
    data={'京都市':3404,'四条':3414,'河原町':3402}
    apikey='(APIキー)'
    place=data[place]
    url='http://api.gnavi.co.jp/RestSearchAPI/20150630/?keyid={key}&format=json&category_s=RSFST09004&areacode_s=AREAS{place}'.format(key=API_KEY,place=place)

    html=requests.get(url)

    data=json.loads(html.text)

    with open('a.csv','w',newline='',encoding='utf-8') as w:
        writer=csv.writer(w)
        for k in data['rest']:
            writer.writerow([k['name'],k['url']])

def line_answer():
    data=[]
    csvfile = 'a.csv'
    f = open(csvfile, "r",encoding="utf-8")
    reader = csv.reader(f)
    for x in reader:
        data.append(x)
    f.close()
    return data

こうしてline_answerの返り値として得られた飲み屋のリストをnomiyasに格納し、そこから1件のデータの店名とURLを得て送信する、というわけです。

課題

当座しのぎで実装した、地区名に一致するエリアSのコードをAPIに投げるという処理を、上記のように別のAPIを挟む形で解決できたら、それなりに使い物になるbotになると思います。
その際の地区名との一致について、今回はClovaを使った実装にはしなかったのですが、こちらであればコンソール上で言葉の定義の幅を指定することができ、より柔軟に実際の用例に対応できると思います。

ソースコード

GitHubに公開してあります。
https://github.com/silloi/nomikai-suggest-bot

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14