Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

LINE Beaconと LINE Official Account と Slackを連携して子どもを見守る仕組みを作ってみた

こんにちは。初めてのQiita投稿です。
筆者は新卒から17年ほどWeb系のエンジニアをやっていましたが今は不登校の子どもたちをサポートするフリースクールを運営しています。

さて、新型コロナウイルス(COVID-19)の影響で全国の学校で休校になり、外出の自粛で家にこもりきりになってしまう子どもたちに少しでも不安やストレスを和らげることができないかなと考えて思いついたのが、LINEでbotが話し相手になりつつ、悩み事や聞いてほしいことがあるなど、いざという時は人が相談に乗るという仕組みを作ることでした。
おまけでLINE Beaconを使って、子どもが教室に入ってきたことをSlackに連携する仕組みも作りました。
ちょっと特殊な用途ですが同じような仕組みを取り入れたいというスクールが他にあった場合に役に立てるのではないかと思い、記事にまとめることにしました。

何をつくるのか

この記事では以下についてまとめまたいと思います。

  • 話しかけると適当に返事をするLINE botを作る
  • 会話の内容をSlackに連携する
  • 会話に特定のキーワードが含まれているとSlackでダイレクトメッセージを送る
  • LINE botを友達登録した子どもが教室に入ってきたらSlackに通知する(おまけ)

話しかけると適当に返事をするLINE botを作る

まずはLINEのbotを作ります。大まかな流れとしては、以下のようになります。

  1. LINEのBotアカウントを取得する
  2. サーバー(Heroku)のセットアップ
  3. プログラムを書く
  4. サーバー(Heroku)にデプロイする

LINEのBotアカウントを取得する

話し相手になるLINEのBotのアカウントを取得します。
なお、すでに運用しているLINE Official AccountをBotにしたい場合もあると思います。(営業時間外はBotが話し相手になるなど)その場合は別のやり方があるので後ほど解説します。

LINE Developers からアカウントを作成します。
スクリーンショット 2020-04-19 21.40.02.png

LINEアカウントでログインしたら、まずプロバイダを作成します。
プロバイダー名は任意です。

LINE_Developers.png

次にチャンネルを新規作成します。
LINE_Developers_と_Slack___mimamori-lacina___SHIJUKU_FREESCHOOL_LACINA__N_P_O_と_main_py_—___workspace_lacina-line-beacon.png

チャンネルの種類でMessaging APIを選択し、他の必須項目を入力して作成します。

チャンネルを作成したら、

  • 「チャンネル基本設定」タブの「チャンネルシークレット」
  • 「Messaging API設定」タブの「チャネルアクセストークン(ロングターム)」

をメモします。設定は一旦これで終了ですが、後ほどWebhook URLの設定を行うためこの画面に戻ってきます。

すでに運用しているLINE Official AccountをBotにしたい場合

すでに運用しているLINE Official AccountでBotを作ることもできます。
今までチャットモードでのみ運用していたアカウントにBotを組み込みたい場合などはこの方法になります。

まず、LINE Official Account Managerのアカウントのホーム画面から「応答モード」をクリックします。
LINE_Official_Account_Manager.png

次に左のメニューからMessaging APIを選択し、「Messaging APIを利用する」をクリックします。
LINE_Official_Account_Manager.png

既存のプロバイダーを選択するか新規作成して、規約を読み、「同意する」をクリックします。
そのあとの流れは新規にチャンネルを作成するのと同じです。
LINE_Official_Account_Manager.png

すでに運用しているアカウントに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」ボタンをクリックするとログインできます。

スクリーンショット 2020-04-19 23.18.06.png

$ 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-tech.co.jp/product/talkAPI/ のサイトで、API KEYを発行します。

TalkAPI___PRODUCT___A3RT.png

利用規約、プライバシーポリシーを読んで同意したらチェックボックスにチェックを入れ、メールアドレスを入力して送信します。

API発行___Talk_API___PRODUCT___A3RT.png

確認のメールが届くのでメールを開き、URLをクリックすると、APIキーが書かれたメールが再度送られてきます。このAPIキーをメモしておきます。

PythonでTalk APIを利用する

LINE botがメッセージを受け取ったらTalk APIにメッセージ内容を受け渡して、返却された回答をLINEで返信するプログラムをPythonで書いていきます。

main.py
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-tech.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で動作させるためのコードを追加します。

Procfile
web: python main.py
requirements.txt
Flask
line-bot-sdk
freeze
slackweb
runtime.txt
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_Official_Account_Manager.png

ここまでで、話しかけると返事してくれるLINE botの出来上がりです。
LINE botを友達登録して話しかけてみてください。Talk APIで返事が返ってくるはずです。

IMG_0864.PNG

年齢は秘密みたいです。

うまく動かない場合

なにかエラーが出ているかもしれません。Herokuのログを見て解決の糸口を探しましょう。

$ heroku logs --tail --app lacina-line-beacon

