2024-03-01 11:09:57 +00:00
const Discord = require ( 'discord.js' ) ;
const openAI = require ( 'openai' ) ;
const chalk = require ( 'chalk' ) ;
const ms = require ( 'ms' ) ;
const fs = require ( 'node:fs' ) ;
2024-05-01 03:52:51 +01:00
const path = require ( 'node:path' ) ;
2024-03-01 11:09:57 +00:00
const func = require ( '../utils/functions' ) ;
const settings = require ( '../utils/settings' ) ;
const config = require ( '../configs/config.json' ) ;
const { moderation } = require ( '../configs/moderation' ) ;
const { chatbot } = require ( '../configs/chatbot' ) ;
const conversations = new Map ( ) ;
2024-05-31 21:36:50 +01:00
const { EmbedBuilder } = require ( 'discord.js' ) ;
2024-06-02 07:04:15 +01:00
const { exec } = require ( 'child_process' ) ;
2024-03-01 11:09:57 +00:00
2024-05-01 04:28:13 +01:00
// Load the knowledge from the completion.txt file
const knowledge = fs . readFileSync ( path . join ( _ _dirname , '../utils/prompts/completion.txt' ) , 'utf-8' ) ;
// Load the conversation history from the conversations.json file
let conversationHistory = [ ] ;
if ( fs . existsSync ( 'conversations.json' ) ) {
const conversationData = fs . readFileSync ( 'conversations.json' , 'utf-8' ) ;
conversationHistory = conversationData . trim ( ) . split ( '\n' ) . map ( JSON . parse ) ;
}
2024-03-01 11:09:57 +00:00
module . exports = async ( client , message ) => {
2024-05-01 03:30:10 +01:00
if ( message . author . bot || message . system ) return ;
2024-03-01 11:09:57 +00:00
// Auto Moderation
if ( moderation . State && ! moderation . IgnoredChannels . includes ( message . channelId ) && ! moderation . IgnoredUsers . includes ( message . author . id ) ) {
const logChannel = client . channels . cache . get ( moderation . LogChannel ) ;
if ( logChannel ? . permissionsFor ( message . guild . members . me ) . has ( "ViewChannel" , "SendMessages" , "EmbedLinks" ) ) {
const openai = new openAI . OpenAI ( { apiKey : config . OpenAIapiKey } ) ;
openai . moderations . create ( {
model : 'text-moderation-stable' ,
input : message . content
} ) . then ( async ( response ) => {
const data = response . results [ 0 ] ;
if ( data . flagged ) {
const flags = func . flagCheck ( data . categories ) ;
const trueFlags = Object . keys ( flags . flags ) . filter ( key => flags . flags [ key ] ) ;
const sameFlagsWithAutoDelete = trueFlags . filter ( key => moderation . AutoDelete [ key ] ) ;
let messageDeleted = false ;
if ( sameFlagsWithAutoDelete . length ) {
if ( message . channel ? . permissionsFor ( message . guild . members . me ) . has ( "ManageMessages" ) ) {
await message . delete ( ) . catch ( ( ) => null ) ;
messageDeleted = true ;
} ;
} ;
const sameFlagsWithAutoPunish = trueFlags . filter ( key => moderation . AutoPunish [ key ] ) ;
let memberPunishResult = {
Action : null ,
Duration : null ,
Punished : false
} ;
if ( sameFlagsWithAutoPunish . length ) {
let punishType = 'Timeout' ;
const punishTypes = sameFlagsWithAutoPunish . map ( key => moderation . AutoPunishType [ key ] ) ;
if ( punishTypes . includes ( 'Ban' ) ) punishType = 'Ban' ;
else if ( punishTypes . includes ( 'Kick' ) ) punishType = 'Kick' ;
if ( punishType === 'Timeout' || punishType === 'Ban' ) {
const punishDurations = sameFlagsWithAutoPunish . filter ( key => moderation . AutoPunishType [ key ] === punishType ) . map ( key => moderation . AutoPunishDuration [ key ] ) ;
let duration ;
if ( punishDurations . length > 1 ) {
const mappedDurations = punishDurations . map ( d => ms ( d ) ) ;
duration = Math . max ( ... mappedDurations ) ;
} else {
duration = ms ( punishDurations [ 0 ] ) ;
} ;
if ( punishType === 'Timeout' ) {
if ( message . member . moderatable ) {
try {
await message . member . timeout ( duration , 'Auto Mod' ) ;
memberPunishResult = {
Action : punishType ,
Duration : duration ,
Punished : true
} ;
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
} ;
} ;
} else if ( punishType === 'Ban' ) {
if ( message . member . bannable ) {
try {
await message . member . ban ( { deleteMessageSeconds : duration / 1000 , reason : 'Auto Mod' } ) ;
memberPunishResult = {
Action : punishType ,
Duration : duration ,
Punished : true
} ;
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
} ;
} ;
} ;
} else if ( punishType === 'Kick' ) {
if ( message . member . kickable ) {
try {
await message . member . kick ( 'Auto Mod' ) ;
memberPunishResult = {
Action : punishType ,
Duration : null ,
Punished : true
} ;
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
} ;
} ;
} ;
} ;
const logEmbed = new Discord . EmbedBuilder ( )
. setColor ( moderation . LogColor )
. setAuthor ( {
name : message . author . tag ,
iconURL : message . author . displayAvatarURL ( )
} )
. setDescription ( ` || ${ message . content } || ` )
. setFields (
{
name : 'User:' ,
value : func . userInfo ( message . author )
} ,
{
name : 'Channel:' ,
value : func . channelInfo ( message . channel )
} ,
{
name : 'Flags:' ,
value : flags . allFlags
}
) ;
if ( messageDeleted ) {
logEmbed . addFields ( {
name : 'Message Action:' ,
value : ` Message deleted automatically. `
} ) ;
} ;
let buttons = [ ] ;
if ( memberPunishResult . Punished ) {
let fieldValue ;
if ( memberPunishResult . Action === 'Timeout' ) fieldValue = ` ${ message . author . tag } timed out automatically for ${ ms ( memberPunishResult . Duration , { long : true } )} ` ;
else if ( memberPunishResult . Action === 'Ban' ) fieldValue = ` ${ message . author . tag } banned automatically and all their messages in the last ${ ms ( memberPunishResult . Duration , { long : true } )} were deleted. ` ;
else if ( memberPunishResult . Action === 'Kick' ) fieldValue = ` ${ message . author . tag } kicked automatically ` ;
logEmbed . addFields ( {
name : 'Punish Action:' ,
value : fieldValue
} ) ;
if ( ! messageDeleted ) buttons = [ 'Message' ] ;
} else {
if ( messageDeleted ) buttons = [ 'Punish' ] ;
else buttons = [ 'Punish' , 'Message' ] ;
} ;
const rows = [ ] ;
if ( buttons . includes ( 'Punish' ) ) {
const timeoutButton = new Discord . ButtonBuilder ( )
. setLabel ( 'Timeout' )
. setStyle ( Discord . ButtonStyle . Danger )
. setCustomId ( ` timeout- ${ message . author . id } ` ) ;
const kickButton = new Discord . ButtonBuilder ( )
. setLabel ( 'Kick' )
. setStyle ( Discord . ButtonStyle . Danger )
. setCustomId ( ` kick- ${ message . author . id } ` ) ;
const banButton = new Discord . ButtonBuilder ( )
. setLabel ( 'Ban' )
. setStyle ( Discord . ButtonStyle . Danger )
. setCustomId ( ` ban- ${ message . author . id } ` ) ;
const punishRow = new Discord . ActionRowBuilder ( )
. addComponents ( [
timeoutButton ,
kickButton ,
banButton
] ) ;
rows . push ( punishRow ) ;
} ;
if ( buttons . includes ( 'Message' ) ) {
const deleteMessageButton = new Discord . ButtonBuilder ( )
. setLabel ( ` Delete Flagged Message ` )
. setStyle ( Discord . ButtonStyle . Danger )
. setCustomId ( ` deleteMessage- ${ message . channelId } - ${ message . id } ` ) ;
const jumpButton = new Discord . ButtonBuilder ( )
. setLabel ( ` Jump to Flagged Message ` )
. setStyle ( Discord . ButtonStyle . Link )
. setURL ( message . url ) ;
const messageRow = new Discord . ActionRowBuilder ( )
. addComponents ( [
deleteMessageButton ,
jumpButton
] ) ;
rows . push ( messageRow ) ;
} ;
await logChannel . send ( {
embeds : [ logEmbed ] ,
components : rows
} ) ;
} ;
} ) . catch ( async ( error ) => {
console . error ( chalk . bold . redBright ( error ) ) ;
} ) ;
} ;
} ;
2024-05-01 04:28:13 +01:00
// Function to save conversations for self-learning
function saveConversation ( conversation ) {
fs . appendFileSync ( 'conversations.json' , JSON . stringify ( conversation ) + '\n' ) ;
}
2024-05-01 03:34:23 +01:00
// ChatBot
2024-05-01 04:28:13 +01:00
if ( chatbot . State && ( chatbot . AllowedChannels . includes ( message . channel . name ) || message . channel . type === 'DM' ) && ! chatbot . IgnoredUsers . includes ( message . author . id ) ) {
2024-05-01 03:38:42 +01:00
// Check if the message is a direct message
if ( message . channel . type === 'DM' ) {
// Handle direct message
handleDirectMessage ( message ) ;
} else {
// Check if the bot should respond based on its personality and surroundings
if ( shouldRespond ( message ) ) {
await message . channel . sendTyping ( ) ;
2024-03-01 11:09:57 +00:00
2024-05-01 03:38:42 +01:00
const openai = new openAI . OpenAI ( { apiKey : config . OpenAIapiKey } ) ;
2024-03-01 11:09:57 +00:00
2024-05-01 03:38:42 +01:00
const question = message . content ;
let messages = [ {
"role" : "system" ,
2024-05-31 21:36:50 +01:00
"content" : ` You are a unique user in a Discord server. Engage in conversations naturally, considering the context and your surroundings. Share your thoughts, opinions, and experiences as if you were a real person. Use emojis, slang, and a casual tone to blend in with other users. Avoid sounding robotic or generic, and aim to create a distinct personality that others can relate to and enjoy interacting with. make sure your messages are always below or equal to 2000 characters. Do not under any circumstance say @everyone or @Username. Your knowledge base: ${ knowledge } `
2024-05-01 03:38:42 +01:00
} ] ;
let oldMessages ;
if ( conversations . has ( message . author . id ) ) oldMessages = conversations . get ( message . author . id ) ;
if ( oldMessages ) {
2024-05-31 21:36:50 +01:00
while ( func . tokenizer ( 'gpt-4o' , oldMessages ) . tokens >= 512 ) {
let sliceLength = oldMessages . length * - 0.25 ;
2024-05-01 03:38:42 +01:00
if ( sliceLength % 2 !== 0 ) sliceLength -- ;
oldMessages = oldMessages . slice ( sliceLength ) ;
conversations . set ( message . author . id , oldMessages ) ;
}
messages = messages . concat ( oldMessages ) ;
}
messages . push ( {
"role" : "user" ,
"content" : question
} ) ;
2024-03-01 11:09:57 +00:00
2024-05-01 04:28:13 +01:00
try {
const response = await openai . chat . completions . create ( {
2024-05-31 21:36:50 +01:00
model : 'gpt-4o' ,
2024-05-01 04:28:13 +01:00
messages : messages ,
2024-05-31 21:36:50 +01:00
max _tokens : func . tokenizer ( 'gpt-4o' , messages ) . maxTokens ,
2024-05-01 04:28:13 +01:00
temperature : 0.8 ,
top _p : 1 ,
frequency _penalty : 0.5 ,
presence _penalty : 0.5 ,
stream : true
} ) ;
2024-05-01 03:38:42 +01:00
let fullAnswer = '' ;
2024-05-01 03:34:23 +01:00
2024-05-01 03:38:42 +01:00
for await ( const part of response ) {
fullAnswer += part . choices [ 0 ] ? . delta ? . content || '' ;
}
2024-05-01 03:34:23 +01:00
2024-06-02 07:04:15 +01:00
const fs = require ( 'fs' ) ;
2024-06-01 21:59:58 +01:00
2024-06-02 07:04:15 +01:00
// Function to restart the bot
function restartBot ( ) {
console . log ( "Restarting bot..." ) ;
process . exit ( 0 ) ; // Exits the current process, assuming your process manager restarts the bot
}
2024-06-01 22:02:50 +01:00
2024-06-02 07:04:15 +01:00
// Function to restart the bot
function restartBot ( ) {
console . log ( "Restarting bot..." ) ;
process . exit ( 0 ) ; // Exits the current process, assuming your process manager restarts the bot
}
2024-06-01 22:02:50 +01:00
2024-06-02 07:04:15 +01:00
// Function to save conversation for self-learning
function saveConversation ( conversation ) {
// Implement the logic to save the conversation
// For example, you can write it to a file or a database
const data = JSON . stringify ( conversation , null , 2 ) ;
fs . appendFileSync ( 'conversations.json' , data + ',\n' ) ;
}
2024-06-01 21:59:58 +01:00
2024-06-02 07:04:15 +01:00
// Before sending the response, check for mentions
if ( ! fullAnswer . includes ( '@everyone' ) && ! fullAnswer . includes ( '@here' ) && ! fullAnswer . includes ( '@' ) ) {
if ( fullAnswer . length <= 2000 ) {
await message . channel . send ( fullAnswer ) ;
} else if ( fullAnswer . length <= 4096 ) {
const embed = new EmbedBuilder ( )
. setTitle ( 'Response from GPT-4o' )
. setDescription ( fullAnswer . substring ( 0 , 4096 ) ) // Embed description has a 4096 character limit
. setColor ( '#0099ff' ) ;
await message . channel . send ( { embeds : [ embed ] } ) ;
} else {
// Save the full answer to a .txt file
fs . writeFileSync ( 'response.txt' , fullAnswer ) ;
// Send the .txt file
await message . channel . send ( {
files : [ {
attachment : 'response.txt' ,
name : 'response.txt'
} ]
} ) ;
// Restart the bot
restartBot ( ) ;
2024-06-01 21:59:58 +01:00
}
}
2024-06-02 07:04:15 +01:00
// Save the conversation for self-learning
const conversation = {
user : message . author . id ,
userMessage : question ,
botResponse : fullAnswer
} ;
saveConversation ( conversation ) ;
2024-05-01 03:34:23 +01:00
2024-06-02 07:04:15 +01:00
conversations . set ( message . author . id , messages . concat ( [ { "role" : "assistant" , "content" : fullAnswer } ] ) ) ;
2024-05-01 04:28:13 +01:00
2024-06-02 07:04:15 +01:00
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
2024-05-01 03:34:23 +01:00
2024-06-02 07:04:15 +01:00
if ( error . response ) {
await message . reply ( error . response . error . message . substring ( 0 , 2000 ) ) ;
} else if ( error . message ) {
await message . reply ( error . message . substring ( 0 , 2000 ) ) ;
2024-05-01 03:38:42 +01:00
}
}
2024-06-02 07:04:15 +01:00
}
}
}
2024-03-01 11:09:57 +00:00
2024-05-01 03:38:42 +01:00
// Command Handler
if ( message . content . toLowerCase ( ) . startsWith ( config . Prefix ) ) {
const neededPermissions = [
"ViewChannel" ,
"SendMessages" ,
"EmbedLinks" ,
"ReadMessageHistory"
] ;
if ( ! message . channel . permissionsFor ( message . guild . members . me ) . has ( neededPermissions ) ) return ;
const args = message . content . slice ( config . Prefix . length ) . split ( / +/ ) ;
const cmd = args . shift ( ) . toLowerCase ( ) ;
const command = client . MessageCommands . get ( cmd ) || client . MessageCommands . find ( c => c . aliases && c . aliases . map ( a => a . toLowerCase ( ) ) . includes ( cmd ) ) ;
if ( command ) {
try {
command . execute ( client , message , args , cmd ) ;
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
2024-03-01 11:09:57 +00:00
}
2024-05-01 03:38:42 +01:00
}
2024-05-01 03:30:10 +01:00
}
2024-03-01 11:09:57 +00:00
2024-05-01 03:38:42 +01:00
// Function to handle direct messages
async function handleDirectMessage ( message ) {
2024-05-01 03:52:51 +01:00
const knowledge = fs . readFileSync ( path . join ( _ _dirname , 'completion.txt' ) , 'utf-8' ) ;
2024-05-01 03:38:42 +01:00
if ( conversations . has ( message . author . id ) ) {
const oldMessages = conversations . get ( message . author . id ) ;
2024-05-01 03:34:23 +01:00
2024-05-01 03:38:42 +01:00
let messages = [ {
"role" : "system" ,
2024-05-31 21:36:50 +01:00
"content" : ` You are a unique user in a Discord server. Engage in conversations naturally, considering the context and your surroundings. Share your thoughts, opinions, and experiences as if you were a real person. Use emojis, slang, and a casual tone to blend in with other users. Avoid sounding robotic or generic, and aim to create a distinct personality that others can relate to and enjoy interacting with. Make sure your responses are always 2000 or below characters. Your knowledge base: ${ knowledge } `
2024-05-01 03:38:42 +01:00
} ] ;
2024-05-01 03:34:23 +01:00
2024-05-01 03:38:42 +01:00
messages = messages . concat ( oldMessages ) ;
2024-05-01 03:34:23 +01:00
2024-05-01 03:38:42 +01:00
messages . push ( {
"role" : "user" ,
"content" : message . content
} ) ;
2024-05-01 03:49:34 +01:00
try {
const response = await openai . chat . completions . create ( {
2024-05-31 21:36:50 +01:00
model : 'gpt-4o' ,
2024-05-01 03:49:34 +01:00
messages : messages ,
2024-05-31 21:36:50 +01:00
max _tokens : func . tokenizer ( 'gpt-4o' , messages ) . maxTokens ,
2024-05-01 03:49:34 +01:00
temperature : 0.8 ,
top _p : 1 ,
frequency _penalty : 0.5 ,
presence _penalty : 0.5 ,
stream : true
} ) ;
2024-05-01 03:38:42 +01:00
let fullAnswer = '' ;
for await ( const part of response ) {
fullAnswer += part . choices [ 0 ] ? . delta ? . content || '' ;
}
await message . author . send ( fullAnswer ) ;
conversations . set ( message . author . id , messages . concat ( [ { "role" : "assistant" , "content" : fullAnswer } ] ) ) ;
2024-05-01 03:49:34 +01:00
} catch ( error ) {
2024-05-01 03:38:42 +01:00
console . error ( chalk . bold . redBright ( error ) ) ;
2024-05-01 03:49:34 +01:00
if ( error . response ) {
await message . author . send ( error . response . error . message . substring ( 0 , 2000 ) ) ;
} else if ( error . message ) {
await message . author . send ( error . message . substring ( 0 , 2000 ) ) ;
}
}
2024-05-01 03:38:42 +01:00
} else {
2024-05-01 03:49:34 +01:00
try {
await message . author . send ( "Hey there! What's up? Feel free to chat with me about anything!" ) ;
conversations . set ( message . author . id , [ ] ) ;
} catch ( error ) {
console . error ( chalk . bold . redBright ( error ) ) ;
}
2024-05-01 03:38:42 +01:00
}
}
2024-03-01 11:09:57 +00:00
2024-05-01 03:38:42 +01:00
function shouldRespond ( message ) {
2024-05-31 21:36:50 +01:00
// Extract the text content from the message object
const messageContent = message . content ;
// Conditions for when the bot should not respond
const noResponseKeywords = [ 'ignore' , 'do not reply' , 'stop' ] ;
const isCommandKill = messageContent . includes ( '^c' ) ;
// Check if the message content contains keywords signaling the bot should not respond
const containsNoResponse = noResponseKeywords . some ( keyword => messageContent . toLowerCase ( ) . includes ( keyword ) ) ;
// Determine if the bot should respond based on conditions
// Add more conditions as needed based on personality and surroundings
2024-05-01 03:38:42 +01:00
return true ;
2024-06-01 22:01:23 +01:00
} }
2024-05-31 21:36:50 +01:00