制作作品解説

DiscordのTimesをAIで要約するBotを作りたい!!【そこのお前シリーズ外伝】

制作のきっかけ

こんにちは、広島大学ゲーム制作同好会の元々副会長のニンです(先日GSDでは政権譲渡が発生し、先々代になりました)

さて、我々ゲーム制作同好会ではコミュニケーションツールとして、Discordを用いています。

そのDiscordの中では、皆さんが耳にしたことがあるかもしれない、Times文化というものがあります。

Times文化とは?
Slackなどで個人の分報チャンネルを作り、業務の進捗・思考・雑談などをリアルタイムでつぶやき、チーム内の状況をオープンにするコミュニケーション文化です。
Generated By Gemini 2.5Pro

このTimes文化、サークル員の人となりを知ることができたり、好きな話題で盛り上がれたり、くだらないことでふざけられたり、非常にいい文化です。

スタンプをつけれるのもDiscordのいい特徴ですね。リアクションに対するハードルが低くなる。画像はいわゆるクソリプ。

ただ、ありがたいことにサークルの規模が大きくなり、それに伴いTimesの数も増加してくると、なかなかすべてを追うのが非常に難しくなります。
親しい人のTimes追うのが精いっぱいで、あまり親しくない人のTimesはあとでまとめて……みたいな経験、あると思います。学園アイドルマスター!

そこで、タイトルのような機能をもつBotを作ってみようと思い立ち、作ってみました(即決即断思い立ったら即行動!!)。
一部機能が人力で、まだまだ発展しがいがありそうですが、サーバーとかAPIの値段などを考えてみるといったんこのくらいでまとめてみようと思い、記事にしています。

この先の自動化は君自身の目で確かめてくれ!!

制作方法

Discord Botの準備(開発者モードON)

もしOFFにしていたら、これを先にやっておきましょう。チャンネルIDの取得に必須です。

  • やり方:Discordの ユーザー設定 ⚙️ → 詳細設定開発者モードをONにする。

必要なキーを2つ取得する

Botを動かすための「秘密の鍵」を2つ手に入れます。いわゆるキーとかトークンってやつ。

Discord Botトークン

Discord Developer Portal にアクセスし、右上の New Application をクリックして新しいアプリを作成します。

風呂上がりに耳かきをすると、湿っている。

左のメニューから Bot タブを選びます。

Reset Token をクリックしてトークンを生成・表示し、コピーしてメモ帳などに保存します。(このページを離れると見えなくなります)

コラム:GSDには肉体改造部なる組織が存在しているらしい。噂では、歴代の副会長は必ず参加しなければいけないらしい。

同じページで、少し下にある MESSAGE CONTENT INTENT のスイッチを ON にします。これを忘れるとメッセージが読めません。きおつけなはれや!!

ユニコーンオーバーロード、めちゃくちゃ面白いです。おすすめ

最後に、Botをサーバーに招待します。左メニューの OAuth2URL Generator を選び、スコープで bot にチェックを入れ、下の権限で以下にチェックを入れてください。

  • View Channels (チャンネルを見る)
  • Send Messages (メッセージを送信)
  • Read Message History (メッセージ履歴を読む)

生成されたURLをブラウザで開き、Botを追加したいサーバーを選んで認証します。

OpenAPIキー

OpenAI Platform にアクセスします。

Create new secret key をクリックしてAPIキーを作成し、コピーしてメモ帳などに保存します。(これも一度しか表示されません)

初めて利用する場合は、クレジットカード情報などを登録して支払い設定を有効にする必要があります。
たぶん初めてだから入力しといてね。

プログラミングの準備

次に、PC上でBotのプログラムを開発する環境を整えます。

使用言語とライブラリ

開発にはPythonを使用し、Discordを操作するためのdiscord.py、APIキーを安全に管理するpython-dotenv、そしてChatGPTを利用するためのopenaiライブラリをインストールします。以下のコマンドをコマンドラインなどで実行してください。

pip install discord.py python-dotenv openai

*キス:Pythonをそもそもダウンロードしてないって人は、
生成AIに訊け!!!
長くなるからここでは省略しています。すんません……。すんません!!!!!!!!!!