会話の内容をSlackに連携する

会話の内容を人力でモニタリングして、相談がありそうとか悩んでそうとか気になる内容があればチャットモード(手動の会話モード)に切り替えて対応できるようにユーザーとLINE botが会話した内容をSlackに連携します。

プログラムの修正

先ほど作成したLINE bot用のプログラムにSlackに連携するためのコードを追加していきます。

main.py(追加コード)

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の設定ページにアクセスします。

Incoming_Webhook___SHIJUKU_FREESCHOOL_LACINA__N_P_O_Slack.png

投稿先のチャンネルを選択し、Incomming Webhookインテグレーションの追加ボタンを押下します。

Incoming_Webhook___Slack_App_ディレクトリ.png

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___mimamori-lacina___SHIJUKU_FREESCHOOL_LACINA__N_P_O_と_「_コピー_LINE_Beaconと_LINE_Official_Account_と_Slackを連携して子どもを見守る仕組みを作ってみた」を編集_-_Qiita.png

会話に特定のキーワードが含まれているとSlackでダイレクトメッセージを送る

botとの会話の中に、気になるキーワードが入っていた場合に、LINEの応答モードをbotからチャットに変更して人が対応できるように、キーワードを検知したらSlackでチャンネル全体にメンションするのと同時に個人当てにダイレクトメッセージを送ります。

プログラムの修正

LINEメッセージの受信イベントの中にコードを追加していきます。

main.py(追加コード)

...

@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を子どもの入退室記録に活用できないかと思ってサンプルプログラムを書いていたところから今回の仕組みを作ることを思いつきました。なのでチャンネル名やコードの中にその名残がいろいろ残っています。

IMG_0865.jpg

3年前くらいに入手したLINE Beacon。どこのネットショップで入手したか忘れてしまいました。
基盤がむき出しで、ON/OFFスイッチが付いてます。
省電力なのでスイッチONのままでも3年くらいは電池が持つはずです。

LINE beaconを登録する

まずはビーコンとbotアカウントを連携させます。
Line official Acoount Managerにログインし、
https://manager.line.biz/beacon/register
にアクセスします。隠し機能になっているのか、管理画面にこのページに行くためのボタンやリンクは見当たりません。直接URLを叩いてアクセスするしかないようです。

ビーコンとBotアカウントを連携のボタンをクリックします。

LINE_Official_Account_Manager.png

LINEビーコンと連携させるbotアカウントを選択するとハードウェアIDとパスコードを入力する画面が表示されます。

LINE_Official_Account_Manager.png

ビーコン端末に記載されているハードウェアIDとパスコードを入力して連携ボタンをクリックします。

LINE_Official_Account_Manager.png

連携が完了すると、メニューにLINE Beaconが追加され、連携済みのビーコンを確認したり、連携を解除したりすることができます。
また、この画面にはユーザーがLINE BeaconのWebhookイベントを受け取る方法(アプリ側の設定方法)が記載されています。

LINE BeaconのWebhookイベントを受け取る方法

  1. LINEアプリを端末にインストールしてBluetoothをオンにします。
  2. LINEアプリの[設定]>[プライバシー管理]>[情報の提供]で[LINE Beacon]をオンにします。
  3. Botアカウントを友だち追加します。
  4. ビーコンの電源が入っていることを確認して、端末をビーコンに近づけます。
  5. LINEアプリがビーコンを検知して、BotアカウントがWebhookイベントを受け取ることを確認します。

プログラムの修正

LINE beaconのイベントをフックするハンドラーを追加していきます。

main.py(追加コード)
@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してデプロイして完成です。

Slack___mimamori-lacina___SHIJUKU_FREESCHOOL_LACINA__N_P_O.png

LINEを起動して、ビーコンに近づくと、Slackに入室したことを通知します。
注意点として、LINEの設定でビーコンの利用を許可していないといけないのと、かなりの確率でLINEがフォアグラウンドでないと検知しないことです。iOSでもAndroidでも多分同じです(もしかしたらビーコン端末のハードウェア的な問題かもしれないですが)。
あと、leaveイベントは廃止予定になっていて、使わない方が無難です。
いずれにしてもLINEアプリを開いていないとビーコンを検知しないため、ICカードによる入退室管理の代わりとして使うのはちょっと厳しそうです。

おわりに

実はPythonは始めてで、Herokuも使ったことがなく、いろいろなサイトの記事を参考になんとか作りましたが、大変勉強になりました。日曜大工的に作ったものなので不備な点が色々あるかもしれませんが、見つけたらコメントでご指摘いただけると助かります。
普段みなさんが書かれたQiitaの記事には大変お世話になっているのに、自分で書くのは初めてで、ありがたみが身にしみました。正直プログラム作るよりこの記事書くほうが時間かかりました(笑)
何かのお役に立てれば幸いです。

参考サイト

主に以下のサイトを参考にさせていただきました。

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
4
Help us understand the problem. What are the problem?