🗨️

DiscordBot「まとめくん」をつくった

に公開

はじめに

社内でDiscordサーバーで日々のアイデア出しに役立つ情報や気になる記事などを投稿するチャンネルを運用しています。そこで月に一回まとめ記事を作っていました。それが案外手間だったため、自動化するべく、Botを作成するにいたりました。毎月自動で前月の投稿を収集し、Gemini APIを使っていい感じに要約して再投稿しています。

作ったもの

「Discord月次まとめBot」

機能: 指定したチャンネルの過去1ヶ月分の投稿を取得。
AI: Google Gemini 2.5 Flash を使用して、記事のリンクと1行説明だけの極めてシンプルなリストに要約。
運用: GitHub ActionsのCronで毎月1日に完全自動実行。
技術スタック
Runtime: Node.js (v20)
Library: discord.js
AI Model: Gemini 2.5 Flash
CI/CD: GitHub Actions (Schedule trigger)

仕組みの全体像

  1. GitHub Actionsが起動: 毎月1日 10:00にCronでトリガー。
  2. Discordから取得: discord.jsを使い、指定したチャンネルから「先月1日〜当月1日」のメッセージを全取得。
  3. AI要約: チャンネルごとにメッセージ本文をまとめ、Gemini APIに投げる。
  4. 整形: 返ってきた要約文を一つのメッセージに結合。
  5. Discordへ投稿: まとめチャンネルに送信。

準備編:Discord Botの作成

まずはDiscord上でBotを動かすための準備をします。

Developer Portalでのアプリ作成

Discord Developer Portalにアクセスし、「New Application」からアプリケーションを作成します。
左メニューの「Bot」からBotユーザーを追加し、「Reset Token」でBot Tokenを取得します。これは後で使います。

重要な権限設定 (Message Content Intent)

今回のBotは「メッセージの中身を読んで要約する」ため、以下の設定が必須です。

Bot設定ページの下部にある "Message Content Intent" をONにする。
これを忘れると、Botはメッセージを取得できても中身が空文字になってしまいます。

サーバーへの招待

「OAuth2」>「URL Generator」から招待URLを発行します。

SCOPES: bot
BOT PERMISSIONS:
Read Messages/View Channels
Send Messages
Read Message History
発行されたURLから、Botを自分のサーバーに招待してください。

実装編:Node.jsでBotを作る

次に、ローカルでプログラムを作成します。
使用した主なライブラリ:
discord.js:Discord API操作
@google/generative-ai:GeminiAPI

プロジェクト作成

npm init -y
npm install discord.js @google/generative-ai dotenv

プロンプトの調整

もともと手動でまとめていたころのフォーマットがあったため、それにそってまとめるように調整しました。ざっくり以下のような感じ。

提供された例のように、マークダウンリンク形式で簡潔にまとめてください。
各トピックについて、以下の形式を厳守してください: [タイトル](URL) by 投稿者名 そのトピックの説明(1〜2行。何が画期的か、どのようなものか、チャンネル内のコメントや反応を反映して記載)
「要点:」「詳細:」などの見出しは不要です。

運用編:GitHub Actionsで定期実行

Botができたら、GitHub Actionsを使ってサーバーレスで定期実行させます。

name: Monthly Summary

on:
  schedule:
    # 毎月1日 JST 10:00 に実行
    # JST = UTC+9 なので、JST 10:00 = UTC 01:00
    - cron: '0 1 1 * *'
  workflow_dispatch: # 手動実行も可能にする
    inputs:
      dry_run:
        description: 'Dry Run (投稿せずにテスト実行)'
        required: false
        default: false
        type: boolean

jobs:
  summarize:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run monthly summary
        env:
          DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
          DISCORD_GUILD_ID: ${{ secrets.DISCORD_GUILD_ID }}
          SOURCE_CHANNEL_IDS: ${{ secrets.SOURCE_CHANNEL_IDS }}
          SUMMARY_CHANNEL_ID: ${{ secrets.SUMMARY_CHANNEL_ID }}
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          GEMINI_MODEL: ${{ secrets.GEMINI_MODEL }}
          TIMEZONE: ${{ secrets.TIMEZONE }}
          # 手動実行時は入力値を使用、スケジュール実行等の場合はfalse(投稿する)
          DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} 
        run: npm run start

環境変数の設定 (Secrets)

BotのTokenやAPIキーは、GitHubリポジトリの Settings > Secrets and variables > Actions に登録します。これでコード内にキーを書くことなく安全に実行できます。

GitHubActionsでの実行

今回、初めてGitHubActionsを使いました。

GitHubActionsでできること

サーバーレスでの定期実行 (schedule)
cronでスケジュールを記述するだけで、決まった時間に環境を立ち上げ、スクリプトを実行し、終了後に破棄してくれます。 コストをかけずにBot運用できるのがメリットです。

安全な秘匿情報の管理 (secrets)
散々GitHubを使ってきて全く知らなかったのですが、実はSecretIDをリポジトリの設定で保存できます(初知り)。そこに記入しておけばワークフロー内から ${{ secrets.MY_KEY }} のように安全に参照できるのでとても便利です。

柔軟な手動実行と入力 (workflow_dispatch)
ブラウザ上のGUIにのCheckboxを置いたりもできます。これにより、コードを書き換えずに本番/テスト挙動を切り替えられます。

Dry Runモードの実装

「プロンプトを調整したいけど、毎回Discordに投稿されるのは困る」という時のために、workflow_dispatch(手動実行)時に dry_run オプションを選べるようにしました。 これにチェックを入れると、Discordへの投稿APIだけスキップし、生成されたテキストをGitHub Actionsのログに出力して終了します。これがデバッグ時に非常に便利でした。

まとめ

以前は私が手動でまとめていたので、どうしても「私が興味があるかどうか」のフィルターを通したまとめになってしまっていたところがありました。それを第三者の誰でもないものがまとめてくれるので良いものになります。

Discussion