プロジェクト構成

専用のフォルダを用意して、以下の4つのファイルを用意してください。

.env: DiscordとOpenAIのAPIキーを保存する、外部に見せてはいけないファイル。

config.py: 要約を投稿するチャンネルIDなど、設定を保存するファイル。

channels.json: コマンドで追加・削除するTimesチャンネルのIDリストを永続的に保存するファイル。

bot.py: Bot本体の全体像を記述するメインプログラム。

_pyacache_はなくても気にしなくていいよ!(一度実行すると生成されるキャッシュです)
が美が美過ぎないか?

Botのコード作成

では、実際にコードを作成しています。このコードをもとに好きにいろいろいじくってみてください。全部コピペでOKよ!!日本語のところは各自で入力してね。

.env

DiscordとOpenAIのAPIキーを保存するファイル。メモッた自分のキーとトークンを入れてみてね。
*キス:絶対に他人にこのファイルを見せてはいけません!

DISCORD_BOT_TOKEN= 自分のDiscordのAPIキーを入力してね
OPENAI_API_KEY= 自分のOpenAiのAPIキーを入力してね
config.py

まとめを投稿するチャンネルIDだけを記述する、シンプルな設定ファイルです。

# config.py
# 結果を投稿するチャンネルのID
SUMMARY_CHANNEL_ID =  # #まとめ チャンネルのIDをここに設定
channels.json

監視するDiscordのチャンネルのIDを補完するファイル。
これはファイルを作るだけで大丈夫です。(中には誰もいませんよ)

bot.py

以下がBotの全コードです。主な機能は次の通りです。コピペでOKです。

  • 手動実行: 管理者が!summaryコマンドを実行すると、要約生成プロセスが開始されます。
  • 昨日を対象: コマンドを実行した日の「前日1日分(0:00〜23:59)」の投稿を収集します。
  • チャンネル管理: !addchannelなどのコマンドで、どのTimesを監視対象にするかを柔軟に設定できます。
# bot.py
import discord
from discord.ext import commands
import os
import openai
from dotenv import load_dotenv
from datetime import datetime, timedelta, timezone
import json
import config

# --- 初期設定 ---
load_dotenv()
DISCORD_BOT_TOKEN = os.getenv('DISCORD_BOT_TOKEN')
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
if OPENAI_API_KEY:
    openai.api_key = OPENAI_API_KEY

intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)

CHANNELS_FILE = 'channels.json'
target_channel_ids = set()

# --- ファイル操作 ---
def load_channels():
    global target_channel_ids
    try:
        with open(CHANNELS_FILE, 'r') as f:
            target_channel_ids = set(json.load(f))
    except FileNotFoundError:
        target_channel_ids = set()

def save_channels():
    with open(CHANNELS_FILE, 'w') as f:
        json.dump(list(target_channel_ids), f, indent=4)

# --- AI要約 ---
def summarize_text_with_gpt(text):
    if not text.strip(): return "対象期間の投稿はありませんでした!"
    prompt = f"以下のDiscordのTimes投稿群を、親しみやすい言葉で要約してください。\n\n---\n{text}\n---\n\n要約結果:"
    try:
        response = openai.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "system", "content": "あなたは優秀なアシスタントです。"}, {"role": "user", "content": prompt}],
            max_tokens=500, temperature=0.7,
        )
        return response.choices[0].message.content
    except Exception: return "すみません、AIによる要約中にエラーが発生しました。"

# --- 要約作成のメイン処理 ---
async def create_yesterday_summary():
    JST = timezone(timedelta(hours=+9), 'JST')
    now = datetime.now(JST)
    until = now.replace(hour=0, minute=0, second=0, microsecond=0)
    since = until - timedelta(days=1)
    
    all_texts, top_post, max_reactions = "", None, -1
    for channel_id in target_channel_ids:
        channel = bot.get_channel(channel_id)
        if not channel: continue
        async for message in channel.history(after=since, before=until):
            if message.author.bot: continue
            all_texts += f"{message.author.display_name}: {message.content}\n"
            reaction_count = sum(r.count for r in message.reactions)
            if reaction_count > max_reactions:
                max_reactions, top_post = reaction_count, message

    summary = summarize_text_with_gpt(all_texts)
    summary_channel = bot.get_channel(config.SUMMARY_CHANNEL_ID)
    if not summary_channel: return

    embed = discord.Embed(title=f"📅 {since.strftime('%Y年%m月%d日')}のTimesまとめ", description=summary, color=discord.Color.blue())
    if top_post:
        embed.add_field(name="🎉 昨日のNo.1投稿!", value=f"**{top_post.author.display_name}** さんの[この投稿]({top_post.jump_url})でした! (リアクション数: {max_reactions})", inline=False)
    await summary_channel.send(embed=embed)

