挑戦者が現れた時に通知してくれるSlack Botを作った

# 概要
- 会社の人たちと「Slackを使ったおもしろいアプリを作る」というテーマで土善旅館で最高な開発合宿をしてきました。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/2000bcfc-2547-ae3f-1e58-b22de331e292.jpeg" width=50%>

- 「参戦」という文字を入れてメンションを飛ばすと、そのユーザのアイコンでスマブラ風なコラ画像を作成し返信してくれるSlack botを作りました。
- 土善旅館は最高

# 成果物
![run_challenger.gif](https://qiita-image-store.s3.amazonaws.com/0/150789/8be2e4eb-8c9a-386b-77b3-6ff325453fd1.gif)


# 主な処理
- 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です。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/fa70fa50-db1b-2abb-7b2c-f9b7e6141087.jpeg" width=50%>

メンション検知後、メンションを飛ばしたユーザーのアイコンです。512×512のサイズで取得しています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/b04936e5-6f25-047e-fe26-5c918512054c.png" width=50%>

白い部分に合わせ素材画像にアイコンをペーストします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/9ab0eecf-6524-fc06-f7e3-27a1069c8f66.png" width=50%>

白い部分を切り抜くためにマスク画像を用意します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/cf05c307-cfde-8020-7b3f-ee8bcf013cdb.png" width=50%>

ペーストした画像とマスク画像を合わせます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/ba9954a9-2fb5-bf98-fc85-31f1d8f5331a.png" width=50%>



---

# コラージュ生成処理（コード）
以下は先ほどの処理を行なっているコードです。 
メンション検知後にこれらの処理が呼ばれコラ画像作成後に返信を行なっています。 

```python:collage_generator.py

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` はこの処理の前に以下の関数で取得しています。

```python:util.py
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を作りたかったのですが...
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/3416d08d-dc0d-1fb7-8475-442a6950c349.jpeg" width=50%>


輪郭の切り取り（背景の削除）やユーザ名の書き込みがうまくいかず時間切れに。
下図のようなクオリティになってしまったので「挑戦者が現れました！！」に変更しました。
<img src="https://qiita-image-store.s3.amazonaws.com/0/150789/d6f4433d-cce9-aeda-4f7b-361bc3240c6f.png" width=50%>
なんだか思ってたのと違う...

# まとめ
土善旅館は猫もいるしご飯もうまいし開発環境も揃っているしホスピタリティ最高！！

# 参考
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/