とりあえずAPIを投げて返信してくれるまでを作成しました。
本当はGCPのCompute EngineのVMなどで実行し続けるのがいいと思いますが、そこまで行くと規模が大きくなってしまうので、一旦ローカルでサーバ上げてる間に返信してくれるのがゴールとします。
ローカルで立ち上げてる間に返信するだけなら無料の範囲ですし、自分がMacでBotを起動中にスリープモードにしてもBotが返信してくれることは確認できました。
環境準備編
作業を始める前に、以下の準備を済ませておきます。
- Discord Botの登録、およびTokenの発行
Discord Botの登録編
Botの登録をする
-
ここでNew Applicationから登録します。適切な名前を入力します。
サーバに適切な権限で招待を行う
- とりあえず、チャンネルに返信してくれるだけだったらこれでいいと思います。
- 返信をするためには他のユーザの入力を見る必要があるため、チャンネルの閲覧権限を付与しておきます。
- チェックを入れたら、下のCopyからURLをコピーし、URLに飛んで適切なサーバに招待してください。
OpenAIのAPIキー発行編
https://platform.openai.com/account/api-keys
ここに関しては検索すれば分かると思いますし、恐らく難しいことは無いと思うので割愛します。
ただ、APIキーは一度発行するともう一度見れないようになっているのでご注意ください。
必ずどこかにコピペして控えることをオススメします。
もし忘れてしまった場合は新規にAPIキーを発行し、必要であれば以前のAPIキーを削除してください。
返信プログラム動かす編
とりあえず動かすのに、まずは秘匿情報を入力します。
~/.env
を作成し、以下の情報を入力してください。
BOT_TOKENには登録したBotのTOKEN部分を入力します。(こちらも1度しか表示されないものなので控えておいてください)
API_KEYにはOPENAIのAPIキーを入力してください
BOT_USER_NAME=BOTユーザ名
BOT_TOKEN=xxx
API_KEY=xxx
起動編
いつもどおり npm i
でインストールして npm run dev
で実行です。ログインできたらなんかログ出ます
npm i
npm run dev
ローカルで起動しログインが完了したらDiscordでBotに聞きたいことをメンションしましょう。
このときロールではなくユーザ名でメンションする必要があることに注意してください。(1敗)
同名のため間違うことがあります。
補足
また、このリポジトリを2つ立ち上げて2種類のBotを実行しようとすると環境変数が衝突?するようでうまくいかなくなります。
なので、BOT_USER_NAMEおよびBOT_TOKENは末尾に2をつけるなどしてコードも変える形で対応してください。
Botを1種類しか使用しない人は気にしなくて大丈夫です。
おまけ
これだけだと面白くないので、プロンプトを弄ります
const body = JSON.stringify({
model: "gpt-3.5-turbo",
messages: [
{
role: "user",
content: message + "また、必ず一人称には吾輩を使用し、二人称には貴様を使用してください。なお、口調は厳格な30代男性軍人のような喋り方をするものとします。",
},
],
});
おしまい
みなさんも自分だけの最強のBotを作ってください
番外編 使用しているコードの解説
Discord Botを操作する部分はDiscord.jsという外部ライブラリに依存しています。
ChatGPT APIを叩く部分は特に複雑な処理も必要なさそうだったため、cross-fetchを使用し結果を取得しています。
Client作成
dicordjsのclientを作成します。このとき、適切な権限を設定します。
自分はとりあえず必要そうなものを指定しました。
const options :ClientOptions = {
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
};
const client = new Client(options);
メッセージを確認し、メンションが含まれていたら返信
- Events.MessageCreateでチャンネルにメッセージが送信されたら関数が発火するようになります。
- 早期returnがないとチャンネルにメッセージが送信されるたびに喋りかけてくるウザいBotになるため、ちゃんと自分へのmentionがあるか確認してからAPIを叩きます。
-
message.channel.sendTyping();
を実行するとBotが入力中表示をしてUXが向上します。 - ChatGPT APIのレスポンスが返ってくるまでにはかなり時間がかかるので普通に入力中が途切れますが気にしなくていいです。
うまくmentionされていることを確認したら、あとはAPIに投げて結果をチャンネルに投稿して終了です。
ChatGPT APIに投げる前に、mentionされている部分を切り取らないとそのままリクエストされるため、なんかいい感じに切り取ってください。 自分は<@xxxxxxxxxxxxxx> の >部分までを消すようにしました。
client.on(Events.MessageCreate, async (message) => {
if (message.mentions.users.first()?.username !== process.env.BOT_USER_NAME) return;
try {
message.channel.sendTyping();
const text = await chatCompletion(requestStr(message.content));
if (!text) throw Error(text);
await message.channel.send(text);
} catch (error) {
console.log(error);
}
});
// mention部分のtextを削除し、本文のみでAPIにリクエストする
const requestStr = (str: string) => str.substring(str.indexOf(">"), str.length);
参考記事