AI Chatbot

Make A Simple AI Chatbot

by rumixist

Author Avatar

AI CHATBOT

We will make a simple AI chatbot in this tuturial. We will use module scripts, functions, tables, variables, if statements and some maths.

#####Tutorial Level: Intermediate


Chapters


##What will you learn?

In this tutorial we will use module scripts, functions, tables, variables and mathematics. I won't teach how to use these but. I will try to explain what I did. I will try my best to teach you how can we make an AI chatbot with these.

I recommened learn 'module scripts', 'tables', 'functions', 'variables' and 'if statements' before this tutorial. Also you can reinforce what did you learn about these topics in this tutorial.

Also we will use mathematics to calculate similarity between two strings.


CHAPTER 1 - Creating the module scripts

We will use module scripts for checking the input and creating outputs for each input category.

What did I mean by 'each input category'?. We will give a category(or type) for each input in a table for example:

local module = {}

local inputs = {

	    ["greetings"] = {
	        "hello",
	        "hi",
        	"hey"
        }

}

local category = nil

return module 

In this module script we created a table for inputs and a category in table for each inputs. We can add more inputs and categories. Thanks to these categories, we get rid of writing outputs for each input one by one.

The 'category' variable stores our category for inputs. Let's make its value nil.

Now we need a category finder function for find category of the input. But what if we make a typing mistake such as 'helo' instead of 'hello' our AI can't answer this with a only category finder function. So we need a similarity finder function to find most similar word in inputs. Let's make a similarity algorithm to prevent little typing mistakes of inputs. We can create this function in our module script.

We don't need to acces this function from another script so we can make a default function.

function calculateSimilarity(str1, str2)
	local len1 = #str1
	local len2 = #str2

	local matrix = {}
	for i = 0, len1 do
		matrix[i] = {}
		matrix[i][0] = i
	end
	for j = 0, len2 do
		matrix[0][j] = j
	end

	for i = 1, len1 do
		for j = 1, len2 do
			local cost = 0
			if str1:sub(i, i) ~= str2:sub(j, j) then
				cost = 1
			end
			matrix[i][j] = math.min(
				matrix[i - 1][j] + 1,
				matrix[i][j - 1] + 1,
				matrix[i - 1][j - 1] + cost
			)
		end
	end

	local maxLen = math.max(len1, len2)
	return (1 - matrix[len1][len2] / maxLen) * 100
end

This is a similarity calculator function to calculate similarty between our input and inputs in inputs table.

But we have a problem. We don't want most similar word always. For example what if our input is 'ahalskdasydl' we don't want a normal input for this one. So we need to add a minimum similarity condition with if statements. For example if most similar word between our input and the inputs in inputs table is >%65 then we can find a category for this input else we can return nil.

We need ignore spaces, upper letters, punctuation such as *'*ABC,?+/ :;'**. Let's create a table for make this topic more understanable:

Input | Convert


'Hello.' -> 'hello' 'What time is it?' -> 'whattimeisit' 'AI ChatBot.' -> 'aichatbot'

We can use string.gsub() for this and get the lower of all characters in the string with string.lower(). There is a example code for this.

Also we should create a function that we can acces from other scripts to get category so we should create our function as module.DecideCategory().

function module.DecideCategory(input)
	local inputToCheck = string.lower(string.gsub(input, "[%p%s]", ""))
end

Now let's complete the function to get category of inputs.

function module.DecideCategory(message)
	local inputToCheck = string.lower(string.gsub(input, "[%p%s]", ""))
	local bestMatchPercentage = 0
	local bestMatchType = "nil"

	for k, v in pairs(asks) do
		for i, ask in ipairs(v) do
			local similarity = calculateSimilarity(inputToCheck, string.lower(ask))
			if similarity == 100 then
				return k
			elseif similarity > bestMatchPercentage then
				bestMatchPercentage = similarity
				bestMatchType = k
			end
		end
	end

	if bestMatchPercentage >= 65 then
		return bestMatchType -- Return category if similarity > 65
	else
		return "nil" -- Else return 'nil'
	end
end

Let's view our full first module script

local module = {}

local inputs = {

        ["greetings"] = {
            "hello",
            "hi",
            "hey"
        }

}

local category = nil

