1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Slack × Dify で「指定日の自分の投稿を自動要約」する SelfLog ボットを作った話

1
Posted at

はじめに

Slack を使っていると、
「あれ、今日何やったっけ?」
「昨日どんなことを投稿したんだっけ?」
と振り返りたい瞬間がよくあります。

特にタスク管理や学習ログ、自分用のメモを Slack に残している人ほど、
“まとめてチェックしたいのに探すのが面倒” というジレンマに陥りがちです。

そこで今回は、Slack にメンションするだけで、指定日の自分の投稿を自動で収集し、LLM が要約して返してくれる「SelfLog ボット」 を Dify(クラウド版)だけで構築しました。

やりたかったこと

Slack にて、

@SelfLog 2025/12/6の投稿まとめて

とメンションするだけで、

  • 指定日の自分の投稿を複数チャンネル横断で取得
  • Bot への指示メッセージ(メンションなど)は除外
  • 必要なメッセージのみ抽出してまとめる
  • LLM が 1 日の振り返りを要約してくれる
  • 要約結果をメンションスレッドに返す
    という 「Slack 日報自動作成ボット」 を Dify(クラウド版)だけで構築しました。

この記事では、同じものを誰でも再現できるように 具体的なノード構成・コード・プロンプトのすべて をまとめていきます。


全体アーキテクチャ

作成したワークフローはおおむね次のような流れです:
スクリーンショット 2025-12-07 20.42.07.png

Slack @mention  
   ↓  
extract_date(LLMで日付解析)  
   ↓  
parse_date_json(PythonでUNIX秒レンジ生成)  
   ↓  
get_channels(Bot が参加しているチャンネル一覧)  
   ↓  
parse_channels(チャンネルID配列を作成)  
   ↓  
multi_fetch_and_extract(全チャンネル巡回&自分の投稿抽出)  
   ↓
IF(投稿が空かどうか)
   ├ True → reply_to_slack_empty
   └ False → summarize(LLM) → reply_to_slack

事前準備&ハマりポイントまとめ

実装してみて「ここでつまずきやすいな」と感じたポイントを、最初にまとめておきます。

1. 要約対象チャンネルに Slack アプリを追加しておく

SelfLog ボットは、アプリが参加しているチャンネルの投稿しか読めません。
たとえば、次のようなイメージです:
#random にも自分のメモを残している
#dev-memo にも技術メモを残している
どちらも要約対象にしたいという場合、それぞれのチャンネルで アプリを招待する必要があります。

#random チャンネルで:
/invite @SelfLog
#dev-memo チャンネルで:
/invite @SelfLog

これをやっておかないと、
「ワークフローは正常終了しているのに、全然メッセージが拾われない…」
という状況になります。

2. Slack Bot Token を環境変数に仕込んでおく

Dify から Slack API を呼び出す際は、Slack Bot Token(xoxb- で始まるやつ) を使います。Dify 側では、アプリの「環境変数」に以下のような形で設定しておくと便利です。

SLACK_BOT_TOKEN = xoxb-xxxxxxxxxxxxxxxxx

そして HTTP ノードのヘッダーでは、次のように参照します:

Authorization: Bearer {{ env.SLACK_BOT_TOKEN }}

3. Slack App のパーミッション設定

メッセージ取得とチャンネル一覧取得のためには、
Slack App 側で適切な Scope を付与しておく必要があります。
一例として、以下のような Scope を付けておくとスムーズです(ワークスペースのポリシーに合わせて調整)。

  • channels:history
  • groups:history
  • channels:read
  • groups:read
  • users:read

Scope を追加したあとは 必ず「再インストール」 して反映させるのを忘れずに。


具体的な手順

1. Slack からトリガーを受ける

Dify の「アプリ連携 → Slack」で作成。
トリガーは App Mention に設定し、
raw_payload.event.textraw_payload.event.user を取得します。

2. extract_date(「LLM」ブロックで実装)

Slack で以下のように指示します。

  • @SelfLog 12/5 のメモまとめて
  • @SelfLog 2025-12-06 まとめて

メッセージ文から 日付を抽出して JSON で返す ノードです。

▼ System プロンプト

あなたはSlackメッセージから対象日を抽出するアシスタントです。

要求

  • 入力されるテキストには、「2025-12-05」「12/5」などの日付表現が含まれます。

  • JST(Asia/Tokyo)を前提に

    • その1日の "date"(YYYY-MM-DD)
    • その日の 00:00:00 JST のUNIX秒 “oldest”
    • その日の 23:59:59 JST のUNIX秒 “latest”
  • 日付が明示されない場合は「昨日」

  • 出力は以下の JSON のみ:

{
  "date": "YYYY-MM-DD",
  "oldest": 1701711600,
  "latest": 1701797999
}

▼ User プロンプト

メンションされたSlackメッセージ:
{{ raw_payload.event.text }}

