DiscordにOpenAIのAPIを使用してbotを導入した話

はてなブログはめちゃくちゃ久しぶりに更新します(そもそも書物自体が久しぶり)。
今回は、自身で管理しているdiscordのサーバーにChatGPTのbotを導入してみたという技術的な備忘録です。

自分のため+技術的な話に興味のある人向けの話になります。

概要

今回のゴールとしては「botに話しかけるとそれっぽい回答を返してくれるChatGPTbotを常時稼働させる」となります。
この要件を満たすために必要なことは、大まかに言えば次のようになるかなと思います。

  • discordのbotアカウントを作成する
  • OpenAI(ChatGPT)のAPI利用登録をする
  • APIを利用してbotを稼働させるためにコーディングする
  • 常時稼働のために何かしらのサーバーサービスに実装したコードを配置する

これらについて、ひとつずつ見ていこうと思います。

discord botアカウントの作成

まず、ChatGPTの機能を載せるbotを用意しなければなりません。
discordのbot作成の方法については調べれば簡単に情報が手に入るので詳細はここでは省きますが、下記discordポータルサイトにアクセスしてアカウントを作成します。

discord.com

今回はこんな感じです。
管理しているサーバーが「まこらん邸(オンライン)」と言うので、自宅で忠実な犬を飼ってる…みたいなイメージですw

作成したら後に実装でTokenが必要になるのでどこかにメモっておきましょう。これは一度生成されると二度と同じものは表示されないので注意が必要です。
※万が一紛失してしまったら再生成しましょう。

これでdiscord botアカウントの作成は完了です。

OpenAIのAPI利用登録

次に今回のキモであるOpen AIの利用登録です。
こちらも調べれば詳細の情報は簡単に手に入るので詳細は省きますが、下記のOpenAIの公式サイトで(なければ)アカウントを作成します。

platform.openai.com

アカウントを作成し「Welcome to the OpenAI platform」というようなページが表示されたら、画面右上のPersonalから「View API keys」を選択。

「Create new secret key」ボタンを押してAPI keyを生成しましょう。
こちらも先程のdiscord Tokenと同じで後の実装で使用するのでメモっておきましょう。

ちなみにOpenAIのAPIは従量課金制です。
登録して3ヶ月間は$5分のクレジットが無料で利用できます(ちょっと前までは$18まで利用できたらしい)が、これを使い切るか3ヶ月経過すると「openai.error.RateLimitError」エラーが発生し、有償アカウントに移行しないとAPIは利用できなくなります。
OpenAIページの「Billing」から「Payment methods」からクレジットカードの登録をし、「Usage limits」で月々の課金上限額を設定することで有償アカウントに移行でき、APIを利用できます。
詳細説明は省きますが、OpenAIの文章生成APIトークン(単語数みたいな理解でだいたいOK)という括りで課金をしており、今回利用しているgpt-3.5-turboは1000トークンあたり$0.002くらい日本円で0.3円いかないくらいなので、めちゃくちゃAPIを利用しない限りそんなに高額な請求は来ないと思います…!
Soft Limit(超過するとメール通知が来る額)とHard Limit(超過するとAPIアクセスを拒否される額)の2つの上限を設定できますが、今回はとりあえず月々$10で上限を設定することとしました。

discord botのコーディングをする

それではここまでで生成したdiscord tokenとOpenAI API keyを利用してコーディングを進めていきます。
Pythonで実装するため、まず開発環境にPythonがなければPythonのインストールが必要です。
後述するdiscord.pyがPython3.8以上でないと動作しないので、インストールするPythonのバージョンには注意が必要です。

github.com

Pythonのインストールが済んだら、次はライブラリのインストールをします。
discord上でbotに対話式で応答してもらいたいのでdiscordのライブラリが必要になるのと、当然OpenAIの機能が必要になってくるため、OpenAIのライブラリが必要になってきます。

pip install discord.py
pip install openai

これで開発環境が整ったので、あとはPythonコードを実装していきます。
なお今回の導入ではいろんな先行事例を参考にほぼコピペで要所だけ変更して書いてます。ありがとう先駆者の皆様…!
※コードは実際に動いているものを改変して載せてます。

import discord
import openai

intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)

