要は
SnapBotという画面変化を検知してスクリーンショット~Slackのスレッドへの送信を自動で行うツールを開発しました。
このBotを使用することで、単純作業であるスクリーンショットのアップロードを自動化し、作業効率を向上させることができます。
こんな感じでスレッド上でスクショを送り続けます。
Why
なぜこのBotを作ろうと思ったのかというと、勉強会などの機会にスクリーンショットのアップロード作業が手間だったからです。
毎回手動でスクリーンショットを撮影して、それをSlackにアップロードする必要がありました。
What
SnapBotを、作成しました!
- SlackAppとopenCVを使用して、画面の変化を検知してスクショをアップロードするBot
このBotを使用することで、スクリーンショットを自動的に取得し、Slackチャンネルにアップロードすることができます。以下に、Botの作成手順を説明します。
How
簡単に技術紹介します。
詳しくはレポジトリを参照してください!
SlackAppを作成
manifest.yamlを使用しました.
漏れやすいポチポチ設定を省けるのでめっちゃ便利。。
とりあえず、ファイルの読み書きを設定しました
display_information:
name: SnapBot
features:
bot_user:
display_name: SnapBot
always_online: true
oauth_config:
scopes:
bot:
- files:write
- files:read
settings:
interactivity:
is_enabled: true
org_deploy_enabled: false
socket_mode_enabled: true
token_rotation_enabled: false
スクリーンショット
スクリーンショットコマンドを使用しました。
import os
def screenshot():
os.makedirs("images", exist_ok=True)
os.system(
'screencapture -x -o -R0,0,1680,1080 ./images/$(date "+%y%m%d_%H%M%S")_image.png'
)
直近のスクリーンショットと差分を比較
opencvで画像の特徴量を抽出して差分を定量化しています
import cv2
import numpy as np
THRESHOLD = 10
def judge_image_difference(img1_path, img2_path):
diff = _image_difference(img1_path, img2_path)
print(diff)
return _judge_diff(diff, threshold=THRESHOLD)
def _image_difference(img1_path, img2_path):
# 画像読み込み
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 画像をグレースケールに変換
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 特徴量抽出器の生成
orb = cv2.ORB_create()
# 特徴量の検出と記述子の計算
_, des1 = orb.detectAndCompute(img1_gray, None)
_, des2 = orb.detectAndCompute(img2_gray, None)
# 特徴量のマッチング
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
# マッチングされた特徴点の距離の平均値を計算
dist_sum = 0
for match in matches:
dist_sum += match.distance
dist_avg = dist_sum / len(matches)
# 2つの画像の距離を計算
diff = np.abs(dist_avg)
return diff
def _judge_diff(diff, threshold=THRESHOLD):
if diff < threshold:
return True
else:
return False
スレッドへ送信
slack_sdk
を使用しました
Slack_Bot_tokenなどの変数は.env
に隠蔽しました
import logging
import os
from dotenv import load_dotenv
# Import WebClient from Python SDK (github.com/slackapi/python-slack-sdk)
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
load_dotenv()
# WebClient instantiates a client that can call API methods
# When using Bolt, you can use either `app.client` or the `client` passed to listeners.
client = WebClient(token=os.getenv("SLACK_BOT_TOKEN"))
def send_image_to_thread(is_true, image_path):
"""
与えられた判定結果と画像を使用して、スレッドに画像を送信する関数。
判定結果がTrueの場合は、画像をスレッドに送信します。
"""
if is_true:
try:
# Call the files.upload method using the WebClient
# Uploading files requires the `files:write` scope
result = client.files_upload_v2(
channels=os.getenv("CHANNEL_ID"),
thread_ts=os.getenv("THREAD_TS"),
file=image_path,
initial_comment="SNAP :camera:",
)
# Log the result
logger.info(result)
except SlackApiError as e:
print(f"Error: {e}")
else:
print("判定結果はFalseです。何もしません。")
気づき
- Slack Appの開発ハードルが低いことを知れた
- 充実したライブラリとパッケージ
- manifest.ymlを用いた再現性の高いアプリの構築
- Slackへのアクションまで一貫すると"自然"に使える
- 普段から使用するコミュニケーションツール上で動くのは、体験としてめっちゃ良かった
余談1
CopilotとChatGPTが大活躍して数日で要件通り動くものができました
MVPのハードルが下がっているのをめっちゃ感じました
余談2
記事に関しても骨子はChatGPTが作ってくれました、楽ちん