const Discord = require('discord.js'); const fetch = require('node-fetch'); const emptyResponses = require('./assets/emptyMessages.js'); const { resetResponses, userResetMessages } = require('./assets/resetMessages.js'); const { errorMessages, busyResponses } = require('./assets/errorMessages.js'); require('dotenv').config() const { Client, GatewayIntentBits, ActivityType, Partials } = require('discord.js'); const client = new Client({ intents: [ GatewayIntentBits.DirectMessages, GatewayIntentBits.Guilds, GatewayIntentBits.GuildBans, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, ], partials: [Partials.Channel], }); // Grab ChannelIDs from the .env file const channelIDs = process.env.CHANNEL_IDS.split(','); const conversations = new Map(); function setBusy(userId, isBusy) { if (conversations.has(userId)) { conversations.get(userId).busy = isBusy; } else { conversations.set(userId, { busy: isBusy }); } } function isAnyConversationBusy() { for (const conversation of conversations.values()) { if (conversation.busy) { setPresenceBusy() return true; } } return false; } function setPresenceBusy() { client.user.setPresence({ activities: [{ name: `Processing a Request`, type: ActivityType.Playing }], status: 'dnd', }); } function setPresenceOnline() { client.user.setPresence({ activities: [{ name: `Ready for Request`, type: ActivityType.Playing }], status: 'online', }); } client.once('ready', () => { console.log('Bot is ready.'); setPresenceOnline() }); client.on('messageCreate', async (message) => { async function sendRand(array) { const arrayChoice = array[Math.floor(Math.random() * array.length)]; await message.channel.send(arrayChoice); // give a notification of reset using a human like response. } async function sendRandDM(array) { const arrayChoice = array[Math.floor(Math.random() * array.length)]; await message.author.send(arrayChoice); // give a notification of reset using a human like response. } // Only respond in the specified channels if (!channelIDs.includes(message.channel.id)) { return; } if (message.author.bot) return; // Ignore messages from bots // Check if any conversation is busy if (isAnyConversationBusy()) { // Update bot presence to "Busy" setPresenceBusy() message.delete(); sendRandDM(busyResponses); return; } const userID = message.author.id; let conversation = conversations.get(userID) || { messages: [], busy: false }; if (conversation.messages.length === 0) { conversation.messages.push({ role: 'user', content: `You are rAi, the most helpful writing AI, you code, write and provide information without any mistakes.` }); conversation.messages.push({ role: 'user', content: `My name is ${message.author.username}. \nIf you address me, tag me using @${message.author.username}` }); conversation.messages.push({ role: 'assistant', content: `Hello, ${message.author.username}, I am here to answer any question you have, how may I help you?` }); } if (message.content === '!reset' || message.content === '!r') { conversations.delete(userID); // Delete user's conversation map if they request reset sendRand(userResetMessages) return; } // Append user message to conversation history conversation.messages.push({ role: 'user', content: message.cleanContent }); try { setPresenceBusy() setBusy(message.author.id, true); const response = await generateResponse(conversation); // Append bot message to conversation history conversation.messages.push({ role: 'assistant', content: response }); if (response && response.trim()) { // Send response to user if it's not empty await message.channel.send(response); setPresenceOnline() setBusy(message.author.id, false); } else { // Handle empty response here sendRand(emptyResponses) conversations.delete(userID); // Delete user's conversation map if they request reset sendRand(resetResponses) setPresenceOnline() conversation.busy = false; } conversations.set(userID, conversation); // Update user's conversation map in memory } catch (err) { console.error(err); sendRand(errorMessages) } finally { setPresenceOnline() setBusy(message.author.id, false); } }); async function generateResponse(conversation) { const controller = new AbortController(); const timeout = setTimeout(() => { controller.abort(); }, 900000); const messagesCopy = [...conversation.messages]; // create a copy of the messages array console.log(conversation) try { const response = await fetch(`http://${process.env.ROOT_IP}:${process.env.ROOT_PORT}/v1/chat/completions`, { method: 'POST', headers: { 'accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: messagesCopy // use the copy of the messages array }), signal: controller.signal }); const responseData = await response.json(); console.log(JSON.stringify(responseData)) const choice = responseData.choices[0]; // Remove "user None:" and any text after it from the response const responseText = choice.message.content.trim(); const startIndex = responseText.indexOf('user None:'); const sanitizedResponse = startIndex === -1 ? responseText : responseText.substring(0, startIndex); return sanitizedResponse; } catch (err) { throw err; } finally { clearTimeout(timeout); } } client.login(process.env.THE_TOKEN); // Replace with your bot token