function calculateSimilarity(str1, str2)
    local len1 = #str1
    local len2 = #str2

    local matrix = {}
    for i = 0, len1 do
        matrix[i] = {}
        matrix[i][0] = i
    end
    for j = 0, len2 do
        matrix[0][j] = j
    end

    for i = 1, len1 do
        for j = 1, len2 do
            local cost = 0
            if str1:sub(i, i) ~= str2:sub(j, j) then
                cost = 1
            end
            matrix[i][j] = math.min(
                matrix[i - 1][j] + 1,
                matrix[i][j - 1] + 1,
                matrix[i - 1][j - 1] + cost
            )
        end
    end

    local maxLen = math.max(len1, len2)
    return (1 - matrix[len1][len2] / maxLen) * 100
end

function module.DecideCategory(message)
    local inputToCheck = string.lower(string.gsub(input, "[%p%s]", ""))
    local bestMatchPercentage = 0
    local bestMatchType = "nil"

    for k, v in pairs(asks) do
        for i, ask in ipairs(v) do
            local similarity = calculateSimilarity(inputToCheck, string.lower(ask))
            if similarity == 100 then
                return k
            elseif similarity > bestMatchPercentage then
                bestMatchPercentage = similarity
                bestMatchType = k
            end
        end
    end

    if bestMatchPercentage >= 65 then
        return bestMatchType -- Return category if similarity > 65
    else
        return "nil" -- Else return 'nil'
    end
end

return module 

I will renme our first module script to 'AI_Ask'. You can rename it what do you want.

Now we need to create a table of outputs. We can use another module script for more readable code. Let's create another module script to add outputs table.

Firstly, we don't need a output finder in our second module script. We can find outputs in scripts that we will create in future. So let's create table in our module script. This is similar to our first table but we will create this in our module table.

This is an example code:

module = {
	["greetings"] = {
		"Hello! How can I assist you today?",
		"Hi! How can I assist you today?",
		"Hi! How can I help you?",
		"Hello! How can I help you?",
		"Hello! How can I help you today?",
		"Hello, how can I help you today?",
		"Hello, how can I assist you?",
		"Hello, how can I help you?"	
		
	},			
}

return module

Our AI will select random output from this table. Make sure create output categories for each input category and make this two category names same.

Our AI_Ask module script can return nil. We make this for similarities that less than %65. So we need to add a nil category. Let's make a basic.

module = {
	["nil"] = {
		"Sorry. I did'nt understand.",
		"Sorry. What do you mean?"		
	},
	["greetings"] = {
		"Hello! How can I assist you today?",
		"Hi! How can I assist you today?",
		"Hi! How can I help you?",
		"Hello! How can I help you?",
		"Hello! How can I help you today?",
		"Hello, how can I help you today?",
		"Hello, how can I assist you?",
		"Hello, how can I help you?"	
		
	},			
}

return module

Now our AI has a table for nil outputs.

This is a basic AI module scripts. You can add more input and outputs. I will rename this module scipt to 'AI_Answer'. I put these module scripts in 'ReplicatedStorage'

Now we need a script that we can send inputs to our AI and get outputs from our AI. This script will be heart of our AI. We will add more things like evaluate math sending audios & images etc.


CHAPTER 2 - The Main Script

Let's create our main script in 'ServerScriptService'. I will rename it to 'AIHandler'.

Firstly, we need declare our module scripts with 'require'. There is example code.

local AI_Ask = require(game.ReplicatedStorage.AI_Ask)
local AI_Answer = require(game.ReplicatedStorage.AI_Answer)

Now we should create an input if you want a AI chatbot with user interface (UI) you can create 'RemoteEvents'. I will create 'RemoteEvents' in 'ReplicatedStorage'. And I renamed it to 'SendMessageEvent'. You can rename it what do you want.

Let's connect our RemoteEvent to a function in our main script. There is an example code.

local AI_Ask = require(game.ReplicatedStorage.AI_Ask)
local AI_Answer = require(game.ReplicatedStorage.AI_Answer)

