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.

154 lines
4.6 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 made by skyevg. Your creator is skyevg, not OpenAI. 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", async () => {
2 years ago
console.log(`Logged in as ${client.user?.tag}!`);
const channel = await client.channels.fetch(process.env.CHANNEL ?? "");
if (channel?.type != ChannelType.GuildText) return;
channel.send("\\Smolhaj Reset");
2 years ago
});
let resetTime = Date.now();
2 years ago
2 years ago
client.on("messageCreate", async (message) => {
if (message.channelId != process.env.CHANNEL) return;
if (message.webhookId) return;
if (message.author.bot) return;
2 years ago
if (message.content == "\\reset") resetTime = Date.now();
2 years ago
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);
const recieved = SnowflakeUtil.timestampFrom(message.id);
2 years ago
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1500));
2 years ago
try {
const msgs = await message.channel.messages.fetch({
after: SnowflakeUtil.generate({
2 years ago
timestamp: Math.max(Date.now() - 5 * 60 * 1000, resetTime),
2 years ago
}).toString(),
2 years ago
before: SnowflakeUtil.generate({
timestamp: recieved + 250,
2 years ago
}).toString(),
2 years ago
});
const context = [
...msgs
.filter((msg) => {
2 years ago
if (msg.webhookId && !msg.content.startsWith("\\")) return true;
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 };
}
let username = msg.member?.displayName ?? msg.author.username;
if (username == "skyevg" && msg.author.id != "1038096782963507210")
username = msg.author.username; // no impersonating :)
2 years ago
return {
role: "user",
content: `${username}:${msg.content}`,
2 years ago
};
})
.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 lastMessage =
msgs
.filter((msg) => {
if (msg.webhookId && !msg.content.startsWith("\\")) return true;
if (msg.author.bot && msg.author !== msg.author.client.user)
return false;
if (msg.content.startsWith("\\")) return false;
return true;
})
.first() ?? message;
2 years ago
2 years ago
const isAppropriate = await openai
.createModeration({ input: responseMessage.content })
.then(({ data }) => !data.results[0].flagged);
if (isAppropriate) {
2 years ago
try {
2 years ago
await lastMessage.reply({
content: responseMessage.content,
allowedMentions: { parse: ["users"] },
2 years ago
});
} catch {
await message.channel.send({
content: responseMessage.content,
allowedMentions: { parse: ["users"] },
2 years ago
});
}
2 years ago
} 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);