# --- コマンド ---
@bot.command(name='summary')
@commands.has_permissions(administrator=True)
async def summary_command(ctx):
    await ctx.send("📝 昨日の投稿の要約を作成します。少し時間がかかります...")
    await create_yesterday_summary()

@bot.command()
@commands.has_permissions(administrator=True)
async def addchannel(ctx, channel: discord.TextChannel):
    target_channel_ids.add(channel.id)
    save_channels()
    await ctx.send(f"👍 チャンネル <#{channel.id}> を監視対象に追加しました。")

@bot.command()
@commands.has_permissions(administrator=True)
async def removechannel(ctx, channel: discord.TextChannel):
    target_channel_ids.discard(channel.id)
    save_channels()
    await ctx.send(f"🗑️ チャンネル <#{channel.id}> を監視対象から削除しました。")

@bot.command()
@commands.has_permissions(administrator=True)
async def listchannels(ctx):
    if not target_channel_ids:
        await ctx.send("現在、監視対象のチャンネルはありません。")
        return
    channel_links = [f"<#{cid}>" for cid in target_channel_ids]
    await ctx.send("現在、以下のチャンネルを監視しています:\n" + "\n".join(channel_links))

# --- 起動 ---
@bot.event
async def on_ready():
    print(f'Logged in as {bot.user.name}')
    load_channels()

bot.run(DISCORD_BOT_TOKEN)

使用コマンド

昨日の投稿を要約するには、「!summary」 と入力します。

監視するチャンネルを追加するには、「!addchannel #チャンネル名 」のように入力します。

監視からチャンネルを外すには、「!removechannel #チャンネル名 」と入力します。

監視中の全チャンネルを確認するには、「!listchannels」 と入力します。

実行結果

開発したBotを実際に動かしてみます。 まず、自身の制作したファイルがあるフォルダに移動してください。フォルダ移動の仕方がわからない方、
生成AIに訊け!!!
移動できたら、以下のコマンドをコマンドラインで実行してみてください.

python bot.py

そしたら、コマンドラインで実行しながら、Discordで!addchannelコマンドで監視したいTimesチャンネルを複数登録します。その後、自分の好きなタイミングで!summaryコマンドを実行すると、Botが応答し、バックグラウンドで要約の作成を開始します。

数秒〜数十秒待つと、指定したまとめ用チャンネルに、昨日の投稿の要約が投稿されます。

できた!!やったね!!!
記事執筆してるのが深夜なのがバレバレだね。

作ってみた感想

はい、初めてのBot開発でしたが、いかがだったでしょうか。
初心者がこれだけのものをすぐ作れるのは、すごい時代だなぁと思ってしまいますな。
Gemini君の力をだいぶ借りましたが、個人的にはいいモノを作れたと思うので大満足です。
自分の研究でも似たようなこと(認知負荷を軽減する的なもの)をしているので、いい経験になった気がします。
良ければぜひぜひ制作して利用してみてくださいね。

注意事項

当たり前ですが、お金がかかります!!GPT4o-miniを使っているのでまあよほどのことがない限り大丈夫だと思いますが。なんか最近エラーで異常な金額が要求されたみたいな話も聞いたので、くれぐれも自己責任で!!

あと、エラーが起きた場合の最強の解決方法を教えます。これは唯一にして絶対の方法です。

生成AIに訊け!!!

このサイトの筆者、コードの説明書いてないじゃん、という人、

生成AIに訊け!!!

この記事なんか読みずらいな……要約してくれないかな

生成AIに訊け!!!

じゃあな!

タイトルとURLをコピーしました