ABEJA Platform + Cloud Functions + LINE Botで機械学習アプリをつくる


はじめに

本記事は、以下の手順をまとめた記事です。

- ABEJA Platform + Google Cloud Functions + LINE Botでサーバーレスな機械学習アプリをつくる


システム構成


  • LINE Botに画像を送信する

  • LINE Messaging API からの HTTPリクエスト(webhook)をCloud Functionsで受ける

  • Cloud Functionsから、ABEJA Platform上にデプロイされた画像分類の機械学習APIにHTTPリクエストを送り、画像のクラスの予測結果を取得する

  • 予測結果をLINEに返す


事前準備


機械学習モデルの学習・デプロイ

ABEJA Platform上に機械学習モデルをデプロイします。ABEJA Platformのテンプレートの機能を使うことで、ノンプログラミングで機械学習モデルを学習・デプロイすることができます。

今回は、以下の記事の手順に沿って作成した、花の画像の分類モデルをサンプルとして使用します。

(参考)

ABEJA Platformのテンプレートを使用して、ノンプログラミングで機械学習モデルを学習する

https://qiita.com/yushin_n/items/6852ad042913617d8892

ABEJA Platformのテンプレートを使用して、ノンプログラミングで機械学習モデルをデプロイする

https://qiita.com/yushin_n/items/fb338ca9bd3c685ad691

デプロイメントの画面から、デプロイしたモデルのエンドポイントを控えておきます。


LINE Developersのチャネル作成

LINE Messaging APIを使ってボットを作成するため、まずLINE Developersコンソールでチャネルを作成します。

(参考)

Messaging APIを利用するには

https://developers.line.biz/ja/docs/messaging-api/getting-started/

チャネルを作成した後、「チャネル基本設定」に記載されているChannel Secretアクセストークンを控えておきます。


Google Cloud Functionsのファンクションの作成

Google Cloud Functionsのコンソールからプロジェクトとファンクションを作成します。

Inline editorを選択して、RuntimeにはPython 3.7を指定します。

その後、main.pyにソースコードを書きます。

ソースコードは、line-bot-sdk-pythonのサンプルを参考にしました。


main.py


import os
import io
import sys
import requests
import flask
import linebot
import linebot.exceptions
import linebot.models
import googletrans

# set API endpoint
endpoint = os.getenv('ABEJA_PLATFORM_API_ENDPOINT', None)

# set ABEJA Platform credential
user_id = os.getenv('ABEJA_PLATFORM_USER_ID', None)
personal_access_token = os.getenv('ABEJA_PLATFORM_USER_TOKEN', None)

credential = {
'user_id': user_id,
'personal_access_token': personal_access_token
}

# get channel_secret and channel_access_token from your environment variable
channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)

if channel_secret is None:
print('Specify LINE_CHANNEL_SECRET as environment variable.')
sys.exit(1)
if channel_access_token is None:
print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
sys.exit(1)

line_bot_api = linebot.LineBotApi(channel_access_token)
parser = linebot.WebhookParser(channel_secret)

def main(request):
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']

# get request body as text
body = request.get_data(as_text=True)

try:
# parse webhook body
events = parser.parse(body, signature)
for event in events:
# initialize reply message
text = ''

# if message is TextMessage, then ask for image
if event.message.type == 'text':
text = u'画像を送ってください!'

# if message is ImageMessage, then predict
if event.message.type == 'image':
message_id = event.message.id
message_content = line_bot_api.get_message_content(message_id)
img_io = io.BytesIO(message_content.content)
content_type = 'image/jpeg'

# post image to api endpoint for prediction
res = requests.post(endpoint, data=img_io, headers={'Content-Type': content_type},
auth=(user_id, personal_access_token))
result = res.json()

# translate english label to japanese
label_en = result['result'][0]['label']
translator = googletrans.Translator()
label_ja = translator.translate(label_en.lower(), dest='ja')

prob = result['result'][0]['probability']

# set reply message
text = u'{}%の確率で、{}です!'.format(int(prob*100), label_ja.text)

line_bot_api.reply_message(
event.reply_token,
linebot.models.TextSendMessage(text=text))

except linebot.exceptions.InvalidSignatureError:
flask.abort(400)

return 'OK'


requirements.txtにline-bot-sdkgoogletransを追加します。


requirements.txt

# Function dependencies, for example:

# package>=version
line-bot-sdk
googletrans

環境変数に、以下を指定します。

- LINE_CHANNEL_SECRET(LINEのChannel Secret)

- LINE_CHANNEL_ACCESS_TOKEN(LINEのアクセストークン)

- ABEJA_PLATFORM_USER_ID(ABEJA PlatformのユーザーID)

- ABEJA_PLATFORM_USER_TOKEN(ABEJA Platformのアクセストークン)

- ABEJA_PLATFORM_API_ENDPOINT(デプロイしたモデルのエンドポイント)

ファンクションをデプロイした後、TriggerのURLをLINE DevelopersのチャネルのWebhook URLに登録します。これで準備完了です。

*接続確認をクリックすると「Webhookが無効なHTTPステータスコードを返しました(期待されるステータスコードは200です)」と出てしまいましたが、実際は接続できていました。


LINEでの画像の送信

設定したとおり、チャネルにテキストを送信すると「画像を送ってください!」というメッセージが返ってきます。

また、画像を送信すると、画像のクラスの予測結果とクラス所属確率が返ってきました!


まとめ

本記事では、ABEJA Platform + Google Cloud Functions + LINE Botでサーバーレスな機械学習アプリをつくる手順をまとめました。今回は、5種類の花(デイジー、ローズ、タンポポ、ヒマワリ、チューリップ)を分類する機械学習モデルを使いましたが、HTTPリクエストを送る機械学習APIを変えることで、色々なアプリケーションをつくることができますね :dog:


参考

ABEJA Platform + AWS Lambda(Node.js) + LINE Botの事例もあります。

https://qiita.com/peisuke/items/f46e46a98692c3490f15

ABEJA Platformは、トライアルも提供しています。気になられた方は、是非、お気軽にお問い合わせください。また、フォーラムもありますので、是非、ご活用ください。

ABEJA Platformに関するお問い合わせ

https://abejainc.com/platform/ja/contact/

ABEJA Platform Forum

https://forums.abeja.io/