(2018/10/23追記)LINE developers communityのBot一覧に掲載されました https://www.line-community.me/bots
作ったもの
グループチャットに追加された状態で、「(地区名)へ飲みに行くぞ!」と誰かが発言すると、その地区に存在する居酒屋のうち1軒を、ぐるなびの紹介ページのURLとともに提案してくれるbotをハッカソンで作りました。
以下のQRコードから登録できます。
ただし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.py
のif __name__ == "__main__":
部分を書き換える(Herokuで動かすための措置) - Herokuの環境変数設定にChannel Secretとともに必要なアクセストークンはチャネル基本設定上で発行
- Webhook送信のURLは
https://(アプリ名).herokuapp.com/callback
として登録 これをデプロイするととりあえずbotとしては動作するようになりますが、グループチャットで適切に応答してもらうために、 - 「Botのグループトーク参加」を「利用する」にする
- 「自動応答メッセージ」を「利用しない」にする
などの変更もチャネル基本設定上でしておきます。
メッセージ送信部分の書き換え
元のコードを眺めていると、次の箇所がbotにメッセージを送信させている記述だとわかる。
@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
に格納 という処理を行うよう、次のように書き換えました。
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でも結構広域なので、実際に一致させるにはもう少し工夫が必要かもしれません。
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