const { Client, GatewayIntentBits, REST, Routes, EmbedBuilder, SlashCommandBuilder } = require('discord.js'); const axios = require('axios'); const he = require('he'); const fs = require('fs'); require('dotenv').config(); const { userResetMessages } = require('./assets/messages.js'); const client = new Client({ intents: [GatewayIntentBits.Guilds] }); // Load or initialize the user privacy settings const userPrivacyFilePath = './userPrivacySettings.json'; let userPrivacySettings = {}; if (fs.existsSync(userPrivacyFilePath)) { userPrivacySettings = JSON.parse(fs.readFileSync(userPrivacyFilePath)); } // Save the user privacy settings function saveUserPrivacySettings() { fs.writeFileSync(userPrivacyFilePath, JSON.stringify(userPrivacySettings, null, 2)); } // Define the commands const commands = [ new SlashCommandBuilder().setName('reset').setDescription('Reset the conversation'), new SlashCommandBuilder().setName('restartcore').setDescription('Restart the core service'), new SlashCommandBuilder().setName('chat').setDescription('Send a chat message') .addStringOption(option => option.setName('message') .setDescription('Message to send') .setRequired(true)), new SlashCommandBuilder().setName('privacy').setDescription('Toggle between ephemeral and standard responses') ].map(command => { const commandJSON = command.toJSON(); const extras = { "integration_types": [0, 1], // 0 for guild, 1 for user "contexts": [0, 1, 2] // 0 for guild, 1 for app DMs, 2 for GDMs and other DMs }; Object.keys(extras).forEach(key => commandJSON[key] = extras[key]); return commandJSON; }); // Register commands with Discord const rest = new REST({ version: '10' }).setToken(process.env.THE_TOKEN_2); client.once('ready', async () => { try { console.log(`Logged in as ${client.user.tag}!`); await rest.put(Routes.applicationCommands(process.env.DISCORD_CLIENT_ID), { body: commands }); console.log('Successfully registered application commands with extras.'); } catch (error) { console.error('Error registering commands: ', error); } }); client.on('interactionCreate', async interaction => { if (!interaction.isCommand()) return; const { commandName, options } = interaction; if (commandName === 'reset') { return await resetConversation(interaction); } else if (commandName === 'restartcore') { await restartCore(interaction); } else if (commandName === 'chat') { const content = options.getString('message'); await handleUserMessage(interaction, content); } else if (commandName === 'privacy') { await togglePrivacy(interaction); } }); // Toggle privacy for the user async function togglePrivacy(interaction) { const userId = interaction.user.id; const currentSetting = userPrivacySettings[userId] || false; userPrivacySettings[userId] = !currentSetting; // Toggle the setting saveUserPrivacySettings(); const message = userPrivacySettings[userId] ? 'Your responses are now set to ephemeral (visible only to you).' : 'Your responses are now standard (visible to everyone).'; await interaction.reply({ content: message, ephemeral: true }); } // Check if the user's responses should be ephemeral function isEphemeral(userId) { return userPrivacySettings[userId] || false; // Default to false (standard response) if not set } async function handleUserMessage(interaction, content) { const encodedMessage = he.encode(content); // Start typing indicator await interaction.deferReply({ ephemeral: isEphemeral(interaction.user.id) }); try { const response = await axios.post(`http://${process.env.ROOT_IP}:${process.env.ROOT_PORT}/api/v1/chat`, { message: encodedMessage, max_tokens: Number(process.env.MAX_TOKENS), repeat_penalty: Number(process.env.REPEAT_PENALTY) }, { headers: { 'Content-Type': 'application/json', 'x-forwarded-for-id': interaction.user.id, 'x-forwarded-for-name': interaction.user.username } }); const data = response.data; await sendLongMessage(interaction, data.content); } catch (error) { if (error.response && error.response.status === 429) { try { await interaction.editReply({ content: 'I am currently busy. Please try again later.', ephemeral: isEphemeral(interaction.user.id) }); } catch (dmError) { console.error('Failed to send DM:', dmError); interaction.editReply({ content: 'I am currently busy. Please try again later.', ephemeral: isEphemeral(interaction.user.id) }); } } else { interaction.editReply({ content: 'Error: ' + error.message, ephemeral: isEphemeral(interaction.user.id) }); } } } async function resetConversation(interaction) { try { const response = await axios.post(`${process.env.API_PATH}/reset-conversation`, {}, { headers: { 'Content-Type': 'application/json', 'x-forwarded-for-id': interaction.user.id, 'x-forwarded-for-name': interaction.user.username } }); console.log(response.status); interaction.reply({ content: 'Conversation reset successfully.', ephemeral: isEphemeral(interaction.user.id) }); } catch (error) { console.log(error); interaction.reply({ content: 'Failed to reset the conversation.', ephemeral: isEphemeral(interaction.user.id) }); } } async function restartCore(interaction) { try { await axios.post(`${process.env.API_PATH}/restart-core`); interaction.reply({ content: 'Core service restarted successfully.', ephemeral: isEphemeral(interaction.user.id) }); } catch (error) { console.log(error); interaction.reply({ content: 'Failed to restart the core.', ephemeral: isEphemeral(interaction.user.id) }); } } async function sendLongMessage(interaction, responseText) { const limit = 8096; if (responseText.length > limit) { const lines = responseText.split('\n'); const chunks = []; let currentChunk = ''; for (const line of lines) { if (currentChunk.length + line.length > limit) { chunks.push(currentChunk); currentChunk = ''; } currentChunk += line + '\n'; } if (currentChunk.trim() !== '') { chunks.push(currentChunk.trim()); } if (chunks.length >= 80) return await interaction.reply({ content: "Response chunks too large. Try again", ephemeral: isEphemeral(interaction.user.id) }); for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; const embed = new EmbedBuilder() .setDescription(chunk) .setColor("#3498DB") .setTimestamp(); setTimeout(() => { interaction.followUp({ embeds: [embed], ephemeral: isEphemeral(interaction.user.id) }); }, i * (process.env.OVERFLOW_DELAY || 3) * 1000); } } else { const embed = new EmbedBuilder() .setDescription(responseText) .setColor("#3498DB") .setTimestamp(); interaction.editReply({ embeds: [embed], ephemeral: isEphemeral(interaction.user.id) }); } } // Log in the bot client.login(process.env.THE_TOKEN_2);