#本来であれば環境変数等に持たせておくほうがベター
token = "----------discordのtoken----------" 
openai.api_key = #----------OpenAIのAPIkey----------"

model_engine = "gpt-3.5-turbo"

@client.event
async def on_ready():
    print(f'We have logged in as {client.user}')

@client.event
async def on_message(message):
    global model_engine
    if message.author.bot:
        return
    if message.author == client.user:
        return

    #メンションに反応
    if client.user in message.mentions:
                #botに話しかけて待機中に表示されるメッセージ
        msg = await message.reply("わんわんわんわん…………!!!!", mention_author=False)
        try:
            prompt = message.content.replace('※ここでメンションされたbot垢ID文字列を空文字に置換して削除 ', '')
            if not prompt:
                await msg.delete()
                await message.channel.send("質問内容がありません")
                return
            completion = openai.ChatCompletion.create(
            model=model_engine,
            messages=[
                {
                    "role": "system",
                    #↓この命令を一文書くことですべての会話に犬っぽく返してくれるようになる
                    "content": "犬になりきって日本語で返答してください。一人称は「ぼく」で語尾に「ワン」を付けてください。"
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],)

            response = completion["choices"][0]["message"]["content"]
            await msg.delete()
            await message.reply(response, mention_author=False)
        except:
            import traceback
            traceback.print_exc()
            await message.reply("エラーだわん", mention_author=False)

client.run(token)

コーディングが完了したら、まずはローカルでこのPythonコードを実行して起動し待機状態にします。
discord上で今回用意したbotに話しかけて反応があれば成功です。
起動したらこんな感じでログが表示されます。

cmd >python gpt.py
[2023-08-29 15:40:12] [INFO    ] discord.client: logging in using static token
[2023-08-29 15:40:14] [INFO    ] discord.gateway: Shard ID None has connected to Gateway (Session ID: 002465b215a698d8b7e7523941431e1b).
We have logged in as 邸の愛犬#8035

OpenAI botを常時稼働させる

ローカルでの起動に成功したら今度はそれを常時稼働できるようにしたいと思います。
まぁ無難にクラウドに乗っけるのがいいかなということで今回はGCPのCompute Engineの無料枠を利用して環境を構築していきたいと思います。
cloud.google.com

利用するにあたり、GCE(Google Compute Engine)上にVMの設定をしていきます。
個人利用で利用料金をかけたくないので、「インスタンスの作成」からこの辺を参考に無料枠の設定を行ってVMインスタンスを作成します。
cloud.google.com

作成したインスタンスにはブラウザからSSH接続が可能なので、それを利用してコンソールにリモートログインし、ローカル環境を作ったときと同じように各種ライブラリのインストールを進めます。
環境が構築できたら、nohupでコードを実行するとターミナルを消したバックグラウンドでも動作してくれるようなのでそれでPythonコードを実行します。

GCE上でPythonコードを実行し、ローカルで実行したように待機状態になったら、同じようにdiscordからbotに話しかけてみましょう。

成功ですね!
今回は犬になりきらせたbotを作ったのでこんな感じの回答になってます。

まとめ

discord+OpenAI+GCPの組み合わせで、常時稼働するChatGPT botをそれなりに低コストで作成することができました。
気になる料金についてですが、これは今年8月頭に実装したので約1ヶ月でOpenAIのAPI料金はおよそ$0.18(約25円)程度です。結構遊んだんですけどねw

今回の事例で初めてdiscordAPIやOpenAIAPI、GCPを触ったのであまり詳細なことについてはまだ理解できていないところもあり、そこまで詳細な説明にはなってないかもしれませんが、なんとなく興味がある人の助けくらいにはなれていれば幸いです。
いちエンジニアとして生成AIはやっぱ避けて通れないと思うんで、こういう形で触ってみれただけでも価値のある経験だったかなと思います。

参考にさせていただいたページ

ChatGPT + discord.py で対話bot - Qiita
Discord.pyとOpenAI APIで簡単なBotを作った - Qiita
openai apiを使ってdiscordのbotを作る。
OpenAI APIのエラー(openai.error.RateLimitError)について - Qiita
gpt-3.5-turboの利用料金を徹底調査!日本円でいくら? | Code Wizardry