✖️

openai apiを使ってdiscordのbotを作る。

2023/08/02に公開

おのれTwitter(X)

Twitterの仕様がどんどん悪くなりDMが一日20件程度しか送れなくなりました。さらに凍結までされてしまってこれまでフォローしていた人が分からなくなり、結構混乱した。
twitterのDMで友人とやり取りをしていたのでこの仕様変更から主にdiscordでやりとりすることになり、
せっかくなら何かbot作りたいな~と思っていたので、試しに昔一度手を付けていたopenaiのapiを使った、
「わからないことを相手に聞かれたときに私がggrksと返信する前に答えてくれるbot」
を制作してみました。

使ったもの

discordのbot
openaiのapi(gpt-3.5-turbo)
GCP:無料枠(らしい)
python:3.9.2
pythonライブラリ(追加分)
 - openai_api: 0.27.8
 - discord.py: 2.3.1

やったこと

bot作成とdiscordのトークンとopenai_apiのキーを取得

botは前つくっていたので割愛
apiもchatgptのアカウントでplatform openaiにログインしてapiの欄から取得する
参考記事:
https://discord.com/developers/applications
https://discordpy.readthedocs.io/ja/latest/discord.html
openai apiでの動作を試すためのplaygroundが結構便利でした。
実際に作りたいアプリの動作を試す場所としても使えますし、コードもここから引っ張ってこれます。私はここでシステムのプロンプトと長さを指定してそのコードを引っ張ってきました。

全体コード

import discord
import os
import openai
import re

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

token = os.environ['discord_token']
openai.api_key = os.environ['openai_api_key']

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

@client.event
async def on_message(message):
    # 自分自身のメッセージを無視
    if message.author == client.user:
        return
    # 1つ目の正規表現パターンに一致する場合にChatGPTに質問
    trigger_pattern1 = r"(?i)(^|.*\s)(なんで|何で|なぜ|何故)(?.+?)?(の|?)?$"
    if re.search(trigger_pattern1, message.content):
        response = await ask_chatgpt(message.content)
        await message.channel.send(response)
    # 2つ目の正規表現パターンに一致する場合にChatGPTに質問
    trigger_pattern2 = r"(?i).+(?:って何|ってなに|ってなんなの|って何なの|ってだれ|って誰|なのなんで|なぁぜなぁぜ)(?:\?|?)?"
    if re.search(trigger_pattern2, message.content):
        response = await ask_chatgpt(message.content)
        await message.channel.send(response)
	
async def ask_chatgpt(question):
    try:
        # ChatGPT APIを呼び出して返答を取得
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[
                {
                    "role": "system",
                    "content": "あなたは寄せられた疑問に答えます.疑問に簡潔に返答してください."
                },
                {
                    "role": "user", "content":question
                }
            ],
            temperature=1,
            max_tokens=200,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        if 'choices' in response and len(response['choices']) > 0:
            return response['choices'][0]['message']['content'].strip()
        else:
            return "ChatGPTからの無効な応答です。"
    except openai.error.APIError as e:
        return f"ChatGPTでエラーが発生しました: {e}"

client.run(token)



トリガーになる部分

    # 1つ目の正規表現パターンに一致する場合にChatGPTに質問
    trigger_pattern1 = r"(?i)(^|.*\s)(なんで|何で|なぜ|何故)(?.+?)?(の|?)?$"
    if re.search(trigger_pattern1, message.content):
        response = await ask_chatgpt(message.content)
        await message.channel.send(response)
    # 2つ目の正規表現パターンに一致する場合にChatGPTに質問
    trigger_pattern2 = r"(?i).+(?:って何|ってなに|ってなんなの|って何なの|ってだれ|って誰|なのなんで|なぁぜなぁぜ)(?:\?|?)?"
    if re.search(trigger_pattern2, message.content):
        response = await ask_chatgpt(message.content)
        await message.channel.send(response)

今回はggrksbotのトリガーとなる言葉は、
・(何で/何故)hogehogehoge(の)という文と、
・hogehoge(って何/って何なの/って誰/なのなんで/なぁぜなぁぜ)
それぞれ漢字と平仮名?ありなし合わせて24パターン用意した。
(なぁぜなぁぜ以外は)日常会話だとだいたいこのあたりを使うから決めた。
自然言語処理とかやろうと思ったけどレスポンスはなるべくはやくしたかったので正規表現を使った。

openai_api部分

async def ask_chatgpt(question):
    try:
        # ChatGPT APIを呼び出して返答を取得
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[
                {
                    "role": "system",
                    "content": "あなたは寄せられた疑問に答えます.疑問に簡潔に返答してください."
                },
                {
                    "role": "user", "content":question
                }
            ],
            temperature=1,
            max_tokens=200,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        if 'choices' in response and len(response['choices']) > 0:
            return response['choices'][0]['message']['content'].strip()
        else:
            return "ChatGPTからの無効な応答です。"
    except openai.error.APIError as e:
        return f"ChatGPTでエラーが発生しました: {e}"

response部分はplaygroundからコード引っ張ってきてif 'choice'辺りは他記事のコードでうまくいかなかったのでチャッピー使いながらやりました。

動かした結果

GCPにもって行く前にローカルの環境で動かしました。

性能としては平気で嘘吐くけどまあいいでしょう。

GCEで無料枠のVMを作る。

ここから無料枠を選んで作る。
https://cloud.google.com/compute?hl=ja
https://cloud.google.com/free/docs/free-cloud-features?hl=ja#compute
ブラウザからsshで接続できるのが楽だった。
debianをインストールした。pythonは入っていたがpipはインストールされていなかったのでpipとdiscord.pyとopenaiを入れた。

sudo apt update
sudo apt install python3-pip
sudo python3 -m pip install discord.py openai

後は環境変数にapi_keyとtokenをいれてコードをnohupというもので動かす。コレを使うとターミナルを消してもプログラムが動き続いてくれる。

nohup python3 discordbot.py &

コレを動かすとnohup.outというファイルができるがそこには
print(f'We have logged in as {client.user}')
が表示されなくて戸惑ったがdiscordで実際に試してみると動いていた。
https://enjoy-pglife.com/ubuntu/1469/

まとめ

それなりに簡単にほとんど無料で作ることができた。
これから機能拡張するかもしれないし、しないかもしれない。とりあえずopenaiのapiがなくなるまでは運用していこうかと思っている。

他参考サイト

https://zenn.dev/mixi/articles/97a39d8d6d9890
https://note.com/el_el_san/n/n36c1305cc8f8
https://qiita.com/amama-nagigi/items/4d09eab14a6f9f88ac3a

Discussion