Slackの盛り上がりを検出するbotを作った

みなさんリモートワークしてますか? リモートワークのときのコミュニケーションツールはSlackですか?Chatworkですか?Discordですか?

リモートワークをしていると,全体的にコミュニケーション量は減ると思います. オフィスにいれば,たとえSlackで会話していても,周囲からそれとなく笑い声とか聞こえてきて「ああ,time-h3potetoが盛り上がってるらしいぜ」みたいなことが分かったりしますが,リモートしているとこういうことに気づくタイミングがありません. timeチャンネルなんかを作っていると特にそうですが,自分のtime以外って,そんなに頻繁に見に行っているわけでもないので,知らないうちに盛り上がっていても気づけなかったります.

というわけでこの「time-h3potetoが盛り上がってるみたい」を検出して通知してくれるSlack botを作りました.

github.com

見た目

どこかのチャンネルが盛り上がると,こんな感じで通知してくれる.

f:id:h3poteto:20200312174754p:plain

このbotは参加しているチャンネルの会話しかモニタリングしないので,参加していないチャンネルが盛り上がっていても残念ながら検出できない. とりあえずインストールしたら,いろんなチャンネルにinviteしよう.

また,盛り上がりが検出された場合に,どこのチャンネルに通知してほしいかというのは,botの起動コマンドで選べる.

使い方

そんなわけで使い方. goで作ったCLIなので,だいたいどこでも動くけど,Docker Imageを用意してあるのでそっちを使ったほうが楽である.

このbotはEventAPIを使ったbotと,RTMを使ったbot,両方を実装してある.どちらもやることは同じなので,どっちで起動してくれても構わない. オプションは event でも rtm でも,同じ引数を取るようになっている.

$ ./slack-rage event --channel=random --period=1200 --threshold=10

みたいにして使う.

--channel は,盛り上がりを検出した際に,どのチャンネルに通知するかを指定する.存在しないチャンネルの場合は,通知時にエラーになる.

--period--threshold は,盛り上がり検出のしきい値を指定する.このbotは,とあるチャンネルで period 秒以内に threshold 以上のメッセージが投稿された際に,盛り上がりと判定する.ただし,threshold 件のメッセージは会話になっている必要があるので,会話参加人数が2人以上だった場合に盛り上がりと判定している(botは除く).独り言をどれだけ繰り返しても盛り上がりとは判定されない.

デフォルトでは,1200秒以内に10投稿あった場合に盛り上がりと判定している.が,ここは導入する組織の会話度合いに応じてちょうどいい値を見つけてほしい.

また,継続的に盛り上がっているチャンネルの場合,投稿されるたびに盛り上がり検出され通知されてしまう.これを防ぐため,一度通知すると10分間はクールタイムとして,同じチャンネルに関する盛り上がりは通知しなくなる.

インストール方法

RTM

現在,新しいSlack Appは,RTMをサポートしていない.

New Slack apps may not use any Real Time Messaging API method. Create a classic app and use the V1 Oauth flow to use RTM.

api.slack.com

そのため,RTMを使ったbotを使う場合は,Classic Slack Appを作る必要がある. ここからAppを作成し,Botsを有効化して,Workspaceにインストールする.

すると, OAuth Access TokenBot User OAuth Access Token を取得できる.この両方を環境変数にセットしてやる必要がある. これをセットして,どこかのサーバでDocker Imageを起動する.

$ docker run --rm -e SLACK_TOKEN={BotUserOAuthAccessToken} -e OAUTH_TOKEN=${OAuthAccessToken} h3poteto/slack-rage

Classic Slack Appで,botを有効化すると,OAuth & Permissions にはデフォルトで bot というScopeが有効になっている. この他に,

  • channels:history
  • channels:read
  • chat:write:bot
  • user:read

が必要になるので,これを与える.

f:id:h3poteto:20200312175201p:plain

これで,botは動く状態になった. あとは,盛り上がりを検出してほしいチャンネルに,このbotをinviteしよう.

Event API

新しくSlack App を作る.Bots を有効化して,Workspaceにインストールする. すると,Bot User OAuth Access Token が手に入るので,これを環境変数にセットして,サーバ上でDocker Imageを起動する.

$ docker run --rm -e SLACK_TOKEN={BotUserOAuthAccessToken} h3poteto/slack-rage event

ちなみに,Event APIは,いわゆるWebhookをSlackから受け取るという方式なので,インターネットからアクセスできるサーバが必要になる. event で起動すると,こいつは 9090 ポートでHTTPサーバを起動する.ここに,適当なドメインを振って(slack-rage.example.com)外部からアクセスできるようにしておく.

Slack Appに戻り,Event Subscriptions を有効化するとURL入力を求められるので,先程設定したドメイン(slack-rage.example.com)を入れる.このとき,URLの確認リクエストが飛んでくるので,この段階ですでにslack-rage.example.comでは,slack-rageが動いている必要がある.

次に,Subscribe to bot events に, message.channels を追加する.これで,メッセージが投稿されるたびにWebhookが飛ぶようになる.

f:id:h3poteto:20200312175225p:plain

そして,OAuth & PermissionsScopes

  • channels:history
  • channels:read
  • chat:write
  • users:read

を追加する.

f:id:h3poteto:20200312175237p:plain

これで,botが動く状態になる. あとは,盛り上がりを検出してほしいチャンネルに,このbotをinviteしよう.

バグとかやりたいこととか

Event APIを使っていると,たまにほぼ同タイミングで同じイベントが重複して送られてくることがある. これの原因がわかっていないのと,原因がなんであるにしろ重複イベントを無視する機構を入れたいとは思っている. 現状,重複イベントが送られると,クールタイム判定が間に合わずに多重検出される場合がある.

また,会話人数カウントの際にbotは除外しているのだが,会話数の判定時にはbot判定ができていないので,これを入れたい.SlackのAPI構造的に,messageから取得できるのはUserIDまでで,IsBotの判定は都度 users.info を取りに行かなければならない.

他にやりたいこととしては,会話の参加人数やクールタイムも引数で取るようにしてしまいたい. おそらく人数が多い組織だと,2人の会話というのはそんなに盛り上がっている,みんなで見に行くべき盛り上がりではないような気がしている.

が,とりあえずなんか見つけたらIssueにしてください.別にPullRequestにしてくれてもいいですよ.