こんな感じのWikipedia検索できるLINE BOTを作成してみました。土日で何か作ろうと思って、言葉を検索できるLINE BOTをミニマムで作ってみた。 pic.twitter.com/SgzzsAFVjc
— 辻佳佑 (@t0daaay) December 22, 2019
思った以上に簡単に作れたので、作り方を紹介します。
時間測ってないですが、初心者でも1時間あれば全然作れる気がします(知らんけど)
振り返りながら書いているので、手順が抜けていたらごめんなさい...
今回は、python(Flask)で開発し、herokuにデプロイしていきます。
#LINE Developersの登録
まずはじめに、LINE Developersに登録しましょう。
https://developers.line.biz/ja/ へアクセス
登録後、サービス提供者を表す「プロバイダー」を作成。
続けて、登録したプロバイダー内で新規チャネルを作成。
チャネルの種類はMessage APIを選択してください。
#herokuの登録
続いてherokuにも登録します。
今更初めて使ったけど素晴らしい...
PaaSと呼ばれるサービスで、超簡単にデプロイできちゃいます。
- サーバー
- OS
- DB
- プログラミング言語の実行環境
といったサービス公開のために必要なものを用意してくれて、しかも無料で使えるという。
無料で使うと、挙動が遅くなってしまったりと、制約つきではありますが、簡単なLINE BOTを遊びで作るには十分かと思います。
それでは、登録していきましょう。
https://jp.heroku.com/ へアクセス
右上の新規登録から、手順に沿って登録しましょう。
日本語の説明に沿って入力するだけですので、詳しい説明は割愛します。
登録完了すると、こんな画面が表示されます。
続いてアプリケーションの作成をします。
コマンドでの作成も可能なのですが、今回はブラウザ上で作成します。
右上のNewをクリック、続けてCreate new appをクリックしましょう。
すると次のような画面に遷移するので、名前とリージョンを選択します。どっちでも良いかと思いますが、今回、リージョンはアメリカにします。
続いてherokuをインストールしていきます。
下記URLより、対応するOSのインストーラーから、もしくはコマンド入力でインストールします。
https://devcenter.heroku.com/articles/heroku-cli#download-and-install
インストールするとherokuのコマンドラインが使えるようになります。
まずはログインしてみましょう。
$ heroku login
すると、メールアドレスとパスワードを求められるので、heroku登録時のアドレスとパスワードを入力しましょう。
Enter your Heroku credentials:
Email: 登録したアドレスを入力
Password: 登録したパスワードを入力
これでログイン完了できたかと思います。
続いて、環境変数を設定していきましょう。
環境変数とは?: https://wa3.i-3-i.info/word11027.html
$ heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークンの文字列" -a アプリケーション名
$ heroku config:set YOUR_CHANNEL_SECRET="チャネルシークレットの文字列" -a アプリケーション名
アプリケーション名は先ほど決めたherokuのApp name、
「アクセストークンの文字列」と「チャネルシークレットの文字列」はLine developersで以下のように確認可能です。
まずは、チャネルアクセストークンの確認。
続けて、チャネルシークレットの確認
これで、「YOUR_CHANNEL_ACCESS_TOKEN」と「YOUR_CHANNEL_SECRET」という環境変数がデプロイ先で使えるようになりました。
ここまでできたらコードを書いていきましょう。pythonで書いていきます。
まず、以下のようにファイル、およびフォルダを作成してください。
lineBot
├── Procfile
├── main.py
├── runtime.txt
└── requirements.txt
作成した後、以下のように作成したファイルに入力していきます。
Pythonのバージョンを記載
python-3.6.6
インストールするライブラリを記載する設定ファイル
Flask==0.12.2
line-bot-sdk==1.5.0
今回は小規模なアプリケーションでも対応しやすいマイクロフレームワーク、flaskを使って開発します。
LINE Messaging API SDKは、LINE BOT開発のためのライブラリです。
参考: https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/
プログラムの実行方法を定義する設定ファイル
# Procfile
web: python main.py
あとは、main.pyに先ほどのLINE Messaging API SDKのリンク先にあるpythonの公式SDKからコードを引用します。
pythonの公式SDK: https://github.com/line/line-bot-sdk-python
ここのSynopsisに記載されるコードがオウム返しのLINE BOTになっています。
少し変更する必要がありますが、基本的には引用でいけるので、一旦、main.pyにコピペします。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
app = Flask(__name__)
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
@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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
if __name__ == "__main__":
app.run()
コードを読んでみると、先ほど定義したherokuの2つの環境変数ではなく、直接代入される形になってしまっているので、これを書き換えます。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
app = Flask(__name__)
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
@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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
if __name__ == "__main__":
port = int(os.getenv("PORT", 5000))
app.run(host="0.0.0.0", port=port)
変更箇所は以下の通りです。
# 追加
import os
app = Flask(__name__)
# 追加
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
//省略//
# 変更
if __name__ == "__main__":
port = int(os.getenv("PORT", 5000))
app.run(host="0.0.0.0", port=port)
これで、定義したOSの環境変数を使用することができます。
ざっくりですが、コード解説
@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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
/callbackへPOSTすると、Webhook(後ほど出てきます)からのリクエストをチェックし、正しく帰ってきたとき、handlerに定義されている関数が呼び出されます。
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
LINEメッセージが正しく送信できると、関数handle_messageが呼び出され、reply_messageの第2引数の値がLINEの返信として返されます。
ここで一度、herokuへデプロイしてみましょう。
$ cd 作成したディレクトリ/
$ git init
$ heroku git:remote -a アプリケーション名
$ git add .
$ git commit -am "make it better"
$ git push heroku master
正しくpushできていれば、
$ git branch -a
で
remotes/heroku/master
と表示されるはずです。
#Webhookの設定
Webhookとは、あるアプリケーションから別のアプリケーションにリアルタイムに情報を送信するための仕組みです。
LINE BOTのイベント通知を、リアルタイムに行うために使います。
設定を行うために、再度、Line Developersにアクセスします。
Message APIの設定 > Webhook設定に
https://<アプリケーション名>.herokuapp.com/callback
を入力、Webhookの利用をオンにしましょう。
これでオウム返しするようになります。ぜひ実際にラインを送ってみてください。
Line Developers の Message APIの設定 にQRコードがあるので、そこから作成したLINE BOTを友達登録して、会話してみましょう。
ただし、このままの設定だと、「あいさつメッセージ」やラインを送信した際に返ってくる「応答メッセージ」など余計なメッセージが表示されてしまいます。
Messaging API設定からあいさつメッセージの内容の変更、または無効化、応答メッセージの無効化など設定できるので修正してください。
#Wikipedia検索できるようにする
オウム返しするだけだと面白くないので、
WikipediaのAPIを使って検索できるようにしてみましょう。
参考: https://pypi.org/project/wikipedia/
まずはWikipediaのライブラリを登録
Flask==0.12.2
line-bot-sdk==1.5.0
wikipedia==1.4.0 # 追加
続いて、先ほどのmain.pyを以下のように書き換えます。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
import wikipedia # 追加
app = Flask(__name__)
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
wikipedia.set_lang("ja") # 追加
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
# 先ほどの関数内にWikipediaのライブラリを使った処理を記述していく
def handle_message(event):
send_message = event.message.text
# 正常に検索結果が返った場合
try:
wikipedia_page = wikipedia.page(send_message)
# wikipedia.page()の処理で、ページ情報が取得できれば、以下のようにタイトル、リンク、サマリーが取得できる。
wikipedia_title = wikipedia_page.title
wikipedia_url = wikipedia_page.url
wikipedia_summary = wikipedia.summary(send_message)
reply_message = '【' + wikipedia_title + '】\n' + wikipedia_summary + '\n\n' + '【詳しくはこちら】\n' + wikipedia_url
# ページが見つからなかった場合
except wikipedia.exceptions.PageError:
reply_message = '【' + send_message + '】\nについての情報は見つかりませんでした。'
# 曖昧さ回避にひっかかった場合
except wikipedia.exceptions.DisambiguationError as e:
disambiguation_list = e.options
reply_message = '複数の候補が返ってきました。以下の候補から、お探しの用語に近いものを再入力してください。\n\n'
for word in disambiguation_list:
reply_message += '・' + word + '\n'
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(reply_message)
)
if __name__ == "__main__":
port = int(os.getenv("PORT", 5000))
app.run(host="0.0.0.0", port=port)
上記のコードで1番最初のtwitterに掲載したようなものが作成できました。
再びデプロイして、挙動を確かめてみてください。
一応これで完成なのですが、wikipedia内で検索してもらえれば分かる通り、日本語検索のアルゴリズムがかなり微妙なので、返ってくるワードがしっくりこなかったりします。多分しゃーない。
以上で解説は終わりです。
色々応用できると思いますので、ぜひともオリジナルのLINE BOTを作成してみてください。
結構急いで書いたので、抜け、漏れ、改善点などあればご指摘いただけますと幸いです。
#最後に
以下は弊社の宣伝になります。
現在弊社では、HRモンスターと呼ばれる
採用の新しいスタイルを提供するサービスをローンチいたしました。
ローンチ後のさらなる機能追加、改善などのPDCAサイクルを回すべく、
エンジニアを募集しております。
https://www.wantedly.com/projects/341182
Kubernetes、Vue.js(Javascript)、Django(Python)といったモダンな技術を使って、
開発しておりますので、もしご興味がある方はぜひ、ご応募お待ちしております。