こんにちは。初めてのQiita投稿です。
筆者は新卒から17年ほどWeb系のエンジニアをやっていましたが今は不登校の子どもたちをサポートするフリースクールを運営しています。
さて、新型コロナウイルス(COVID-19)の影響で全国の学校で休校になり、外出の自粛で家にこもりきりになってしまう子どもたちに少しでも不安やストレスを和らげることができないかなと考えて思いついたのが、LINEでbotが話し相手になりつつ、悩み事や聞いてほしいことがあるなど、いざという時は人が相談に乗るという仕組みを作ることでした。
おまけでLINE Beaconを使って、子どもが教室に入ってきたことをSlackに連携する仕組みも作りました。
ちょっと特殊な用途ですが同じような仕組みを取り入れたいというスクールが他にあった場合に役に立てるのではないかと思い、記事にまとめることにしました。
何をつくるのか
この記事では以下についてまとめまたいと思います。
- 話しかけると適当に返事をするLINE botを作る
- 会話の内容をSlackに連携する
- 会話に特定のキーワードが含まれているとSlackでダイレクトメッセージを送る
- LINE botを友達登録した子どもが教室に入ってきたらSlackに通知する(おまけ)
話しかけると適当に返事をするLINE botを作る
まずはLINEのbotを作ります。大まかな流れとしては、以下のようになります。
- LINEのBotアカウントを取得する
- サーバー(Heroku)のセットアップ
- プログラムを書く
- サーバー(Heroku)にデプロイする
LINEのBotアカウントを取得する
話し相手になるLINEのBotのアカウントを取得します。
なお、すでに運用しているLINE Official AccountをBotにしたい場合もあると思います。(営業時間外はBotが話し相手になるなど)その場合は別のやり方があるので後ほど解説します。
LINE Developers からアカウントを作成します。
LINEアカウントでログインしたら、まずプロバイダを作成します。
プロバイダー名は任意です。
チャンネルの種類でMessaging APIを選択し、他の必須項目を入力して作成します。
チャンネルを作成したら、
- 「チャンネル基本設定」タブの「チャンネルシークレット」
- 「Messaging API設定」タブの「チャネルアクセストークン(ロングターム)」
をメモします。設定は一旦これで終了ですが、後ほどWebhook URLの設定を行うためこの画面に戻ってきます。
すでに運用しているLINE Official AccountをBotにしたい場合
すでに運用しているLINE Official AccountでBotを作ることもできます。
今までチャットモードでのみ運用していたアカウントにBotを組み込みたい場合などはこの方法になります。
まず、LINE Official Account Managerのアカウントのホーム画面から「応答モード」をクリックします。
次に左のメニューからMessaging APIを選択し、「Messaging APIを利用する」をクリックします。
既存のプロバイダーを選択するか新規作成して、規約を読み、「同意する」をクリックします。
そのあとの流れは新規にチャンネルを作成するのと同じです。
すでに運用しているアカウントにbotを導入するときの注意点として、botとチャットは同時に使えない(Webhookはbotモードでしか使えない)という点です。
私も当初チャットモードで人間が対応しつつ、そのトークの内容をSlackに連携しようと考えていたのですがそれができずハマりました。結局チャットモードでのトークの内容はチャットの画面に残るからということで諦めました。
サーバー(Heroku)のセットアップ
botへのリクエストを処理するサーバとしてHerokuを使用します。
作業内容としては、Herokuのアカウント作成とHeroku CLIの導入です。
Herokuアカウントの作成
https://signup.heroku.com/ で必要事項を入力してアカウントを新規作成します。
登録したメールアドレスにアドレス確認のためのメールが届くのでメールを開いてURLをクリックし、パスワード設定の画面でパスワードを設定したらアカウント登録は完了です。
Heroku CLIの導入
Herokuを使うにはHeroku CLIとgitを導入する必要があります。
Heroku CLIは https://devcenter.heroku.com/articles/getting-started-with-python#set-up からインストーラをダウンロードしてインストールします。
gitの導入
Macの場合は最初からgitがインストールされています。
$ git --version
でインストールされているgitのバージョンが確認できます。
Windowsの場合は https://git-scm.com/download/win からインストーラをダウンロードしてインストールします。
Herokuにログインする
ターミナルから以下のコマンドを入力すると、キー入力を求められます。
$ heroku login
q以外のキーを入力するとブラウザが起動し、Herokuのログインページが表示されるので、「Log In」ボタンをクリックするとログインできます。
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/xxxxxx-xxx-xxx
Logging in... done
Logged in as xxxxx@xxx.org
これで初期設定は完了です。
プログラムを書く
いよいよアプリケーションを作っていきます。プログラムを書いて、gitリポジトリを作成して、Herokuへデプロイします。
参考ソースコード
今から説明するソースコードはGithubで公開しています。実際に運用しながら修正を加えて行っていますので汎用的ではないコードも入っていますのでご参考程度に。
あとコミット履歴に「typoを修正」とかあって恥ずかしいです。^^;
リポジトリ
実は作りかけてたLINE Beaconのサンプルアプリを改造して今回のアプリを作ったのでリポジトリ名にline-beaconが入っています。
ディレクトリ構成
ディレクトリ構成は以下のようになっています。後ほど説明するHerokuに一からアプリケーションを作成する場合も同様になります。
lacina-line-beacon
├── Procfile
├── main.py
├── requirements.txt
└── runtime.txt
話し相手になるLINE Botのプログラムを書く
話しかけると適当に返事をするBotを作ります。手順的にはLINEのbotに話しかけられたらメッセージの内容を取得して解析し、返答内容を作って話しかけてきたユーザーにLINEで返信します。会話するAIを自分で作るのは大変なので、今回はA3RTのTalk APIを利用させていただきました。
A3RT Talk APIキーを取得する
Talk APIを利用するには、まず https://a3rt.recruit.co.jp/product/talkAPI/ のサイトで、API KEYを発行します。
利用規約、プライバシーポリシーを読んで同意したらチェックボックスにチェックを入れ、メールアドレスを入力して送信します。
確認のメールが届くのでメールを開き、URLをクリックすると、APIキーが書かれたメールが再度送られてきます。このAPIキーをメモしておきます。
PythonでTalk APIを利用する
LINE botがメッセージを受け取ったらTalk APIにメッセージ内容を受け渡して、返却された回答をLINEで返信するプログラムをPythonで書いていきます。
from flask import Flask, request, abort, send_file
import os
import requests
import json
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError, LineBotApiError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage, BeaconEvent,
)
app = Flask(__name__)
# 環境変数取得
CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
TALK_API_KEY = os.environ["A3RT_API_KEY"]
TALK_API_URL = 'https://api.a3rt.recruit.co.jp/talk/v1/smalltalk'
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
@app.route("/")
def hello_world():
return "hello world!"
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
# LINEユーザー名の取得
user_id = event.source.user_id
try:
user_name = line_bot_api.get_profile(user_id).display_name
except LineBotApiError as e:
user_name = "Unknown"
# Talk APIを使って会話する
r = requests.post(TALK_API_URL,{'apikey':TALK_API_KEY,'query':event.message.text})
data = json.loads(r.text)
if data['status'] == 0:
t = data['results']
ret = t[0]['reply']
else:
ret = '・・・・・・・・・'
line_bot_api.reply_message(
event.reply_token,[
TextSendMessage(text=ret),
])
if __name__ == "__main__":
port = int(os.getenv("PORT"))
app.run(host="0.0.0.0", port=port)
LINE botのチャンネルアクセストークン、チャンネルシークレット、Talk APIのAPI KEYは環境変数から取得しています。
さらにHerokuで動作させるためのコードを追加します。
web: python main.py
Flask
line-bot-sdk
freeze
slackweb
python-3.6.10
Gitリポジトリの作成
HerokuにアプリケーションをデプロイするためにGitリポジトリを作成します。
$ cd (プログラムを格納しているディレクトリ)
$ git init
$ git add .
$ git commit -m "first commit"
サーバー(Heroku)にデプロイする
Herokuにアプリケーションを作成してデプロイします。
以下の例でアプリ名はlacina-line-beaconとしていますが、作成するアプリに合わせて適宜変更してください。
$ heroku create lacina-line-beacon
Creating ⬢ lacina-line-beacon... done
https://lacina-line-beacon.herokuapp.com/ | https://git.heroku.com/lacina-line-beacon.git
環境変数の設定
LINEのチャンネルアクセストークン、LINEのシークレットチャンネル、Talk API KEYは環境変数から取得するようにプログラムしてあるため、それぞれの値をHerokuの環境変数として設定します。
$ heroku config:set YOUR_CHANNEL_ACCESS_TOKEN=[LINEのチャンネルアクセストークン] --app=lacina-line-beacon
$ heroku config:set YOUR_CHANNEL_SECRET=[LINEのチャンネルシークレット] --app=lacina-line-beacon
$ heroku config:set A3RT_API_KEY=[A3RTのTalk API KEY] --app=lacina-line-beacon
デプロイ
gitリポジトリにコミットしたソースコードをherokuにプッシュすることでデプロイします。
$ git push heroku master
LINE に heroku のデプロイ先を登録する
herokuにデプロイしたときに作成されたアプリのURLをLINE botのWebhook URLとして登録します。
上記の例で作成されたURLはhttps://lacina-line-beacon.herokuapp.com なので、Webhook URLは https://lacina-line-beacon.herokuapp.com/callback となります。
ここまでで、話しかけると返事してくれるLINE botの出来上がりです。
LINE botを友達登録して話しかけてみてください。Talk APIで返事が返ってくるはずです。
年齢は秘密みたいです。
うまく動かない場合
なにかエラーが出ているかもしれません。Herokuのログを見て解決の糸口を探しましょう。
$ heroku logs --tail --app lacina-line-beacon
会話の内容をSlackに連携する
会話の内容を人力でモニタリングして、相談がありそうとか悩んでそうとか気になる内容があればチャットモード(手動の会話モード)に切り替えて対応できるようにユーザーとLINE botが会話した内容をSlackに連携します。
プログラムの修正
先ほど作成したLINE bot用のプログラムにSlackに連携するためのコードを追加していきます。
import slackweb
...
# 環境変数取得
WEB_HOOK_LINKS = os.environ["SLACK_WEB_HOOKS_URL"]
TALK_PUSH_FLAG = os.environ["LINE_TO_SLACK"]
...
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
...
slack_info = slackweb.Slack(url=WEB_HOOK_LINKS)
# botとの会話内容をSlackに連携
if TALK_PUSH_FLAG == "true":
send_msg = "[{user_name}] {message}\n".format(user_name=user_name, message=event.message.text) \
+ "[みまもりラシーナ] {ret}\n".format(ret=ret)
# メッセージの送信
slack_info.notify(text=send_msg)
Slackに連携するためslackwebのライブラリを新たにimportして利用しています。
TALK_PUSH_FLAGは、たくさん使われ出して通知が多くなりすぎるようだと逆にモニタリングしにくくなるので会話に特定のキーワードが含まれていた場合のみSlackに連携するなど、のちの改造のために環境変数による設定でSlackに連携するかしないかを切り替えられるようにするためのフラグです。
Incomming Webhookの設定
Slackに連携する際に利用するIncomming Webhookを設定します。
Slackにサインインした状態で、Incomming Webhookの設定ページにアクセスします。
投稿先のチャンネルを選択し、Incomming Webhookインテグレーションの追加ボタンを押下します。
Incomming Webhookインテグレーションが追加できたら設定画面からWebhook URLをメモしておきます。
環境変数の設定
追加したコードで使用しているWebhook URLとSlackにトーク内容を連携するかどうかのフラグを環境変数に設定します。
$ heroku config:set SLACK_WEB_HOOKS_URL=[Incoming WebhookのURL] --app=lacina-line-beacon
$ heroku config:set LINE_TO_SLACK=true --app=lacina-line-beacon
デプロイ
修正したプログラムをgitリポジトリにコミットし、herokuへプッシュします。
$ git add main.py
$ git commit -m "トークの内容をSlackに連携する"
$ git push heroku master
これでトークの内容がSlackに連携されるはずです。
#会話に特定のキーワードが含まれているとSlackでダイレクトメッセージを送る
botとの会話の中に、気になるキーワードが入っていた場合に、LINEの応答モードをbotからチャットに変更して人が対応できるように、キーワードを検知したらSlackでチャンネル全体にメンションするのと同時に個人当てにダイレクトメッセージを送ります。
プログラムの修正
LINEメッセージの受信イベントの中にコードを追加していきます。
...
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
...
# 直接対応するためのキーワードを検知
if "先生" in event.message.text or "スタッフ" in event.message.text or "話" in event.message.text or "呼" in event.message.text or "召喚" in event.message.text or "相談" in event.message.text:
mention = "!channel"
send_msg = "[{user_name}] {message}\n".format(user_name=user_name, message=event.message.text) \
+ "<{mention}> {user_name}さんが直接話したがっています。\n".format(mention=mention, user_name=user_name) \
+ "LINE Official Accountの設定をチャットモードに切り替えて対応してください。\n"
+ "`※対応が終わったらbotモードに切り替えて、Webhookの設定を必ずオンにしてください。`"
# Slackにメッセージを送信
slack_info.notify(text=send_msg)
# ダイレクトメッセージも送る
slack_info.notify(text=send_msg, channel="@tajuta")
特定のキーワードが含まれているかを判定するコードは単純にorで列挙していますがもっと良いやり方がある気がします。
Slackのダイレクトメッセージを送るには、slack_info.notify()のchannelパラメータにSlackのユーザー名を指定します。channelを指定しなかった場合はIncomming Webhooksで設定したチャンネルに投稿されます。
コードを修正したらgitリポジトリにコミットしてデプロイする流れは先ほどと同じです。
(おまけ)LINE botを友達登録した子どもが教室に入ってきたらSlackに通知する
LINE beaconは、その名のとおり、LINEと連携が可能なビーコンで、ビーコンから発する電波をLINEアプリで検知してイベント処理をするという仕組みです。お店に入ってきたらLINEでクーポンを配布する、といったような使い方ができます。
もとはと言えば、買うだけ買って3年くらい放置していたLINE beaconを子どもの入退室記録に活用できないかと思ってサンプルプログラムを書いていたところから今回の仕組みを作ることを思いつきました。なのでチャンネル名やコードの中にその名残がいろいろ残っています。
3年前くらいに入手したLINE Beacon。どこのネットショップで入手したか忘れてしまいました。
基盤がむき出しで、ON/OFFスイッチが付いてます。
省電力なのでスイッチONのままでも3年くらいは電池が持つはずです。
LINE beaconを登録する
まずはビーコンとbotアカウントを連携させます。
Line official Acoount Managerにログインし、
https://manager.line.biz/beacon/register
にアクセスします。隠し機能になっているのか、管理画面にこのページに行くためのボタンやリンクは見当たりません。直接URLを叩いてアクセスするしかないようです。
ビーコンとBotアカウントを連携のボタンをクリックします。
LINEビーコンと連携させるbotアカウントを選択するとハードウェアIDとパスコードを入力する画面が表示されます。
ビーコン端末に記載されているハードウェアIDとパスコードを入力して連携ボタンをクリックします。
連携が完了すると、メニューにLINE Beaconが追加され、連携済みのビーコンを確認したり、連携を解除したりすることができます。
また、この画面にはユーザーがLINE BeaconのWebhookイベントを受け取る方法(アプリ側の設定方法)が記載されています。
LINE BeaconのWebhookイベントを受け取る方法
- LINEアプリを端末にインストールしてBluetoothをオンにします。
- LINEアプリの[設定]>[プライバシー管理]>[情報の提供]で[LINE Beacon]をオンにします。
- Botアカウントを友だち追加します。
- ビーコンの電源が入っていることを確認して、端末をビーコンに近づけます。
- LINEアプリがビーコンを検知して、BotアカウントがWebhookイベントを受け取ることを確認します。
プログラムの修正
LINE beaconのイベントをフックするハンドラーを追加していきます。
@handler.add(BeaconEvent)
def handle_beacon(event):
print(event)
# LINEユーザー名の取得
user_id = event.source.user_id
try:
user_name = line_bot_api.get_profile(user_id).display_name
except LineBotApiError as e:
user_name = "Unknown"
slack_info = slackweb.Slack(url=WEB_HOOK_LINKS)
# slack側に投稿するメッセージの加工
if event.beacon.type == "enter":
send_msg = "{user_name}さんが入室しました。({user_id})\n".format(user_name=user_name,user_id=user_id)
elif event.beacon.type == "leave":
send_msg = "{user_name}さんが退室しました。({user_id})\n".format(user_name=user_name,user_id=user_id)
# メッセージの送信
slack_info.notify(text=send_msg)
先ほどと同じく、プログラムを修正したらgitリポジトリにコミットし、herokuにpushしてデプロイして完成です。
LINEを起動して、ビーコンに近づくと、Slackに入室したことを通知します。
注意点として、LINEの設定でビーコンの利用を許可していないといけないのと、かなりの確率でLINEがフォアグラウンドでないと検知しないことです。iOSでもAndroidでも多分同じです(もしかしたらビーコン端末のハードウェア的な問題かもしれないですが)。
あと、leaveイベントは廃止予定になっていて、使わない方が無難です。
いずれにしてもLINEアプリを開いていないとビーコンを検知しないため、ICカードによる入退室管理の代わりとして使うのはちょっと厳しそうです。
おわりに
実はPythonは始めてで、Herokuも使ったことがなく、いろいろなサイトの記事を参考になんとか作りましたが、大変勉強になりました。日曜大工的に作ったものなので不備な点が色々あるかもしれませんが、見つけたらコメントでご指摘いただけると助かります。
普段みなさんが書かれたQiitaの記事には大変お世話になっているのに、自分で書くのは初めてで、ありがたみが身にしみました。正直プログラム作るよりこの記事書くほうが時間かかりました(笑)
何かのお役に立てれば幸いです。
参考サイト
主に以下のサイトを参考にさせていただきました。