diff --git a/.gitignore b/.gitignore index 494fcca..fbc6e95 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ .vscode/ .idea/ .node-version +/functions/other/settings.sqlite +/personality.txt # Logs logs @@ -108,4 +110,4 @@ dist .dynamodb/ # TernJS port file -.tern-port \ No newline at end of file +.tern-port diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..900ce3a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +.github +package.json +pnpm-lock.yaml \ No newline at end of file diff --git a/README.md b/README.md index df56bac..bf39a90 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,70 @@ image

-## 🤔 What is this bot? -The **Taurus Discord Bot** is a small bot, it can be used for several things such as: -- Image Generation -- AI GPT chats and personality customisations +# 🤔 What is Taurus? + +The Taurus Discord Bot is a small bot with a big impact. It offers several features, including advanced image generation, AI chats, and more. + +
+💬 AI Chats + +- Powered by Google's [Gemini 1.5 Model](https://deepmind.google/technologies/gemini/#gemini-1.5) +- Has a configurable global personality via the ``/personalise`` slash command +- Remembers past messages + +**Ways to interact:** +- Context Menus +- Mention the Bot with your message +- Utilise the ``/taurus`` slash command + +
+ +
+🖼️ Advanced Image Generation + +- 70+ Models +- 17 Style Presets +- Negative Prompt Customisation +- A toggleable NSFW image blocker +- Supports different languages +- And much more! + +
+ +
+🔧 Additional Features + +- Live Console Logging in Discord +- Personality update logs in Discord +- User Commands - Use the bot anywhere on Discord +- An optional CLI via the start scripts +- A Settings Menu in Discord +
## 💾 Install -1. fill in the token and other values in ``config.json.example`` +1. fill in the token and other values in `config.json.example` + +2. Rename the file to `config.json` -2. Rename the file to ``config.json`` +3. Run `pnpm i` -3. Run ``npm i`` +4. Run `node .` -4. Run ``node bot`` +5. In Discord run ``/settings`` and fill in the values -**Note** - Alternatively **instead of steps 3 & 4** you can **run one of the startbot/start scripts.** +> [!NOTE] +> - Alternatively **instead of steps 3 & 4** you can **run one of the startbot/start scripts.** *(Reccomended)* +> - If you do not have pnpm installed you will need to run: ``npm install -g pnpm`` - All PR's are welcome for improvements. ### ℹ️ Getting API Keys: + - https://ai.google.dev - https://app.prodia.com/api ### 🏗️ Additional Credits - This bot utilizes a modified version of the [discord bot template](https://github.com/NamVr/DiscordBot-Template) made - by [Naman Vrati](https://github.com/NamVr)! [\[Apache License 2.0\]](https://github.com/NamVr/DiscordBot-Template/blob/master/LICENSE) \ No newline at end of file + by [Naman Vrati](https://github.com/NamVr)! [\[Apache License 2.0\]](https://github.com/NamVr/DiscordBot-Template/blob/master/LICENSE) diff --git a/bot.js b/bot.js index 9a276f3..c3b4af5 100644 --- a/bot.js +++ b/bot.js @@ -15,7 +15,8 @@ const { GatewayIntentBits, Partials, REST, - Routes + Routes, + SlashCommandBuilder, } = require("discord.js"); const { token, client_id } = require("./config.json"); @@ -57,7 +58,7 @@ for (const file of eventFiles) { } else { client.on( event.name, - async (...args) => await event.execute(...args, client) + async (...args) => await event.execute(...args, client), ); } } @@ -66,8 +67,11 @@ for (const file of eventFiles) { // Define Collection of Slash/Modal Commands and Cooldowns client.slashCommands = new Collection(); +client.buttonCommands = new Collection(); client.modalCommands = new Collection(); +client.contextCommands = new Collection(); client.cooldowns = new Collection(); +client.autocompleteInteractions = new Collection(); client.functions = new Collection(); /**********************************************************************/ @@ -93,6 +97,78 @@ for (const module of slashCommands) { } } +/**********************************************************************/ +// Registration of Autocomplete Interactions. + +/** + * @type {String[]} + * @description All autocomplete interactions. + */ + +const autocompleteInteractions = fs.readdirSync("./interactions/autocomplete"); + +// Loop through all files and store autocomplete interactions in autocompleteInteractions collection. + +for (const module of autocompleteInteractions) { + const files = fs + .readdirSync(`./interactions/autocomplete/${module}`) + .filter((file) => file.endsWith(".js")); + + for (const interactionFile of files) { + const interaction = require( + `./interactions/autocomplete/${module}/${interactionFile}`, + ); + client.autocompleteInteractions.set(interaction.name, interaction); + } +} + +/**********************************************************************/ +// Registration of Context-Menu Interactions + +/** + * @type {String[]} + * @description All Context Menu commands. + */ + +const contextMenus = fs.readdirSync("./interactions/context-menus"); + +// Loop through all files and store context-menus in contextMenus collection. + +for (const folder of contextMenus) { + const files = fs + .readdirSync(`./interactions/context-menus/${folder}`) + .filter((file) => file.endsWith(".js")); + for (const file of files) { + const menu = require(`./interactions/context-menus/${folder}/${file}`); + const keyName = `${folder.toUpperCase()} ${menu.data.name}`; + client.contextCommands.set(keyName, menu); + } +} + +/**********************************************************************/ +// Registration of Button-Command Interactions. + +/** + * @type {String[]} + * @description All button commands. + */ + +const buttonCommands = fs.readdirSync("./interactions/buttons"); + +// Loop through all files and store button-commands in buttonCommands collection. + +for (const module of buttonCommands) { + const commandFiles = fs + .readdirSync(`./interactions/buttons/${module}`) + .filter((file) => file.endsWith(".js")); + + for (const commandFile of commandFiles) { + const command = require(`./interactions/buttons/${module}/${commandFile}`); + for (const id of command.id) { + client.buttonCommands.set(id, command); + } + } +} /**********************************************************************/ // Registration of Modal-Command Interactions. @@ -113,7 +189,13 @@ for (const module of modalCommands) { for (const commandFile of commandFiles) { const command = require(`./interactions/modals/${module}/${commandFile}`); - client.modalCommands.set(command.id, command); + if (Array.isArray(command.id)) { + for (const id of command.id) { + client.modalCommands.set(id, command); + } + } else { + client.modalCommands.set(command.id, command); + } } } @@ -125,17 +207,17 @@ for (const module of modalCommands) { * @description All functions. */ -const functionFiles = fs.readdirSync("./functions"); - -// Loop through all files and store functions in functions collection. +client.once("ready", () => { + const functionFiles = fs.readdirSync("./functions"); -for (const functionFile of functionFiles) { - if (functionFile.endsWith(".js")) { - const func = require(`./functions/${functionFile}`); - client.functions.set(functionFile.replace('.js', ''), func); - func(client); - } -} + for (const functionFile of functionFiles) { + if (functionFile.endsWith(".js")) { + const func = require(`./functions/${functionFile}`); + client.functions.set(functionFile.replace(".js", ""), func); + func(client); + } + } +}); /**********************************************************************/ // Registration of Slash-Commands in Discord API @@ -143,7 +225,19 @@ for (const functionFile of functionFiles) { const rest = new REST({ version: "9" }).setToken(token); const commandJsonData = [ - ...Array.from(client.slashCommands.values()).map((c) => c.data.toJSON()), + ...Array.from(client.slashCommands.values()).map((c) => { + const commandData = + c.data instanceof SlashCommandBuilder ? c.data.toJSON() : c.data; + commandData.integration_types = [0, 1]; + commandData.contexts = [0, 1, 2]; + return commandData; + }), + ...Array.from(client.contextCommands.values()).map((c) => { + const commandData = c.data; + commandData.integration_types = [0, 1]; + commandData.contexts = [0, 1, 2]; + return commandData; + }), ]; (async () => { @@ -153,7 +247,7 @@ const commandJsonData = [ await rest.put( Routes.applicationCommands(client_id), - { body: commandJsonData } + { body: commandJsonData }, ); console.log("Successfully reloaded application (/) commands."); @@ -168,10 +262,20 @@ client.login(token); /**********************************************************************/ // Anti Crash script - -process.on("unhandRejection", (reason, promise) => { +process.on("unhandledRejection", (reason, promise) => { console.error(`🚫 Critical Error detected:\n\n`, reason, promise); + + // Uncomment the below lines below to see the full error details. - ADVANCED DEBUGGING // + + // console.dir(reason, { showHidden: true, depth: null }); + // console.log("Promise: ", promise); }); + process.on("uncaughtException", (error, origin) => { console.error(`🚫 Critical Error detected:\n\n`, error, origin); -}); \ No newline at end of file + + // Uncomment the below lines below to see the full error details. - ADVANCED DEBUGGING // + + // console.dir(error, { showHidden: true, depth: null }); + // console.log("Origin: ", origin); +}); diff --git a/config.json.example b/config.json.example index 9f30171..8508fc4 100644 --- a/config.json.example +++ b/config.json.example @@ -1,11 +1,10 @@ { - "token": "...", - "owner": ["719815864135712799","483359783831732255"], - "client_id": "...", - "guild_id_logs": "...", - "channel_id_logs": "...", - "webhook_url_console_logs": "...", - "Gemini_API_KEY": "...", - "XProdiaKey": "...", - "Block_NSFW_Images": true + "token": "...", + "owner": ["719815864135712799","483359783831732255", "OWNER USER IDS HERE"], + "client_id": "...", + "emojis": { + "loading": "⭕", + "working": "🟢", + "failed": "🔴" + } } \ No newline at end of file diff --git a/events/autocompleteInteraction.js b/events/autocompleteInteraction.js new file mode 100644 index 0000000..9349331 --- /dev/null +++ b/events/autocompleteInteraction.js @@ -0,0 +1,46 @@ +/** + * @file Autocomplete Interaction Handler + * @author Naman Vrati + * @since 3.3.0 + * @version 3.3.2 + */ + +const { Events } = require("discord.js"); + +module.exports = { + name: Events.InteractionCreate, + + /** + * @description Executes when an interaction is created and handle it. + * @author Naman Vrati + * @param {import('discord.js').AutocompleteInteraction & { client: import('../typings').Client }} interaction The interaction which was created + */ + + async execute(interaction) { + // Deconstructed client from interaction object. + const { client } = interaction; + + // Checks if the interaction is an autocomplete interaction (to prevent weird bugs) + + if (!interaction.isAutocomplete()) return; + + // Checks if the request is available in our code. + + const request = client.autocompleteInteractions.get( + interaction.commandName, + ); + + // If the interaction is not a request in cache return. + + if (!request) return; + + // A try to execute the interaction. + + try { + await request.execute(interaction); + } catch (err) { + console.error(err); + return Promise.reject(err); + } + }, +}; diff --git a/events/buttonInteraction.js b/events/buttonInteraction.js new file mode 100644 index 0000000..361892c --- /dev/null +++ b/events/buttonInteraction.js @@ -0,0 +1,51 @@ +/** + * @file Button Interaction Handler + * @author Naman Vrati + * @since 3.0.0 + * @version 3.3.2 + */ + +const { Events } = require("discord.js"); + +module.exports = { + name: Events.InteractionCreate, + + /** + * @description Executes when an interaction is created and handle it. + * @author Naman Vrati + * @param {import('discord.js').ButtonInteraction & { client: import('../typings').Client }} interaction The interaction which was created + */ + + async execute(interaction) { + // Deconstructed client from interaction object. + const { client } = interaction; + + // Checks if the interaction is a button interaction (to prevent weird bugs) + + if (!interaction.isButton()) return; + + const command = client.buttonCommands.get(interaction.customId); + + // If the interaction is not a command in cache, return error message. + // You can modify the error message at ./messages/defaultButtonError.js file! + + if (!command) { + return await require("../messages/defaultButtonError").execute( + interaction, + ); + } + + // A try to execute the interaction. + + try { + return await command.execute(interaction); + } catch (err) { + console.error(err); + // console.dir(err, { showHidden: true, depth: null }); + await interaction.reply({ + content: "There was an issue while executing that button!", + ephemeral: true, + }); + } + }, +}; diff --git a/events/contextInteraction.js b/events/contextInteraction.js new file mode 100644 index 0000000..772af8f --- /dev/null +++ b/events/contextInteraction.js @@ -0,0 +1,84 @@ +/** + * @file Context Interaction Handler + * @author Krish Garg & Naman Vrati + * @since 3.0.0 + * @version 3.3.2 + */ +const { Events } = require("discord.js"); +const { botInGuild } = require("../functions/other/utils"); + +module.exports = { + name: Events.InteractionCreate, + + /** + * @description Executes when an interaction is created and handle it. + * @author Naman Vrati + * @param {import("discord.js").ContextMenuCommandInteraction & { client: import("../typings").Client }} interaction The interaction which was created + */ + + execute: async (interaction) => { + // Deconstructed client from interaction object. + const { client } = interaction; + + // Checks if the interaction is a context interaction (to prevent weird bugs) + + if (!interaction.isContextMenuCommand()) return; + + /**********************************************************************/ + + // Checks if the interaction target was a user + + if (interaction.isUserContextMenuCommand()) { + const command = client.contextCommands.get( + "USER " + interaction.commandName, + ); + + // A try to execute the interaction. + + try { + return await command.execute(interaction); + } catch (err) { + console.error(err); + await interaction.reply({ + content: + "There was an issue while executing that context command! If the issue persists please contact the bot owners.", + ephemeral: true, + }); + } + } + // Checks if the interaction target was a message + else if (interaction.isMessageContextMenuCommand()) { + const command = client.contextCommands.get( + "MESSAGE " + interaction.commandName, + ); + + // A try to execute the interaction. + + try { + return await command.execute(interaction); + } catch (err) { + if (!botInGuild(interaction)) { + return await interaction.reply({ + content: + "This command can only be executed in servers in which the bot is in, or in DMs/Group Chats.", + ephemeral: true, + }); + } + console.error(err); + await interaction.reply({ + content: + "There was an issue while executing that context command! If the issue persists please contact the bot owners.", + ephemeral: true, + }); + } + } + + // Practically not possible, but we are still caching the bug. + // Possible Fix is a restart! + else { + return console.error( + "Something weird happening in context menu. Received a context menu of unknown type. If the issue persists please contact the bot owners.", + ); + } + }, +}; diff --git a/events/modalInteraction.js b/events/modalInteraction.js index 828425a..a038e3e 100644 --- a/events/modalInteraction.js +++ b/events/modalInteraction.js @@ -24,7 +24,7 @@ module.exports = { if (!interaction.isModalSubmit()) return; - if (interaction.customId === 'taurus_ai_personality') return; + if (interaction.customId === "taurus_ai_personality") return; const command = client.modalCommands.get(interaction.customId); @@ -32,13 +32,17 @@ module.exports = { // You can modify the error message at ./messages/defaultModalError.js file! if (!command) { - return await require("../messages/defaultModalError").execute(interaction); + return await require("../messages/defaultModalError").execute( + interaction, + ); } // A try to execute the interaction. const error = new EmbedBuilder() - .setDescription("**There was an issue while understanding this modal!\n\nPlease contact the Developers.**") + .setDescription( + "**There was an issue while understanding this modal!\n\nPlease contact the Developers.**", + ) .setColor("Red"); try { diff --git a/events/onMention.js b/events/onMention.js index 2a31b72..3a315b8 100644 --- a/events/onMention.js +++ b/events/onMention.js @@ -5,24 +5,23 @@ const { Events, EmbedBuilder } = require("discord.js"); - module.exports = { name: Events.MessageCreate, - async execute(message) { - - const {client} = message; + const { client } = message; if ( message.content == `<@${client.user.id}>` || message.content == `<@!${client.user.id}>` ) { const bot_message = new EmbedBuilder() - .setDescription(`Hi ${message.author}! I am Taurus. Chat to me by mentioning me and typing your message! Or alternatively run \`/taurus\`!`) + .setDescription( + `Hi ${message.author}! I am Taurus. Chat to me by mentioning me and typing your message! Or alternatively run \`/taurus\`!`, + ) .setColor("Gold"); - return message.reply({embeds: [bot_message]}); + return message.reply({ embeds: [bot_message] }); } }, }; diff --git a/events/onReady.js b/events/onReady.js index da24715..d71718f 100644 --- a/events/onReady.js +++ b/events/onReady.js @@ -16,15 +16,18 @@ module.exports = { * @param {import('../typings').Client} client Main Application Client. */ execute(client) { - client.user.setPresence({ - activities: [{ - type: ActivityType.Custom, - name: "Status", - state: "💾 Chilling on my owners computer!" - }] - }) + activities: [ + { + type: ActivityType.Custom, + name: "Status", + state: "💾 Chilling in the Cloud!", + }, + ], + }); - console.log(`Ready! Logged in as ${client.user.tag}`); + setTimeout(() => { + console.log(`Ready! Logged in as ${client.user.tag}`); + }, 25); }, }; diff --git a/events/slashCreate.js b/events/slashCreate.js index 402fddd..63ea47e 100644 --- a/events/slashCreate.js +++ b/events/slashCreate.js @@ -7,7 +7,8 @@ */ const { Collection, EmbedBuilder, Events } = require("discord.js"), -{ owner } = require("../config.json"); + { botInGuild } = require("../functions/other/utils"), + { owner } = require("../config.json"); module.exports = { name: Events.InteractionCreate, @@ -42,19 +43,28 @@ module.exports = { let cooldownAmount = command.cooldown ?? defaultCooldownDuration; if (interaction.inGuild()) { - allowedRoleIds = ["...", "..."]; - if (interaction.member.roles.cache.some(role => allowedRoleIds.includes(role.id))) { - const cooldownPercentage = 0.5; - cooldownAmount = Math.floor(cooldownAmount * cooldownPercentage); + if (botInGuild(interaction)) { + allowedRoleIds = ["...", "..."]; + if ( + interaction.member.roles.cache.some((role) => + allowedRoleIds.includes(role.id), + ) + ) { + const cooldownPercentage = 0.5; + cooldownAmount = Math.floor(cooldownAmount * cooldownPercentage); + } } } const isOwner = owner.includes(interaction.user.id); if (!isOwner && timestamps.has(interaction.user.id)) { - const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount * 1000; + const expirationTime = + timestamps.get(interaction.user.id) + cooldownAmount * 1000; const timeLeft = (expirationTime - now) / 1000; const embed = new EmbedBuilder() - .setDescription(`Please wait \`\`${timeLeft.toFixed(1)}\`\` more second(s) before reusing the \`${interaction.commandName}\` command.`) + .setDescription( + `Please wait \`\`${timeLeft.toFixed(1)}\`\` more second(s) before reusing the \`${interaction.commandName}\` command.`, + ) .setColor("Orange"); if (now < expirationTime) { const expiredTimestamp = Math.round(expirationTime / 1000); @@ -63,19 +73,25 @@ module.exports = { } timestamps.set(interaction.user.id, now); - setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount * 1000); + setTimeout( + () => timestamps.delete(interaction.user.id), + cooldownAmount * 1000, + ); const error = new EmbedBuilder() - .setDescription("**There was an issue while executing that command!\n\nPlease contact the Developers.**") + .setDescription( + "**There was an issue while executing that command!\n\nPlease contact the Developers.**", + ) .setColor("Red"); try { await command.execute(interaction); } catch (err) { + console.error(err); await interaction.reply({ embeds: [error], - ephemeral: true + ephemeral: true, }); } - } + }, }; diff --git a/events/taurusai.js b/events/taurusai.js index b6619ed..b825333 100644 --- a/events/taurusai.js +++ b/events/taurusai.js @@ -3,218 +3,163 @@ * @author TechyGiraffe999 */ - -const { Collection, ChannelType, Events, EmbedBuilder } = require("discord.js"); -const fs = require('fs').promises; -const path = require('path'); -const { GoogleGenerativeAI, HarmBlockThreshold, HarmCategory } = require("@google/generative-ai"); -const { Gemini_API_KEY } = require("../config.json"); -const genAI = new GoogleGenerativeAI(Gemini_API_KEY); +const { Events, EmbedBuilder } = require("discord.js"); +const fs = require("fs").promises; +const path = require("path"); +const { GoogleGenerativeAI } = require("@google/generative-ai"); +const { + getSafetySettings, + handleGeminiError, + handleResponse, + fetchThreadMessages, +} = require("../functions/other/utils"); +const { QuickDB } = require("quick.db"); +const { get } = require("http"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../functions/other/settings.sqlite"), +}); module.exports = { - name: Events.MessageCreate, - - async execute(message) { - if (message.author.bot || message.author.id === message.client.user.id) return; - if (message.type === 21) return; - - if (!Gemini_API_KEY || Gemini_API_KEY.length < 4) { - invalid_api = new EmbedBuilder() - .setTitle("⚠️ Invalid API Key") - .setDescription("> **The API Key for Gemini is invalid or not provided.**") - .setColor("Red") - return message.reply({ embeds: [invalid_api] }); - } - - let userQuestion - let threadMessages = []; - - if (message.reference) { - const originalMessage = await message.channel.messages.fetch(message.reference.messageId); - - if (originalMessage.author.id !== message.client.user.id) return; - - if (originalMessage.author.id === message.client.user.id) { - let currentMessage = message; - - while (currentMessage.reference) { - currentMessage = await message.channel.messages.fetch(currentMessage.reference.messageId); - const sender = currentMessage.author.id === message.client.user.id ? 'model' : 'user'; - let content = currentMessage.content; - if (sender === 'user') { - content = content.replace(/<@\d+>\s*/, ''); - } - threadMessages.unshift({ role: sender, parts: content }); - } - } - userQuestion = message.content - - } else if (!message.reference) { - const botMention = `<@${message.client.user.id}>`; - const regex = new RegExp(`^${botMention}\\s+.+`); - - if (!regex.test(message.content)) return; - - userQuestion = message.content - .replace(botMention, "") - .trim(); - } - - const user = message.author; - const sendTypingInterval = setInterval(() => { - message.channel.sendTyping(); - }, 5000); - - const loadingEmbed = new EmbedBuilder() - .setTitle("**⌛Loading your response**") - .setDescription("*TaurusAI may display innacurate/offensive info.*\n\n> *I am powered by Google's Generative AI, [Gemini](https://gemini.google.com) and was integrated by <@719815864135712799>.*") - .setFooter({text: "This may take a while", iconURL: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`}) - .setTimestamp() - const loadingMsg = await message.reply({ embeds: [loadingEmbed] }); - const loadingDots = [" ⌛ ", " ⏳ "]; - let i = 0; - const loadingInterval = setInterval(() => { - loadingEmbed.setTitle(`**${loadingDots[i]} Loading your response**`); - loadingMsg.edit({ embeds: [loadingEmbed] }); - i = (i + 1) % loadingDots.length; - }, 2000); - - const personalityFilePath = path.join(__dirname, '../personality.txt'); - const personalityContent = await fs.readFile(personalityFilePath, 'utf-8'); - const personalityLines = personalityContent.split('\n'); - - - const safetySettings = [ - { - category: HarmCategory.HARM_CATEGORY_HARASSMENT, - threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH, - }, - { - category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, - threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, - }, - { - category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, - threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, - }, - { - category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, - threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, - }, - ]; - - const user_status = message.member?.presence.clientStatus || {} - const status_devices = Object.entries(user_status) - .map(([platform, status]) => `${platform}: ${status}`) - .join("\n"); - - parts1 = `${personalityLines}\n Please greet the user with a greeting and then their name which is: <@${message.author.id}>.` - - if (Object.keys(user_status).length) { - parts1 += ` The user's presence is currently:\n${status_devices}`; - } - - async function run() { - const generationConfig = { - maxOutputTokens: 750, - }; - const model = genAI.getGenerativeModel({ model: "gemini-pro", safetySettings, generationConfig}); - - var history = [ - { - role: "user", - parts: parts1, - }, - { - role: "model", - parts: `I will greet the user with their name: <@${message.author.id}>. I will also limit all of my responses to 2000 characters or less, regardless of what you say. Feel feel free to ask me anything! 😊`, - }, - ]; - - if (history.length > 0 && threadMessages.length > 0 && history[history.length - 1].role === 'model' && threadMessages[0].role === 'model') { - history[history.length - 1].parts += threadMessages[0].parts; - threadMessages.shift(); - } - - history = history.concat(threadMessages); - - const chat = model.startChat({ - history, - generationConfig: { - maxOutputTokens: 750, - }, - }); - - const result = await chat.sendMessage(userQuestion); - const response = await result.response; - - const responseLength = response.text().length; - if (responseLength > 2000) { - response.text = response.text().substring(0, 1928 - "... \n\n".length) + "... \n\n*Response was cut short due to Discords character limit of 2000*"; - } - clearInterval(loadingInterval); - clearInterval(sendTypingInterval); - - let responseText = response.text(); - const regex = /<@&?\d+>/g; - let match; - - while ((match = regex.exec(responseText)) !== null) { - if (match[0] !== `<@${message.author.id}>`) { - const ping_error = new EmbedBuilder() - .setTitle("⚠️ Response Cannot Be Sent") - .setDescription("> *The generated message contains a mention of a Role or different User to the one that sent the original message/command.*") - .setColor("Red") - return await loadingMsg.edit({ embeds: [ping_error] }); - } - } - - responseText = responseText.replace(/(?"); - return await loadingMsg.edit({ content: responseText, embeds: [] }); - } - - try{ - await run(); - } catch (err) { - clearInterval(loadingInterval); - clearInterval(sendTypingInterval); - - switch (err.message) { - case "[GoogleGenerativeAI Error]: Text not available. Response was blocked due to SAFETY": - const safety_error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("> *The response was blocked due to **SAFETY**.*") - .setColor("Red") - - return await loadingMsg.edit({ embeds: [safety_error]}); - - case "[GoogleGenerativeAI Error]: Error fetching from https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent: [400 Bad Request] User location is not supported for the API use.": - const location_error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("> *The user location is not supported for Gemini API use. Please contact the Developers.*") - .setColor("Red") - - return await loadingMsg.edit({ embeds: [location_error]}); - - case "Cannot send an empty message": - case "response.text is not a function": - const error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("An error occurred while processing your request. Please try again later, or in a few minutes. \n*If this issue persists, please contact the Developers.* \n\n> - Generated response may be too long. *(Fix this by specifying for the generated response to be smaller, e.g. 10 Lines)*\n> - Token Limit for this minute may have been reached.") - .setColor("Red") - - return await loadingMsg.edit({ embeds: [error]}); - - default: - const error_unknown = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("An unknown error occurred while processing your request. Please try again later, or in a few minutes. \n*If this issue persists, please contact the Developers*\n> - Token Limit for this minute may have been reached.") - .setColor("Red") - - await loadingMsg.edit({embeds: [error_unknown] - }); - } - } - - }, -}; \ No newline at end of file + name: Events.MessageCreate, + + async execute(message) { + if (message.author.bot || message.author.id === message.client.user.id) + return; + if ([18, 21].includes(message.type)) return; + + const apiKeys = await db.get("apiKeys"); + const geminiApiKey = apiKeys.gemini; + const modelSettings = await db.get("model"); + let modelId = modelSettings.model; + const genAI = new GoogleGenerativeAI(geminiApiKey); + + let userQuestion; + let messageDeleted; + let threadMessages = []; + + if (message.reference) { + const { + userQuestion: fetchedUserQuestion, + threadMessages: fetchedThreadMessages, + messageDeleted: fetchedMessageDeleted, + } = await fetchThreadMessages(message); + if (fetchedUserQuestion === null && fetchedThreadMessages === null) + return; + threadMessages = fetchedThreadMessages; + userQuestion = fetchedUserQuestion; + messageDeleted = fetchedMessageDeleted; + } else if (!message.reference) { + const botMention = `<@${message.client.user.id}>`; + const regex = new RegExp(`^${botMention}\\s+.+`); + + if (!regex.test(message.content)) return; + userQuestion = message.content.replace(botMention, "").trim(); + } + + const user = message.author; + const sendTypingInterval = setInterval(() => { + message.channel.sendTyping(); + }, 5000); + + let loadingInterval; + let loadingMsg; + + async function run() { + const loadingEmbed = new EmbedBuilder() + .setTitle("**⌛Loading your response**") + .setDescription( + "*TaurusAI may display innacurate/offensive info.*\n\n> *I am powered by Google's Generative AI, [Gemini](https://gemini.google.com) and was integrated by <@719815864135712799>.*", + ) + .setFooter({ + text: "This may take a while", + iconURL: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`, + }) + .setTimestamp(); + loadingMsg = loadingMsg + ? await loadingMsg.edit({ embeds: [loadingEmbed] }) + : await message.reply({ embeds: [loadingEmbed] }); + const loadingDots = [" ⌛ ", " ⏳ "]; + let i = 0; + loadingInterval = setInterval(() => { + loadingEmbed.setTitle(`**${loadingDots[i]} Loading your response**`); + loadingMsg.edit({ embeds: [loadingEmbed] }); + i = (i + 1) % loadingDots.length; + }, 2000); + + const user_status = message.member?.presence.clientStatus || {}; + const status_devices = Object.entries(user_status) + .map(([platform, status]) => `${platform}: ${status}`) + .join("\n"); + + const personalityFilePath = path.join(__dirname, "../personality.txt"); + const personalityContent = await fs.readFile( + personalityFilePath, + "utf-8", + ); + const personalityLines = personalityContent.split("\n"); + + instruction = `${personalityLines}\n Please greet the user with a greeting and then the current users name, which is: <@${message.author.id}> and limit your responses to 2000 characters or less. Please note the current user may change.`; + + if (Object.keys(user_status).length) { + instruction += ` The user's status/presence is currently:\n${status_devices}`; + } + + const generationConfig = { + maxOutputTokens: 750, + }; + + const model = genAI.getGenerativeModel({ + model: modelId, + systemInstruction: instruction, + safetySettings: await getSafetySettings(), + generationConfig, + }); + + if ( + threadMessages && + threadMessages.length > 0 && + threadMessages[0].role === "model" + ) { + messageDeleted = "threadDeleted"; + threadMessages = []; + } + + const chat = model.startChat({ + history: threadMessages, + generationConfig: { + maxOutputTokens: 750, + }, + }); + + clearInterval(loadingInterval); + clearInterval(sendTypingInterval); + await handleResponse( + chat, + userQuestion, + false, + message, + loadingMsg, + messageDeleted, + ); + } + + let errorType = null; + do { + try { + await run(); + errorType = null; + } catch (err) { + clearInterval(loadingInterval); + sendTypingInterval && clearInterval(sendTypingInterval); + + errorType = await handleGeminiError(err, loadingMsg); + if (errorType === "quotaErrorBalance") { + modelId = + modelId === "gemini-1.5-pro-latest" + ? "gemini-1.5-flash-latest" + : "gemini-1.5-pro-latest"; + } + } + } while (errorType === "quota_error" || errorType === "quotaErrorBalance"); + }, +}; diff --git a/functions/logConsole.js b/functions/logConsole.js index b89b71b..de7e0f5 100644 --- a/functions/logConsole.js +++ b/functions/logConsole.js @@ -1,64 +1,98 @@ module.exports = (client) => { - const { WebhookClient, EmbedBuilder } = require('discord.js'); - const {webhook_url_console_logs} = require('../config.json'); - const webhookURL = webhook_url_console_logs; + const { WebhookClient, EmbedBuilder } = require("discord.js"); + const { QuickDB } = require("quick.db"); + const { + webhookUpdateEvent, + } = require("../interactions/modals/Settings/webhooks"); + const path = require("path"); + const db = new QuickDB({ + filePath: path.join(__dirname, "./other/settings.sqlite"), + }); + (async () => { + const webhooks = await db.get("webhooks"); + webhookUrlConsoleLogs = webhooks.console; + webhookURL = webhookUrlConsoleLogs; + let isWebhookSetupSuccessful = false; - let webhookClient; - try { - webhookClient = new WebhookClient({ url: webhookURL }); - } catch (error) { - console.log('\x1b[31m\x1b[1m%s\x1b[0m', 'CONSOLE LOGGING IN DISCORD DISABLED. WEBHOOK URL NOT PROVIDED OR INVALID.'); - return; - } + let webhookClient; + const setupWebhookClient = async () => { + try { + webhookClient = new WebhookClient({ url: webhookURL }); + isWebhookSetupSuccessful = true; + } catch (error) { + console.log( + "\x1b[31m\x1b[1m%s\x1b[0m", + "CONSOLE LOGGING IN DISCORD DISABLED. SET WEBHOOK URL WITH /SETTINGS.", + ); + isWebhookSetupSuccessful = false; + } + }; + await setupWebhookClient(); - function customLogger(type, ...messages) { - const combinedMessage = messages.map(m => (typeof m === 'object' ? JSON.stringify(m, null, 2) : m)).join(' '); - - if (combinedMessage === "By passing no model path, you're using the model hosted by Infinite.red - Please download and host the model before releasing this in production. See NSFWJS docs for instructions.") { - return; - } + webhookUpdateEvent.on("update", async (newWebhookUrl) => { + webhookURL = newWebhookUrl; + await setupWebhookClient(); + }); - let messageToSend = combinedMessage; - if (combinedMessage.length > 4070) { - messageToSend = `${combinedMessage.slice(0, 4067)}...`; - } - - const embed = new EmbedBuilder() - .setDescription(`\`\`\`console\n${messageToSend}\`\`\``) - .setColor(0x3498DB) - - if (type === 'error') { - embed.setColor('Red'); - } else if (type === 'warn') { - embed.setColor('Orange'); - } else if (combinedMessage === 'Started refreshing application (/) commands.' || - combinedMessage === 'Successfully reloaded application (/) commands.' || - combinedMessage.startsWith('Ready! Logged in as')) { - embed.setColor('Green'); - if (combinedMessage === 'Started refreshing application (/) commands.') { - embed.setTitle('💾 Console Log'); - } - } - - webhookClient.send({ - username: 'Taurus Console', - avatarURL: 'https://github.com/TecEash1/TecEash1/assets/92249532/bd4aca7e-daab-4eeb-9265-e53cc1925e8c', - embeds: [embed] - }).catch(console.error); - - console.originalLog(combinedMessage); - } - - console.originalLog = console.log; - console.log = customLogger.bind(null, 'log'); - - console.originalError = console.error; - console.error = customLogger.bind(null, 'error'); - - console.originalWarn = console.warn; - console.warn = customLogger.bind(null, 'warn'); - - console.originalInfo = console.info; - console.info = customLogger.bind(null, 'info'); + function customLogger(type, ...messages) { + const combinedMessage = messages + .map((m) => (typeof m === "object" ? JSON.stringify(m, null, 2) : m)) + .join(" "); -}; \ No newline at end of file + const blockedMessages = [ + "By not specifying 'modelOrUrl' parameter, you're using the default model: 'MobileNetV2'. See NSFWJS docs for instructions on hosting your own model (https://github.com/infinitered/nsfwjs?tab=readme-ov-file#host-your-own-model).", + "%cBy not specifying 'modelOrUrl' parameter, you're using the default model: 'MobileNetV2'. See NSFWJS docs for instructions on hosting your own model (https://github.com/infinitered/nsfwjs?tab=readme-ov-file#host-your-own-model). color: lightblue", + ]; + + if (blockedMessages.includes(combinedMessage)) return; + + let messageToSend = combinedMessage; + if (combinedMessage.length > 4070) { + messageToSend = `${combinedMessage.slice(0, 4067)}...`; + } + + const embed = new EmbedBuilder() + .setDescription(`\`\`\`console\n${messageToSend}\`\`\``) + .setColor(0x3498db); + + if (type === "error") { + embed.setColor("Red"); + } else if (type === "warn") { + embed.setColor("Orange"); + } else if ( + combinedMessage === "Started refreshing application (/) commands." || + combinedMessage === "Successfully reloaded application (/) commands." || + combinedMessage.startsWith("Ready! Logged in as") + ) { + embed.setColor("Green"); + if (combinedMessage === `Ready! Logged in as ${client.user.tag}`) { + embed.setTitle("💾 Console Log"); + } + } + + if (isWebhookSetupSuccessful) { + webhookClient + .send({ + username: "Taurus Console", + avatarURL: client.user.displayAvatarURL(), + embeds: [embed], + }) + .catch(console.error); + } + + console.originalLog(combinedMessage); + } + + console.originalLog = console.log; + console.log = customLogger.bind(null, "log"); + + console.originalError = console.error; + console.error = customLogger.bind(null, "error"); + + console.originalWarn = console.warn; + console.warn = customLogger.bind(null, "warn"); + + console.originalInfo = console.info; + console.info = customLogger.bind(null, "info"); + })(); +}; diff --git a/functions/other/settings.sqlite b/functions/other/settings.sqlite new file mode 100644 index 0000000..d2f4bb0 Binary files /dev/null and b/functions/other/settings.sqlite differ diff --git a/functions/other/utils.js b/functions/other/utils.js new file mode 100644 index 0000000..68830fc --- /dev/null +++ b/functions/other/utils.js @@ -0,0 +1,353 @@ +const { HarmCategory, HarmBlockThreshold } = require("@google/generative-ai"); +const { EmbedBuilder, DiscordAPIError, WebhookClient } = require("discord.js"); +const { owner } = require("../../config.json"); +const path = require("path"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "./settings.sqlite"), +}); +const axios = require("axios"); + +function botInGuild(interaction) { + const botGuilds = interaction.client.guilds.cache; + return botGuilds.has(interaction.guildId); +} + +async function getSafetySettings() { + const model = await db.get("model"); + const safetyEnabled = model.safetySystem; + + const safetySettings = [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, + }, + { + category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, + threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, + }, + { + category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, + threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, + }, + ].map((setting) => { + if (!safetyEnabled) { + setting.threshold = HarmBlockThreshold.BLOCK_NONE; + } + return setting; + }); + return safetySettings; +} + +async function handleGeminiError(err, loadingMsg) { + switch (err.message) { + case "[GoogleGenerativeAI Error]: Candidate was blocked due to SAFETY": + const safety_error = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "> *The response was blocked due to **SAFETY**.* \n- *Result based on your input. Safety Blocking may not be 100% correct.*", + ) + .setColor("Red"); + + return await loadingMsg.edit({ embeds: [safety_error] }); + case "Cannot send an empty message": + const error_empty = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "An error occurred while processing your request. Please try again later, or in a few minutes. \n▸ *If this issue persists, please contact the Developers.* \n> - Generated response may be too long. *(Fix this by specifying for the generated response to be smaller, e.g. 10 Lines)*\n> - Token Limit for this minute may have been reached.", + ) + .setColor("Red"); + + return await loadingMsg.edit({ embeds: [error_empty] }); + } + + switch (err.status) { + case 400: + const location_error = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "> *The user location is not supported for Gemini API use. Please contact the Developers.*", + ) + .setColor("Red"); + + return await loadingMsg.edit({ embeds: [location_error] }); + case 429: + const quota_error = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "There are a lot of requests at the moment. Please try again later, or in a few minutes. \n▸ *If this issue persists after a few minutes, please contact the Developers.* \n - *We are aware of these issues and apologize for the inconvenience.* \n> - Token Limit for this minute has been reached.", + ) + .setColor("Red"); + + const model = await db.get("model"); + const fallbackSystem = model.fallbackSystem; + if (fallbackSystem) { + return "quotaErrorBalance"; + } else { + for (let i = 5; i > 0; i--) { + quota_error.setFooter({ text: `⏱️ Retrying request in (${i})` }); + await loadingMsg.edit({ embeds: [quota_error] }); + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + return "quota_error"; + } + case 500: + const error_internal = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "An error occurred while processing your request. This error originated from Google's side, not ours. \n▸ *If this issue persists, please contact the Developers.* \n> - Please retry and make another request.", + ) + .setColor("Red"); + + return await loadingMsg.edit({ embeds: [error_internal] }); + case 403: + const invalid_api = new EmbedBuilder() + .setTitle("⚠️ Invalid API Key") + .setDescription( + "> **The API Key for Gemini is invalid or not provided.**", + ) + .setColor("Red"); + return await loadingMsg.edit({ embeds: [invalid_api] }); + default: + console.error(err.message); + const error_unknown = new EmbedBuilder() + .setTitle("⚠️ An Error Occurred") + .setDescription( + "An unknown error occurred while processing your request. Please try again later, or in a few minutes. \n▸ *If this issue persists, please contact the Developers.*\n> - Token Limit for this minute may have been reached.", + ) + .setColor("Red"); + + return await loadingMsg.edit({ embeds: [error_unknown] }); + } +} + +async function handleResponse( + chat, + userQuestion, + interaction, + message, + loadingMsg, + messageDeleted, + isContextMenuCommand, +) { + const result = await chat.sendMessage(userQuestion); + const response = await result.response; + let responseText = response.text(); + + const responseLength = response.text().length; + if (responseLength > 2000) { + responseText = + response.text().substring(0, 1936 - "... \n\n".length) + + "... \n\n*Response was cut short due to Discords character limit of 2000*"; + } + + const regex = /<@&?\d+>/g; + let match; + + while ((match = regex.exec(responseText)) !== null) { + const id = + message && message.author ? message.author.id : interaction.user.id; + + if (match[0] !== `<@${id}>`) { + const ping_error = new EmbedBuilder() + .setTitle("⚠️ Response Cannot Be Sent") + .setDescription( + "> *The generated message contains a mention of a Role or different User to the one that sent the original message/command.*", + ) + .setColor("Red"); + return await loadingMsg.edit({ embeds: [ping_error] }); + } + } + + let info_embed = []; + if (isContextMenuCommand) { + const footerText = `Response to message by ${message.author.tag}\n\n${message.content}`; + const truncatedFooterText = + footerText.length > 2030 ? `${footerText.slice(0, 2027)}...` : footerText; + + const info = new EmbedBuilder() + .setFooter({ text: truncatedFooterText }) + .setColor("Blue"); + + info_embed.push(info); + } + + switch (messageDeleted) { + case "threadDeleted": + const deletedThread = new EmbedBuilder() + .setFooter({ + text: "A message has been deleted/is not accessible in the reply thread, Taurus does not know the past reply thread history.", + }) + .setColor("Orange"); + + info_embed.push(deletedThread); + break; + case "slashCommand": + const deletedSlashCommand = new EmbedBuilder() + .setFooter({ + text: "Reply thread history not accessible, utilise history by mentioning me to chat instead.", + }) + .setColor("Orange"); + + info_embed.push(deletedSlashCommand); + break; + default: + break; + } + + // responseText = responseText.replace(/(https?:\/\/(?!media\.discordapp\.net\/attachments\/)[^\s\)]+)/g, "<$1>"); + return await loadingMsg.edit({ content: responseText, embeds: info_embed }); +} + +async function fetchThreadMessages(message) { + let threadMessages = []; + let messageDeleted; + userQuestion = message.content; + + try { + const originalMessage = await message.channel.messages.fetch( + message.reference.messageId, + ); + + const startStrings = [ + "Response to message by", + "A message has been deleted", + "Reply thread history", + ]; + + const linkRegex = + /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; + + if ( + originalMessage.author.id !== message.client.user.id || + (originalMessage.embeds.length > 0 && + (!originalMessage.embeds[0].footer || + !originalMessage.embeds[0].footer.text || + !startStrings.some((str) => + originalMessage.embeds[0].footer.text.startsWith(str), + )) && + !linkRegex.test(originalMessage.content)) + ) { + return { + userQuestion: null, + threadMessages: null, + messageDeleted: "threadDeleted", + }; + } + + if (originalMessage.author.id === message.client.user.id) { + let currentMessage = message; + + while ( + currentMessage.reference && + !( + currentMessage.author.id === message.client.user.id && + currentMessage.embeds.length > 0 && + !linkRegex.test(currentMessage.content) + ) + ) { + currentMessage = await message.channel.messages.fetch( + currentMessage.reference.messageId, + ); + const sender = + currentMessage.author.id === message.client.user.id + ? "model" + : "user"; + let content = currentMessage.content; + if (sender === "user") { + content = content.replace(/<@\d+>\s*/, ""); + } else if ( + sender === "model" && + currentMessage.embeds.length > 0 && + currentMessage.embeds[0].footer && + currentMessage.embeds[0].footer.text && + currentMessage.embeds[0].footer.text.startsWith( + "Response to message by", + ) + ) { + const footerText = currentMessage.embeds[0].footer.text; + const userMessage = footerText.split("\n")[2]; + threadMessages.unshift({ role: sender, parts: [{ text: content }] }); + threadMessages.unshift({ + role: "user", + parts: [{ text: userMessage }], + }); + continue; + } + threadMessages.unshift({ role: sender, parts: [{ text: content }] }); + } + } + } catch (error) { + if (error instanceof DiscordAPIError && error.code === 10008) { + messageDeleted = "threadDeleted"; + threadMessages = []; + } else { + throw error; + } + } + + return { userQuestion, threadMessages, messageDeleted }; +} + +async function checkWebhook(webhookURL) { + try { + const webhookClient = new WebhookClient({ url: webhookURL }); + return true; + } catch (error) { + return false; + } +} + +const checkAPIKey = async (type, apiKey) => { + let url, headers; + + switch (type.toLowerCase()) { + case "prodia": + url = "https://api.prodia.com/v1/sd/loras"; + headers = { "X-Prodia-Key": apiKey, accept: "application/json" }; + break; + case "gemini": + url = `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`; + headers = {}; + break; + default: + throw new Error(`Invalid API type: ${type}`); + } + + try { + const response = await axios.get(url, { headers }); + return response.status === 200; + } catch (error) { + return false; + } +}; + +function checkOwnerAndReply(interaction) { + const no_access = new EmbedBuilder() + .setDescription("**⚠️ This is limited to Developers Only!**") + .setColor("Red"); + + if (!owner.includes(interaction.user.id)) { + interaction.reply({ + embeds: [no_access], + ephemeral: true, + }); + return false; + } + return true; +} + +module.exports = { + botInGuild, + getSafetySettings, + handleGeminiError, + handleResponse, + fetchThreadMessages, + checkWebhook, + checkAPIKey, + checkOwnerAndReply, +}; diff --git a/interactions/autocomplete/category/imageModel.js b/interactions/autocomplete/category/imageModel.js new file mode 100644 index 0000000..68b07af --- /dev/null +++ b/interactions/autocomplete/category/imageModel.js @@ -0,0 +1,54 @@ +/** + * @file Image Autocomplete Interaction + * @author TechyGiraffe999 + */ + +/** + * @type {import("../../../typings").AutocompleteInteraction} + */ + +const { QuickDB } = require("quick.db"); +const path = require("path"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); +module.exports = { + name: "image", + async execute(interaction) { + const focusedOption = interaction.options.getFocused(); + + const apiKeys = await db.get("apiKeys"); + const XProdiaKey = apiKeys.prodia; + + const sdk = require("api")("@prodia/v1.3.0#6fdmny2flsvwyf65"); + sdk.auth(XProdiaKey); + + async function fetchAndFormatModels(apiMethod) { + try { + const { data } = await apiMethod(); + const models = JSON.parse(data); + return models; + } catch (e) { + console.error("Error fetching models: ", e); + } + } + + const [sdModels, sdxlModels] = await Promise.all([ + fetchAndFormatModels(sdk.listModels), + fetchAndFormatModels(sdk.listSdxlModels), + ]); + + const allModels = [...sdModels, ...sdxlModels]; + const filteredModels = allModels.filter((model) => + model.toLowerCase().startsWith(focusedOption.toLowerCase()), + ); + + const results = filteredModels.map((model) => ({ + name: model, + value: model, + })); + + await interaction.respond(results.slice(0, 25)).catch(() => {}); + return; + }, +}; diff --git a/interactions/buttons/settings/apiKeys.js b/interactions/buttons/settings/apiKeys.js new file mode 100644 index 0000000..e602013 --- /dev/null +++ b/interactions/buttons/settings/apiKeys.js @@ -0,0 +1,38 @@ +/** + * @file Settings API Key button interaction + * @author TechyGiraffe999 + */ + +/** + * @type {import('../../../typings').ButtonInteractionCommand} + */ +const { + ActionRowBuilder, + ModalBuilder, + TextInputBuilder, + TextInputStyle, +} = require("discord.js"); +const { checkOwnerAndReply } = require("../../../functions/other/utils"); +module.exports = { + id: ["gemini", "prodia"], + + async execute(interaction) { + if (!checkOwnerAndReply(interaction)) { + return; + } + const modal = new ModalBuilder() + .setCustomId(`${interaction.customId}`) + .setTitle("API Key Configuration"); + + const apiKeyForm = new TextInputBuilder() + .setCustomId("apiKey") + .setLabel("Your API Key") + .setPlaceholder("Your API Key Here") + .setMinLength(35) + .setMaxLength(50) + .setStyle(TextInputStyle.Short); + + modal.addComponents(new ActionRowBuilder().addComponents(apiKeyForm)); + return await interaction.showModal(modal); + }, +}; diff --git a/interactions/buttons/settings/model.js b/interactions/buttons/settings/model.js new file mode 100644 index 0000000..c452eec --- /dev/null +++ b/interactions/buttons/settings/model.js @@ -0,0 +1,70 @@ +/** + * @file Settings Other/Model Button interaction + * @author TechyGiraffe999 + */ + +/** + * @type {import('../../../typings').ButtonInteractionCommand} + */ +const { EmbedBuilder } = require("discord.js"); +const path = require("path"); +const { QuickDB } = require("quick.db"); +const { emojis } = require("../../../config.json"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); +const { checkOwnerAndReply } = require("../../../functions/other/utils"); + +module.exports = { + id: ["fallbackSystem", "safetySystem", "model"], + + async execute(interaction) { + if (!checkOwnerAndReply(interaction)) { + return; + } + const modelSettings = await db.get("model"); + let updatedSetting; + + switch (interaction.customId) { + case "fallbackSystem": + modelSettings.fallbackSystem = !modelSettings.fallbackSystem; + updatedSetting = `**🛡️ Fallback System ${modelSettings.fallbackSystem ? "Enabled" : "Disabled"}**`; + break; + case "safetySystem": + modelSettings.safetySystem = !modelSettings.safetySystem; + updatedSetting = `**${modelSettings.safetySystem ? "🔒" : "🔓"} Safety System ${modelSettings.safetySystem ? "Enabled" : "Disabled"}**`; + break; + case "model": + modelSettings.model = + modelSettings.model === "gemini-1.5-flash-latest" + ? "gemini-1.5-pro-latest" + : "gemini-1.5-flash-latest"; + updatedSetting = `**🧠 Model switched to \`\`${modelSettings.model === "gemini-1.5-flash-latest" ? "Gemini 1.5 Flash" : "Gemini 1.5 Pro"}\`\`**`; + break; + } + + await db.set("model", modelSettings); + const embed = new EmbedBuilder() + .setDescription(updatedSetting) + .setColor("Green"); + + const message = await interaction.message.fetch(); + const embedData = message.embeds[0]; + const otherFieldIndex = embedData.data.fields.find( + (field) => field.name === "🧠 Model:", + ); + otherFieldIndex.value = `${modelSettings.fallbackSystem ? emojis.working : emojis.failed} **Fallback System**\n${modelSettings.safetySystem ? emojis.working : emojis.failed} **Safety System**\n${modelSettings.model === "gemini-1.5-flash-latest" ? "⚡" : "💪"} **${modelSettings.model + .replace(/-latest$/, "") + .replace(/-/g, " ") + .split(" ") + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" ")}**`; + + message.edit({ embeds: [embedData] }); + + return await interaction.reply({ + embeds: [embed], + ephemeral: true, + }); + }, +}; diff --git a/interactions/buttons/settings/other.js b/interactions/buttons/settings/other.js new file mode 100644 index 0000000..5658684 --- /dev/null +++ b/interactions/buttons/settings/other.js @@ -0,0 +1,54 @@ +/** + * @file Settings Other Button interaction + * @author TechyGiraffe999 + */ + +/** + * @type {import('../../../typings').ButtonInteractionCommand} + */ +const { EmbedBuilder } = require("discord.js"); +const path = require("path"); +const { QuickDB } = require("quick.db"); +const { emojis } = require("../../../config.json"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); +const { checkOwnerAndReply } = require("../../../functions/other/utils"); + +module.exports = { + id: ["blockNSFWImages"], + + async execute(interaction) { + if (!checkOwnerAndReply(interaction)) { + return; + } + const otherSettings = await db.get("other"); + let updatedSetting; + + switch (interaction.customId) { + case "blockNSFWImages": + otherSettings.blockNSFWImages = !otherSettings.blockNSFWImages; + updatedSetting = `**🔞 NSFW Image Blocking ${otherSettings.blockNSFWImages ? "Enabled" : "Disabled"}**`; + break; + } + + await db.set("other", otherSettings); + const embed = new EmbedBuilder() + .setDescription(updatedSetting) + .setColor("Green"); + + const message = await interaction.message.fetch(); + const embedData = message.embeds[0]; + const otherFieldIndex = embedData.data.fields.find( + (field) => field.name === "⚙️ Other:", + ); + otherFieldIndex.value = `${otherSettings.blockNSFWImages ? emojis.working : emojis.failed} **NSFW Image Blocking**`; + + message.edit({ embeds: [embedData] }); + + return await interaction.reply({ + embeds: [embed], + ephemeral: true, + }); + }, +}; diff --git a/interactions/buttons/settings/webhooks.js b/interactions/buttons/settings/webhooks.js new file mode 100644 index 0000000..5d0f142 --- /dev/null +++ b/interactions/buttons/settings/webhooks.js @@ -0,0 +1,38 @@ +/** + * @file Settings Webhook button interaction + * @author TechyGiraffe999 + */ + +/** + * @type {import('../../../typings').ButtonInteractionCommand} + */ + +const { + ActionRowBuilder, + ModalBuilder, + TextInputBuilder, + TextInputStyle, +} = require("discord.js"); +const { checkOwnerAndReply } = require("../../../functions/other/utils"); + +module.exports = { + id: ["personality", "console"], + + async execute(interaction) { + if (!checkOwnerAndReply(interaction)) { + return; + } + const modal = new ModalBuilder() + .setCustomId(`${interaction.customId}`) + .setTitle("Webhook Configuration"); + + const webhookForm = new TextInputBuilder() + .setCustomId("webhook") + .setLabel("Your Webhook") + .setPlaceholder("Your Webhook URL Here") + .setStyle(TextInputStyle.Paragraph); + + modal.addComponents(new ActionRowBuilder().addComponents(webhookForm)); + return await interaction.showModal(modal); + }, +}; diff --git a/interactions/context-menus/message/taurusai.js b/interactions/context-menus/message/taurusai.js new file mode 100644 index 0000000..d64b276 --- /dev/null +++ b/interactions/context-menus/message/taurusai.js @@ -0,0 +1,185 @@ +/** + * @file Taurus Context Menu. + * @author TechyGiraffe999 + */ + +/** + * @type {import("../../../typings").ContextInteractionCommand} + */ + +const { EmbedBuilder } = require("discord.js"); +const fs = require("fs").promises; +const path = require("path"); +const { GoogleGenerativeAI } = require("@google/generative-ai"); +const { + getSafetySettings, + handleGeminiError, + handleResponse, + fetchThreadMessages, +} = require("../../../functions/other/utils"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); + +module.exports = { + data: { + name: "Taurus", + type: 3, + }, + + async execute(interaction) { + const { channel, targetId } = interaction; + const apiKeys = await db.get("apiKeys"); + const geminiApiKey = apiKeys.gemini; + const modelSettings = await db.get("model"); + let modelId = modelSettings.model; + const genAI = new GoogleGenerativeAI(geminiApiKey); + + const message = await channel.messages.fetch(targetId); + + if (message.author.bot || message.author.id === message.client.user.id) { + return interaction.reply({ + content: "I cant reply to myself or another bot!", + ephemeral: true, + }); + } + + let userQuestion; + let messageDeleted; + let threadMessages = []; + + if (message.reference) { + const { + userQuestion: fetchedUserQuestion, + threadMessages: fetchedThreadMessages, + messageDeleted: fetchedMessageDeleted, + } = await fetchThreadMessages(geminiApiKey, message); + if (fetchedUserQuestion === null && fetchedThreadMessages === null) + return; + threadMessages = fetchedThreadMessages; + userQuestion = fetchedUserQuestion; + messageDeleted = fetchedMessageDeleted; + } else if (!message.reference) { + const botMention = `<@${message.client.user.id}>`; + const regex = new RegExp(`^${botMention}\\s+.+`); + + userQuestion = message.content.replace(botMention, "").trim(); + } + + const sendTypingInterval = setInterval(() => { + interaction.channel.sendTyping(); + }, 5000); + + const user = message.author; + + let loadingInterval; + let loadingMsg; + + async function run() { + const loadingEmbed = new EmbedBuilder() + .setTitle("**⌛Loading your response**") + .setDescription( + "*TaurusAI may display innacurate/offensive info.*\n\n> *I am powered by Google's Generative AI, [Gemini](https://gemini.google.com) and was integrated by <@719815864135712799>.*", + ) + .setFooter({ + text: "This may take a while", + iconURL: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`, + }) + .setTimestamp(); + loadingMsg = loadingMsg + ? await loadingMsg.edit({ embeds: [loadingEmbed] }) + : await interaction.reply({ embeds: [loadingEmbed] }); + const loadingDots = [" ⌛ ", " ⏳ "]; + let i = 0; + const loadingInterval = setInterval(() => { + loadingEmbed.setTitle(`**${loadingDots[i]} Loading your response**`); + loadingMsg.edit({ embeds: [loadingEmbed] }); + i = (i + 1) % loadingDots.length; + }, 2000); + + const personalityFilePath = path.join( + __dirname + "../../../../personality.txt", + ); + const personalityContent = await fs.readFile( + personalityFilePath, + "utf-8", + ); + const personalityLines = personalityContent.split("\n"); + + const botMention = `<@${message.client.user.id}>`; + + userQuestion = message.content.replace(botMention, "").trim(); + + const user_status = message.member?.presence.clientStatus || {}; + const status_devices = Object.entries(user_status) + .map(([platform, status]) => `${platform}: ${status}`) + .join("\n"); + + instruction = `${personalityLines}\n Please greet the user with a greeting and then their name which is: <@${message.author.id}> and limit your responses to 2000 characters or less.`; + + if (Object.keys(user_status).length) { + instruction += ` The user's status/presence is currently:\n${status_devices}`; + } + + const generationConfig = { + maxOutputTokens: 750, + }; + + const model = genAI.getGenerativeModel({ + model: modelId, + systemInstruction: instruction, + safetySettings: await getSafetySettings(), + generationConfig, + }); + + if ( + threadMessages && + threadMessages.length > 0 && + threadMessages[0].role === "model" + ) { + messageDeleted = "threadDeleted"; + threadMessages = []; + } + + const chat = model.startChat({ + history: threadMessages, + generationConfig: { + maxOutputTokens: 750, + }, + }); + + clearInterval(loadingInterval); + sendTypingInterval && clearInterval(sendTypingInterval); + await handleResponse( + chat, + userQuestion, + interaction, + message, + loadingMsg, + messageDeleted, + true, + ); + } + + let errorType = null; + do { + try { + await run(); + errorType = null; + } catch (err) { + clearInterval(loadingInterval); + sendTypingInterval && clearInterval(sendTypingInterval); + + errorType = await handleGeminiError(err, loadingMsg); + + if (errorType === "quotaErrorBalance") { + modelId = + modelId === "gemini-1.5-pro-latest" + ? "gemini-1.5-flash-latest" + : "gemini-1.5-pro-latest"; + } + } + } while (errorType === "quota_error" || errorType === "quotaErrorBalance"); + }, +}; diff --git a/interactions/modals/AI/ask.js b/interactions/modals/AI/ask.js new file mode 100644 index 0000000..b08b4bc --- /dev/null +++ b/interactions/modals/AI/ask.js @@ -0,0 +1,139 @@ +/** + * @file TaurusAI Ask Modal. + * @author TechyGiraffe999 + */ + +/** + * @type {import("../../../../typings").ModalInteractionCommand} + */ +const fs = require("fs").promises; +const path = require("path"); +const { EmbedBuilder } = require("discord.js"); +const { GoogleGenerativeAI } = require("@google/generative-ai"); +const { + botInGuild, + getSafetySettings, + handleGeminiError, + handleResponse, +} = require("../../../functions/other/utils"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); + +module.exports = { + id: "taurus_ai", + + async execute(interaction) { + const apiKeys = await db.get("apiKeys"); + const geminiApiKey = apiKeys.gemini; + const modelSettings = await db.get("model"); + let modelId = modelSettings.model; + const genAI = new GoogleGenerativeAI(geminiApiKey); + + const personalityFilePath = path.join( + __dirname + "../../../../personality.txt", + ); + const personalityContent = await fs.readFile(personalityFilePath, "utf-8"); + const personalityLines = personalityContent.split("\n"); + + const userQuestion = + interaction.fields.getTextInputValue("question_taurusai"); + + const sendTypingInterval = + interaction.inGuild() && botInGuild(interaction) + ? setInterval(() => { + interaction.channel.sendTyping(); + }, 5000) + : null; + + let loadingInterval; + let loadingMsg; + + async function run() { + const loadingEmbed = new EmbedBuilder() + .setTitle("**Loading your response . . .**") + .setDescription( + "*TaurusAI may display innacurate/offensive info.*\n\n> *I am powered by Google's Generative AI, [Gemini](https://gemini.google.com) and was integrated by <@719815864135712799>.*", + ) + .setFooter({ + text: "⏳ This may take a while", + iconURL: interaction.user.displayAvatarURL(), + }) + .setTimestamp(); + loadingMsg = loadingMsg + ? await loadingMsg.edit({ embeds: [loadingEmbed] }) + : await interaction.reply({ embeds: [loadingEmbed] }); + const loadingDots = ["", " . ", " . . ", " . . ."]; + let i = 0; + const loadingInterval = setInterval(async () => { + loadingEmbed.setTitle(`**Loading your response ${loadingDots[i]}**`); + await loadingMsg.edit({ embeds: [loadingEmbed] }); + i = (i + 1) % loadingDots.length; + }, 500); + + const user_status = + interaction.inGuild() && botInGuild(interaction) + ? interaction.member?.presence.clientStatus + : {}; + + const status_devices = Object.entries(user_status) + .map(([platform, status]) => `${platform}: ${status}`) + .join("\n"); + + instruction = `${personalityLines}\n Please greet the user with a greeting and then their name which is: <@${interaction.user.id}> and limit your responses to 2000 characters or less.`; + + if (Object.keys(user_status).length) { + instruction += ` The user's status/presence is currently:\n${status_devices}`; + } + + const generationConfig = { + maxOutputTokens: 750, + }; + + const model = genAI.getGenerativeModel({ + model: modelId, + systemInstruction: instruction, + safetySettings: await getSafetySettings(), + generationConfig, + }); + + const chat = model.startChat({ + generationConfig: { + maxOutputTokens: 750, + }, + }); + + clearInterval(loadingInterval); + clearInterval(sendTypingInterval); + await handleResponse( + chat, + userQuestion, + interaction, + false, + loadingMsg, + "slashCommand", + ); + } + + let errorType = null; + do { + try { + await run(); + errorType = null; + } catch (err) { + clearInterval(loadingInterval); + sendTypingInterval && clearInterval(sendTypingInterval); + + errorType = await handleGeminiError(err, loadingMsg); + + if (errorType === "quotaErrorBalance") { + modelId = + modelId === "gemini-1.5-pro-latest" + ? "gemini-1.5-flash-latest" + : "gemini-1.5-pro-latest"; + } + } + } while (errorType === "quota_error" || errorType === "quotaErrorBalance"); + }, +}; diff --git a/interactions/modals/Settings/apiKeys.js b/interactions/modals/Settings/apiKeys.js new file mode 100644 index 0000000..459539c --- /dev/null +++ b/interactions/modals/Settings/apiKeys.js @@ -0,0 +1,92 @@ +/** + * @file APIKey Settings Modal. + * @author TechyGiraffe999 + */ + +/** + * @type {import("../../../../typings").ModalInteractionCommand} + */ +const fs = require("fs").promises; +const path = require("path"); +const { EmbedBuilder } = require("discord.js"); +const { checkAPIKey } = require("../../../functions/other/utils"); +const { emojis } = require("../../../config.json"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); + +module.exports = { + id: ["gemini", "prodia"], + + async execute(interaction) { + const apiKeyName = + interaction.customId.charAt(0).toUpperCase() + + interaction.customId.slice(1); + embed = new EmbedBuilder() + .setDescription(`**${emojis.loading} Checking ${apiKeyName} API Key**`) + .setColor("Green"); + + await interaction.reply({ embeds: [embed], ephemeral: true }); + const apiKey = interaction.fields.getTextInputValue("apiKey"); + const apiKeys = await db.get("apiKeys"); + + if (apiKeys[interaction.customId] === apiKey) { + const alreadyRegistered = new EmbedBuilder() + .setDescription( + `**🔑 ${apiKeyName} API Key is already registered. (Duplicate Key)**`, + ) + .setColor("Yellow"); + await interaction.editReply({ + embeds: [alreadyRegistered], + ephemeral: true, + }); + return; + } + + let isValidKey; + isValidKey = await checkAPIKey(interaction.customId, apiKey); + + if (!isValidKey) { + const invalidKey = new EmbedBuilder() + .setDescription( + `**🔑 ${apiKeyName} API Key Checking Failed, Key invalid**`, + ) + .setColor("Red"); + await interaction.editReply({ embeds: [invalidKey] }); + return; + } + + const successEmbed = new EmbedBuilder() + .setDescription( + `**🔑 ${apiKeyName} API Key Checking Successful, the Key was updated!**`, + ) + .setColor("Green"); + await interaction.editReply({ embeds: [successEmbed] }); + + const message = await interaction.message.fetch(); + const embedData = message.embeds[0]; + + const apiKeysFieldIndex = embedData.data.fields.findIndex( + (field) => field.name === "🔑 API Keys:", + ); + const apiKeysFieldValue = embedData.data.fields[apiKeysFieldIndex].value; + const prodiaKeyStatus = apiKeysFieldValue.split("\n")[0]; + const geminiKeyStatus = apiKeysFieldValue.split("\n")[1]; + + switch (interaction.customId) { + case "prodia": + apiKeys.prodia = apiKey; + embedData.data.fields[apiKeysFieldIndex].value = + `${isValidKey ? emojis.working : emojis.failed} **Prodia**\n${geminiKeyStatus}`; + break; + case "gemini": + apiKeys.gemini = apiKey; + embedData.data.fields[apiKeysFieldIndex].value = + `${prodiaKeyStatus}\n${isValidKey ? emojis.working : emojis.failed} **Gemini**`; + } + + await db.set("apiKeys", apiKeys); + await message.edit({ embeds: [embedData] }); + }, +}; diff --git a/interactions/modals/Settings/webhooks.js b/interactions/modals/Settings/webhooks.js new file mode 100644 index 0000000..7ca2947 --- /dev/null +++ b/interactions/modals/Settings/webhooks.js @@ -0,0 +1,111 @@ +/** + * @file Webhook Settings Modal. + * @author TechyGiraffe999 + */ + +/** + * @type {import("../../../../typings").ModalInteractionCommand} + */ +const fs = require("fs").promises; +const path = require("path"); +const { EventEmitter } = require("events"); +const webhookUpdateEvent = new EventEmitter(); +const { EmbedBuilder, WebhookClient } = require("discord.js"); +const { checkWebhook } = require("../../../functions/other/utils"); +const { emojis } = require("../../../config.json"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); + +module.exports = { + id: ["personality", "console"], + webhookUpdateEvent, + + async execute(interaction) { + const webhookName = + interaction.customId.charAt(0).toUpperCase() + + interaction.customId.slice(1); + embed = new EmbedBuilder() + .setDescription(`**${emojis.loading} Checking ${webhookName} Webhook**`) + .setColor("Green"); + + await interaction.reply({ embeds: [embed], ephemeral: true }); + const webhook = interaction.fields.getTextInputValue("webhook"); + const webhooks = await db.get("webhooks"); + + let isValidWebhook; + isValidWebhook = await checkWebhook(webhook); + + if (webhooks[interaction.customId] === webhook) { + const alreadyRegistered = new EmbedBuilder() + .setDescription( + `**🔑 ${webhookName} Webhook is already registered. (Duplicate Webhook)**`, + ) + .setColor("Yellow"); + await interaction.editReply({ + embeds: [alreadyRegistered], + ephemeral: true, + }); + return; + } + + if (!isValidWebhook) { + const invalidWebhook = new EmbedBuilder() + .setDescription( + `**🔑 ${webhookName} Webhook Checking Failed, Webhook invalid**`, + ) + .setColor("Red"); + await interaction.editReply({ embeds: [invalidWebhook] }); + return; + } + + webhookClient = new WebhookClient({ url: webhook }); + const emoji = interaction.customId === "console" ? "💾" : "✨"; + const webhookEmbed = new EmbedBuilder() + .setDescription( + `**${emoji} Taurus ${webhookName} Webhook Registered, Updates will be logged here**`, + ) + .setColor("Green"); + webhookClient + .send({ + username: `Taurus ${webhookName}`, + avatarURL: interaction.client.user.displayAvatarURL(), + embeds: [webhookEmbed], + }) + .catch(console.error); + + const successEmbed = new EmbedBuilder() + .setDescription( + `**🔑 ${webhookName} Webhook Checking Successful, the Webhook was updated!**`, + ) + .setColor("Green"); + await interaction.editReply({ embeds: [successEmbed] }); + + const message = await interaction.message.fetch(); + const embedData = message.embeds[0]; + + const webhookFieldIndex = embedData.data.fields.findIndex( + (field) => field.name === "🔗 Webhooks:", + ); + const webhooksFieldValue = embedData.data.fields[webhookFieldIndex].value; + const personalityWebhookStatus = webhooksFieldValue.split("\n")[0]; + const consoleWebhookStatus = webhooksFieldValue.split("\n")[1]; + + switch (interaction.customId) { + case "personality": + webhooks.personality = webhook; + embedData.data.fields[webhookFieldIndex].value = + `${isValidWebhook ? emojis.working : emojis.failed} **Personality**\n${consoleWebhookStatus}`; + break; + case "console": + webhooks.console = webhook; + embedData.data.fields[webhookFieldIndex].value = + `${personalityWebhookStatus}\n${isValidWebhook ? emojis.working : emojis.failed} **Console**`; + webhookUpdateEvent.emit("update", webhooks.console); + } + + await db.set("webhooks", webhooks); + await message.edit({ embeds: [embedData] }); + }, +}; diff --git a/interactions/modals/category/ask.js b/interactions/modals/category/ask.js deleted file mode 100644 index c4c514e..0000000 --- a/interactions/modals/category/ask.js +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file TaurusAI Ask Modal. - * @author TechyGiraffe999 - */ - -/** - * @type {import("../../../../typings").ModalInteractionCommand} - */ -const fs = require('fs').promises; -const path = require('path'); -const { EmbedBuilder } = require("discord.js"); -const { GoogleGenerativeAI, HarmBlockThreshold, HarmCategory } = require("@google/generative-ai"); -const { Gemini_API_KEY } = require("../../../config.json"); -const genAI = new GoogleGenerativeAI(Gemini_API_KEY); - - -module.exports = { - id: "taurus_ai", - - async execute(interaction) { - if (!Gemini_API_KEY || Gemini_API_KEY.length < 4) { - invalid_api = new EmbedBuilder() - .setTitle("⚠️ Invalid API Key") - .setDescription("> **The API Key for Gemini is invalid or not provided.**") - .setColor("Red") - return interaction.reply({ embeds: [invalid_api] }); - } - - const personalityFilePath = path.join(__dirname + '../../../../personality.txt'); - const personalityContent = await fs.readFile(personalityFilePath, 'utf-8'); - const personalityLines = personalityContent.split('\n'); - - const userQuestion = interaction.fields.getTextInputValue("question_taurusai"); - - const sendTypingInterval = setInterval(() => { - interaction.channel.sendTyping(); - }, 5000); - - const loadingEmbed = new EmbedBuilder() - .setTitle("**Loading your response . . .**") - .setDescription("*TaurusAI may display innacurate/offensive info.*\n\n> *I am powered by Google's Generative AI, [Gemini](https://gemini.google.com) and was integrated by <@719815864135712799>.*") - .setFooter({text: "⏳ This may take a while", iconURL: interaction.user.displayAvatarURL()}) - .setTimestamp() - const loadingMsg = await interaction.reply({ embeds: [loadingEmbed] - //, ephemeral: true - }); - const loadingDots = [""," . ", " . . ", " . . ."]; - let i = 0; - const loadingInterval = setInterval(async () => { - loadingEmbed.setTitle(`**Loading your response ${loadingDots[i]}**`); - await loadingMsg.edit({ embeds: [loadingEmbed] }); - i = (i + 1) % loadingDots.length; - }, 500); - - const safetySettings = [ - { - category: HarmCategory.HARM_CATEGORY_HARASSMENT, - threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH, - }, - { - category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, - threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, - }, - { - category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, - threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, - }, - { - category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, - threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, - }, - ]; - - const user_status = interaction.member?.presence.clientStatus || {} - const status_devices = Object.entries(user_status) - .map(([platform, status]) => `${platform}: ${status}`) - .join("\n"); - - parts1 = `${personalityLines}\n Please greet the user with a greeting and then their name which is: <@${interaction.user.id}>.` - - if (Object.keys(user_status).length) { - parts1 += ` The user's presence is currently:\n${status_devices}`; - } - - async function run() { - const generationConfig = { - maxOutputTokens: 750, - }; - const model = genAI.getGenerativeModel({ model: "gemini-pro", safetySettings, generationConfig}); - - const chat = model.startChat({ - history: [ - { - role: "user", - parts: parts1, - }, - { - role: "model", - parts: `I will greet the user with their name: <@${interaction.user.id}>. I will also limit all of my responses to 2000 characters or less, regardless of what you say. Feel feel free to ask me anything! 😊`, - }, - ], - generationConfig: { - maxOutputTokens: 750, - }, - }); - - - const result = await chat.sendMessage(userQuestion); - const response = await result.response; - - const responseLength = response.text().length; - if (responseLength > 2000) { - response.text = response.text().substring(0, 1928 - "... \n\n".length) + "... \n\n*Response was cut short due to Discords character limit of 2000*"; - } - clearInterval(loadingInterval); - clearInterval(sendTypingInterval); - - let responseText = response.text(); - const regex = /<@&?\d+>/g; - let match; - - while ((match = regex.exec(responseText)) !== null) { - if (match[0] !== `<@${interaction.user.id}>`) { - const ping_error = new EmbedBuilder() - .setTitle("⚠️ Response Cannot Be Sent") - .setDescription("> *The generated message contains a mention of a Role or different User to the one that sent the original message/command.*") - .setColor("Red") - return await interaction.editReply({ embeds: [ping_error] }); - } - } - - responseText = responseText.replace(/(?"); - return await loadingMsg.edit({ content: responseText, embeds: [] }); - } - - try{ - await run(); - } catch (err) { - clearInterval(loadingInterval); - clearInterval(sendTypingInterval); - - switch (err.message) { - case "[GoogleGenerativeAI Error]: Text not available. Response was blocked due to SAFETY": - const safety_error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("> *The response was blocked due to **SAFETY**.*") - .setColor("Red") - - return await interaction.editReply({ embeds: [safety_error]}); - - case "[GoogleGenerativeAI Error]: Error fetching from https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent: [400 Bad Request] User location is not supported for the API use.": - const location_error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("> *The user location is not supported for Gemini API use. Please contact the Developers.*") - .setColor("Red") - - return await interaction.editReply({ embeds: [location_error]}); - - case "Cannot send an empty message": - case "response.text is not a function": - const error = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("An error occurred while processing your request. Please try again later, or in a few minutes. \n*If this issue persists, please contact the Developers.* \n\n> - Generated response may be too long. *(Fix this by specifying for the generated response to be smaller, e.g. 10 Lines)*\n> - Token Limit for this minute may have been reached.") - .setColor("Red") - - return await interaction.editReply({ embeds: [error]}); - - default: - const error_unknown = new EmbedBuilder() - .setTitle("⚠️ An Error Occurred") - .setDescription("An unknown error occurred while processing your request. Please try again later, or in a few minutes. \n*If this issue persists, please contact the Developers.*\n> - Token Limit for this minute may have been reached.") - .setColor("Red") - - await interaction.editReply({embeds: [error_unknown] - }); - } - } - } -}; \ No newline at end of file diff --git a/interactions/slash/misc/help.js b/interactions/slash/misc/help.js index f376bca..62b9f6f 100644 --- a/interactions/slash/misc/help.js +++ b/interactions/slash/misc/help.js @@ -3,25 +3,32 @@ * @author TechyGiraffe999 */ - const { EmbedBuilder, SlashCommandBuilder, Embed } = require("discord.js"); /** * @type {import('../../../typings').SlashInteractionCommand} */ module.exports = { - data: new SlashCommandBuilder() - .setName('help') - .setDescription('Display available slash commands'), - async execute(interaction, client) { - const commands = interaction.client.slashCommands; - const commandList = commands.map((command) => `**/${command.data.name}**: ${command.data.description}`).join('\n'); + data: new SlashCommandBuilder() + .setName("help") + .setDescription("Display available slash commands"), + async execute(interaction) { + const commands = ( + await interaction.client.application.commands.fetch() + ).filter((command) => command.type === 1); + + const commandList = commands + .map( + (command) => + `****: ${command.description}`, + ) + .join("\n"); - const embed = new EmbedBuilder() - .setTitle("⚙️ Available Commands") - .setDescription(commandList) - .setColor("Blurple") + const embed = new EmbedBuilder() + .setTitle("⚙️ Available Commands") + .setDescription(commandList) + .setColor("Blurple"); - await interaction.reply({ embeds: [embed] }); - }, -}; \ No newline at end of file + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/interactions/slash/misc/image.js b/interactions/slash/misc/image.js index 7422310..c8f48d3 100644 --- a/interactions/slash/misc/image.js +++ b/interactions/slash/misc/image.js @@ -7,237 +7,366 @@ * @type {import('../../../typings').SlashInteractionCommand} */ -const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); -const {XProdiaKey, Block_NSFW_Images} = require('../../../config.json') +const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"); +const { checkAPIKey } = require("../../../functions/other/utils"); const translate = require("@iamtraction/google-translate"); -const axios = require('axios'); -const tf = require('@tensorflow/tfjs-node'); -const nsfw = require('nsfwjs'); +const { QuickDB } = require("quick.db"); +const path = require("path"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); +const axios = require("axios"); +const tf = require("@tensorflow/tfjs-node"); +const nsfw = require("nsfwjs"); + +let nsfwModelPromise = null; + +async function loadNsfwModel() { + if (!nsfwModelPromise) { + nsfwModelPromise = nsfw.load(); + } + return nsfwModelPromise; +} + +function resizeImage(imageTensor) { + const [height, width] = imageTensor.shape.slice(0, 2); + const aspectRatio = width / height; + + let newWidth, newHeight; + + if (aspectRatio > 1) { + newHeight = 224; + newWidth = Math.round(aspectRatio * 224); + } else { + newWidth = 224; + newHeight = Math.round(224 / aspectRatio); + } + + const resizedImage = tf.image.resizeBilinear(imageTensor, [ + newHeight, + newWidth, + ]); + return resizedImage; +} + +async function nsfwGetPic(image, nsfw_embed, interaction) { + const model = await loadNsfwModel(); + const pic = await axios.get(image, { responseType: "arraybuffer" }); + const imageTensor = tf.node.decodeImage(pic.data, 3); + + const resizedImage = resizeImage(imageTensor); + imageTensor.dispose(); + + const predictions = await model.classify(resizedImage); + resizedImage.dispose(); + + if ( + (predictions[0].probability > 0.5 && predictions[0].className === "Porn") || + predictions[0].className === "Hentai" || + predictions[0].className === "Sexy" + ) { + await interaction.followUp({ embeds: [nsfw_embed] }); + return true; + } + return image; +} + +let nsfwWordsCache = null; + +async function getNsfwWords() { + if (!nsfwWordsCache) { + const response = await fetch( + "https://raw.githubusercontent.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words/master/en", + ); + const data = await response.text(); + nsfwWordsCache = data + .split("\n") + .filter((word) => word !== "suck" && word !== "sucks"); + } + return nsfwWordsCache; +} module.exports = { - data: new SlashCommandBuilder() - .setName('image') - .setDescription('Have AI generate an image!') - .addStringOption(o => o.setName('prompt').setDescription('The description of the image to generate!').setRequired(true)) - .addStringOption(o => o.setName('model').setDescription('The Model to Use')) - .addStringOption(o => o.setName('negative-prompt').setDescription('The Negative Prompt to Use')) - .addIntegerOption(option => - option.setName("steps") - .setDescription("The Number of Steps to Use") - .setMinValue(1) - .setMaxValue(30) - ) - .addIntegerOption(option => - option.setName("cfg-scale") - .setDescription("The CFG Scale") - .setMinValue(1) - .setMaxValue(30) - ) - .addIntegerOption(option => - option.setName("seed") - .setDescription("The Seed") - .setMinValue(-1) - ) - .addStringOption(option => - option.setName("style-preset") - .setDescription("The Image Style Prese") + data: new SlashCommandBuilder() + .setName("image") + .setDescription("Have AI generate an image!") + .addStringOption((o) => + o + .setName("prompt") + .setDescription("The description of the image to generate!") + .setRequired(true), + ) + .addStringOption((o) => + o + .setName("model") + .setDescription("The Model to Use") + .setAutocomplete(true), + ) + .addStringOption((o) => + o.setName("negative-prompt").setDescription("The Negative Prompt to Use"), + ) + .addIntegerOption((option) => + option + .setName("steps") + .setDescription("The Number of Steps to Use") + .setMinValue(1) + .setMaxValue(50), + ) + .addIntegerOption((option) => + option + .setName("cfg-scale") + .setDescription("The CFG Scale") + .setMinValue(1) + .setMaxValue(20), + ) + .addIntegerOption((option) => + option.setName("seed").setDescription("The Seed").setMinValue(-1), + ) + .addStringOption((option) => + option + .setName("style-preset") + .setDescription("The Image Style Preset") .addChoices( { name: "3d Model", value: "3d-model" }, { name: "Analog Film", value: "analog-film" }, - { name: "Anime", value: "anime" }, - { name: "Cinematic", value: "cinematic" }, - { name: "Comic Book", value: "comic-book" }, - { name: "Digital Art", value: "digital-art" }, - { name: "Enhance", value: "enhance" }, - { name: "Fantasy Art", value: "fantasy-art" }, - { name: "Isometric", value: "isometric" }, - { name: "Line Art", value: "line-art" }, - { name: "Low Poly", value: "low-poly" }, - { name: "Neon Punk", value: "neon-punk" }, - { name: "Origami", value: "origami" }, - { name: "Photographic", value: "photographic" }, - { name: "Pixel Art", value: "pixel-art" }, - { name: "Texture", value: "texture" }, - { name: "Craft Clay", value: "craft-clay" }, - )) - .addStringOption(option => - option.setName("sampler") - .setDescription("The Image Sampler") - .addChoices( - { name: "Euler a", value: "Euler a" }, - { name: "LMS", value: "LMS" }, - { name: "Heun", value: "Heun" }, - { name: "DPM2", value: "DPM2" }, - { name: "DPM2 a", value: "DPM2 a" }, - { name: "DPM++ 2S a", value: "DPM++ 2S a" }, - { name: "DPM++ 2M", value: "DPM++ 2M" }, - { name: "DPM++ 2M SDE", value: "DPM++ 2M SDE" }, - { name: "DPM++ 2M SDE Heun Karras", value: "DPM++ 2M SDE Heun Karras" }, - { name: "DPM++ 3M SD", value: "DPM++ 3M SD" }, - { name: "DPM++ 3M SD Karras", value: "DPM++ 3M SD Karras" }, - { name: "DPM++ 3M SD Exponential", value: "DPM++ 3M SD Exponential" }, - { name: "DPM fast", value: "DPM fast" }, - { name: "DPM adaptive", value: "DPM adaptive" }, - { name: "LMS Karras", value: "LMS Karras" }, - { name: "DPM2 Karras", value: "DPM2 Karras" }, - { name: "DPM2 a Karras", value: "DPM2 a Karras" }, - { name: "DPM++ 2S a Karras", value: "DPM++ 2S a Karras" }, - { name: "DPM++ 2M Karras", value: "DPM++ 2M Karras" }, - { name: "DPM++ SDE Karras", value: "DPM++ SDE Karras" }, - { name: "DPM++ SDE Karras", value: "DPM++ SDE Karras" }, - { name: "DPM++ 2M SDE Exponential", value: "DPM++ 2M SDE Exponential" }, - { name: "DDIM", value: "DDIM" }, - { name: "PLMS", value: "PLMS" }, - { name: "UniPC", value: "UniPC" }, - )), - - async execute(interaction, client) { - - if (!XProdiaKey || XProdiaKey.length < 4) { - invalid_api = new EmbedBuilder() - .setTitle("⚠️ Invalid API Key") - .setDescription("> **The API Key for Prodia is invalid or not provided.**") - .setColor("Red") - return interaction.reply({ embeds: [invalid_api] }); - } - - const error = new EmbedBuilder() - .setTitle('⚠️ Error!') - .setDescription('**An Error Occured, please try again later!**\n\n> - API Monthly Credits may have been used up\n> - Might be a problem with the API at the moment\n> - Or the Model/Sampler/Style is not available.') - .setColor('Red'); - - await interaction.deferReply(); - - const style_preset = interaction.options.getString('style-preset'); - const steps = interaction.options.getInteger('steps'); - const cfg_scale = interaction.options.getInteger('cfg-scale'); - const seed = interaction.options.getInteger('seed'); - const sampler = interaction.options.getString('sampler'); - - let prompt = interaction.options.getString('prompt'); - let negative_prompt = interaction.options.getString('negative-prompt'); - let model = interaction.options.getString('model'); - - prompt = (await translate(prompt, { to: 'en' })).text; - negative_prompt = (await translate(negative_prompt, { to: 'en' })).text; - - const nsfw_embed = new EmbedBuilder() - .setDescription(`**⚠️ NSFW content detected!**`) - .setColor('Red'); - - if (Block_NSFW_Images) { - try { - const response = await fetch('https://raw.githubusercontent.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words/master/en'); - const data = await response.text(); - let nsfw_words = data.split('\n'); - nsfw_words = nsfw_words.filter(word => word !== 'suck' && word !== 'sucks'); - - let promptWords = prompt.split(' '); - - for (let word of nsfw_words) { - if (promptWords.includes(word)) { - await interaction.followUp({ embeds: [nsfw_embed] }); - return; - } - } - } catch (err) { - console.error(err); - } - } - - async function nsfw_getPic(image) { - const pic = await axios.get(image, { responseType: 'arraybuffer' }); - const model = await nsfw.load(); - image_analyse = await tf.node.decodeImage(pic.data, 3); - const predictions = await model.classify(image_analyse); - image_analyse.dispose(); - - if (predictions[0].probability > 0.5 && (predictions[0].className === "Porn") || (predictions[0].className === "Hentai") || (predictions[0].className === "Sexy")) { - await interaction.followUp({ embeds: [nsfw_embed] }); - return true; - } - return image - } - - const sdk = require('api')('@prodia/v1.3.0#6fdmny2flsvwyf65'); - - sdk.auth(XProdiaKey); - - try{ - const {data} = await sdk.listModels(); - choices = JSON.parse(data); - } catch (e) { - return interaction.followUp({embeds: [error]}); - } - - if (model && !choices.includes(model)) { - const no_model = new EmbedBuilder() - .setDescription(`**${model}** is not a valid model!\n\n> Run \`/models\` to see the available models!`) - .setColor('Red'); - - return interaction.followUp({embeds: [no_model]}); - } - - if (!model) { - model = "absolutereality_V16.safetensors [37db0fc3]"; - } - - let generateParams = { - model: model, - prompt: prompt, - ...(style_preset && { style_preset: style_preset }), - ...(negative_prompt && { negative_prompt: negative_prompt }), - ...(steps && { steps: steps }), - ...(sampler && { sampler: sampler }), - ...(cfg_scale && { cfg_scale: cfg_scale }), - ...(seed && { seed: seed }) - }; - - - - try{ - sdk.generate(generateParams) - .then(({ data }) => { - const jobId = data.job; - const intervalId = setInterval(() => { - sdk.getJob({jobId: jobId}) - .then(({ data }) => { - if (data.status === 'succeeded') { - clearInterval(intervalId); - - let image = data.imageUrl; - - (async () => { - if (Block_NSFW_Images) { - const newImage = await nsfw_getPic(image); - image = newImage; - if (image === true) { - return; - } - } - - const success = new EmbedBuilder() - .setImage(image) - .setTitle('🖼️ Generated Image!') - .setDescription(`> **${prompt}**`) - .setColor('Random') - .setFooter({ text: `Requested by ${interaction.user.tag}, Powered By Prodia`, iconURL: interaction.user.displayAvatarURL() }) - - return interaction.followUp({embeds: [success]}); - - })(); - - } else if (data.status === 'failed') { - clearInterval(intervalId); - return interaction.followUp({embeds: [error]}); - } - }) - .catch(err => console.error(err)); - }, 2000); - }) - .catch(err => console.error(err)); - } catch(err) { - return interaction.followUp({embeds: [error]}); - } - } -} \ No newline at end of file + { name: "Anime", value: "anime" }, + { name: "Cinematic", value: "cinematic" }, + { name: "Comic Book", value: "comic-book" }, + { name: "Digital Art", value: "digital-art" }, + { name: "Enhance", value: "enhance" }, + { name: "Fantasy Art", value: "fantasy-art" }, + { name: "Isometric", value: "isometric" }, + { name: "Line Art", value: "line-art" }, + { name: "Low Poly", value: "low-poly" }, + { name: "Neon Punk", value: "neon-punk" }, + { name: "Origami", value: "origami" }, + { name: "Photographic", value: "photographic" }, + { name: "Pixel Art", value: "pixel-art" }, + { name: "Texture", value: "texture" }, + { name: "Craft Clay", value: "craft-clay" }, + ), + ) + .addStringOption((option) => + option.setName("sampler").setDescription("The Image Sampler").addChoices( + { name: "Euler a", value: "Euler a" }, + { name: "LMS", value: "LMS" }, + { name: "Heun", value: "Heun" }, + { name: "DPM2", value: "DPM2" }, + { name: "DPM2 a", value: "DPM2 a" }, + { name: "DPM++ 2S a", value: "DPM++ 2S a" }, + { name: "DPM++ 2M", value: "DPM++ 2M" }, + { name: "DPM++ 2M SDE", value: "DPM++ 2M SDE" }, + { + name: "DPM++ 2M SDE Heun Karras", + value: "DPM++ 2M SDE Heun Karras", + }, + { name: "DPM++ 3M SD", value: "DPM++ 3M SD" }, + { name: "DPM++ 3M SD Karras", value: "DPM++ 3M SD Karras" }, + { name: "DPM++ 3M SD Exponential", value: "DPM++ 3M SD Exponential" }, + { name: "DPM fast", value: "DPM fast" }, + { name: "DPM adaptive", value: "DPM adaptive" }, + { name: "LMS Karras", value: "LMS Karras" }, + { name: "DPM2 Karras", value: "DPM2 Karras" }, + { name: "DPM2 a Karras", value: "DPM2 a Karras" }, + { name: "DPM++ 2S a Karras", value: "DPM++ 2S a Karras" }, + { name: "DPM++ 2M Karras", value: "DPM++ 2M Karras" }, + { name: "DPM++ SDE Karras", value: "DPM++ SDE Karras" }, + { name: "DPM++ SDE Karras", value: "DPM++ SDE Karras" }, + { + name: "DPM++ 2M SDE Exponential", + value: "DPM++ 2M SDE Exponential", + }, + { name: "DDIM", value: "DDIM" }, + { name: "PLMS", value: "PLMS" }, + { name: "UniPC", value: "UniPC" }, + ), + ) + .addBooleanOption((o) => + o.setName("upscale").setDescription("Enable 2x Upscale"), + ) + .addIntegerOption((option) => + option + .setName("width") + .setDescription("The Width of the Image") + .setMinValue(1) + .setMaxValue(1024), + ) + .addIntegerOption((option) => + option + .setName("height") + .setDescription("The Height of the Image") + .setMinValue(1) + .setMaxValue(1024), + ), + + async execute(interaction) { + const apiKeys = await db.get("apiKeys"); + const XProdiaKey = apiKeys.prodia; + + const other = await db.get("other"); + const blockNSFWImages = other.blockNSFWImages; + + const invalid_api = new EmbedBuilder() + .setTitle("⚠️ Invalid API Key") + .setDescription( + "> *The API Key for Prodia is invalid or not provided*\n> **Please contact the developers**", + ) + .setColor("Red"); + + if (!XProdiaKey || XProdiaKey.length < 4) { + return interaction.reply({ embeds: [invalid_api] }); + } + + await interaction.deferReply(); + + const isValidKey = await checkAPIKey("prodia", XProdiaKey); + if (!isValidKey) { + return interaction.reply({ embeds: [invalid_api] }); + } + + const error = new EmbedBuilder() + .setTitle("⚠️ Error!") + .setDescription( + "**An Error Occured, please try again later!**\n\n> - API Monthly Credits may have been used up\n> - Might be a problem with the API at the moment\n> - Or the Model/Sampler/Style is not available.", + ) + .setColor("Red"); + + const style_preset = interaction.options.getString("style-preset"); + const steps = interaction.options.getInteger("steps"); + const cfg_scale = interaction.options.getInteger("cfg-scale"); + const seed = interaction.options.getInteger("seed"); + const sampler = interaction.options.getString("sampler"); + const upscale = interaction.options.getBoolean("upscale"); + const width = interaction.options.getInteger("width"); + const height = interaction.options.getInteger("height"); + + let prompt = interaction.options.getString("prompt"); + let negative_prompt = interaction.options.getString("negative-prompt"); + let model = interaction.options.getString("model"); + + prompt = (await translate(prompt, { to: "en" })).text; + negative_prompt = (await translate(negative_prompt, { to: "en" })).text; + + const nsfw_embed = new EmbedBuilder() + .setDescription(`**⚠️ NSFW content detected!**`) + .setColor("Red"); + + if (blockNSFWImages) { + try { + const nsfw_words = await getNsfwWords(); + let promptWords = prompt.split(" "); + for (let word of nsfw_words) { + if (promptWords.includes(word)) { + await interaction.followUp({ embeds: [nsfw_embed] }); + return; + } + } + } catch (err) { + console.error(err); + } + } + + const sdk = require("api")("@prodia/v1.3.0#6fdmny2flsvwyf65"); + + sdk.auth(XProdiaKey); + + async function fetchModels(apiMethod) { + try { + const { data } = await apiMethod(); + return JSON.parse(data); + } catch (e) { + console.error(e); + return interaction.followUp({ embeds: [error] }); + } + } + + const [choices, sdxlChoices] = await Promise.all([ + fetchModels(sdk.listModels), + fetchModels(sdk.listSdxlModels), + ]); + + const allModels = [...choices, ...sdxlChoices]; + + if (model && !allModels.includes(model)) { + const no_model = new EmbedBuilder() + .setDescription( + `**${model}** is not a valid model!\n\n> Run \`/models\` to see the available models!`, + ) + .setColor("Red"); + + return interaction.followUp({ embeds: [no_model] }); + } + + if (!model) { + model = "absolutereality_V16.safetensors [37db0fc3]"; + } + + let generateParams = { + model: model, + prompt: prompt, + ...(style_preset && { style_preset: style_preset }), + ...(negative_prompt && { negative_prompt: negative_prompt }), + ...(steps && { steps: steps }), + ...(sampler && { sampler: sampler }), + ...(cfg_scale && { cfg_scale: cfg_scale }), + ...(seed && { seed: seed }), + ...(upscale && { upscale: upscale }), + ...(width && { width: width }), + ...(height && { height: height }), + }; + + try { + const generateMethod = sdxlChoices.includes(model) + ? sdk.sdxlGenerate + : sdk.generate; + generateMethod(generateParams) + .then(({ data }) => { + const jobId = data.job; + const intervalId = setInterval(() => { + sdk + .getJob({ jobId: jobId }) + .then(({ data }) => { + if (data.status === "succeeded") { + clearInterval(intervalId); + + let image = data.imageUrl; + + (async () => { + if (blockNSFWImages) { + const newImage = await nsfwGetPic( + image, + nsfw_embed, + interaction, + ); + image = newImage; + if (image === true) { + return; + } + } + + const success = new EmbedBuilder() + .setImage(image) + .setTitle("🖼️ Generated Image!") + .setDescription(`> **${prompt}**`) + .setColor("Random") + .setFooter({ + text: `Requested by ${interaction.user.tag}, Powered By Prodia`, + iconURL: interaction.user.displayAvatarURL(), + }); + + return interaction.followUp({ embeds: [success] }); + })(); + } else if (data.status === "failed") { + clearInterval(intervalId); + return interaction.followUp({ embeds: [error] }); + } + }) + .catch((err) => console.error(err)); + }, 5000); + }) + .catch((err) => console.error(err)); + } catch (err) { + return interaction.followUp({ embeds: [error] }); + } + }, +}; diff --git a/interactions/slash/misc/info.js b/interactions/slash/misc/info.js index 899eeb0..4093810 100644 --- a/interactions/slash/misc/info.js +++ b/interactions/slash/misc/info.js @@ -3,45 +3,57 @@ * @author TechyGiraffe999 */ - -const { EmbedBuilder, SlashCommandBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require("discord.js"); +const { + EmbedBuilder, + SlashCommandBuilder, + ButtonBuilder, + ButtonStyle, + ActionRowBuilder, +} = require("discord.js"); /** * @type {import('../../../typings').SlashInteractionCommand} */ module.exports = { - data: new SlashCommandBuilder() - .setName('info') - .setDescription('Displays info on me!'), - async execute(interaction) { - - const github = new ButtonBuilder() - .setURL('https://github.com/TecEash1/Taurus') - .setLabel('GitHub Repository') - .setEmoji("⚒️") - .setStyle(ButtonStyle.Link); - - const buttons = new ActionRowBuilder() - .addComponents(github); - - let totalSecs = (interaction.client.uptime / 1000); - let days = Math.floor(totalSecs / 86400);totalSecs %= 86400; - let hrs = Math.floor(totalSecs / 3600);totalSecs %= 3600; - let mins = Math.floor(totalSecs / 60); - let seconds = Math.floor(totalSecs % 60); - let uptime = `**${days}**d **${hrs}**h **${mins}**m **${seconds}**s`; - - const embed = new EmbedBuilder() - .setTitle("🤖 Info") - .setDescription("I am a bot created by TechyGiraffe999. I was made to be a specialised AI Bot.") - .addFields( - { name: `**⌛ UPTIME**`, value: `${uptime}`}, - { name: `**📡 PING**`, value: `Responded in \`\`${interaction.client.ws.ping}ms\`\``} - ) - .setThumbnail("https://github.com/TecEash1/TecEash1/assets/92249532/bd4aca7e-daab-4eeb-9265-e53cc1925e8c") - .setColor("Blurple"); - - await interaction.reply({ embeds: [embed], components: [buttons]}); - }, -}; \ No newline at end of file + data: new SlashCommandBuilder() + .setName("info") + .setDescription("Displays info on me!"), + async execute(interaction) { + const github = new ButtonBuilder() + .setURL("https://github.com/TecEash1/Taurus") + .setLabel("GitHub Repository") + .setEmoji("⚒️") + .setStyle(ButtonStyle.Link); + + const buttons = new ActionRowBuilder().addComponents(github); + + let totalSecs = interaction.client.uptime / 1000; + let days = Math.floor(totalSecs / 86400); + totalSecs %= 86400; + let hrs = Math.floor(totalSecs / 3600); + totalSecs %= 3600; + let mins = Math.floor(totalSecs / 60); + let seconds = Math.floor(totalSecs % 60); + let uptime = `**${days}**d **${hrs}**h **${mins}**m **${seconds}**s`; + + const embed = new EmbedBuilder() + .setTitle("🤖 Info") + .setDescription( + "I am a bot created by TechyGiraffe999. I was made to be a specialised AI Bot.", + ) + .addFields( + { name: `**⌛ UPTIME**`, value: `${uptime}` }, + { + name: `**📡 PING**`, + value: `Responded in \`\`${interaction.client.ws.ping}ms\`\``, + }, + ) + .setThumbnail( + "https://github.com/TecEash1/TecEash1/assets/92249532/bd4aca7e-daab-4eeb-9265-e53cc1925e8c", + ) + .setColor("Blurple"); + + await interaction.reply({ embeds: [embed], components: [buttons] }); + }, +}; diff --git a/interactions/slash/misc/models.js b/interactions/slash/misc/models.js index 01fe140..def790e 100644 --- a/interactions/slash/misc/models.js +++ b/interactions/slash/misc/models.js @@ -7,54 +7,67 @@ * @type {import('../../../typings').SlashInteractionCommand} */ -const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); -const {XProdiaKey} = require('../../../config.json') - +const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"); +const { QuickDB } = require("quick.db"); +const path = require("path"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); module.exports = { - data: new SlashCommandBuilder() - .setName('models') - .setDescription('List the available models for image generation!'), - - async execute(interaction, client) { - - if (!XProdiaKey || XProdiaKey.length < 4) { - invalid_api = new EmbedBuilder() - .setTitle("⚠️ Invalid API Key") - .setDescription("> **The API Key for Prodia is invalid or not provided.**") - .setColor("Red") - return interaction.reply({ embeds: [invalid_api] }); - } - - const error = new EmbedBuilder() - .setTitle("⚠️ An Unknown Error Occured") - .setDescription("> **The Prodia API Key usage may have been used up, or the API is invalid or not working at the moment.**\n\n> Please try again later or contact the developers.") - .setColor("Red") - - await interaction.deferReply(); - - const sdk = require('api')('@prodia/v1.3.0#6fdmny2flsvwyf65'); - - sdk.auth(XProdiaKey); - - try{ - const {data} = await sdk.listModels(); - choices = JSON.parse(data); - } catch (e) { - return interaction.followUp({embeds: [error]}); - } - - - const choices_string = "```\n- " + choices.join("\n- ") + "\n```"; - - const models = new EmbedBuilder() - .setTitle('🖼️ Available Models') - .setDescription(choices_string) - .setColor('Random') - - return interaction.followUp({embeds: [models]}); - - - }, -}; + data: new SlashCommandBuilder() + .setName("models") + .setDescription("List the available models for image generation!"), + + async execute(interaction) { + const apiKeys = await db.get("apiKeys"); + const XProdiaKey = apiKeys.prodia; + + if (!XProdiaKey || XProdiaKey.length < 4) { + invalid_api = new EmbedBuilder() + .setTitle("⚠️ Invalid API Key") + .setDescription( + "> **The API Key for Prodia is invalid or not provided.**\n> **Please contact the developers**", + ) + .setColor("Red"); + return interaction.reply({ embeds: [invalid_api] }); + } + + const error = new EmbedBuilder() + .setTitle("⚠️ An Unknown Error Occured") + .setDescription( + "> **The Prodia API Key usage may have been used up, or the API is invalid or not working at the moment.**\n\n> Please try again later or contact the developers.", + ) + .setColor("Red"); + + await interaction.deferReply(); + const sdk = require("api")("@prodia/v1.3.0#6fdmny2flsvwyf65"); + + sdk.auth(XProdiaKey); + + async function fetchAndFormatModels(apiMethod) { + try { + const { data } = await apiMethod(); + const models = JSON.parse(data); + return "```\n- " + models.join("\n- ") + "\n```"; + } catch (e) { + return interaction.followUp({ embeds: [error] }); + } + } + + const [choices_string, sdxlChoices_string] = await Promise.all([ + fetchAndFormatModels(sdk.listModels), + fetchAndFormatModels(sdk.listSdxlModels), + ]); + + const models = new EmbedBuilder() + .setTitle("🖼️ Available Models") + .setDescription( + `**\n🌟 SD Models:**\n\n ${choices_string}\n\n**🚀 SDXL Models:**\n\n ${sdxlChoices_string}`, + ) + .setColor("Random"); + + return interaction.followUp({ embeds: [models] }); + }, +}; diff --git a/interactions/slash/misc/personalise.js b/interactions/slash/misc/personalise.js index 4f17e30..26c2f31 100644 --- a/interactions/slash/misc/personalise.js +++ b/interactions/slash/misc/personalise.js @@ -7,284 +7,352 @@ * @type {import('../../../typings').SlashInteractionCommand} */ -const { SlashCommandBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, EmbedBuilder, ButtonBuilder } = require("discord.js"); -const axios = require('axios'); -const fs = require('fs').promises; -const path = require('path'); -const {guild_id_logs, channel_id_logs, owner} = require("../../../config.json"); - -const serverId = guild_id_logs; -const channelId = channel_id_logs; - -const no_access = new EmbedBuilder() - .setDescription("**Only my developers can directly update my global personality prompt!**\n\nIf you want to suggest a change, please let us know!") - .setColor("Red"); +const { + SlashCommandBuilder, + ModalBuilder, + TextInputBuilder, + TextInputStyle, + ActionRowBuilder, + EmbedBuilder, + ButtonBuilder, + WebhookClient, +} = require("discord.js"); +const axios = require("axios"); +const fs = require("fs").promises; +const path = require("path"); +const { checkOwnerAndReply } = require("../../../functions/other/utils"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); const link_error = new EmbedBuilder() - .setDescription("**The file link is not a valid URL!**") - .setColor("Red"); + .setDescription("**The file link is not a valid URL!**") + .setColor("Red"); const error_null = new EmbedBuilder() - .setDescription("**You must select at least one option!**") - .setColor("Red"); + .setDescription("**You must select at least one option!**") + .setColor("Red"); const error_multiple = new EmbedBuilder() - .setDescription("**You can only select one option!**") - .setColor("Red"); + .setDescription("**You can only select one option!**") + .setColor("Red"); const file_read_error = new EmbedBuilder() - .setDescription("**There was an error while reading the file!**") - .setColor("Red"); + .setDescription("**There was an error while reading the file!**") + .setColor("Red"); const txt_only = new EmbedBuilder() - .setDescription("**You can only upload a .txt file!**") - .setColor("Red"); + .setDescription("**You can only upload a .txt file!**") + .setColor("Red"); module.exports = { data: new SlashCommandBuilder() .setName("personalise") .setDescription("Customise my Personality!") - .addAttachmentOption(option => option - .setRequired(false) - .setName("file") - .setDescription("The personality text file")) - .addStringOption(option => option - .setRequired(false) - .setName("file-link") - .setDescription("The personality text file link")) - .addStringOption(option => - option.setName("other") + .addAttachmentOption((option) => + option + .setRequired(false) + .setName("file") + .setDescription("The personality text file"), + ) + .addStringOption((option) => + option + .setRequired(false) + .setName("file-link") + .setDescription("The personality text file link"), + ) + .addStringOption((option) => + option + .setName("other") .setDescription("Other Options") .addChoices( { name: "Get", value: "get" }, { name: "Modal", value: "modal" }, - )), + ), + ), async execute(interaction) { + const webhooks = await db.get("webhooks"); + const personalityWebhook = webhooks.personality; + const file = interaction.options.getAttachment("file"); - const file_link = interaction.options.getString("file-link"); - const other = interaction.options.getString("other"); - - if (!owner.includes(interaction.user.id)) { - return await interaction.reply({ embeds: [no_access], ephemeral: true }); - } - - const selectedOptions = [file, file_link, other].filter(option => option != null).length; - - if (selectedOptions === 0 || selectedOptions > 1) { - const errorMessage = selectedOptions === 0 ? error_null : error_multiple; - return await interaction.reply({ embeds: [errorMessage], ephemeral: true }); - } - - const urlRegex = /^(ftp|http|https):\/\/[^ "]+$/; - if (file_link && !urlRegex.test(file_link)) { - return interaction.reply({ embeds: [link_error], ephemeral: true }); - } - - let personalityPrompt; - - async function getPersonalityPrompt(file, file_link) { - const url = file?.url || file_link; - - try { - const response = await axios.get(url); - return response.data; - } catch (error) { - return error - } - } - - if (file || file_link) { - const url = file?.url || file_link; - - const txtRegex = /\.txt(?=\?|$)/; - if (!txtRegex.test(url)) { - return await interaction.reply({ embeds: [txt_only], ephemeral: true }); - } - - const result = await getPersonalityPrompt(file, file_link); - - if (result instanceof Error) { - return await interaction.reply({ embeds: [file_read_error], ephemeral: true }); - } else { - personalityPrompt = result; - } - } - - - const personalityFilePath = path.join(__dirname + '../../../../personality.txt'); - - - let personalityContent; - try { - personalityContent = await fs.readFile(personalityFilePath, 'utf-8'); - } catch (err) { - console.error(err); - } - - let submitted - let modal_error - - if (other) { - switch(other){ - case "get": - return await interaction.reply({ files: [{ attachment: personalityFilePath, name: 'personality.txt' }], ephemeral: true }); - case "modal": - const personalise = new ModalBuilder() - .setTitle("Customise how Taurus responds") - .setCustomId("taurus_ai_personality"); - - const prompt = new TextInputBuilder() - .setCustomId("personalise_taurusai") - .setRequired(true) - .setLabel("Personality Prompt:") - .setStyle(TextInputStyle.Paragraph); - const prompt2 = new TextInputBuilder() - .setCustomId("personalise_taurusai2") - .setRequired(false) - .setLabel("Extra Space:") - .setStyle(TextInputStyle.Paragraph); - const prompt3 = new TextInputBuilder() - .setCustomId("personalise_taurusai3") - .setRequired(false) - .setLabel("Extra Space:") - .setStyle(TextInputStyle.Paragraph); - - - const taurusai_personality_ActionRow = new ActionRowBuilder().addComponents(prompt); - const taurusai_personality_ActionRow2 = new ActionRowBuilder().addComponents(prompt2); - const taurusai_personality_ActionRow3 = new ActionRowBuilder().addComponents(prompt3); - - personalise.addComponents(taurusai_personality_ActionRow, taurusai_personality_ActionRow2, taurusai_personality_ActionRow3); - await interaction.showModal(personalise); - - submitted = await interaction.awaitModalSubmit({ - time: 300000, - filter: i => i.user.id === interaction.user.id, - }).catch(error => { - modal_error = true; - return false - }) - - if (submitted) { - personalityPrompt = await submitted.fields.getTextInputValue("personalise_taurusai"); - const personalityPrompt2 = await submitted.fields.getTextInputValue("personalise_taurusai2"); - const personalityPrompt3 = await submitted.fields.getTextInputValue("personalise_taurusai3"); - if (personalityPrompt2) { - personalityPrompt += personalityPrompt2; - } - if (personalityPrompt3) { - personalityPrompt += personalityPrompt3; - } - } - } - } - - if (modal_error) return; - - success = new EmbedBuilder() - .setDescription("✅ **Personality prompt updated successfully!**") - .setColor("Green"); - - cancel = new EmbedBuilder() - .setDescription("❌ **Operation cancelled.**") - .setColor("Red"); - - const error = new EmbedBuilder() - .setDescription("⚠️ There was an error while fetching the TaurusAI Log channel, please contact the Developers.") - .setColor("Red"); - - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId('yes_botai_personality') - .setLabel('Update') - .setEmoji('✅') - .setStyle('Primary'), - new ButtonBuilder() - .setCustomId('no_botai_personality') - .setLabel('Cancel') - .setEmoji('❌') - .setStyle('Primary'), - ); - - let personalityContent_truncate = personalityContent; - if (personalityContent.length > 2002) { - personalityContent_truncate = personalityContent.substring(0, 2002) + '...'; - } - - let personalityPrompt_truncate = personalityPrompt; - if (personalityPrompt.length > 2002) { - personalityPrompt_truncate = personalityPrompt.substring(0, 2002) + '...'; - } - - let description = `**Current personality prompt:**\n\`\`\`${personalityContent_truncate}\`\`\`\n\n**New personality prompt:**\n\`\`\`${personalityPrompt_truncate}\`\`\``; - - embed = new EmbedBuilder() - .setTitle("Are you sure you want to update the personality prompt?") - .setDescription(description) - .setFooter({ text: `⚠️ This will wipe the old Prompt, resetting it with the new one.`, iconURL: interaction.user.displayAvatarURL() }) - .setColor("Orange") - - await (submitted ?? interaction).reply({ - embeds: [embed], - components: [row], - files: [{ attachment: personalityFilePath, name: 'current_personality.txt' }], - ephemeral: true - }); - - const filter = i => i.customId === 'yes_botai_personality' || i.customId === 'no_botai_personality'; - const collector = interaction.channel.createMessageComponentCollector({ filter, time: 60000 }); - - collector.on('collect', async i => { - collector.stop(); - if (i.customId === 'yes_botai_personality') { - - const personalityFilePath = path.join(__dirname, '../../../personality.txt'); - const tempFilePath = path.join(__dirname, 'temp.txt'); - - let oldPersonalityContent; - try { - oldPersonalityContent = await fs.readFile(personalityFilePath, 'utf-8'); - await fs.writeFile(tempFilePath, oldPersonalityContent); - } catch (err) { - console.error(err); - } - - await fs.writeFile(personalityFilePath, personalityPrompt); - - try{ - const guild = interaction.client.guilds.cache.get(serverId); - const channel = guild.channels.cache.get(channelId); - - - update = new EmbedBuilder() - .setDescription(`**Personality prompt updated by <@${interaction.user.id}>**`) - .setColor("Orange") - .setFooter({ text: `ID: ${interaction.user.id}`, iconURL: interaction.user.displayAvatarURL() }) - .setTimestamp(); - - await channel.send({ - embeds: [update], - files: [ - { attachment: personalityFilePath, name: 'new_personality.txt' }, - { attachment: tempFilePath, name: 'old_personality.txt' } - ] - }); - await i.update({ embeds: [success], components: [], files: [] }); - } catch (err) { - await i.update({ embeds: [success,error], components: [], files: [] }); - } - - try { - await fs.unlink(tempFilePath); - } catch (err) { - console.error(err); - } - - } else { - await i.update({ embeds: [cancel], components: [], files: [] }); - } - }); - } -} \ No newline at end of file + const file_link = interaction.options.getString("file-link"); + const other = interaction.options.getString("other"); + + if (!checkOwnerAndReply(interaction)) { + return; + } + const selectedOptions = [file, file_link, other].filter( + (option) => option != null, + ).length; + + if (selectedOptions === 0 || selectedOptions > 1) { + const errorMessage = selectedOptions === 0 ? error_null : error_multiple; + return await interaction.reply({ + embeds: [errorMessage], + ephemeral: true, + }); + } + + const urlRegex = /^(ftp|http|https):\/\/[^ "]+$/; + if (file_link && !urlRegex.test(file_link)) { + return interaction.reply({ embeds: [link_error], ephemeral: true }); + } + + let personalityPrompt; + + async function getPersonalityPrompt(file, file_link) { + const url = file?.url || file_link; + + try { + const response = await axios.get(url); + return response.data; + } catch (error) { + return error; + } + } + + if (file || file_link) { + const url = file?.url || file_link; + + const txtRegex = /\.txt(?=\?|$)/; + if (!txtRegex.test(url)) { + return await interaction.reply({ embeds: [txt_only], ephemeral: true }); + } + + const result = await getPersonalityPrompt(file, file_link); + + if (result instanceof Error) { + return await interaction.reply({ + embeds: [file_read_error], + ephemeral: true, + }); + } else { + personalityPrompt = result; + } + } + + const personalityFilePath = path.join( + __dirname + "../../../../personality.txt", + ); + + let personalityContent; + try { + personalityContent = await fs.readFile(personalityFilePath, "utf-8"); + } catch (err) { + console.error(err); + } + + let submitted; + let modal_error; + + if (other) { + switch (other) { + case "get": + return await interaction.reply({ + files: [ + { attachment: personalityFilePath, name: "personality.txt" }, + ], + ephemeral: true, + }); + case "modal": + const personalise = new ModalBuilder() + .setTitle("Customise how Taurus responds") + .setCustomId("taurus_ai_personality"); + + const prompt = new TextInputBuilder() + .setCustomId("personalise_taurusai") + .setRequired(true) + .setLabel("Personality Prompt:") + .setStyle(TextInputStyle.Paragraph); + const prompt2 = new TextInputBuilder() + .setCustomId("personalise_taurusai2") + .setRequired(false) + .setLabel("Extra Space:") + .setStyle(TextInputStyle.Paragraph); + const prompt3 = new TextInputBuilder() + .setCustomId("personalise_taurusai3") + .setRequired(false) + .setLabel("Extra Space:") + .setStyle(TextInputStyle.Paragraph); + + const taurusai_personality_ActionRow = + new ActionRowBuilder().addComponents(prompt); + const taurusai_personality_ActionRow2 = + new ActionRowBuilder().addComponents(prompt2); + const taurusai_personality_ActionRow3 = + new ActionRowBuilder().addComponents(prompt3); + + personalise.addComponents( + taurusai_personality_ActionRow, + taurusai_personality_ActionRow2, + taurusai_personality_ActionRow3, + ); + await interaction.showModal(personalise); + + submitted = await interaction + .awaitModalSubmit({ + time: 300000, + filter: (i) => i.user.id === interaction.user.id, + }) + .catch((error) => { + modal_error = true; + return false; + }); + + if (submitted) { + personalityPrompt = await submitted.fields.getTextInputValue( + "personalise_taurusai", + ); + const personalityPrompt2 = await submitted.fields.getTextInputValue( + "personalise_taurusai2", + ); + const personalityPrompt3 = await submitted.fields.getTextInputValue( + "personalise_taurusai3", + ); + if (personalityPrompt2) { + personalityPrompt += personalityPrompt2; + } + if (personalityPrompt3) { + personalityPrompt += personalityPrompt3; + } + } + } + } + + if (modal_error) return; + + success = new EmbedBuilder() + .setDescription("✅ **Personality prompt updated successfully!**") + .setColor("Green"); + + cancel = new EmbedBuilder() + .setDescription("❌ **Operation cancelled.**") + .setColor("Red"); + + const error = new EmbedBuilder() + .setDescription( + "**⚠️ There was an error while fetching the TaurusAI Log channel, please contact the Developers.**", + ) + .setColor("Red"); + + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("yes_botai_personality") + .setLabel("Update") + .setEmoji("✅") + .setStyle("Primary"), + new ButtonBuilder() + .setCustomId("no_botai_personality") + .setLabel("Cancel") + .setEmoji("❌") + .setStyle("Primary"), + ); + + let personalityContent_truncate = personalityContent; + if (personalityContent.length > 2002) { + personalityContent_truncate = + personalityContent.substring(0, 2002) + "..."; + } + + let personalityPrompt_truncate = personalityPrompt; + if (personalityPrompt.length > 2002) { + personalityPrompt_truncate = personalityPrompt.substring(0, 2002) + "..."; + } + + let description = `**Current personality prompt:**\n\`\`\`${personalityContent_truncate}\`\`\`\n\n**New personality prompt:**\n\`\`\`${personalityPrompt_truncate}\`\`\``; + + embed = new EmbedBuilder() + .setTitle("Are you sure you want to update the personality prompt?") + .setDescription(description) + .setFooter({ + text: `⚠️ This will wipe the old Prompt, resetting it with the new one.`, + iconURL: interaction.user.displayAvatarURL(), + }) + .setColor("Orange"); + + await (submitted ?? interaction).reply({ + embeds: [embed], + components: [row], + files: [ + { attachment: personalityFilePath, name: "current_personality.txt" }, + ], + ephemeral: true, + }); + + const filter = (i) => + i.customId === "yes_botai_personality" || + i.customId === "no_botai_personality"; + const collector = interaction.channel.createMessageComponentCollector({ + filter, + time: 60000, + }); + + collector.on("collect", async (i) => { + collector.stop(); + if (i.customId === "yes_botai_personality") { + const personalityFilePath = path.join( + __dirname, + "../../../personality.txt", + ); + const tempFilePath = path.join(__dirname, "temp.txt"); + + let oldPersonalityContent; + try { + oldPersonalityContent = await fs.readFile( + personalityFilePath, + "utf-8", + ); + await fs.writeFile(tempFilePath, oldPersonalityContent); + } catch (err) { + console.error(err); + } + + await fs.writeFile(personalityFilePath, personalityPrompt); + + try { + const webhookClient = new WebhookClient({ + url: personalityWebhook, + }); + + update = new EmbedBuilder() + .setDescription( + `**Personality prompt updated by <@${interaction.user.id}>**`, + ) + .setColor("Orange") + .setFooter({ + text: `ID: ${interaction.user.id}`, + iconURL: interaction.user.displayAvatarURL(), + }) + .setTimestamp(); + + await webhookClient.send({ + username: "Taurus Personality", + avatarURL: interaction.client.user.displayAvatarURL(), + embeds: [update], + files: [ + { attachment: personalityFilePath, name: "new_personality.txt" }, + { attachment: tempFilePath, name: "old_personality.txt" }, + ], + }); + await i.update({ embeds: [success], components: [], files: [] }); + } catch (err) { + await i.update({ + embeds: [success, error], + components: [], + files: [], + }); + } + + try { + await fs.unlink(tempFilePath); + } catch (err) { + console.error(err); + } + } else { + await i.update({ embeds: [cancel], components: [], files: [] }); + } + }); + }, +}; diff --git a/interactions/slash/misc/settings.js b/interactions/slash/misc/settings.js new file mode 100644 index 0000000..58bef2d --- /dev/null +++ b/interactions/slash/misc/settings.js @@ -0,0 +1,232 @@ +/** + * @file Settings Command + * @author TechyGiraffe999 + */ + +const { + EmbedBuilder, + SlashCommandBuilder, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Embed, +} = require("discord.js"); +const path = require("path"); +const { + checkWebhook, + checkAPIKey, + checkOwnerAndReply, +} = require("../../../functions/other/utils"); +const { emojis } = require("../../../config.json"); +const { QuickDB } = require("quick.db"); +const db = new QuickDB({ + filePath: path.join(__dirname, "../../../functions/other/settings.sqlite"), +}); + +async function updateFieldValueAndReply( + interaction, + settings, + fieldName, + fieldValue, +) { + const field = settings.data.fields.find((field) => field.name === fieldName); + field.value = fieldValue; + await interaction.editReply({ embeds: [settings] }); +} + +/** + * @type {import('../../../typings').SlashInteractionCommand} + */ +module.exports = { + data: new SlashCommandBuilder() + .setName("settings") + .setDescription("View the settings for Taurus"), + async execute(interaction) { + try { + const settings = new EmbedBuilder() + .setTitle("Taurus Settings") + .setColor("6414eb") + .addFields( + { + name: "🔗 Webhooks:", + value: `${emojis.loading} **Personality**\n${emojis.loading} **Console**`, + inline: true, + }, + { + name: "🔑 API Keys:", + value: `${emojis.loading} **Prodia**\n${emojis.loading} **Gemini**`, + inline: true, + }, + { + name: "🧠 Model:", + value: `${emojis.loading} **Fallback System**\n${emojis.loading} **Safety System**\n${emojis.loading} **Model**`, + inline: true, + }, + { + name: "⚙️ Other:", + value: `${emojis.loading} **NSFW Image Blocking**`, + inline: true, + }, + ) + .setThumbnail( + "https://github.com/TecEash1/TecEash1/assets/92249532/bd4aca7e-daab-4eeb-9265-e53cc1925e8c", + ); + + if (!checkOwnerAndReply(interaction)) { + return; + } + await interaction.reply({ embeds: [settings] }); + + const webhooks = await db.get("webhooks"); + const apiKeys = await db.get("apiKeys"); + const modelSettings = await db.get("model"); + const otherSettings = await db.get("other"); + + // WEBHOOK CHECKING + let isPersonalityWebhookValid = await checkWebhook(webhooks.personality); + await updateFieldValueAndReply( + interaction, + settings, + "🔗 Webhooks:", + `${isPersonalityWebhookValid ? emojis.working : emojis.failed} **Personality**\n${emojis.loading} **Console**`, + ); + + let isConsoleWebhookValid = await checkWebhook(webhooks.console); + await updateFieldValueAndReply( + interaction, + settings, + "🔗 Webhooks:", + `${isPersonalityWebhookValid ? emojis.working : emojis.failed} **Personality**\n${isConsoleWebhookValid ? emojis.working : emojis.failed} **Console**`, + ); + + // API KEY CHECKING + let isProdiaKeyValid = await checkAPIKey("prodia", apiKeys.prodia); + await updateFieldValueAndReply( + interaction, + settings, + "🔑 API Keys:", + `${isProdiaKeyValid ? emojis.working : emojis.failed} **Prodia**\n${emojis.loading} **Gemini**`, + ); + + let isGeminiKeyValid = await checkAPIKey("gemini", apiKeys.gemini); + await updateFieldValueAndReply( + interaction, + settings, + "🔑 API Keys:", + `${isProdiaKeyValid ? emojis.working : emojis.failed} **Prodia**\n${isGeminiKeyValid ? emojis.working : emojis.failed} **Gemini**`, + ); + + // MODEL SETTINGS CHECKING + + let isFallbackSystemEnabled = modelSettings.fallbackSystem; + await updateFieldValueAndReply( + interaction, + settings, + "🧠 Model:", + `${isFallbackSystemEnabled ? emojis.working : emojis.failed} **Fallback System**\n${emojis.loading} **Safety System**\n${emojis.loading} **Model**`, + ); + + let isSafetySystemEnabled = modelSettings.safetySystem; + await updateFieldValueAndReply( + interaction, + settings, + "🧠 Model:", + `${isFallbackSystemEnabled ? emojis.working : emojis.failed} **Fallback System**\n${isSafetySystemEnabled ? emojis.working : emojis.failed} **Safety System**\n${emojis.loading} **Model**`, + ); + + let modelName = modelSettings.model; + let modelEmoji = modelName === "gemini-1.5-flash-latest" ? "⚡" : "💪"; + let modelNameFormatted = modelName + .replace(/-latest$/, "") + .replace(/-/g, " ") + .split(" ") + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" "); + await updateFieldValueAndReply( + interaction, + settings, + "🧠 Model:", + `${isFallbackSystemEnabled ? emojis.working : emojis.failed} **Fallback System**\n${isSafetySystemEnabled ? emojis.working : emojis.failed} **Safety System**\n${modelEmoji} **${modelNameFormatted}**`, + ); + + // OTHER SETTINGS CHECKING + let isNSFWBlockingEnabled = otherSettings.blockNSFWImages; + await updateFieldValueAndReply( + interaction, + settings, + "⚙️ Other:", + `${isNSFWBlockingEnabled ? emojis.working : emojis.failed} **NSFW Image Blocking**`, + ); + + // BUTTONS + const personality = new ButtonBuilder() + .setCustomId("personality") + .setLabel("Personality") + .setEmoji("✨") + .setStyle(ButtonStyle.Secondary); + const console = new ButtonBuilder() + .setCustomId("console") + .setLabel("Console") + .setEmoji("💾") + .setStyle(ButtonStyle.Secondary); + const webhooksRow = new ActionRowBuilder().addComponents( + personality, + console, + ); + + const prodia = new ButtonBuilder() + .setCustomId("prodia") + .setLabel("Prodia") + .setEmoji("🖼️") + .setStyle(ButtonStyle.Secondary); + const gemini = new ButtonBuilder() + .setCustomId("gemini") + .setLabel("Gemini") + .setEmoji("🤖") + .setStyle(ButtonStyle.Secondary); + const apiKeysRow = new ActionRowBuilder().addComponents(prodia, gemini); + + const fallbackSystem = new ButtonBuilder() + .setCustomId("fallbackSystem") + .setLabel("Fallback System") + .setEmoji("🛡️") + .setStyle(ButtonStyle.Secondary); + const safetySystem = new ButtonBuilder() + .setCustomId("safetySystem") + .setLabel("Safety System") + .setEmoji("🔒") + .setStyle(ButtonStyle.Secondary); + const model = new ButtonBuilder() + .setCustomId("model") + .setLabel("Model") + .setEmoji("🔁") + .setStyle(ButtonStyle.Secondary); + const modelRow = new ActionRowBuilder().addComponents( + fallbackSystem, + safetySystem, + model, + ); + + const nsfw = new ButtonBuilder() + .setCustomId("blockNSFWImages") + .setLabel("NSFW Image Blocking") + .setEmoji("🔞") + .setStyle(ButtonStyle.Secondary); + const otherRow = new ActionRowBuilder().addComponents(nsfw); + + await interaction.editReply({ + components: [webhooksRow, apiKeysRow, modelRow, otherRow], + }); + } catch (error) { + console.error(error); + // console.dir(error, { showHidden: true, depth: null }); + error = new EmbedBuilder() + .setDescription("⚠️ **An Error occurred**") + .setColor("Red"); + await interaction.followUp({ + embeds: [errors], + ephemeral: true, + }); + } + }, +}; diff --git a/interactions/slash/misc/taurusai.js b/interactions/slash/misc/taurusai.js index 0bc4d16..d8cb61e 100644 --- a/interactions/slash/misc/taurusai.js +++ b/interactions/slash/misc/taurusai.js @@ -3,27 +3,33 @@ * @author TechyGiraffe999 */ -const { SlashCommandBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, EmbedBuilder } = require("discord.js"); - +const { + SlashCommandBuilder, + ModalBuilder, + TextInputBuilder, + TextInputStyle, + ActionRowBuilder, +} = require("discord.js"); module.exports = { - data: new SlashCommandBuilder() - .setName('taurus') - .setDescription('Ask Taurus a question!'), - async execute(interaction) { - - const taurus = new ModalBuilder() - .setTitle("Ask TaurusAI something") - .setCustomId("taurus_ai"); + data: new SlashCommandBuilder() + .setName("taurus") + .setDescription("Ask Taurus a question!"), + async execute(interaction) { + const taurus = new ModalBuilder() + .setTitle("Ask TaurusAI something") + .setCustomId("taurus_ai"); - const question = new TextInputBuilder() - .setCustomId("question_taurusai") - .setRequired(true) - .setLabel("Question:") - .setStyle(TextInputStyle.Paragraph); + const question = new TextInputBuilder() + .setCustomId("question_taurusai") + .setRequired(true) + .setLabel("Question:") + .setStyle(TextInputStyle.Paragraph); - const taurusai_question_ActionRow = new ActionRowBuilder().addComponents(question); - taurus.addComponents(taurusai_question_ActionRow); - await interaction.showModal(taurus); - } -}; \ No newline at end of file + const taurusai_question_ActionRow = new ActionRowBuilder().addComponents( + question, + ); + taurus.addComponents(taurusai_question_ActionRow); + await interaction.showModal(taurus); + }, +}; diff --git a/messages/defaultButtonError.js b/messages/defaultButtonError.js new file mode 100644 index 0000000..b06df1b --- /dev/null +++ b/messages/defaultButtonError.js @@ -0,0 +1,23 @@ +/** + * @file Default Error Message On Error Button Interaction + * @author Naman Vrati + * @since 3.0.0 + */ +const excluded_ids = ["yes_botai_personality", "no_botai_personality"]; + +module.exports = { + /** + * @description Executes when the button interaction could not be fetched. + * @author Naman Vrati + * @param {import('discord.js').ButtonInteraction} interaction The Interaction Object of the command. + */ + + async execute(interaction) { + if (excluded_ids.includes(interaction.customId)) return; + await interaction.reply({ + content: "There was an issue while fetching this button!", + ephemeral: true, + }); + return; + }, +}; diff --git a/messages/defaultModalError.js b/messages/defaultModalError.js index 284fce2..6a98784 100644 --- a/messages/defaultModalError.js +++ b/messages/defaultModalError.js @@ -5,7 +5,9 @@ const { EmbedBuilder } = require("discord.js"); const error = new EmbedBuilder() - .setDescription("**There was an issue while fetching this modal!\n\nPlease contact the Developers.**") + .setDescription( + "**There was an issue while fetching this modal!\n\nPlease contact the Developers.**", + ) .setColor("Red"); module.exports = { diff --git a/package.json b/package.json index 126c4a4..88bfd9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "taurus", - "version": "3.0", + "version": "4.0", "description": "An AI Discord Bot!", "types": "./typings.d.ts", "main": "bot.js", @@ -23,18 +23,23 @@ "url": "https://github.com/TecEash1/Taurus/issues" }, "dependencies": { - "@google/generative-ai": "^0.2.1", + "@google/generative-ai": "^0.11.3", "@iamtraction/google-translate": "^2.0.1", - "@tensorflow/tfjs-node": "^4.17.0", + "@tensorflow/tfjs-node": "^4.19.0", "api": "^6.1.1", - "axios": "^1.6.7", + "axios": "^1.6.8", + "better-sqlite3": "^10.0.0", "blessed": "^0.1.81", "chalk": "^5.3.0", - "discord-api-types": "^0.37.43", - "discord.js": "^14.11.0", + "discord-api-types": "^0.37.84", + "discord.js": "^14.15.2", "figlet": "^1.7.0", "moment": "^2.30.1", - "nsfwjs": "^3.0.0", - "os": "^0.1.2" + "nsfwjs": "^4.1.0", + "os": "^0.1.2", + "quick.db": "^9.1.7" + }, + "devDependencies": { + "prettier": "3.2.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..580bba2 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3032 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@google/generative-ai': + specifier: ^0.11.3 + version: 0.11.3 + '@iamtraction/google-translate': + specifier: ^2.0.1 + version: 2.0.1 + '@tensorflow/tfjs-node': + specifier: ^4.19.0 + version: 4.19.0(seedrandom@3.0.5) + api: + specifier: ^6.1.1 + version: 6.1.1(openapi-types@12.1.3) + axios: + specifier: ^1.6.8 + version: 1.6.8 + better-sqlite3: + specifier: ^10.0.0 + version: 10.0.0 + blessed: + specifier: ^0.1.81 + version: 0.1.81 + chalk: + specifier: ^5.3.0 + version: 5.3.0 + discord-api-types: + specifier: ^0.37.84 + version: 0.37.84 + discord.js: + specifier: ^14.15.2 + version: 14.15.2 + figlet: + specifier: ^1.7.0 + version: 1.7.0 + moment: + specifier: ^2.30.1 + version: 2.30.1 + nsfwjs: + specifier: ^4.1.0 + version: 4.1.0(@tensorflow/tfjs@4.19.0(seedrandom@3.0.5)) + os: {specifier: ^0.1.2, version: 0.1.2} + quick.db: + specifier: ^9.1.7 + version: 9.1.7 + devDependencies: + prettier: + specifier: 3.2.5 + version: 3.2.5 + +packages: + + '@apidevtools/openapi-schemas@2.1.0': + resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} + engines: {node: '>=10'} + + '@apidevtools/swagger-methods@3.0.2': + resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + + '@babel/code-frame@7.24.2': + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.5': + resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.5': + resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.24.5': + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + + '@discordjs/builders@1.8.1': + resolution: {integrity: sha512-GkF+HM01FHy+NSoTaUPR8z44otfQgJ1AIsRxclYGUZDyUbdZEFyD/5QVv2Y1Flx6M+B0bQLzg2M9CJv5lGTqpA==} + engines: {node: '>=16.11.0'} + + '@discordjs/collection@1.5.3': + resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==} + engines: {node: '>=16.11.0'} + + '@discordjs/collection@2.1.0': + resolution: {integrity: sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==} + engines: {node: '>=18'} + + '@discordjs/formatters@0.4.0': + resolution: {integrity: sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==} + engines: {node: '>=16.11.0'} + + '@discordjs/rest@2.3.0': + resolution: {integrity: sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==} + engines: {node: '>=16.11.0'} + + '@discordjs/util@1.1.0': + resolution: {integrity: sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==} + engines: {node: '>=16.11.0'} + + '@discordjs/ws@1.1.0': + resolution: {integrity: sha512-O97DIeSvfNTn5wz5vaER6ciyUsr7nOqSEtsLoMhhIgeFkhnxLRqSr00/Fpq2/ppLgjDGLbQCDzIK7ilGoB/M7A==} + engines: {node: '>=16.11.0'} + + '@exodus/schemasafe@1.3.0': + resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + + '@google/generative-ai@0.11.3': + resolution: {integrity: sha512-QtQ1hz6rcybbw35uxXlFF26KNnaTVr2oWwnmDkC1M35KdzN4tVc4wakgJp8uXbY9KDCNHksyp11DbFg0HPckZQ==} + engines: {node: '>=18.0.0'} + + '@humanwhocodes/momoa@2.0.4': + resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==} + engines: {node: '>=10.10.0'} + + '@iamtraction/google-translate@2.0.1': + resolution: {integrity: sha512-kOTkt23zflxpgxLIe9tLvDU8IvNscXYbgMSXydNkZGWDtJ75YJiU3v7EBz+t7h/gSiY7sT5r4dlFkMrHCl+N6A==} + engines: {node: '>=16.0.0'} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@mapbox/node-pre-gyp@1.0.9': + resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==} + hasBin: true + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@readme/better-ajv-errors@1.6.0': + resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==} + engines: {node: '>=14'} + peerDependencies: + ajv: 4.11.8 - 8 + + '@readme/data-urls@1.0.1': + resolution: {integrity: sha512-FNP4ntG5rCgmrvQGoNH/Ljivc6jSWaaVeMuXneOyQ6oLuhm/NkysXJN3DnBrIsJUJbSae7qIs2QfPYnaropoHw==} + engines: {node: '>=14'} + + '@readme/http-status-codes@7.2.0': + resolution: {integrity: sha512-/dBh9qw3QhJYqlGwt2I+KUP/lQ6nytdCx3aq+GpMUhibLHF3O7fwoowNcTwlbnwtyJ+TJYTIIrp3oVUlRNx3fA==} + + '@readme/json-schema-ref-parser@1.2.0': + resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==} + + '@readme/oas-extensions@17.0.1': + resolution: {integrity: sha512-PCU7WLz8TkbdxsiE4eQGvJYDYZQPiyLhXme3SvLboSmH+8G6AJPJ5OymzSAdlf5sXpSSoD2q3dTIou3Cb2DirQ==} + engines: {node: '>=14'} + deprecated: The functionality for this library has been moved into `oas`. + peerDependencies: + oas: ^20.0.0 + + '@readme/oas-to-har@20.1.1': + resolution: {integrity: sha512-rz8YpdZw+Jqrd8VQhQaYrzctkCAYdBldoQ5qDQyF9vGvq2lpA1yMvQPgKCJXfPGXH8Cm+NjLbunxnYabKQeKeA==} + engines: {node: '>=14'} + + '@readme/openapi-parser@2.5.1': + resolution: {integrity: sha512-p9ndWhwjtP+DEiOOF6jeNMpdmYIPM4nl+JEIdnQNdq7b68esI024x7HiYACZpaYaSvISDSyKc7aiRJx4K4IDhg==} + engines: {node: '>=18'} + peerDependencies: + openapi-types: '>=7' + + '@readme/postman-to-openapi@4.1.0': + resolution: {integrity: sha512-VvV2Hzjskz01m8doSn7Ypt6cSZzgjnypVqXy1ipThbyYD6SGiM74VSePXykOODj/43Y2m6zeYedPk/ZLts/HvQ==} + engines: {node: '>=14'} + + '@sapphire/async-queue@1.5.2': + resolution: {integrity: sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + + '@sapphire/shapeshift@3.9.7': + resolution: {integrity: sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==} + engines: {node: '>=v16'} + + '@sapphire/snowflake@3.5.3': + resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + + '@tensorflow/tfjs-backend-cpu@4.19.0': + resolution: {integrity: sha512-7pT05Ea6GTXjbqRgkmayZRYvaiNl3LLk1TyfUvC8iIqMw5d7p4Wgte2pfM2gMbIZ/opOxURhFYuI0FiQvUrW6g==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-backend-webgl@4.19.0': + resolution: {integrity: sha512-R0DC1W65lqTOccCwxMhH+VOKCgSrhd9GEejIIGhjeXt6oZlACFnOx4SuUr/qKLCDsL5I4E9iFLxAJMmsfYvARw==} + engines: {yarn: '>= 1.3.2'} + peerDependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-converter@4.19.0': + resolution: {integrity: sha512-xIOE6enaVHPYCXKpHxJnUlN8hzlcQkgFSymHjBmdDnNCresuRwBGz4dqYAQMeQG21Ei3lxCQFdDDH7aSvUEAPw==} + peerDependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-core@4.19.0': + resolution: {integrity: sha512-GZ0d53PG0HGQCC7hbWv1qDnZctHYe/cafHZrBY5eNeQjQE6fBr3NsR5GfLadT0TELwmX9/nyritGDzvy6xmzHQ==} + engines: {yarn: '>= 1.3.2'} + + '@tensorflow/tfjs-data@4.19.0': + resolution: {integrity: sha512-n0ZgJp5UhhBatohUt9pXSCCApusK+1Flyk6yDrQYuxOTjhRppd6jYrF7LCDG3hMFi3QLGl0jab1zYrn9BwtC/w==} + peerDependencies: + '@tensorflow/tfjs-core': 4.19.0 + seedrandom: ^3.0.5 + + '@tensorflow/tfjs-layers@4.19.0': + resolution: {integrity: sha512-NufvuRaZdIyoG+R13d7oL8G5Bywox+ihPMiMZ3tWU+me8C8Y0pVC69mrnhOS9R8an7GDxKKSTTNEZhUvPvMGiQ==} + peerDependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-node@4.19.0': + resolution: {integrity: sha512-1HLIAuu5azP8SW7t5EZc1W5VOdjWndJYz1N1agz0It/tMtnuWIdAfcY08VjfuiI/NhAwuPShehqv6CZ3SYh+Vg==} + engines: {node: '>=8.11.0'} + + '@tensorflow/tfjs@4.19.0': + resolution: {integrity: sha512-d2A1lTc6my7GJ5LwqzXa+igJ5+18exwsnaphZ3roi5nJ197uwxVSMIc2vSJnqZz1KajC5/mZgQr67EZrpTFlBg==} + hasBin: true + + '@ts-morph/common@0.18.1': + resolution: {integrity: sha512-RVE+zSRICWRsfrkAw5qCAK+4ZH9kwEFv5h0+/YeHTLieWP7F4wWq4JsKFuNWG+fYh/KF+8rAtgdj5zb2mm+DVA==} + + '@types/har-format@1.2.15': + resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + + '@types/node@20.12.12': + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + + '@types/offscreencanvas@2019.3.0': + resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} + + '@types/offscreencanvas@2019.7.3': + resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} + + '@types/seedrandom@2.4.34': + resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==} + + '@types/ws@8.5.10': + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + + '@vladfrangu/async_event_emitter@2.2.4': + resolution: {integrity: sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + + '@webgpu/types@0.1.38': + resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==} + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + adm-zip@0.5.12: + resolution: {integrity: sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==} + engines: {node: '>=6.0'} + + agent-base@4.3.0: + resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==} + engines: {node: '>= 4.0.0'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + api@6.1.1: + resolution: {integrity: sha512-we3fnLinpYWlKOHdX4S/Ky9gZvColCnht/qhtv04K2jQbrC/z4SxvZVAT8W8PCC5NLLU4H35r3u4Lt77ZaiY9w==} + engines: {node: '>=16'} + hasBin: true + + aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + + are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + better-sqlite3@10.0.0: + resolution: {integrity: sha512-rOz0JY8bt9oMgrFssP7GnvA5R3yln73y/NizzWqy3WlFth8Ux8+g4r/N9fjX97nn4X1YX6MTER2doNpTu5pqiA==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + blessed@0.1.81: + resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==} + engines: {node: '>= 0.8.0'} + hasBin: true + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + code-block-writer@11.0.3: + resolution: {integrity: sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==} + + code-error-fragment@0.0.230: + resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==} + engines: {node: '>= 4'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compute-gcd@1.2.1: + resolution: {integrity: sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==} + + compute-lcm@1.1.2: + resolution: {integrity: sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + + core-js@3.29.1: + resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} + + datauri@4.1.0: + resolution: {integrity: sha512-y17kh32+I82G+ED9MNWFkZiP/Cq/vO1hN9+tSZsT9C9qn3NrvcBnh7crSepg0AQPge1hXx2Ca44s1FRdv0gFWA==} + engines: {node: '>= 10'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + + detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} + + discord-api-types@0.37.83: + resolution: {integrity: sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==} + + discord-api-types@0.37.84: + resolution: {integrity: sha512-NngmTBW8vermlbO0qNtaS7SHCWB/R96ICqflTwM/cV7zsxyQGd38E2bBlwaxLbXgb2YTF3+Yx6+qGs/3sXedCw==} + + discord.js@14.15.2: + resolution: {integrity: sha512-wGD37YCaTUNprtpqMIRuNiswwsvSWXrHykBSm2SAosoTYut0VUDj9yo9t4iLtMKvuhI49zYkvKc2TNdzdvpJhg==} + engines: {node: '>=16.11.0'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + engines: {node: '>=0.10'} + + es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + + es6-promise@3.3.1: + resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} + + es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + + event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fetch-har@8.1.5: + resolution: {integrity: sha512-c9WDro4RWC+suOVRJFNW21cgqTOELRZpvFJgfENvOM7Yt/VA4QeFtRax795SyOpTisdpcl5XNQlQZdAE6HERDA==} + engines: {node: '>=14'} + + figlet@1.7.0: + resolution: {integrity: sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg==} + engines: {node: '>= 0.4.0'} + hasBin: true + + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data-encoder@1.9.0: + resolution: {integrity: sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-minipass@1.2.7: + resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + google-protobuf@3.21.2: + resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http2-client@1.3.5: + resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} + + https-proxy-agent@2.2.4: + resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==} + engines: {node: '>= 4.5.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + image-size@1.0.0: + resolution: {integrity: sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==} + engines: {node: '>=12.0.0'} + hasBin: true + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic-fetch@3.0.0: + resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-schema-compare@0.2.2: + resolution: {integrity: sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==} + + json-schema-merge-allof@0.8.1: + resolution: {integrity: sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==} + engines: {node: '>=12.0.0'} + + json-schema-to-ts@2.12.0: + resolution: {integrity: sha512-uTde38yBm5lzJSRPWRaasxZo72pb+JGE4iUksNdNfAkFaLhV4N9akeBxPPUpZy5onINt9Zo0oTLrAoEXyZESiQ==} + engines: {node: '>=16'} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-to-ast@2.1.0: + resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==} + engines: {node: '>= 4'} + + jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + + jsonpath-plus@7.2.0: + resolution: {integrity: sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA==} + engines: {node: '>=12.0.0'} + + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.deburr@4.1.0: + resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.setwith@4.3.2: + resolution: {integrity: sha512-Cv2pndcuNDaqDMJ0gbLm5qNG5jyfsL6f8+f5PfZVVNhQCv+y+P5gAKkCdZbtiQlux7nsnWF7UmZd8JEFIo/4tg==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + lru-queue@0.1.0: + resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + + magic-bytes.js@1.10.0: + resolution: {integrity: sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + marked@4.3.0: + resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} + engines: {node: '>= 12'} + hasBin: true + + memoizee@0.4.15: + resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimer@2.0.2: + resolution: {integrity: sha512-izxvjsB7Ur5HrTbPu6VKTrzxSMBFBqyZQc6dWlZNQ4/wAvf886fD4lrjtFd8IQ8/WmZKdxKjUtqFFNaj3hQ52g==} + engines: {node: '>= 12'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@2.9.0: + resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.1: + resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@1.3.3: + resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + + napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + + node-abi@3.62.0: + resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==} + engines: {node: '>=10'} + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch-h2@2.3.0: + resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==} + engines: {node: 4.x || >=6.0.0} + + node-fetch@2.6.13: + resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-readfiles@0.2.0: + resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} + + nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + + nsfwjs@4.1.0: + resolution: {integrity: sha512-2V27SoNXUJbAAi+vW8RHJbONs2AHa1odmjlRsVX2mirxR4IGt1OIzZ49IXgPVg6nktwA8Su61YEJql7VreEKyg==} + peerDependencies: + '@tensorflow/tfjs': ^4.0.0 + + oas-kit-common@1.0.8: + resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==} + + oas-linter@3.2.2: + resolution: {integrity: sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==} + + oas-normalize@8.4.1: + resolution: {integrity: sha512-cGODg+AntZteJRHBiYDWKtcO2svWGMXuFWYu2I8b4hOrNiwB3hgDs/ScX3O9mYm6RpLsUIftt6rDHGc8eYG8aA==} + engines: {node: '>=14'} + + oas-resolver@2.5.6: + resolution: {integrity: sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==} + hasBin: true + + oas-schema-walker@1.1.5: + resolution: {integrity: sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==} + + oas-validator@5.0.8: + resolution: {integrity: sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==} + + oas@20.10.3: + resolution: {integrity: sha512-dBxDuwn2ssggPMOqEKEzT4sjCqbkol8JozuWrpwD7chcmbKbverj5vpk2kmsczeyguFkLcKUOMcqUUimf9h+IQ==} + engines: {node: '>=14'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + os@0.1.2: + resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + quick.db@9.1.7: + resolution: {integrity: sha512-ZLPVLVFZtvFRLHqIK99iyrLDUznOTpnp5tB+QpGErT+reDSvgBELuVsMkGSSiqKT9R2YSOhO+096Wb0xTaOHMA==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + reftools@1.1.9: + resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + remove-undefined-objects@2.0.2: + resolution: {integrity: sha512-b6x4MUtR4YBW1aCoGx3tE4mA2PFjiXSmtSdNmLexQzUdZa4ybnJAItXLKpkcVgCUJIzJtk2DFG402sMSEMlonQ==} + engines: {node: '>=14'} + + remove-undefined-objects@3.0.0: + resolution: {integrity: sha512-nxG1yYfc/Jxi+bNCBiqKhxVJPE+QvziIOKbD+Dxc93Uisz92v/ZYpo4WR0TJuf+dk2xE8lW2WPJsA3mDFzXy8w==} + engines: {node: '>=16'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + seedrandom@3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + should-equal@2.0.0: + resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} + + should-format@3.0.3: + resolution: {integrity: sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==} + + should-type-adaptors@1.1.0: + resolution: {integrity: sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==} + + should-type@1.4.0: + resolution: {integrity: sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==} + + should-util@1.0.1: + resolution: {integrity: sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==} + + should@13.2.3: + resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssri@10.0.6: + resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + swagger2openapi@7.0.8: + resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} + hasBin: true + + tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@4.4.19: + resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} + engines: {node: '>=4.5'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + timers-ext@0.1.7: + resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-algebra@1.2.2: + resolution: {integrity: sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==} + + ts-mixer@6.0.4: + resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} + + ts-morph@17.0.1: + resolution: {integrity: sha512-10PkHyXmrtsTvZSL+cqtJLTgFXkU43Gd0JCc0Rw6GchWbqKe0Rwgt1v3ouobTZwQzF1mGhDeAlWYBMGRV7y+3g==} + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + type@2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} + + undici@6.13.0: + resolution: {integrity: sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==} + engines: {node: '>=18.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + validate.io-array@1.0.6: + resolution: {integrity: sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==} + + validate.io-function@1.0.2: + resolution: {integrity: sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==} + + validate.io-integer-array@1.0.0: + resolution: {integrity: sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==} + + validate.io-integer@1.0.5: + resolution: {integrity: sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==} + + validate.io-number@1.0.3: + resolution: {integrity: sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + +snapshots: + + '@apidevtools/openapi-schemas@2.1.0': {} + + '@apidevtools/swagger-methods@3.0.2': {} + + '@babel/code-frame@7.24.2': + dependencies: + '@babel/highlight': 7.24.5 + picocolors: 1.0.1 + + '@babel/helper-validator-identifier@7.24.5': {} + + '@babel/highlight@7.24.5': + dependencies: + '@babel/helper-validator-identifier': 7.24.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/runtime@7.24.5': + dependencies: + regenerator-runtime: 0.14.1 + + '@discordjs/builders@1.8.1': + dependencies: + '@discordjs/formatters': 0.4.0 + '@discordjs/util': 1.1.0 + '@sapphire/shapeshift': 3.9.7 + discord-api-types: 0.37.83 + fast-deep-equal: 3.1.3 + ts-mixer: 6.0.4 + tslib: 2.6.2 + + '@discordjs/collection@1.5.3': {} + + '@discordjs/collection@2.1.0': {} + + '@discordjs/formatters@0.4.0': + dependencies: + discord-api-types: 0.37.83 + + '@discordjs/rest@2.3.0': + dependencies: + '@discordjs/collection': 2.1.0 + '@discordjs/util': 1.1.0 + '@sapphire/async-queue': 1.5.2 + '@sapphire/snowflake': 3.5.3 + '@vladfrangu/async_event_emitter': 2.2.4 + discord-api-types: 0.37.83 + magic-bytes.js: 1.10.0 + tslib: 2.6.2 + undici: 6.13.0 + + '@discordjs/util@1.1.0': {} + + '@discordjs/ws@1.1.0': + dependencies: + '@discordjs/collection': 2.1.0 + '@discordjs/rest': 2.3.0 + '@discordjs/util': 1.1.0 + '@sapphire/async-queue': 1.5.2 + '@types/ws': 8.5.10 + '@vladfrangu/async_event_emitter': 2.2.4 + discord-api-types: 0.37.83 + tslib: 2.6.2 + ws: 8.17.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@exodus/schemasafe@1.3.0': {} + + '@fastify/busboy@2.1.1': {} + + '@google/generative-ai@0.11.3': {} + + '@humanwhocodes/momoa@2.0.4': {} + + '@iamtraction/google-translate@2.0.1': + dependencies: + undici: 5.28.4 + + '@jsdevtools/ono@7.1.3': {} + + '@mapbox/node-pre-gyp@1.0.9': + dependencies: + detect-libc: 2.0.3 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.7.0 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.6.2 + tar: 6.2.1 + transitivePeerDependencies: + - encoding + - supports-color + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@readme/better-ajv-errors@1.6.0(ajv@8.13.0)': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/runtime': 7.24.5 + '@humanwhocodes/momoa': 2.0.4 + ajv: 8.13.0 + chalk: 4.1.2 + json-to-ast: 2.1.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + + '@readme/data-urls@1.0.1': {} + + '@readme/http-status-codes@7.2.0': {} + + '@readme/json-schema-ref-parser@1.2.0': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + call-me-maybe: 1.0.2 + js-yaml: 4.1.0 + + '@readme/oas-extensions@17.0.1(oas@20.10.3)': + dependencies: + oas: 20.10.3 + + '@readme/oas-to-har@20.1.1': + dependencies: + '@readme/data-urls': 1.0.1 + '@readme/oas-extensions': 17.0.1(oas@20.10.3) + oas: 20.10.3 + qs: 6.12.1 + remove-undefined-objects: 2.0.2 + transitivePeerDependencies: + - encoding + + '@readme/openapi-parser@2.5.1(openapi-types@12.1.3)': + dependencies: + '@apidevtools/openapi-schemas': 2.1.0 + '@apidevtools/swagger-methods': 3.0.2 + '@jsdevtools/ono': 7.1.3 + '@readme/better-ajv-errors': 1.6.0(ajv@8.13.0) + '@readme/json-schema-ref-parser': 1.2.0 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + call-me-maybe: 1.0.2 + openapi-types: 12.1.3 + + '@readme/postman-to-openapi@4.1.0': + dependencies: + '@readme/http-status-codes': 7.2.0 + js-yaml: 4.1.0 + jsonc-parser: 3.2.0 + lodash.camelcase: 4.3.0 + marked: 4.3.0 + mustache: 4.2.0 + + '@sapphire/async-queue@1.5.2': {} + + '@sapphire/shapeshift@3.9.7': + dependencies: + fast-deep-equal: 3.1.3 + lodash: 4.17.21 + + '@sapphire/snowflake@3.5.3': {} + + '@tensorflow/tfjs-backend-cpu@4.19.0(@tensorflow/tfjs-core@4.19.0)': + dependencies: + '@tensorflow/tfjs-core': 4.19.0 + '@types/seedrandom': 2.4.34 + seedrandom: 3.0.5 + + '@tensorflow/tfjs-backend-webgl@4.19.0(@tensorflow/tfjs-core@4.19.0)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.19.0(@tensorflow/tfjs-core@4.19.0) + '@tensorflow/tfjs-core': 4.19.0 + '@types/offscreencanvas': 2019.3.0 + '@types/seedrandom': 2.4.34 + seedrandom: 3.0.5 + + '@tensorflow/tfjs-converter@4.19.0(@tensorflow/tfjs-core@4.19.0)': + dependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-core@4.19.0': + dependencies: + '@types/long': 4.0.2 + '@types/offscreencanvas': 2019.7.3 + '@types/seedrandom': 2.4.34 + '@webgpu/types': 0.1.38 + long: 4.0.0 + node-fetch: 2.6.13 + seedrandom: 3.0.5 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-data@4.19.0(@tensorflow/tfjs-core@4.19.0)(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-core': 4.19.0 + '@types/node-fetch': 2.6.11 + node-fetch: 2.6.13 + seedrandom: 3.0.5 + string_decoder: 1.3.0 + transitivePeerDependencies: + - encoding + + '@tensorflow/tfjs-layers@4.19.0(@tensorflow/tfjs-core@4.19.0)': + dependencies: + '@tensorflow/tfjs-core': 4.19.0 + + '@tensorflow/tfjs-node@4.19.0(seedrandom@3.0.5)': + dependencies: + '@mapbox/node-pre-gyp': 1.0.9 + '@tensorflow/tfjs': 4.19.0(seedrandom@3.0.5) + adm-zip: 0.5.12 + google-protobuf: 3.21.2 + https-proxy-agent: 2.2.4 + progress: 2.0.3 + rimraf: 2.7.1 + tar: 4.4.19 + transitivePeerDependencies: + - encoding + - seedrandom + - supports-color + + '@tensorflow/tfjs@4.19.0(seedrandom@3.0.5)': + dependencies: + '@tensorflow/tfjs-backend-cpu': 4.19.0(@tensorflow/tfjs-core@4.19.0) + '@tensorflow/tfjs-backend-webgl': 4.19.0(@tensorflow/tfjs-core@4.19.0) + '@tensorflow/tfjs-converter': 4.19.0(@tensorflow/tfjs-core@4.19.0) + '@tensorflow/tfjs-core': 4.19.0 + '@tensorflow/tfjs-data': 4.19.0(@tensorflow/tfjs-core@4.19.0)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 4.19.0(@tensorflow/tfjs-core@4.19.0) + argparse: 1.0.10 + chalk: 4.1.2 + core-js: 3.29.1 + regenerator-runtime: 0.13.11 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - seedrandom + + '@ts-morph/common@0.18.1': + dependencies: + fast-glob: 3.3.2 + minimatch: 5.1.6 + mkdirp: 1.0.4 + path-browserify: 1.0.1 + + '@types/har-format@1.2.15': {} + + '@types/json-schema@7.0.15': {} + + '@types/long@4.0.2': {} + + '@types/node-fetch@2.6.11': + dependencies: + '@types/node': 20.12.12 + form-data: 4.0.0 + + '@types/node@20.12.12': + dependencies: + undici-types: 5.26.5 + + '@types/offscreencanvas@2019.3.0': {} + + '@types/offscreencanvas@2019.7.3': {} + + '@types/seedrandom@2.4.34': {} + + '@types/ws@8.5.10': + dependencies: + '@types/node': 20.12.12 + + '@vladfrangu/async_event_emitter@2.2.4': {} + + '@webgpu/types@0.1.38': {} + + abbrev@1.1.1: {} + + adm-zip@0.5.12: {} + + agent-base@4.3.0: + dependencies: + es6-promisify: 5.0.0 + + agent-base@6.0.2: + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + ajv-draft-04@1.0.0(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + api@6.1.1(openapi-types@12.1.3): + dependencies: + '@readme/oas-to-har': 20.1.1 + '@readme/openapi-parser': 2.5.1(openapi-types@12.1.3) + caseless: 0.12.0 + chalk: 4.1.2 + commander: 10.0.1 + datauri: 4.1.0 + execa: 5.1.1 + fetch-har: 8.1.5 + figures: 3.2.0 + find-cache-dir: 3.3.2 + form-data-encoder: 1.9.0 + formdata-node: 4.4.1 + get-stream: 6.0.1 + isomorphic-fetch: 3.0.0 + js-yaml: 4.1.0 + json-schema-to-ts: 2.12.0 + json-schema-traverse: 1.0.0 + lodash.camelcase: 4.3.0 + lodash.deburr: 4.1.0 + lodash.merge: 4.6.2 + lodash.setwith: 4.3.2 + lodash.startcase: 4.4.0 + make-dir: 3.1.0 + node-abort-controller: 3.1.1 + oas: 20.10.3 + ora: 5.4.1 + prompts: 2.4.2 + remove-undefined-objects: 2.0.2 + semver: 7.6.2 + ssri: 10.0.6 + ts-morph: 17.0.1 + validate-npm-package-name: 5.0.1 + transitivePeerDependencies: + - encoding + - openapi-types + + aproba@2.0.0: {} + + are-we-there-yet@2.0.0: + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.6.8: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + better-sqlite3@10.0.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.2 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + blessed@0.1.81: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + call-me-maybe@1.0.2: {} + + caseless@0.12.0: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + chownr@1.1.4: {} + + chownr@2.0.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + code-block-writer@11.0.3: {} + + code-error-fragment@0.0.230: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-support@1.1.3: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@10.0.1: {} + + commondir@1.0.1: {} + + compute-gcd@1.2.1: + dependencies: + validate.io-array: 1.0.6 + validate.io-function: 1.0.2 + validate.io-integer-array: 1.0.0 + + compute-lcm@1.1.2: + dependencies: + compute-gcd: 1.2.1 + validate.io-array: 1.0.6 + validate.io-function: 1.0.2 + validate.io-integer-array: 1.0.0 + + concat-map@0.0.1: {} + + console-control-strings@1.1.0: {} + + core-js@3.29.1: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.2 + + datauri@4.1.0: + dependencies: + image-size: 1.0.0 + mimer: 2.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + delayed-stream@1.0.0: {} + + delegates@1.0.0: {} + + detect-libc@2.0.3: {} + + discord-api-types@0.37.83: {} + + discord-api-types@0.37.84: {} + + discord.js@14.15.2: + dependencies: + '@discordjs/builders': 1.8.1 + '@discordjs/collection': 1.5.3 + '@discordjs/formatters': 0.4.0 + '@discordjs/rest': 2.3.0 + '@discordjs/util': 1.1.0 + '@discordjs/ws': 1.1.0 + '@sapphire/snowflake': 3.5.3 + discord-api-types: 0.37.83 + fast-deep-equal: 3.1.3 + lodash.snakecase: 4.1.1 + tslib: 2.6.2 + undici: 6.13.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + emoji-regex@8.0.0: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + + es6-promise@3.3.1: {} + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + + escalade@3.1.2: {} + + escape-string-regexp@1.0.5: {} + + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.2 + + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + expand-template@2.0.3: {} + + ext@1.7.0: + dependencies: + type: 2.7.2 + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + fast-safe-stringify@2.1.1: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fetch-har@8.1.5: + dependencies: + '@readme/data-urls': 1.0.1 + '@types/har-format': 1.2.15 + readable-stream: 3.6.2 + optionalDependencies: + formdata-node: 4.4.1 + + figlet@1.7.0: {} + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + + file-uri-to-path@1.0.0: {} + + fill-range@7.0.1: + dependencies: + to-regex-range: 5.0.1 + + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + follow-redirects@1.15.6: {} + + form-data-encoder@1.9.0: {} + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + fs-constants@1.0.0: {} + + fs-minipass@1.2.7: + dependencies: + minipass: 2.9.0 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + gauge@3.0.2: + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + + get-caller-file@2.0.5: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-stream@6.0.1: {} + + github-from-package@0.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + google-protobuf@3.21.2: {} + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + grapheme-splitter@1.0.4: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-unicode@2.0.1: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http2-client@1.3.5: {} + + https-proxy-agent@2.2.4: + dependencies: + agent-base: 4.3.0 + debug: 3.2.7 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + ieee754@1.2.1: {} + + image-size@1.0.0: + dependencies: + queue: 6.0.2 + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-interactive@1.0.0: {} + + is-number@7.0.0: {} + + is-promise@2.2.2: {} + + is-stream@2.0.1: {} + + is-unicode-supported@0.1.0: {} + + isexe@2.0.0: {} + + isomorphic-fetch@3.0.0: + dependencies: + node-fetch: 2.7.0 + whatwg-fetch: 3.6.20 + transitivePeerDependencies: + - encoding + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-schema-compare@0.2.2: + dependencies: + lodash: 4.17.21 + + json-schema-merge-allof@0.8.1: + dependencies: + compute-lcm: 1.1.2 + json-schema-compare: 0.2.2 + lodash: 4.17.21 + + json-schema-to-ts@2.12.0: + dependencies: + '@babel/runtime': 7.24.5 + '@types/json-schema': 7.0.15 + ts-algebra: 1.2.2 + + json-schema-traverse@1.0.0: {} + + json-to-ast@2.1.0: + dependencies: + code-error-fragment: 0.0.230 + grapheme-splitter: 1.0.4 + + jsonc-parser@3.2.0: {} + + jsonpath-plus@7.2.0: {} + + jsonpointer@5.0.1: {} + + kleur@3.0.3: {} + + leven@3.1.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.camelcase@4.3.0: {} + + lodash.deburr@4.1.0: {} + + lodash.merge@4.6.2: {} + + lodash.setwith@4.3.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + long@4.0.0: {} + + lru-queue@0.1.0: + dependencies: + es5-ext: 0.10.64 + + magic-bytes.js@1.10.0: {} + + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + + marked@4.3.0: {} + + memoizee@0.4.15: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-weak-map: 2.0.3 + event-emitter: 0.3.5 + is-promise: 2.2.2 + lru-queue: 0.1.0 + next-tick: 1.1.0 + timers-ext: 0.1.7 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.5: + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimer@2.0.2: {} + + mimic-fn@2.1.0: {} + + mimic-response@3.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@2.9.0: + dependencies: + safe-buffer: 5.2.1 + yallist: 3.1.1 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.1: {} + + minizlib@1.3.3: + dependencies: + minipass: 2.9.0 + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp-classic@0.5.3: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + moment@2.30.1: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + mustache@4.2.0: {} + + napi-build-utils@1.0.2: {} + + next-tick@1.1.0: {} + + node-abi@3.62.0: + dependencies: + semver: 7.6.2 + + node-abort-controller@3.1.1: {} + + node-domexception@1.0.0: {} + + node-fetch-h2@2.3.0: + dependencies: + http2-client: 1.3.5 + + node-fetch@2.6.13: + dependencies: + whatwg-url: 5.0.0 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-readfiles@0.2.0: + dependencies: + es6-promise: 3.3.1 + + nopt@5.0.0: + dependencies: + abbrev: 1.1.1 + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npmlog@5.0.1: + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + + nsfwjs@4.1.0(@tensorflow/tfjs@4.19.0(seedrandom@3.0.5)): + dependencies: + '@tensorflow/tfjs': 4.19.0(seedrandom@3.0.5) + + oas-kit-common@1.0.8: + dependencies: + fast-safe-stringify: 2.1.1 + + oas-linter@3.2.2: + dependencies: + '@exodus/schemasafe': 1.3.0 + should: 13.2.3 + yaml: 1.10.2 + + oas-normalize@8.4.1: + dependencies: + '@readme/openapi-parser': 2.5.1(openapi-types@12.1.3) + '@readme/postman-to-openapi': 4.1.0 + js-yaml: 4.1.0 + node-fetch: 2.7.0 + openapi-types: 12.1.3 + swagger2openapi: 7.0.8 + transitivePeerDependencies: + - encoding + + oas-resolver@2.5.6: + dependencies: + node-fetch-h2: 2.3.0 + oas-kit-common: 1.0.8 + reftools: 1.1.9 + yaml: 1.10.2 + yargs: 17.7.2 + + oas-schema-walker@1.1.5: {} + + oas-validator@5.0.8: + dependencies: + call-me-maybe: 1.0.2 + oas-kit-common: 1.0.8 + oas-linter: 3.2.2 + oas-resolver: 2.5.6 + oas-schema-walker: 1.1.5 + reftools: 1.1.9 + should: 13.2.3 + yaml: 1.10.2 + + oas@20.10.3: + dependencies: + '@readme/json-schema-ref-parser': 1.2.0 + '@types/json-schema': 7.0.15 + json-schema-merge-allof: 0.8.1 + jsonpath-plus: 7.2.0 + jsonpointer: 5.0.1 + memoizee: 0.4.15 + oas-normalize: 8.4.1 + openapi-types: 12.1.3 + path-to-regexp: 6.2.2 + remove-undefined-objects: 3.0.0 + transitivePeerDependencies: + - encoding + + object-assign@4.1.1: {} + + object-inspect@1.13.1: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + openapi-types@12.1.3: {} + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + os@0.1.2: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-to-regexp@6.2.2: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + prebuild-install@7.1.2: + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.62.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + + prettier@3.2.5: {} + + progress@2.0.3: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proxy-from-env@1.1.0: {} + + pump@3.0.0: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode@2.3.1: {} + + qs@6.12.1: + dependencies: + side-channel: 1.0.6 + + queue-microtask@1.2.3: {} + + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + quick.db@9.1.7: + dependencies: + lodash: 4.17.21 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + reftools@1.1.9: {} + + regenerator-runtime@0.13.11: {} + + regenerator-runtime@0.14.1: {} + + remove-undefined-objects@2.0.2: {} + + remove-undefined-objects@3.0.0: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + reusify@1.0.4: {} + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.2.1: {} + + seedrandom@3.0.5: {} + + semver@6.3.1: {} + + semver@7.6.2: {} + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + should-equal@2.0.0: + dependencies: + should-type: 1.4.0 + + should-format@3.0.3: + dependencies: + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + + should-type-adaptors@1.1.0: + dependencies: + should-type: 1.4.0 + should-util: 1.0.1 + + should-type@1.4.0: {} + + should-util@1.0.1: {} + + should@13.2.3: + dependencies: + should-equal: 2.0.0 + should-format: 3.0.3 + should-type: 1.4.0 + should-type-adaptors: 1.1.0 + should-util: 1.0.1 + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + + signal-exit@3.0.7: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + sisteransi@1.0.5: {} + + sprintf-js@1.0.3: {} + + ssri@10.0.6: + dependencies: + minipass: 7.1.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-final-newline@2.0.0: {} + + strip-json-comments@2.0.1: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + swagger2openapi@7.0.8: + dependencies: + call-me-maybe: 1.0.2 + node-fetch: 2.7.0 + node-fetch-h2: 2.3.0 + node-readfiles: 0.2.0 + oas-kit-common: 1.0.8 + oas-resolver: 2.5.6 + oas-schema-walker: 1.1.5 + oas-validator: 5.0.8 + reftools: 1.1.9 + yaml: 1.10.2 + yargs: 17.7.2 + transitivePeerDependencies: + - encoding + + tar-fs@2.1.1: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar@4.4.19: + dependencies: + chownr: 1.1.4 + fs-minipass: 1.2.7 + minipass: 2.9.0 + minizlib: 1.3.3 + mkdirp: 0.5.6 + safe-buffer: 5.2.1 + yallist: 3.1.1 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + timers-ext@0.1.7: + dependencies: + es5-ext: 0.10.64 + next-tick: 1.1.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + ts-algebra@1.2.2: {} + + ts-mixer@6.0.4: {} + + ts-morph@17.0.1: + dependencies: + '@ts-morph/common': 0.18.1 + code-block-writer: 11.0.3 + + tslib@2.6.2: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + type@2.7.2: {} + + undici-types@5.26.5: {} + + undici@5.28.4: + dependencies: + '@fastify/busboy': 2.1.1 + + undici@6.13.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + validate-npm-package-name@5.0.1: {} + + validate.io-array@1.0.6: {} + + validate.io-function@1.0.2: {} + + validate.io-integer-array@1.0.0: + dependencies: + validate.io-array: 1.0.6 + validate.io-integer: 1.0.5 + + validate.io-integer@1.0.5: + dependencies: + validate.io-number: 1.0.3 + + validate.io-number@1.0.3: {} + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-fetch@3.6.20: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wide-align@1.1.5: + dependencies: + string-width: 4.2.3 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@8.17.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@1.10.2: {} + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 diff --git a/start.mjs b/start.mjs index bb06e74..4c364af 100644 --- a/start.mjs +++ b/start.mjs @@ -8,7 +8,7 @@ import figlet from "figlet"; // Create a screen object. const screen = blessed.screen({ smartCSR: true, - title: "Taurus Bot Console" + title: "Taurus Bot Console", }); // Create a box that fills the entire screen. @@ -20,15 +20,15 @@ const box = blessed.box({ content: "", tags: true, border: { - type: "line" + type: "line", }, style: { fg: "white", bg: "black", border: { - fg: "#ff0000" // Red - } - } + fg: "#ff0000", // Red + }, + }, }); // Create a console box at the top right. @@ -40,15 +40,15 @@ const consoleBox = blessed.box({ content: "{underline}Taurus Console{/underline}", tags: true, border: { - type: "line" + type: "line", }, style: { fg: "white", bg: "black", border: { - fg: "#ff0000" // Red - } - } + fg: "#ff0000", // Red + }, + }, }); // Append our boxes to the screen. @@ -62,13 +62,15 @@ let botStatus = "Offline"; // Function to start the Discord bot. function startBot() { if (bot) { - writeToConsole(chalk.red("Bot is already running. Please stop the bot first.")); + writeToConsole( + chalk.red("Bot is already running. Please stop the bot first."), + ); return; } // Modify this line to start your bot with the correct command and arguments bot = spawn("node", ["bot.js"], { - stdio: ["pipe", "pipe", "pipe", "pipe", "pipe", "pipe", process.stderr] + stdio: ["pipe", "pipe", "pipe", "pipe", "pipe", "pipe", process.stderr], }); botStartTime = moment(); @@ -93,7 +95,9 @@ function startBot() { // Function to stop the Discord bot. function stopBot() { if (!bot) { - writeToConsole(chalk.red("Bot is not running. Please start the bot first.")); + writeToConsole( + chalk.red("Bot is not running. Please start the bot first."), + ); return; } @@ -111,24 +115,43 @@ function stopBot() { // Function to restart the Discord bot. function restartBot() { - stopBot(); - const gitPull = spawn('git', ['pull']); - - gitPull.stdout.on('data', (data) => { - writeToConsole(chalk.italic(`[GIT] stdout: ${data}`)); - }); - - gitPull.stderr.on('data', (data) => { - writeToConsole(chalk.italic(`[GIT] stderr: ${data}`)); - }); - - gitPull.on('close', (code) => { - writeToConsole(chalk.italic(`[GIT] child process exited with code ${code}`)); - setTimeout(() => { - startBot(); - writeToConsole(chalk.red("Bot restarted.")); - }, 1000); - }); + stopBot(); + const gitPull = spawn("git", ["pull"]); + + gitPull.stdout.on("data", (data) => { + writeToConsole(chalk.italic(`[GIT] stdout: ${data}`)); + }); + + gitPull.stderr.on("data", (data) => { + writeToConsole(chalk.italic(`[GIT] stderr: ${data}`)); + }); + + gitPull.on("close", (code) => { + writeToConsole( + chalk.italic(`[GIT] child process exited with code ${code}`), + ); + + const pnpmInstall = spawn("pnpm", ["install"], { shell: true }); + + pnpmInstall.stdout.on("data", (data) => { + const message = data.toString().trim(); + message && writeToConsole(chalk.italic(`[PNPM] stdout: ${message}`)); + }); + + pnpmInstall.stderr.on("data", (data) => { + writeToConsole(chalk.italic(`[PNPM] stderr: ${data}`)); + }); + + pnpmInstall.on("close", (code) => { + writeToConsole( + chalk.italic(`[PNPM] child process exited with code ${code}`), + ); + setTimeout(() => { + startBot(); + writeToConsole(chalk.red("Bot restarted.")); + }, 1000); + }); + }); } // Function to refresh the console. @@ -139,20 +162,24 @@ function refreshConsole() { } let title = ""; -figlet.text("Taurus", { - font: "Standard", - horizontalLayout: "default", - verticalLayout: "default", - width: 100, - whitespaceBreak: true -}, function(err, data) { - if (err) { - console.log("Something went wrong..."); - console.dir(err); - return; - } - title = chalk.red(data); // Red -}); +figlet.text( + "Taurus", + { + font: "Standard", + horizontalLayout: "default", + verticalLayout: "default", + width: 100, + whitespaceBreak: true, + }, + function (err, data) { + if (err) { + console.log("Something went wrong..."); + console.dir(err); + return; + } + title = chalk.red(data); // Red + }, +); // Function to update the box content with system and bot stats function updateStats() { @@ -162,25 +189,27 @@ function updateStats() { const cpuCores = os.cpus().length.toString(); const osInfo = `${os.type()} (${os.release()})`; - const botUptime = botStartTime ? moment.duration(moment().diff(botStartTime)).humanize() : "Not available"; - const botMemoryUsage = (process.memoryUsage().heapUsed / 1024 / 1024 / 1024).toFixed(2) + " GB"; - - box.setContent(`${title}\n\n` + - `${chalk.red("Bot Status:")} ${botStatus === "Online" ? chalk.green(botStatus) : chalk.red(botStatus)}\n\n` + - `${chalk.red("VPS Uptime:")} ${chalk.white(serverUptime)}\n` + - `${chalk.red("Total Memory:")} ${chalk.white(totalMemory)}\n` + - `${chalk.red("Bot Uptime:")} ${chalk.white(botUptime)}\n` + - `${chalk.red("Bot Memory Usage:")} ${chalk.white(botMemoryUsage)}\n` + - `${chalk.red("CPU Threads:")} ${chalk.white(cpuCores)}\n` + - `${chalk.red("OS Info:")} ${chalk.white(osInfo)}\n\n` + - `${chalk.red("Commands:")}\n` + - - `${chalk.green("S")} - ${chalk.white("Start Bot")}\n` + - `${chalk.green("X")} - ${chalk.white("Stop Bot")}\n` + - `${chalk.green("R")} - ${chalk.white("Restart & Update Bot")}\n` + - `${chalk.green("L")} - ${chalk.white("Refresh Console")}\n\n` + - - `${chalk.red("Press")} ${chalk.white("Ctrl+C")} ${chalk.red("to stop the bot and exit.")}\n\n\n` + const botUptime = botStartTime + ? moment.duration(moment().diff(botStartTime)).humanize() + : "Not available"; + const botMemoryUsage = + (process.memoryUsage().heapUsed / 1024 / 1024 / 1024).toFixed(2) + " GB"; + + box.setContent( + `${title}\n\n` + + `${chalk.red("Bot Status:")} ${botStatus === "Online" ? chalk.green(botStatus) : chalk.red(botStatus)}\n\n` + + `${chalk.red("VPS Uptime:")} ${chalk.white(serverUptime)}\n` + + `${chalk.red("Total Memory:")} ${chalk.white(totalMemory)}\n` + + `${chalk.red("Bot Uptime:")} ${chalk.white(botUptime)}\n` + + `${chalk.red("Bot Memory Usage:")} ${chalk.white(botMemoryUsage)}\n` + + `${chalk.red("CPU Threads:")} ${chalk.white(cpuCores)}\n` + + `${chalk.red("OS Info:")} ${chalk.white(osInfo)}\n\n` + + `${chalk.red("Commands:")}\n` + + `${chalk.green("S")} - ${chalk.white("Start Bot")}\n` + + `${chalk.green("X")} - ${chalk.white("Stop Bot")}\n` + + `${chalk.green("R")} - ${chalk.white("Restart & Update Bot")}\n` + + `${chalk.green("L")} - ${chalk.white("Refresh Console")}\n\n` + + `${chalk.red("Press")} ${chalk.white("Ctrl+C")} ${chalk.red("to stop the bot and exit.")}\n\n\n`, ); screen.render(); } @@ -208,7 +237,6 @@ process.on("SIGINT", () => { // Start the bot when script is run initially. startBot(); - // Listen for keystrokes and map them to commands. screen.key(["S", "s"], () => { startBot(); @@ -226,9 +254,9 @@ screen.key(["L", "l"], () => { refreshConsole(); }); -screen.key(["escape", "q", "C-c"], function(ch, key) { +screen.key(["escape", "q", "C-c"], function (ch, key) { return process.exit(0); }); // Render the screen. -screen.render(); \ No newline at end of file +screen.render(); diff --git a/startbot.bat b/startbot.bat index 4ce816c..8ff2226 100644 --- a/startbot.bat +++ b/startbot.bat @@ -1,7 +1,8 @@ @echo off set "SCRIPT_DIR=%~dp0" cd "%SCRIPT_DIR%" -call npm install +call npm install -g pnpm +call pnpm install pause node start.mjs pause \ No newline at end of file diff --git a/startbot.sh b/startbot.sh index 4cf9cfe..858f855 100644 --- a/startbot.sh +++ b/startbot.sh @@ -1,5 +1,6 @@ SCRIPT_DIR="$( cd "$(dirname "$0")" ; pwd -P )" cd "$SCRIPT_DIR" -npm install +npm install -g pnpm +pnpm install node start.mjs read -p "Press Enter to exit" \ No newline at end of file diff --git a/typings.d.ts b/typings.d.ts index 85c0395..4d18b5d 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -56,7 +56,7 @@ export interface LegacyCommand { */ execute( message: Discord.Message & { client: Client }, - args: string[] + args: string[], ): void | Promise; } @@ -84,7 +84,7 @@ export interface SlashInteractionCommand { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.ChatInputCommandInteraction & { client: Client } + interaction: Discord.ChatInputCommandInteraction & { client: Client }, ): void | Promise; } @@ -102,7 +102,7 @@ export interface ButtonInteractionCommand { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.ButtonInteraction & { client: Client } + interaction: Discord.ButtonInteraction & { client: Client }, ): void | Promise; } @@ -120,7 +120,7 @@ export interface SelectInteractionCommand { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.SelectMenuInteraction & { client: Client } + interaction: Discord.SelectMenuInteraction & { client: Client }, ): void | Promise; } @@ -155,7 +155,7 @@ export interface ContextInteractionCommand { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.ContextMenuCommandInteraction & { client: Client } + interaction: Discord.ContextMenuCommandInteraction & { client: Client }, ): void | Promise; } @@ -173,7 +173,7 @@ export interface ModalInteractionCommand { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.ModalSubmitInteraction & { client: Client } + interaction: Discord.ModalSubmitInteraction & { client: Client }, ): void | Promise; } @@ -192,7 +192,7 @@ export interface TriggerCommand { */ execute( message: Discord.Message & { client: Client }, - args: string[] + args: string[], ): void | Promise; } @@ -210,7 +210,7 @@ export interface AutocompleteInteraction { * @param interaction The interaction that triggered this command. */ execute( - interaction: Discord.AutocompleteInteraction & { client: Client } + interaction: Discord.AutocompleteInteraction & { client: Client }, ): void | Promise; }