LINEに画像を送ると顔の美しさを採点して返信するアプリを作ってみました。
アプリの構成
今回は、AWSを使ってサーバレスのアーキテクチャで構築しました。
利用しているサービスは以下の3つです。
アプリ(Lambda)のソースコード
Lambdaでは画像を受け取り、受け取った画像を顔採点用のAPIに投げてその結果を受け取っています。
顔採点用のAPIはface++を使用していて、詳細はこちらの記事で紹介しています。

【Face++】AIで日本の美女の顔を採点してみた
以下環境で動作確認を行いました。 動作環境 Ubuntu18.04 Python 3.6.9 AI(Face++のDetect API)を使って日本人の美女の美しさを推論してみまし...
今回実装したLambdaのコードです。
from linebot.exceptions import LineBotApiError
from linebot.models import TextSendMessage, MessageEvent, TextMessage, ImageMessage
from linebot import LineBotApi, WebhookHandler
import requests
import json
import os
import logging
import boto3
import base64
from PIL import Image, ImageDraw
logger = logging.getLogger()
logger.setLevel(logging.INFO)
CHANNEL_ACCESS_TOKEN = os.environ["ChannelAccessToken"]
CHANNEL_SECRET = os.environ["ChannelSecret"]
LINE_HANDLER = WebhookHandler(CHANNEL_SECRET)
LINE_BOT_API = LineBotApi(CHANNEL_ACCESS_TOKEN)
def lambda_handler(event, context):
logger.info(event)
signature = event["headers"]["x-line-signature"]
body = event["body"]
# 画像メッセージの場合
@LINE_HANDLER.add(MessageEvent, message=ImageMessage)
def on_image_message(line_event):
image_file_path = "/tmp/file.png"
image = LINE_BOT_API.get_message_content(line_event.message.id)
with open(image_file_path, "wb") as f:
for chunk in image.iter_content():
f.write(chunk)
face_score = face_scoring(image_file_path)
LINE_BOT_API.reply_message(line_event.reply_token, TextSendMessage(f"{face_score}です"))
LINE_HANDLER.handle(body, signature)
return {
"statusCode": 200,
"body": json.dumps(
{
"message": "line API complate",
}
),
}
def face_scoring(file_path):
# 画像ファイルをbase64バイナリ形式で読み出します
with open(file_path, 'rb') as f:
img_file = base64.encodebytes(f.read())
# パラメータ設定
# API
face_api_key = os.environ["FaceApiKey"]
face_api_secret = os.environ["FaceApiSecret"]
# 顔判定
response = requests.post(
'https://api-us.faceplusplus.com/facepp/v3/detect',
{
'api_key': face_api_key,
'api_secret': face_api_secret,
'image_base64': img_file, # 画像のURL
'return_attributes': 'gender,beauty' # 取得したい属性
}
)
json_dict = json.loads(response.text)
result_dict = {}
for faces in json_dict["faces"]:
try:
gender = faces["attributes"]["gender"]["value"]
if gender == "Female":
text = str(faces["attributes"]["beauty"]["female_score"])
else:
text = str(faces["attributes"]["beauty"]["male_score"])
result_dict[f"{faces['face_rectangle']['left']:05}"] = text
except:
pass # 5人以上はレスポンスが帰ってこない
if len(result_dict) == 1:
key = next(iter(result_dict))
result_text = f"{result_dict[key]}点"
else:
result_dict = sorted(result_dict.items()) # 左の人からになるようにソート
result_text = "左から順に\n"
for i_score in result_dict:
result_text += f"{i_score[1]}点\n"
return result_text
Lambda・API Gatewayの作成
AWSの環境はSAM(AWS Serverless Application Model )を使って構築しました。
├ line-face-scoring/ ├ app/ # lambdaのソース用のディレクトリ │ ├ app.py # lambdaのソース │ ├ Dockerfile # lambdaのDocker環境 │ ├ __init__.py │ ├ requirements.txt # lambdaで利用するライブラリ ├ __init__.py ├ samconfig.toml # samコマンドの設定 ├ template.yaml # AWSのリソースの設定
リソースはそれぞれ以下の設定ファイルをもとに作成しています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
python3.8
Sample SAM Template for line-face-scoring
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 30
Api:
OpenApiVersion: 3.0.2 #samのバグを回避(不要なステージが作成される)
Parameters:
Env:
Type: String
AllowedValues:
- dev
- prod
Default: prod
ChannelAccessToken:
Type: String
ChannelSecret:
Type: String
LineUserID:
Type: String
FaceApiKey:
Type: String
FaceApiSecret:
Type: String
Resources:
FaceScoringFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
FunctionName: !Sub lambda-face-scoring-Function
PackageType: Image
Role: !GetAtt FaceScoringFunctionRole.Arn
Environment:
Variables:
ChannelAccessToken: !Ref ChannelAccessToken
ChannelSecret: !Ref ChannelSecret
LineUserID: !Ref LineUserID
FaceApiKey: !Ref FaceApiKey
FaceApiSecret: !Ref FaceApiSecret
Events:
LineAPI:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /facescoring/v1
Method: post
RestApiId:
Ref: FaceScoringAPIateway
ImageUri: !Sub ${Env}-face-scoring:python3.8-v1
Metadata:
Dockerfile: Dockerfile
DockerContext: ./face_scoring
DockerTag: python3.8-v1
FaceScoringAPIateway:
Type: AWS::Serverless::Api
Properties:
StageName: !Sub ${Env}
FaceScoringFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
RoleName: !Sub lambda-line-face-scoring
samconfig.toml
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "face-scoring"
image_repository = "xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/line-api-ecr"
region = "ap-northeast-1"
confirm_changeset = false
capabilities = "CAPABILITY_NAMED_IAM"
parameter_overrides = [
"Env=prod",
"ChannelAccessToken=dummy",
"ChannelSecret=dummy",
"LineUserID=dummy",
"FaceApiKey=dummy",
"FaceApiSecret=dummy"
]
Dockerfile
FROM public.ecr.aws/lambda/python:3.8
COPY app.py requirements.txt ./
RUN python3.8 -m pip install -r requirements.txt -t .
# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]
requirements.txt
requests
line-bot-sdk
Pillow
まとめ
今回はLineとAPIGatewayとLambdaを使って、顔採点アプリを作成してみました。
AIサービスは無料で使えるAPIあるので、それを活用すると簡単に独自のアプリを作ることができますね。
コメント