3. parse_date_json(「コード」ブロックで実装)

LLM から返ってきた JSON をパースし、
その日の UNIX 秒レンジ(0:00〜23:59:59)を決定します。

以下の Python コードを Code ノードにそのまま貼ります:

from datetime import datetime, timedelta, timezone
import json

def main(raw_json: str) -> dict:
    try:
        data = json.loads(raw_json)
    except Exception:
        return {
            "summary_date": "",
            "oldest_ts": "",
            "latest_ts": ""
        }

    date_str = data.get("date")
    if not date_str:
        return {
            "summary_date": "",
            "oldest_ts": "",
            "latest_ts": ""
        }

    tz = timezone(timedelta(hours=9))
    d = datetime.strptime(date_str, "%Y-%m-%d").replace(tzinfo=tz)

    oldest = int(d.timestamp())
    latest = int((d + timedelta(days=1, seconds=-1)).timestamp())

    return {
        "summary_date": date_str,
        "oldest_ts": str(oldest),
        "latest_ts": str(latest),
    }

4. get_channels(「HTTPリクエスト」で実装)

Slack API users.conversations を使って
Bot が参加しているすべてのチャンネル一覧を取得します。

設定:

  • Method: GET

  • URL: https://slack.com/api/users.conversations

  • headers:

    • Authorization: Bearer {{ env.SLACK_BOT_TOKEN }}
  • Query:

    • user = {{ AppMention/raw_payload.event.user }}
    • types = public_channel,private_channel

※ Bot がメッセージ取得対象となるには、各チャンネルで
/invite @SelfLog を実行する必要があります。

5. parse_channels(「コード」ブロックで実装)

get_channels のレスポンスから
channels_ids = ["C0A1...", "C0A2...", ...]
という配列を抽出するノードです。

  • 入力変数:

    • body = {{ get_channels/body }}
  • プロンプト:

import json

def main(body) -> dict:
    # body は JSON文字列 or dict の想定
    if isinstance(body, str):
        try:
            data = json.loads(body)
        except Exception:
            data = {}
    elif isinstance(body, dict):
        data = body
    else:
        data = {}

    channels = data.get("channels", [])

    channel_ids = []
    for c in channels:
        if isinstance(c, dict) and c.get("id"):
            channel_ids.append(c["id"])

    # 例: ["C01...", "C02...", ...]
    return {
        "channels_ids": channel_ids
    }
  • 出力変数:
    • 変数名: channels_ids
    • 型: Array[String]

6. multi_fetch_and_extract(「コード」ブロックで実装)

このノードが 自動ログ収集の中心処理 です。

やっていること:

  1. channels_ids の配列を for ループでまわす
  2. 各チャンネルに対して conversations.history API を叩く
  3. 指定日のメッセージのみ取得
  4. 投稿者が target_user のメッセージのみ抽出
  5. Bot への指示文(メンション)は除外
  6. - [チャンネルID] テキスト の形式でまとめる
  7. 全チャンネル分を結合して返す

結果例:

- [C0A1GJ0QB4P] 〇〇についてメモ
- [C0A1AEGLB3J] 資料作成中

7. IF / ELSE

  • all_messages_text空なら → 投稿なしルート
  • 空でなければ → 要約生成ルートへ

8.(True)summarize_empty(「LLM」ブロックで実装)

「対象日の投稿はありませんでした」を生成する LLM ノードです。


9. reply_to_slack_empty(「HTTPリクエスト」ブロックで実装)

Slack API chat.postMessage を用いて
空結果メッセージをスレッド返信します。


10.(False)summarize(「LLM」ブロックで実装)

投稿ログを入力し、
3〜5 行で要約するように LLM に依頼します。

プロンプト例:

以下は {{ parse_date_json.summary_date }} にあなたがSlackに投稿した一覧です。

{{ multi_fetch_and_extract.all_messages_text }}

これを踏まえて、1日の行動を3〜5行で要約してください。

11. reply_to_slack(「HTTPリクエスト」ブロックで実装)

Slack API chat.postMessage を使い、
要約結果をスレッドに投稿します。


📌 まとめ

今回構築した SelfLog ボットができること:

  • @mention するだけで 1 日分の自分の投稿を抽出
  • Bot への指示文は自動除外
  • 複数チャンネル横断で収集
  • 投稿なしの場合も適切に返答
  • 投稿ありなら LLM が自動要約
  • すべて Dify(クラウド版)のみで実装可能

とても実用的で、Slack を使う日常業務の振り返りが一瞬でできるようになります。


✨ おわりに

生成AIに聞きながら構築しましたが、予想以上に時間がかかってしまいました。
しかし、この仕組みは例えば以下のようなものにも応用が効くと考えております。

  • トピック分類
  • 感情分析
  • 週報・月報の自動生成
  • チームのサマリーボット

今後もDifyを使ってアプリ作成していきたいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?