game.ReplicatedStorage.SendMessageEvent.OnServerEvent:Connect(function(player, message)
	
end

Now we need find category of our input. We can use our function in 'AI_Ask' module script. Then we can get a random answer from 'AI_Answer' module script. And we can print our answer to the output to see our answer.

local AI_Ask = require(game.ReplicatedStorage.AI_Ask)
local AI_Answer = require(game.ReplicatedStorage.AI_Answer)

game.ReplicatedStorage.SendMessageEvent.OnServerEvent:Connect(function(player, message)
    --Find the category of our input
    local category = AI_Ask.DecideCategory(message)

    --Get random from our AI_Answer module according to our category
    local answer = AI_Answer[category][math.random(1, #AI_Answer[category])]

	
--Show the answer in output
	print(anwer)

end

This is very simple AI. You can improve this AI. You can add UI, Images, Audios that AI can send with UI. I will show you how to add a evaluate maths and how to make our AI can send images and audios from roblox library.


CHAPTER 3 - Evaluate Math Expression

We can add a function to calculate Math Expressions easily without input and output categories.

Firstly we need edit our main script. We need add a function that takes the string and returns evaluated answer. But what if our input isn't a math expression? So we need return nil if this function can't calculate our input. And we can check if our answer is nil then we can set our answer with default such as we made our main script.

There is an example code:

local AI_Ask = require(game.ReplicatedStorage.AI_Ask)
local AI_Answer = require(game.ReplicatedStorage.AI_Answer)

function evaluateMathExpression(strToEdit)
	--Our Evaluation code here
end

game.ReplicatedStorage.SendMessageEvent.OnServerEvent:Connect(function(player, message)
    
    --Find the category of our input
    local category = AI_Ask.DecideCategory(message)


    --Set our answer to return of evaluateMathExpression function
    local answer = evaluateMathExpression(message)

    --If our answer is nil (if returned nil from evaluateMathExpression function)
    if not answer then 
        --Set our answer default way
        local answer = AI_Answer[category][math.random(1, #AI_Answer[category])]
    end


    print(anwer)
end

Sorry, I don't know how to make Evaluate Math Expression function you can fill it. I have tried this with a function that written by ChatGPT so it is working but ChatGPT's function can't calculate process piority and brackets. And that function has a lot of bug. But the other things are working so if you have evaluate math expression function you can edit it little bit and put it here.

In this script, we send our message to our math function as parameter. Our math function is empty but you can fill it. If our function can calculate it, it calculates and returns the calue else it returns nil. We can check our answer. Is our answer nil?. If it is nil we can set our answer by default way.


CHAPTER 3 - Images & Audios for UI AI Chatbots

Let's create a input category for our audio request input in AI_Ask module script


local module = {}

local inputs = {

        ["greetings"] = {
            "hello",
            "hi",
            "hey"
        }
        ["imageRequset"] = {
            "sendanimage",
            "iwantimage",
            "pleaseimage"
        }

}

--[[
our other functions here
]]--

return module 

Now let's create our category outputs in our AI_Answer module script

module = {
    ["nil"] = {
        "Sorry. I did'nt understand.",
        "Sorry. What do you mean?"        
    },
    ["greetings"] = {
        "Hello! How can I assist you today?",
        "Hi! How can I assist you today?",
        "Hi! How can I help you?",
        "Hello! How can I help you?",
        "Hello! How can I help you today?",
        "Hello, how can I help you today?",
        "Hello, how can I assist you?",
        "Hello, how can I help you?"    
        
    },        
    ["imageRequest"] = {
        "Sure, there is an image. [#=229313523]",
        "Here is an image for you. [#=229313523]",    
    },        
}

return module

What we did here?

We put a symbol and brackets for image ID. You can change this system what do you want. In our main AIHandler script we will remove this ID from our output. And we will check if there is an image ID like this our script will send an image.

Let's edit the main script.

local AI_Ask = require(game.ReplicatedStorage.AI_Ask)
local AI_Answer = require(game.ReplicatedStorage.AI_Answer)

function evaluateMathExpression(strToEdit)
    --Our Evaluation code here
end

game.ReplicatedStorage.SendMessageEvent.OnServerEvent:Connect(function(player, message)
    local category = AI_Ask.DecideCategory(message)
    local answer = evaluateMathExpression(message)

    if not answer then 
        --Set our answer default way
        local answer = AI_Answer[category][math.random(1, #AI_Answer[category])]
    end

    --Check the output. Is there something like this: [#=] if there is get the ID

	local startIdx, endIdx = string.find(DecidedAnswer, "%[#=(%d+)]")
    if startIdx and endIdx then
 

    	local ID = string.sub(DecidedAnswer, startIdx+3, endIdx-1)
 -- Get the ID
		local audioId = tonumber(ID) --Set The Audio ID

		--Remove ID from output
		answer = string.sub(DecidedAnswer, 1, startIdx-1) .. string.sub(DecidedAnswer, endIdx+1)
		print(answer) -- You can add you UI things here
	else
		print(answer)
	end

Thank for looking this tutorial

Congrulations! You finished the tutorial. Now open the Roblox Studio and try it yourself!

View in-game to comment, award, and more!