Flask+Heroku+LINEで犬猫判定AI botを作ってみる

Yutaka_kun
LSC PSD
Published in
10 min readJul 22, 2020

python初心者が作る、犬猫認識AI」の記事では犬猫判定AIを作ったり、「Flaskを使って機械学習モデルのロード時間を短縮する」の記事ではAIモデルをサーバーに常駐させてみたりしましたが、今回はUIの部分を作ってみようと思います。犬猫シリーズも今回で完結ですね。

Herokuにアカウントを登録

HerokuとはWebアプリケーションを運用するためのクラウドサービスの一つです。無料で月に550時間まで使うことができます。(クレジットカードを登録すると1000時間まで使用可能)

登録方法の説明は他のサイトに譲ります。

最後にアプリ名(好きな名前にできる)を決めると思いますが、今回はdogcat-testにしました。この名前はあとで使います。

GitHubと連携

HerokuはGitHubと連携させることができます。
(必須ではない、がこの方法しかやったことない)
GitHubのリポジトリに作成したファイルやコードをアップロードすると、その変更情報をHerokuが自動で認識してサーバー内の情報を更新してくれます。

連携方法は他にわかりやすいサイトがあると思うのでそちらに譲ります。

LINE開発者登録・プロバイダー作成・チャンネル作成

こちらも説明は他のサイトに譲りますが、流れだけ書いておくと
https://developers.line.biz/console/からLINEアカウントでログインしてLINEDevelopersに登録します。
プロバイダーを新規で作成し、名前を決めます。
Messaging APIのチャネルを作成し、アイコン画像、アプリ名、アプリ説明を適当に入力します。プランは「フリー」で大丈夫で、大業種 小業種は「ウェブサービス」を選択してください。最後に利用情報に同意します。

アクセストークンを発行

Messaging API設定のチャネルアクセストークン(長期)欄にある再発行ボタンを押してアクセストークンを発行します。アクセストークンとはわかりやすく言えば外部からLINEを使うための利用許可証のようなものです。

Webhook設定

これはユーザーからのメッセージが任意のURL(サーバー)に転送してその内容を処理させるための設定項目です。
先ほどHerokuで立ち上げたサーバーのURLを入力します。
サーバー名を「dogcat-test」にしたのでURLは
https://dogcat-test.herokuapp.com/callback
にします。

チャネルの秘密鍵

チャネル基本設定のチャネルシークレットを発行します。

必要な環境、ファイルを用意する

コードはGitHubにまとめてあります。
仮想環境を新たに作成して、必要なパッケージをインストールします。
今回はpython 3.6を使いました。

# flask関係
pip install flask
pip install Flask gunicorn
# LINE関係
pip install line-bot-sdk
# AI関係
pip install numpy
pip install Pillow
pip install keras

新規フォルダの中にtextファイル(Procfile)とpythonファイル(app.py)を用意します。さらに画像を保存するためのフォルダ(static)と学習済みの犬猫認識モデル(dog_cat.h5)も準備します。
*学習済みモデルの作り方はpython初心者が作る、犬猫認識AIを参照してください

--ProcFile
--app.py
--dog_cat.h5
--static

ProcfileはHerokuにアプリケーションをアップロードした時に最初に実行されるコマンドを書きます。またProcfileの拡張子は何もつけないようにしてください。Procfile.txtだとherokuがうまく認識してくれません。

# Procfile
web: gunicorn app:app

app.pyはflaskでルートを記述して学習モデルを呼び出す行を書きます。

# app.py
import numpy as np

from flask import Flask, request, abort

from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextSendMessage, ImageMessage, ImageSendMessage)

from keras.models import load_model
from keras.preprocessing import image

app = Flask(__name__)
ACCESS_TOKEN = # アクセストークンを貼り付け
SECRET = # チャネルシークレットを貼り付け
FQDN = "https://dogcat-test.herokuapp.com"# herokuapp.comの前はアプリ名
line_bot_api = LineBotApi(ACCESS_TOKEN)
handler = WebhookHandler(SECRET)
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']

body = request.get_data(as_text=True)
app.logger.info("Requestbody: " + body)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)

return'OK'
@handler.add(MessageEvent, message=ImageMessage)
def handle_image_message(event):
message_content = line_bot_api.get_message_content(event.message.id)
with open("static/"+event.message.id+".jpg", "wb") as f:
f.write(message_content.content)

test_url = "./static/"+event.message.id+".jpg"
##########ここからAIモデル#################################
img = image.load_img(test_url, target_size=(150, 150))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = x / 255.0

model = load_model('dog_cat.h5')
result_predict = model.predict(x)

if result_predict < 0.5:
text = "This is cat"
if result_predict >= 0.5:
text = "This is dog"
##############################################################
line_bot_api.reply_message(event.reply_token, TextSendMessage(text=text))
if __name__ == "__main__":
app.run()

基本、コピペでいけると思いますが、少し補足しますと、、、

今回はユーザーから送られた画像をキャッチしたいので

from linebot.models import ImageMessage
@handler.add(MassageEvent, massage=ImageMessage)
def handle_image_message(event):
message_content = line_bot_api.get_message_content(event.message.id)

ですが、ユーザーからのメッセージをキャッチしたい場合は

from linebot.models import TextMessage
@handler.add(MassageEvent, massage=TextMessage)
text = event.message.text

でメッセージをキャッチできます。

そして今回はユーザーにテキストを返したいので

from linebot.models import TextSendMessage
...
...
line_bot_api.reply_massage(event.reply_token,
TextSendMessage(text=○○))

ですが、画像を返したい場合は

from linebot.models import ImageSendMessage
...
...
line_bot_api.reply_massage(event.reply_token,
ImageSendMessage(original_content_url="画像path",
preview_image_url="画像path"))

で画像を返すことができます。

なぜurlを2つ指定するかというと、プレビューとタップして表示される画像を別にできるかららしいです。

requirements.txtファイルの作成

サーバー上でAIモデルを動かすのに必要なパッケージのバージョンをテキストファイルに記入しておくと、Herokuが認識して自動でインストールしてくれます。

pip freeze > requirements.txt

で仮想環境に入ってるパッケージのバージョンを自動で書き込んでくれます。

バージョンではなくパスのようなものが書き出されることがありますが、これはAnaconda環境を使用しているとパスが書き出されるみたいです。
その場合は各バージョンを conda list で確認し手書きで直せば問題ないです。

--ProcFile
--app.py
--dog_cat.h5
--static
--requirements.txt

これらのファイルをGitHubにアップロードすれば変更を認識してherokuのサーバーが自動で立ち上がるはずです。
試しに猫の画像を送ってみます。

pip install heroku

しておくと、コマンドラインからherokuサーバーにログインしたり、サーバーの再起動、停止などができます。
入れておくと便利です。

--

--

Yutaka_kun
LSC PSD
Editor for

Microbiology technician,Machine learning engineer(beginner)