Slack APIで自分のリアクション数をスマートに集計しよう！

# はじめに
新卒社員の備忘録、第2弾ですฅ^>ω<^ฅ
Python初挑戦！！

### きっかけ
今年度の目標を達成するためのアクションの一つとして、「他者の発言や投稿に対してリアクションまたはコメントする」というプランを設定しました(とっても真面目)

なのでこのアクションができているかを証明するために、自分のSlackのリアクション数を集計したらいいのではΣ(*ﾟдﾟ*)ﾊｯ!!となり、尊敬している先輩の記事を参考に、Slackの月別リアクション数を集計をしてみました!!

先輩の記事はこちら：

https://qiita.com/Himeka_Kawaguchi/items/66cce374a88c243c439d

https://qiita.com/Himeka_Kawaguchi/items/dfed601108f7caa62009


### 集計してみた
実行結果がこちらです↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3878743/04f42ba9-fca5-8816-2e2a-a9c6a29127cb.png)


指定したユーザー(私)が参加してるすべてのチャンネルを取得し、そのユーザーがリアクションした数を月別に出力することができました！！！

### Tableauで可視化
見えやすいようにTableauでビジュアルを作りました(^^♪
せっかくなので、載せておきます！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3878743/df2c2669-fd22-c061-3a1d-a23a8b10a53e.png)

※集計日が異なるため、結果が上記とは違います<(_ _)>


では次に手順説明↓

# 実際に行ったこと

たったの3工程！とても簡単にできました☆彡

**1\. Slackアプリを作成** 
**2\. SlackのSDKをインストール**
**3\. VisualStudioでPythonコードを実行**


### 手順1:Slackアプリを作成

この手順は先輩の記事↓をご参照ください<(_ _)>


https://qiita.com/Himeka_Kawaguchi/items/66cce374a88c243c439d


### 手順2:SlackのSDKをインストール
コマンドプロンプトを開き、以下を実行します。

    py -m pip install slack-sdk

SDKとは何ぞ？？？？と初心者の私は思いました。
この記事を読んで理解できたので載せておきます

https://qiita.com/seratch/items/8f93fd0bf815b0b1d557

これで簡単にアプリを開発できる！！！！！！

### 手順3:VisualStudioでPythonコードを実行

VisualStudioで実行ボタンを押すと、Terminal上に結果が出力されます！

実行させたコードはこちら↓

```ruby:slack_reaction_count.py
from collections import defaultdict
from datetime import datetime
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

# トークン
SLACK_API_TOKEN = "自分のSlackAPIトークン"
# 特定ユーザーのID
USER_ID = "SlackユーザーID" 

# トークン情報を格納しておく
client = WebClient(token=SLACK_API_TOKEN)

# limitには取得したい上限数、oldestには集計開始日のUNIX時間を指定(ここでは2024年4月1日を指定)
def get_conversations_history(channel_id, limit=1000, oldest=1711897200.0):
    """指定したチャンネルから会話履歴を取得する関数"""
    try:
        response = client.conversations_history(channel=channel_id, limit=limit, oldest=oldest)
        print(f"Retrieved {len(response['messages'])} messages from channel {channel_id}.")
        return response
    except SlackApiError as e:
        print(f"Error retrieving conversations for channel {channel_id}: {e.response['error']}")
        return None

def count_monthly_reactions(response, user_id):
    """指定したユーザーの月別リアクション数をカウントする関数"""
    monthly_reaction_counts = defaultdict(int)
    reacted_message_count = 0
    reaction_user_count = 0

    for post in response['messages']:
        # リアクションのあった投稿を取り出す。
        if 'reactions' in post:
            reacted_message_count += 1
            timestamp = float(post['ts'])
            post_month = datetime.fromtimestamp(timestamp).strftime("%Y-%m")
            
            for reaction in post['reactions']:
                # 特定のユーザーがリアクションを付けた場合
                if user_id in reaction['users']:
                    reaction_user_count += 1
                    monthly_reaction_counts[post_month] += 1
                    print(f"User {user_id} reacted in month {post_month}.")

    print(f"Processed {reacted_message_count} messages with reactions.")
    print(f"User {user_id} has reacted {reaction_user_count} times.")
    return monthly_reaction_counts

def get_joined_channels(user_id):
    """指定したユーザーが参加しているチャンネルを取得する関数"""
    try:
        channels = []
        result = client.users_conversations(types="public_channel,private_channel", user=user_id, limit=1000)
        channels.extend(result["channels"])
        return channels
    except SlackApiError as e:
        print(f"Error retrieving channels for user {user_id}: {e.response['error']}")
        return []

# 指定したユーザーが参加しているすべてのチャンネルを取得
channels = get_joined_channels(USER_ID)

if channels:
    global_monthly_reaction_counts = defaultdict(int)

    for channel in channels:
        channel_id = channel["id"]
        response = get_conversations_history(channel_id)

        if response:
            monthly_reaction_counts = count_monthly_reactions(response, USER_ID)
            for month, count in monthly_reaction_counts.items():
                global_monthly_reaction_counts[month] += count

    # 月別のリアクション数を表示
    print(f"User {USER_ID}が参加しているすべてのチャンネルの月別リアクション数です：")
    for month, count in sorted(global_monthly_reaction_counts.items()):
        print(f"{month}: {count}個のリアクション")
else:
    print("No channels retrieved or an error occurred.")
```

ここだけの話、コードはAI先生に書いてもらえるし、先輩のお手本もあるしでほぼ完成状態でした(感謝)

# 今後の展望
### スレッド内のリアクションを含めたい
実は上記のコードでは、チャンネル内のメッセージのリアクションしか集計されておらず、スレッド内のリアクションは含まれていないです。


理由としては、スレッド内のリアクションも含めて集計すると以下のエラーが出たからです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3878743/a39468a4-08d0-f14f-87d9-6fb4ef5468cd.png)


調べてみると、ratelimited（レートリミットエラー）は、一定期間に多くのAPIリクエストを送信しすぎた場合に発生するエラーだそう。Slack APIには短時間で発行できるリクエストの数に制限がありました。

今回は時間の都合上、メッセージのリアクション数だけの集計に(~_~;)
いつかリベンジします🔥🔥

# おわりに
今回のリアクション集計を通して、プログラムを書くときは一気にゴールを目指すのではなく、細分化して目指すということを学びました。

具体的に説明すると、

**1.お手本のコード（先輩の記事より）が実行できるか確認する**
**2.特定のチャンネルで指定したユーザのリアクション数を集計する(合計値)**
**3.月別に集計するように変更**
**4.ユーザーが参加してるすべてのチャンネルで集計する**

と段階を踏んで、AIにコードを生成させました～～



おわり✨