LineBot+ImageSearchで手軽にAlibabaクラウドの画像検索サービスを利用する
本記事では、LineBotからAlibaba CloudのImageSearchを使って、画像検索機能を利用する方法をご紹介します。
①LineBotを作成するために、下記のURLからLineDevelopersアカウントを作成します。
アカウント作成後、LineBotを一つ作成し、友達を追加します。
LineDevelopersの下記情報をメモして、後ほどLineBotAPIを呼び出しする際利用します。
- (1)Channel secret
- (2)Channel access token (long-lived)
②Alibabaクラウド上で、ImageSearchインスタンスをデプロイ方法は下記のドキュメントを参照します。
③ImageSearchのインスタンス作成後、下記のドキュメントに従って、事前に画像をインプットします。
④今回利用するコードは下記になります。簡単に説明させていただきます。
利用するライブラリは以下になります。
import osimport reimport oss2import base64from io import BytesIOfrom PIL import Imageimport aliyunsdkimagesearch.request.v20190325.AddImageRequest as AddImageRequestimport aliyunsdkimagesearch.request.v20190325.DeleteImageRequest as DeleteImageRequestimport aliyunsdkimagesearch.request.v20190325.SearchImageRequest as SearchImageRequestfrom aliyunsdkcore.client import AcsClientfrom flask import Flaskfrom flask import requestfrom flask import abortfrom linebot import LineBotApifrom linebot import WebhookHandlerfrom linebot.exceptions import InvalidSignatureErrorfrom linebot.models import MessageEventfrom linebot.models import TextMessagefrom linebot.models import TextSendMessagefrom linebot.models import ImageMessagefrom linebot.models import ImageSendMessage
後ほどコードをECSにデプロイするため、ECSの環境変数は以下のものを設定します。
まずはLineBotAPIの呼び出しに必要なトークン情報です。
# LineBot Access TokenCHANNEL_ACCESS_TOKEN = os.environ["CHANNEL_ACCESS_TOKEN"]CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]
次にImageSearchを利用するための必要なトークン情報も設定します。
- (1)Alibabaクラウドにアクセスに必要なアクセスキーとシークレットトークン
- (2)OSSにアクセスするためのURL、バケット名、バケットディレクトリ
- (3)ImageSearchインスタンスのURL、Bot名、リージョン名
# AliCloud Access TokenALICLOUD_ACCESS_KEY = os.environ["ALICLOUD_ACCESS_KEY"]ALICLOUD_ACCESS_SECRET = os.environ["ALICLOUD_ACCESS_SECRET"]ALICLOUD_REGION = os.environ["ALICLOUD_REGION"]ALICLOUD_BUCKET_NAME = os.environ["ALICLOUD_BUCKET_NAME"]ALICLOUD_BUCKET_URL = os.environ["ALICLOUD_BUCKET_URL"]ALICLOUD_BUCKET_DIR = os.environ["ALICLOUD_BUCKET_DIR"]ALICLOUD_IMGSEARCH_URL = os.environ["ALICLOUD_IMGSEARCH_URL"]ALICLOUD_IMGSEARCH_BOT = os.environ["ALICLOUD_IMGSEARCH_BOT"]
さて、本体のLineBotからImageSearchのAPIを呼びだしする部分は以下になります。
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)handler = WebhookHandler(CHANNEL_SECRET)auth = oss2.Auth(ALICLOUD_ACCESS_KEY, ALICLOUD_ACCESS_SECRET)bucket = oss2.Bucket(auth, ALICLOUD_BUCKET_URL, ALICLOUD_BUCKET_NAME)# create AcsClient instanceclient = AcsClient(ALICLOUD_ACCESS_KEY, ALICLOUD_ACCESS_SECRET, ALICLOUD_REGION)# callback()@app.route("/callback", methods=['POST'])def callback():# Get X-Line-Signature header valuesignature = request.headers['X-Line-Signature']# Get request body as textbody = request.get_data(as_text=True)app.logger.info("Request body: " + body)# Handle webhook bodytry:handler.handle(body, signature)except InvalidSignatureError:abort(400)return 'OK'# ImageMessage Handler@handler.add(MessageEvent, message=ImageMessage)def handle_message(event):# get binary imagemessage_id = event.message.idmessage_content = line_bot_api.get_message_content(message_id)image_bin = BytesIO(message_content.content)# search imagerequest = SearchImageRequest.SearchImageRequest()request.set_endpoint(ALICLOUD_IMGSEARCH_URL)request.set_InstanceName(ALICLOUD_IMGSEARCH_BOT)encoded_pic_content = base64.b64encode(image)request.set_PicContent(encoded_pic_content)response = client.do_action_with_exception(request)# get string resultdata = str(response)# get image nameimgName = (re.search("[a-z]*_[0-9]*_[0-9]*", data)).group(0)# get image on ossurl = bucket.sign_url('GET', ALICLOUD_BUCKET_DIR + imgName + '.' + imgFormat, 60)# reply image messageline_bot_api.reply_message(event.reply_token,ImageSendMessage(original_content_url = url,preview_image_url = url))@handler.add(MessageEvent, message=TextMessage)def handle_message(event):line_bot_api.reply_message(event.reply_token,TextSendMessage(text=event.message.text))
iPhoneで取得した画像はサイズだと直接ImageSearchに送信できないため、画像をリサイズします。
※今回は画像サイズを一律(250,800)にしています。
# resize imagepil_img = Image.open(image_bin)re_img = pil_img.resize((250,800))# get binary imageoutput = BytesIO()re_img.save(output, format=imgFormat)image = output.getvalue()
Flaskサーバを外部公開するため、下記のように記載します。
if __name__ == "__main__":callback()app.run(debug=False, host='0.0.0.0', port=443)
⑤作成したプログラムをECSにデプロイし、実行します。
⑥最後はLineDevelopersのWebHookURLに今回公開するサイトのURLを登録して構築完了です
それでは実際動作する際のイメージを確認してみましょう。
(1)作成したImageSearchのBotを選択しチャット画面を開きます。
(2)携帯のカメラを起動して、検索したい画像を写真撮影して送信すれば、一番類似の画像が返ってくることが確認できました。
まとめ
以上でiPhoneから画像を撮影し、LineBotを経由でImageSearchで画像検索ができました。
ImageSearchとLineBotを結合することで、ImageSearchの利用もよりユーザーに近ずくことができると考えて今回のデモを作成しました。
Alibaba Cloudを始めてみましょう
ソフトバンクは、Alibaba Cloudのアカウント開設から、サービス展開までをお手伝いします。