概要
- 会社の人たちと「Slackを使ったおもしろいアプリを作る」というテーマで土善旅館で最高な開発合宿をしてきました。
- 「参戦」という文字を入れてメンションを飛ばすと、そのユーザのアイコンでスマブラ風なコラ画像を作成し返信してくれるSlack botを作りました。
- 土善旅館は最高
成果物
主な処理
- botへ「参戦」という文字を入れてメンションを飛ばす
- Slack Real Time Messaging(RTM)がメンションを検知
- コラ画像生成
メンションを飛ばしたユーザのアイコン、チャンネルを取得
素材画像とアイコンを合成・マスク処理 - コラ画像を投稿
プロジェクト構成
run.py
を起動することでメンションを検知しコラ画像を返信することができます。
AWSで常時稼働させたかったのですがそこまで作る時間がなかったため、今回はおうちオンプレ(ローカルホスト)で運用予定です。
$ tree -I "__pycache__"
.
├── LICENSE
├── README.md
├── images
│ └── challenger.jpg
├── run.py
├── slack_rtm_src
│ ├── __init__.py
│ └── rtm.py
├── slackbot_settings.py
└── src
├── collage_generator.py
├── main_pipeline.py
├── slack_util.py
└── util.py
また、ソースコード、各種設定は下記リポジトリにあるので詳細はそちらをご覧ください。
https://github.com/hatunina/slack_sannsenn_bot
コラージュ生成処理
images
に置いてあるベースになる素材画像です。この記事では縮小して表示していますが元のサイズは1,200×675です。
メンション検知後、メンションを飛ばしたユーザーのアイコンです。512×512のサイズで取得しています。
コラージュ生成処理(コード)
以下は先ほどの処理を行なっているコードです。
メンション検知後にこれらの処理が呼ばれコラ画像作成後に返信を行なっています。
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFilter
def collage_generate_pipeline(icon_image):
# 素材画像を開く
challenger_format = open_image()
# 素材画像にアイコンを貼り付け
back_im = back_image_generate(challenger_format, icon_image)
# マスク処理と複合処理
im = mask_image(challenger_format, back_im)
return im
def open_image():
# 素材画像を開く
challenger_format = Image.open('./images/challenger.jpg')
return challenger_format
def back_image_generate(challenger_format, icon):
# 素材画像にアイコンを貼り付け
back_im = challenger_format.copy()
# x, y
back_im.paste(icon, (580, 80))
return back_im
def mask_image(challenger_format, back_im):
# マスク処理と複合処理
mask = Image.new("L", back_im.size, 0)
draw = ImageDraw.Draw(mask)
# 楕円を切り抜く(x0, y0, x1, y1)
draw.ellipse((650, 90, 1030, 590), fill=255)
# 枠をぼやかす
mask_blur = mask.filter(ImageFilter.GaussianBlur(10))
im = Image.composite(back_im, challenger_format, mask_blur)
return im
collage_generate_pipeline
関数の引数 icon_image
はこの処理の前に以下の関数で取得しています。
import requests
from PIL import Image
import io
def get_icon(message):
icon_url = message.user.get('profile').get('image_512')
icon = requests.get(icon_url, stream=True)
# 取得したバイナリデータはオンメモリで処理するのでImage型に変換
icon_image = Image.open(io.BytesIO(icon.content))
return icon_image
改善点
- 素材画像へのアイコン貼り付け位置や楕円の切り取り範囲がベタ打ちになってしまっているので、別の素材画像やユーザのアイコンによってはいい感じのコラ画像が作成されない
- おうちオンプレ環境を想定しているのでPCを持ち出したりするとメンションを検知できない(AWS lambdaで動かすとかしたかった)
- エラーハンドリング、ログ等...
本当はこんな感じにしたかったやつ
下図のような「参戦!!」をSlackに新メンバーがジョインした後にbotにメンションを飛ばすとアイコン・ユーザ名を取得して返信してくれるbotを作りたかったのですが...
輪郭の切り取り(背景の削除)やユーザ名の書き込みがうまくいかず時間切れに。
下図のようなクオリティになってしまったので「挑戦者が現れました!!」に変更しました。
なんだか思ってたのと違う...
まとめ
土善旅館は猫もいるしご飯もうまいし開発環境も揃っているしホスピタリティ最高!!
参考
https://qiita.com/sukesuke/items/1ac92251def87357fdf6
https://note.nkmk.me/python-pillow-paste/
https://note.nkmk.me/python-pillow-composite/
https://qiita.com/ekzemplaro/items/6bd539983ba8997003b9
「参戦!!」の方のフォント
http://mplus-fonts.osdn.jp/about.html#multilingual-2
土善旅館については下記記事が最高な感じです。
https://darui.io/saikou-no-natsu/