You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.3 KiB

2 years ago
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 the username of the message author, followed by a colon.";
2 years ago
const client = new Client({
2 years ago
intents: [
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.Guilds,
],
2 years ago
});
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;
2 years ago
if (message.content == "die") process.exit(1);
2 years ago
// "adapted" from https://github.com/ryanccn/blahaj/blob/main/src/chat.ts
2 years ago
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) => {
2 years ago
if (msg.author.bot && msg.author !== msg.author.client.user)
2 years ago
return false;
2 years ago
if (msg.content.startsWith("\\")) return false;
2 years ago
return true;
})
.mapValues<ChatCompletionRequestMessage>((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);