diff --git a/base/JaBa.js b/base/JaBa.js index 643ccc3a..0e63f617 100644 --- a/base/JaBa.js +++ b/base/JaBa.js @@ -2,7 +2,8 @@ const { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder } = r { Player } = require("discord-player"), { GiveawaysManager } = require("discord-giveaways"), { REST } = require("@discordjs/rest"), - { Routes } = require("discord-api-types/v10"); + { Routes } = require("discord-api-types/v10"), + { Configuration, OpenAIApi } = require("openai"); const BaseEvent = require("./BaseEvent.js"), BaseCommand = require("./BaseCommand.js"), @@ -42,6 +43,12 @@ class JaBa extends Client { this.databaseCache.usersReminds = new Collection(); this.databaseCache.mutedUsers = new Collection(); + const configuration = new Configuration({ + apiKey: this.config.apiKeys.openai, + }); + + this.openai = new OpenAIApi(configuration); + this.player = Player.singleton(this); this.player.events.on("playerStart", async (queue, track) => { diff --git a/commands/AI/chat.js b/commands/AI/chat.js new file mode 100644 index 00000000..25b05653 --- /dev/null +++ b/commands/AI/chat.js @@ -0,0 +1,108 @@ +const { SlashCommandBuilder, range } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Chat extends BaseCommand { + /** + * + * @param {import("../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("chat") + .setDescription(client.translate("ai/chat:DESCRIPTION")) + .setDescriptionLocalizations({ "uk": client.translate("ai/chat:DESCRIPTION", null, "uk-UA") }) + .setDMPermission(true) + .addStringOption(option => option.setName("prompt") + .setDescription(client.translate("ai/chat:PROMPT")) + .setDescriptionLocalizations({ "uk": client.translate("ai/chat:PROMPT", null, "uk-UA") }) + .setMaxLength(300) + .setRequired(true)), + aliases: [], + dirname: __dirname, + ownerOnly: false, + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Object} data + */ + async execute(client, interaction) { + await interaction.deferReply(); + + const prompt = interaction.options.getString("prompt"); + + try { + const completion = await client.openai.createChatCompletion({ + model: "gpt-3.5-turbo", + messages: [{ role: "user", content: prompt }], + user: `user${interaction.user.id}`, + }), + response = completion.data.choices[0].message.content; + + await interaction.editReply({ + content: interaction.translate("ai/chat:THANKS"), + }); + + if (response.length > 1900) { + if (response.includes("```")) { + const parts = response.split("```"); + + for (const i in parts) { + if (i % 2 === 0) { + await interaction.followUp({ + content: parts[i], + }); + } else { + const codeBlock = parts[i].split("\n"); + let formattedCodeBlock = ""; + + for (let line in codeBlock) { + while (line.length > 50) { + formattedCodeBlock += line.slice(0, 50) + "\n"; + line = line.slice(50, line.length); + } + + formattedCodeBlock += line + "\n"; + } + + if (formattedCodeBlock.length > 1900 + 100) { + const codeblockChunks = []; + for (const i in range({ start: 0, end: formattedCodeBlock.length, step: 1900 })) { + codeblockChunks.push(formattedCodeBlock.slice(i, i + 1900)); + } + + for (const i in codeblockChunks) { + await interaction.followUp({ content: `\`\`\`${i}\`\`\`` }); + } + + } else await interaction.followUp({ content: `\`\`\`${formattedCodeBlock}\`\`\`` }); + } + } + } else { + const responseChunks = []; + for (const i in range({ start: 0, end: response.length, step: 1900 })) { + responseChunks.push(response.slice(i, i + 1900)); + } + + for (const i in responseChunks) { + await interaction.followUp({ content: i }); + } + } + } else await interaction.followUp({ content: response }); + } catch (e) { + console.log(e); + } + } +} + +module.exports = Chat; \ No newline at end of file diff --git a/languages/ru-RU/ai/chat.json b/languages/ru-RU/ai/chat.json new file mode 100644 index 00000000..0045c52d --- /dev/null +++ b/languages/ru-RU/ai/chat.json @@ -0,0 +1,7 @@ +{ + "DESCRIPTION": "Спросить у ChatGPT", + "USAGE": "[query]", + "EXAMPLES": "chat query:Привет! Как тебя зовут?", + "PROMPT": "Запрос", + "THANKS": "> Спасибо за ожидание!" +} \ No newline at end of file diff --git a/languages/uk-UA/ai/chat.json b/languages/uk-UA/ai/chat.json new file mode 100644 index 00000000..296a4337 --- /dev/null +++ b/languages/uk-UA/ai/chat.json @@ -0,0 +1,7 @@ +{ + "DESCRIPTION": "Запитати у ChatGPT", + "USAGE": "[query]", + "EXAMPLES": "chat query:Вітання! Як тебе звати?", + "PROMPT": "Запит", + "THANKS": "> Спасибі за очікування!" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d83e2e30..979eaf8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "moment": "^2.26.0", "mongoose": "^5.13.15", "ms": "^2.1.3", + "openai": "^3.2.1", "play-dl": "^1.9.6" }, "devDependencies": { @@ -828,6 +829,19 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1203,6 +1217,17 @@ "color-support": "bin.js" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", @@ -1409,6 +1434,14 @@ "node": ">=10" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -2109,6 +2142,38 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data-encoder": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.0.tgz", @@ -3303,6 +3368,15 @@ "wrappy": "1" } }, + "node_modules/openai": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", + "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, "node_modules/optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -5044,6 +5118,19 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "requires": { + "follow-redirects": "^1.14.8" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5336,6 +5423,14 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", @@ -5487,6 +5582,11 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -6033,6 +6133,21 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "form-data-encoder": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.0.tgz", @@ -6909,6 +7024,15 @@ "wrappy": "1" } }, + "openai": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", + "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", + "requires": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", diff --git a/package.json b/package.json index ea6b32e7..534781e3 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "moment": "^2.26.0", "mongoose": "^5.13.15", "ms": "^2.1.3", + "openai": "^3.2.1", "play-dl": "^1.9.6" }, "devDependencies": {