LoginSignup
11
4

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-07-09

はじめに

本記事は、以下の手順をまとめた記事です。
- 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/

11
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4