import * as dotenv from "dotenv"; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import dotenv.config(); import { ChannelType, Client, Colors, EmbedBuilder, GatewayIntentBits, SnowflakeUtil, } from "discord.js"; import { type ChatCompletionRequestMessage, Configuration, OpenAIApi, } from "openai"; const SYSTEM_MESSAGE = "You are Smolhaj, a Discord bot. You are helpful and friendly, and answers concisely. Due to the group nature of Discord, Messages not by you will be prefixed with a username, followed by a colon."; const client = new Client({ intents: [ GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages, GatewayIntentBits.Guilds ], }); const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); client.on("ready", () => { console.log(`Logged in as ${client.user?.tag}!`); }); client.on("messageCreate", async (message) => { if (message.channelId != process.env.CHANNEL) return; if (message.webhookId) return; if (message.author.bot) return; if (message.content.startsWith("\\")) return; if (message.channel.type != ChannelType.GuildText) return; await message.channel.sendTyping(); const typingTimer = setInterval(() => { if (message.channel.type == ChannelType.GuildText) message.channel.sendTyping(); }, 5000); try { const msgs = await message.channel.messages.fetch({ after: SnowflakeUtil.generate({ timestamp: Date.now() - 5 * 60 * 1000, }).toString(), }); const context = [ ...msgs .filter((msg) => { if (message.webhookId) return false; if (message.author.bot && msg.author !== msg.author.client.user) return false; if (message.content.startsWith("\\")) return false; return true; }) .mapValues((msg) => { if (msg.author === msg.author.client.user) { return { role: "assistant", content: msg.content }; } return { role: "user", content: `${msg.member?.displayName ?? msg.author.username}:${ msg.content }`, }; }) .values(), ].reverse(); const response = await openai.createChatCompletion({ model: "gpt-3.5-turbo", messages: [{ role: "system", content: SYSTEM_MESSAGE }, ...context], }); const responseMessage = response.data.choices[0].message; if (!responseMessage) return; const isAppropriate = await openai .createModeration({ input: responseMessage.content }) .then(({ data }) => !data.results[0].flagged); if (isAppropriate) { await message.channel.send({ content: responseMessage.content, allowedMentions: { parse: ["users"] }, }); } else { await message.channel.send({ embeds: [ new EmbedBuilder() .setTitle("Response flagged!") .setDescription( "The generated response may have been inappropriate." ) .setColor(Colors.Red), ], }); } clearInterval(typingTimer); } catch (e) { clearInterval(typingTimer); throw e; } }); client.login(process.env.TOKEN);