LoginSignup
2
1

More than 5 years have passed since last update.

serverless framworkで画像認識して関係する映画を推薦するSlack Botを作ったまとめ (No Server November Challenge)

Posted at
  • serverless frameworkを開発しているServerless, Inc.の企画で,No Server Novemberが開催中
  • 11月中に毎週課題が出される
    • Challenges that are designed to help experienced users level up, and brand new users get started
  • githubリポジトリのリンクを#noServerNovemberをつぶやくとなにか(official Serverless swag)もらえる?

  • Nov 12の課題であるAnimalBotとNov 19の課題であるSlack botを組み合わせて開発してみたので内容の紹介

    • Nov 12 AnimalBot: 画像URLをメンションすると写っている動物を返信するTwitter Botを作る課題
    • Nov 19 Slack bot: /actionとすると80年台アクション映画をランダムに教えてくれるSlack Botを作る課題

作ったもの

  • Slack上でBotに画像URLをメンションすると,写っている内容と,関連する映画を教えてくれるシステム
    • 画像認識にはAmazon Rekognitionを利用
    • 映画情報はThe Movie DatabaseからAPI経由で取得

animal-recog-slack-bot.png

結果

  • 猫の画像を送ると,猫が写っていることと,関連映画として魔女の宅急便を教えてくれた😺

screenshot.png

環境

  • MacOS Mojave
  • Python 3.6.5
  • Serverless Framework 1.32.0

つまづきメモ

  • [Lambdaプロキシ] POSTリクエスト本体はevent.bodyの中にStringではいる(JSONじゃない!)ので,event.body配下を再度JSONとして読み込み直す必要あり
def main(event, context):
  body_str = event['body'] ## これだとただの文字列
  body_json = json.loads(event['body']) ## これでJSONとして扱える
  ...
  • Lambda + Pythonで画像処理ライブラリPillow(PIL)を使う場合,ローカルがMac,実行環境はLinuxベースのため,ローカルでライブラリを同梱しても動作しない
    • よって,serverless-python-requirementsを用いてライブラリ管理をする (Amazon LinuxのDockerイメージを利用)
    • 関連する設定は以下
serverless.yml
...
provider:
  name: aws
  runtime: python3.6
  ...

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true
...
  • Lambda上で一時的にファイルを作成したい場合は必ず/tmp配下を指定する

    • 今回はURLで指定された画像を一旦Lambdaローカルに保存し処理
    • その際,保存先は/tmp以外は不可 (権限なし)
      • OSError: [Errno 30] Read-only file system
  • Slack APIでメッセージをPostする際,画像などの付属情報を設定可能なattachmentsは,JSON内でStringとして格納しなければならない

    • つまり,attachmentsの値はjson.dumsする必要あり
# これはOK
data_correct = {
    ...
    "attachments": json.dumps([
        {
            "title": movie_info['title'],
            "image_url": movie_img_url
        }
    ])
}
# これは駄目
data_err = {
    ....
    "attachments": [
        {
            "title": movie_info['title'],
            "image_url": movie_img_url
        }
    ]
}

開発詳細

つくったものはGitHub - jagijagijag1/animal-recog-slack-botで公開

  1. serverless.yml, handler.pyを編集し,ひとまずBot処理を作成
  2. Slack,Movie DBで作業し,API Token取得
  3. serverless.ymlを再度編集し,Lambda環境変数にAPI Token情報

1. Serverless framework + Pythonで開始

$ sls create -t aws-python3 -p <project-name>
serverless.ymlの修正
  • 環境変数部分は後で埋めるのでひとまずブランク
serverless.yml
service: animal-recog-slack-bot

provider:
  name: aws
  runtime: python3.6
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "rekognition:DetectLabels"
      Resource: "*"

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true

functions:
  hello:
    handler: handler.main
    events:
      - http:
          path: /
          method: POST
    environment:
      OAUTH_TOKEN: ''
      BOT_TOKEN: ''
      MOVIE_DB_API_TOKEN: ''
    timeout: 20

関数本体を作成
  • やや長いのでソースコードはこちら参照

  • 画像はURLで受付,一旦Lambda関数ローカルに保存し,RekognitionにByteとして受け渡す

  • Rekognitionではかなり一般的な単語(e.g. Animal, Pet)をラベル候補の上位に出してくるため,暫定処理としてNGワード(ignore_word)を設定し回避

  • 関連映画を取得する処理の概要は以下

    • Rekognitionのラベル検出結果から一語を選択
    • 選択した後がMovie DBでキーワード登録されているか確認(API: /search/keyword)し,登録ありの場合はID取得 (なしの場合は終了)
    • 獲得したキーワードIDを用いて映画検索(API: /discover/movie?with_keyword=)
    • 検索結果からランダムに選択した映画をSlackに返す
デプロイ
$ sls plugin install -n serverless-python-requirements
$ docker pull lambci``/lambda``:build-python3.6
$ sls deploy -v

2. Slack,Movie DBで作業し,API Token取得

Slack app準備
  • Building Slack apps | SlackでCreate
  • その後の画面で左側メニューの"Bot User"を選び,Bot Userを追加
  • 左メニュー"Event Subscriptions"からイベントを有効にし,"Request URL"にAPI GatewayのURLを指定し,challengeが帰ってくることを確認 (Lambdaコードに処理を埋め込み済)
  • challenge成功後,"Subscribe to Bot Events"で"app_mention"イベントを追加
  • 左メニュー"Installed App"からアプリをWorkspaceにインストール
  • 左メニュ「OAuth & Permissions」にてWorkspaceにAppをInstallすると"OAuth Access Token"と"Bot User OAuth Access Token"が発行される (あとでserverless.ymlに追記)
Movie DB準備
  • 登録し,Settingから申請可能
  • 申請完了後もSetting->APIでAPIキーを確認可能
    • 本アプリではv3 auth利用

3. serverless.ymlを再度編集し,Lambda環境変数にAPI Token情報を追記

  • OAUTH_TOKEN: SlackのOAuth Access Token
  • BOT_TOKEN: SlackのBot User OAuth Access Token
  • MOVIE_DB_API_TOKEN: The Movie DatabaseのAPIキー (v3 auth)
serverless.yml
...
functions:
  hello:
    ...
    environment:
      OAUTH_TOKEN: <your-token>
      BOT_TOKEN: <your-token>
      MOVIE_DB_API_TOKEN: <your-token>
...

参考

2
1
0

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
2
1