Pseudo-Natural Language Processing

Pseudo, cuz this isn't actually natural language processing. This method make use of .includes and .match to determine the command as well as the argument. So instead of the traditional prefix + command + args, we can allow users to say whatever they want, as long as they include the command (or its aliases) and the args if needed in the content. For example, instead of using $search discord.js you can do hey bot, can you search "discord.js" for me? I don't even know what that is, thanks! and the bot will do the search and return the result for you.

Pro:

  • Interesting concept
  • Fun to make and use bot
  • Give the bot more personality which might give the bot more popularity boost

Con:

  • Complicated
  • Commands might conflict with each other

Basic Concept

The concept of this is simple, by using either includes or match to see if the content has the command or not, if it does then execute the command. For example, we'll go back to the basic ping feature:

// msg.content = "hey bot, can you do a ping test?"

// the prefix is "hey bot, "
// the prefix should be checked before this code

if (msg.content.includes("ping")) {
    msg.channel.sendMessage("PONG!");
}

// Alternatively

if (msg.content.match(/\bping\b/gi)) {
    msg.channel.sendMessage("PONG!");
}

Using match, imo, is better than includes. Putting performance aside, match allows you to search for the whole word, so only "ping" with match, and things like pinguin will not trigger the command.

For arguments, there are several ways to separate the arguments away from the content. In the example I will demonstrate two ways that I'm using:

// In line and short arguments, wrapped in quotation marks
args = msg.content.split('"');
if (args.length > 1) args = args[1];
else args = false;

// Argument in a new line, for those that are long, like eval commands
args = msg.content.split('\n');
if (args.length > 1) args = args.slice(1).join('\n');
else args = false;

This doesn't mean these are the only two ways of getting the arguments. There are as many ways as you can think of, but I'll leave that to you to think and implement the way that is most suitable for you.

Using this method isn't exactly the best option, Due to allowing natural language, there are times when people issuing a command in which it has another command. For example: hey bot, can you search "discord.js" for me? I don't have much time left. This command's main intention is to make the bot to search on google for discord.js. However in your file there's another command called time which will tell you the local time. In this case and if you're using the basic if - else, then whatever that is checked first will be executed. Making sure that this is not happening is probably one of the biggest headache of this method, as well as coding a natural language processing in general.

Command Objects?

Of course using basic if - else is un-professional and our next step should always be upgrading to the better command handling: the command object.

The command file is the same as the command object tutorial. However how to load the commands as well as how to check check which command should be executed should have a little bit of adjustments.

let commandsList = fs.readdirSync('./commands/'); // return an array of all the files and folders inside the commands folder
Client.commands = {}; // initiate value for the command list of client
Client.commandRegex = []; // innitiate value for the command Regex, which started out as an array first
for (i = 0; i < commandsList.length; i++) {
    let item = commandsList[i];
    if (item.match(/\.js$/)) { // only take js files
        delete require.cache[require.resolve(`./commands/${item}.js`)]; // delete the cache of the require, useful in case you wanna reload the command again
        Client.commands[item.slice(0, -3)] = require(`./commands/${item}.js`); // and put the require inside the client.commands object
        Client.commandRegex.push(`\b${item.slice(0, -3)}\b`);
    }
}
Client.commandRegex = new RegExp(Client.commandRegex.join('|'));

Client.bot.on('message', (msg) => {
    // Skipping the whole bot check and selfbot check cuz you should know how to do it right now
    if (msg.content.startsWith(Client.config.prefix)) {
        content = msg.content.slice(Client.config.prefix.length);
        content = content.split('"');

        // Removing the args from the content to avoid conflicting commands with the args
        if (content.length > 1) args = content.splice(1, 1);
        else args = false;
        content = content.join('"');

        if (command = content.match(Client.commandRegex)) {
            Client.commands[command[0]].func(Client, msg, args);
        }
    }
});

Of course this won't solve the conflicting command problem. But different from if - else block, this would make whatever the command that is said first will be executed.

So there we have it, a basic tutorial of how to make a pseudo-natural language processing. You can expand this by storing the commands and build yourself a self-learning AI mechanism or naming your bot Skynet or something. There are so many ways we can improve this method, but I'll leave it up to you to work it out. Please do not destroy the world though, if you really want to, please leave internet and electricity alone, I'll need those, thanks!

results matching ""

    No results matching ""