🤖

ChatGPTを用いたDiscordBot作成

2023/02/28に公開約4,000字

先日立ち上げたDiscord Serverを便利にしたいと思い、「特定のスタンプを押したらあるチャンネルでシェアするBot」を作りました。
ChatGPTの使い方と合わせて共有です。

  1. プロンプト
  2. プロンプトの改良
  3. リファクタリング
  4. デプロイ
  5. 振り返り

プロンプト

初期プロンプトは以下です。

あなたはプロのエンジニアです。

以下の要件のコードを作成してください。
- Discordのbot
- 投稿に絵文字がついた際に発火
- その投稿のURLをあるチャンネルに投稿する
- 絵文字は特定のカスタム絵文字である
また、コードは以下のサンプルから書き始めてください。

ステップバイステップで考えてください。
  • 役割
  • 要件
  • Zero-shot CoT文(ステップバイ~)

の構成にしています。

出力結果です。

import discord

client = discord.Client()

@client.event
async def on_message(message):
    if message.author.bot:
        return
    if message.content:
        if "絵文字名" in message.content:
            channel = client.get_channel(チャンネルID)
            await channel.send(message.jump_url)

client.run("Botのトークン")

この際以下の問題が生じました。

  • discord.Client()の引数が足りないことによるエラー
  • on_message()などの全体の挙動

まず、旧バージョンの仕様に存在しなかったintentsという引数が増えておりエラーが発生しました。
https://zenn.dev/disneyresidents/articles/discordintents

また理想の挙動が達成できず、on_message()はメッセージを受け取った際に発火する関数であることがわかりました。
理想は「リアクションがついた時」です。
discord.pyのドキュメントを読んだところon_reaction_add()という関数を使えば絵文字の追加を検知できることがわかりました。

プロンプトの改良

上記の課題を受け、2,3度の改良を経て以下のプロンプトになりました。

あなたはプロのエンジニアです。

以下の要件のコードを作成してください。
- Discordのbot
- 投稿に絵文字がついた際に発火
- その投稿のテキストの最初の100文字とURLをあるチャンネルに投稿する
- 投稿の際には最初に「知見がシェアされましたワン!」をつける
- 絵文字は特定のカスタム絵文字である
- `discord.on_reaction_add(reaction, user)`を必ず使用する

ステップバイステップで考えてください。

要件を明確にし、「discord.on_reaction_add(reaction, user)を必ず使用する」といった文章を追加している部分が大きな変化です。

出力結果は以下となりました。

import discord

client = discord.Client()

target_channel_id = 1234567890  # 適切なチャンネルのIDに置き換える

@client.event
async def on_ready():
    print("Bot is ready.")

@client.event
async def on_reaction_add(reaction, user):
    if str(reaction.emoji.name) == TARGET_EMOJI:
        message = reaction.message
        message_text = message.content[:100]
        message_url = message.jump_url
        post_message = f"知見がシェアされましたワン!\n\n{message_text} {message_url}"
        channel = client.get_channel(target_channel_id)
        await channel.send(post_message)

client.run('your_bot_token')

この後intens引数の追加,発火処理の制限などを加え完成コードとなっています。

import discord

client = discord.Client(intents=discord.Intents.適切な権限()) #追加

target_channel_id = 1234567890  # 適切なチャンネルのIDに置き換える

@client.event
async def on_ready():
    print("Bot is ready.")

@client.event
async def on_reaction_add(reaction, user):
    #reaction.conntが1じゃない場合return 
    if reaction.count != 1: #追加
        return
    if str(reaction.emoji.name) == TARGET_EMOJI:
        message = reaction.message
        message_text = message.content[:100]
        message_url = message.jump_url
        post_message = f"知見がシェアされましたワン!\n\n{message_text} {message_url}"
        channel = client.get_channel(target_channel_id)
        await channel.send(post_message)

client.run('your_bot_token')

こうしてあるスタンプがついたらその投稿のURLを投稿するbotを作成することができました。
なお、このbotを動かすには事前にDiscordでの設定が必要となります。こちらもChatGPTに聞きながら作成したのですが、文献としてはいかがおすすめです。
https://dev.classmethod.jp/articles/discord-bot-by-discordpy/

デプロイ

Herokuが有料になってしまったため、評判が良いRailwayにデプロイしてみました。
以下の記事がわかりやすかったです。

https://zenn.dev/mnonamer/articles/f73386390399f6

少しデプロイにつまり、Logを調べたところ依存関係が解決できていないことがわかりました。
Railwayはrequirements.txtが存在すると自動でinstallしてくれるようです。
https://nixpacks.com/docs/providers/python

discord

と書かれたrequirements.txtファイルを追加しいビルドエラーが解消されました。

振り返り

といったところでシェアBOTの完成です!

当初は犬にしようと思っていたのですが、良い感じのキャラが出来上がったため「知見ちゃん」と名付けてました。ワイルドなアライさんみたいで結構気に入ってます。

無事作ることができ嬉しい反面、いくつか気づきがありました。

まず、プロンプト(仕様)の作り込みが甘かったためリファクタリングに少々時間を割いてしまいました。DiscordのBot作成は初めての経験だったため、出力されたコードを信じ込んでしまったことが原因だと思います。
on_messageがうごかかない…」となり、結局ドキュメントに当たりon_reaction_add()の仕様を読みました。
筆者は少しPythonの経験があったのでよかったのですが、知識ゼロの方はだいぶ苦労したはずです。

また、やはりLLMは新しく(ニッチな)知識をあまり得意としないようです。
今回は外部との通信も存在し、また型の指定もないためChatGPTも少し苦労したのではないかと思います。

現時点で仕様からCodeにする最適なパーツとしては、副作用が少なく型がありIN/OUTのしっかりした関数的な処理となるでしょうか。

GitHubで編集を提案

Discussion

ログインするとコメントできます