I have been developing a chatbot. I am here to share how it works I always have found online resources helpful. I’m here to return the favor. If you want to use the script just copy and paste this code block into a textlabel gui element
This is a chatbot model I created. This is a template! You have to feed it data in the form of conversational responses. Basically this is a search engine that searches tables and returns the one with the best match! It’s very effective in my application. You will notice it goes through each database in sequence. SO if no subject is found in the database it goes to the next one in the stack. Simulating priority. You can enhance its functions exponentially by implementing OpenAI’s chat GPT. But You can also use AI to train this. So I wanted to share it with you all. and also link this related article. How to use OpenAI’s new ChatGPT API in roblox - Resources / Community Tutorials - Developer Forum | Roblox
Furthermore, it’s important to clarify that as is this lacks data. The SearchQuery function is for context that is more informational where it blacklists many nouns and pronouns to get accurate results. While the conversational context makes use of nouns and pronouns to provide conversational responses. When constructing your synonymous phrase table to randomize your string is where the magic happens! You could use this in a variety of ways. you could search a database of specific topics. then go more in depth on the topic by doing another search query with the keyword result! The options are limitless! Feel free to use different problem solving methods to get unique results! You can create different modes by creating different logic for which database it searches through.
local Player=game.Players.LocalPlayer
local context=0
local blasklist={}–Adds previous response to blacklist for SearchQuery
local interchangephrases={{“Hey there”,“Hi how are you”,“Greetings to you”},{“I’ve heard,”,“they say,”},{" happy"," elated"},{“sad “,“upset “}}–tables
local Greetings={“Hey there.”,“Hey how are you?”,“I’m doing fine thanks, how are you?”,“The weather is nice today.”,“My favorite color is blue.”}
local Database={” There are many things to do you just have to put your mind to it.”,” You can achieve whatever you set your mind to! Just do your best.”}
local function splitString(str)
local words = {}
for word in str:gmatch(“%w+”) do – %w+ matches one or more alphanumeric characters
table.insert(words, word) – insert the word into the words array
end
return words
end
local function countKeyword(str, keyword)
local count = 0
for _, word in ipairs(splitString(str)) do
if word:lower() == keyword:lower() or word:lower()…“?” == keyword:lower() or word:lower() == keyword:lower()…“.” or word:lower()…“.” == keyword:lower() or word:lower()…“'s” == keyword:lower() or word:lower() == keyword:lower()…“'s” then – compare the words in lowercase
count = count + 1 – increment the count if there is a match
end
end
return count
end
local function findBestMatch(strings, keyword)
local bestMatch = nil – the best match string
local bestCount = 0 – the highest count of keyword occurrences
for _, str in ipairs(strings) do – loop through the strings in the table
local check=false
for _, blkl in ipairs(blasklist) do
if str==blkl then
check=true
end
end
if check==false then
local count = countKeyword(str, keyword) – get the count of keyword occurrences in the string
if count > bestCount then – if the count is higher than the best count so far
bestMatch = str – update the best match string
bestCount = count – update the best count number
end
end
end
return bestMatch, bestCount – return the best match and its count
end
local function SearchQuery(query, database)
local words = splitString(query) – Split the query into words using your splitString function
local matches = {} – A table to store the matches and their scores
for _, word in ipairs(words) do – Loop through the words in the query
–Blacklist a bunch of nouns and non context wwords.
if word~=“were” and word~=“we’re” and word~=“we?” and word~=“when” and word~=“how” and word~=“where” and word~=“do” and word~=“more” and word~=“about” and word~=“tell” and word~=“me” and word~=“what” and word~=“is” and word~=“a” and word~=“the” and word~=“of” and word~=“i” and word ~=“how” and word~=“we” and word~=“us” and word~=“their” and word~=“them” and word~=“you” and word~=“dark” and word~=“if” and word~=“there” and word~=“have” and word~=“many” and word~=“one” and word~=“important” and word~=“situation” and word~=“but” and word~=“can” and word~=“think” and word~=“wondering” and word~=“i’m” and word~=“im” and word~=“and” and word~=“an” and word~=" " and word~=“thinking” and word~=“your” and word~=“hear” and word~=“else” and word~=“have” and word~=“things” and word~=“few” and word~=“or” and word~=“any” and word ~= “be” and word ~= “use” and
word ~= “made” and word ~= “may” and word ~= “give”
and word ~= “help” and word ~= “came” and word ~= “show”
and word ~= “does” and word ~= “must” and word ~= “went”
and word ~= “need” and word ~= “try” and word ~= “found”
and word ~= “should” and word ~= “add” and word ~= “keep”
and word ~= “start” and word ~= “saw” and word ~= “turn”
and word ~= “might” and word ~= “close” and word ~= “seem”
and word ~= “open” and word ~= “begin” and word ~= “got”
and word ~= “began” and word ~= “grow” and word ~= “took”
and word ~= “carry” and word ~= “hear” and word ~= “stop” and word ~= “miss” and word~=“are” then
local bestMatch, bestCount = findBestMatch(database, word) – Find the best match and its count for each word using your findBestMatch function
if bestMatch then – If there is a match
if matches[bestMatch] then – If the match is already in the table
matches[bestMatch] = matches[bestMatch] + bestCount – Add the count to its score
else – If the match is not in the table yet
matches[bestMatch] = bestCount – Set its score to the count
end
end
end
end
local sortedMatches = {} – A table to store the sorted matches by their scores
for match, score in pairs(matches) do – Loop through the matches and their scores
table.insert(sortedMatches, {match = match, score = score}) – Insert each match and its score as a subtable into the sortedMatches table
end
table.sort(sortedMatches, function(a, b) return a.score > b.score end) – Sort the sortedMatches table by the score field in descending order
local result = nil – The result string to return
if #sortedMatches > 0 then – If there is at least one match
--result = "The best match(es) for '" .. query .. "' are:\n" -- Start the result string with an introduction
for i = 1, math.min(#sortedMatches, 3) do -- Loop through the top three matches or less if there are not enough matches
result = sortedMatches[i].match
--.. " (Score: " .. sortedMatches[i].score .. ")\n" -- Append each match and its score to the result string
end
context=context+1
table.insert(blasklist,result)
--result=sortedMatches[math.random(1,math.min(#sortedMatches, 3))]
else -- If there are no matches
result=nil
--result = "Sorry, I couldn't find any match for '" .. query .. "' in the database." -- Set the result string to an error message
end
return result
-- Return the result string
end
local function RepetitiveSearchQuery(query, database)
local words = splitString(query) – Split the query into words using your splitString function
local matches = {} – A table to store the matches and their scores
for _, word in ipairs(words) do – Loop through the words in the query
if word~=nil then
local bestMatch, bestCount = findBestMatch(database, word) – Find the best match and its count for each word using your findBestMatch function
if bestMatch then – If there is a match
if matches[bestMatch] then – If the match is already in the table
matches[bestMatch] = matches[bestMatch] + bestCount – Add the count to its score
else – If the match is not in the table yet
matches[bestMatch] = bestCount – Set its score to the count
end
end
end
end
local sortedMatches = {} – A table to store the sorted matches by their scores
for match, score in pairs(matches) do – Loop through the matches and their scores
table.insert(sortedMatches, {match = match, score = score}) – Insert each match and its score as a subtable into the sortedMatches table
end
table.sort(sortedMatches, function(a, b) return a.score > b.score end) – Sort the sortedMatches table by the score field in descending order
local result = nil – The result string to return
if #sortedMatches > 0 then – If there is at least one match
--result = "The best match(es) for '" .. query .. "' are:\n" -- Start the result string with an introduction
for i = 1, math.min(#sortedMatches, 3) do -- Loop through the top three matches or less if there are not enough matches
result = sortedMatches[i].match
--.. " (Score: " .. sortedMatches[i].score .. ")\n" -- Append each match and its score to the result string
end
--table.insert(blasklist,result)
--result=sortedMatches[math.random(1,math.min(#sortedMatches, 3))]
else -- If there are no matches
result=nil
--result = "Sorry, I couldn't find any match for '" .. query .. "' in the database." -- Set the result string to an error message
end
return result
-- Return the result string
end
local function SearchQueryUnfiltered(query, database)
local words = splitString(query) – Split the query into words using your splitString function
local matches = {} – A table to store the matches and their scores
for _, word in ipairs(words) do – Loop through the words in the query
if word~=nil then
local bestMatch, bestCount = findBestMatch(database, word) – Find the best match and its count for each word using your findBestMatch function
if bestMatch then – If there is a match
if matches[bestMatch] then – If the match is already in the table
matches[bestMatch] = matches[bestMatch] + bestCount – Add the count to its score
else – If the match is not in the table yet
matches[bestMatch] = bestCount – Set its score to the count
end
end
end
end
local sortedMatches = {} – A table to store the sorted matches by their scores
for match, score in pairs(matches) do – Loop through the matches and their scores
table.insert(sortedMatches, {match = match, score = score}) – Insert each match and its score as a subtable into the sortedMatches table
end
table.sort(sortedMatches, function(a, b) return a.score > b.score end) – Sort the sortedMatches table by the score field in descending order
local result = nil – The result string to return
if #sortedMatches > 0 then – If there is at least one match
--result = "The best match(es) for '" .. query .. "' are:\n" -- Start the result string with an introduction
for i = 1, math.min(#sortedMatches, 3) do -- Loop through the top three matches or less if there are not enough matches
result = sortedMatches[i].match
--.. " (Score: " .. sortedMatches[i].score .. ")\n" -- Append each match and its score to the result string
end
table.insert(blasklist,result)
--result=sortedMatches[math.random(1,math.min(#sortedMatches, 3))]
else -- If there are no matches
result=nil
--result = "Sorry, I couldn't find any match for '" .. query .. "' in the database." -- Set the result string to an error message
end
return result
-- Return the result string
end
local function randomizeString(str)
– Split the string into sentences
local sentences = {}
for s in str:gmatch(“[^%.]+”) do
table.insert(sentences, s)
end
– Loop through the sentences and replace any matching phrases with a random one from the table
local newSentences = {}
for i, s in ipairs(sentences) do
local newS = s
for j, phrases in ipairs(interchangephrases) do
for k, phrase in ipairs(phrases) do
if s:find(phrase) then
– Pick a random phrase from the same group
local randomPhrase = phrases[math.random(#phrases)]
– Replace the original phrase with the random one
newS = newS:gsub(phrase, randomPhrase)
for i, s in ipairs(splitString(newS)) do
local newS = s
for j, phrases in ipairs(interchangephrases) do
for k, phrase in ipairs(phrases) do
if s:find(phrase) then
– Pick a random phrase from the same group
local randomPhrase = phrases[math.random(#phrases)]
– Replace the original phrase with the random one
newS = newS:gsub(phrase, randomPhrase)
break
end
end
end
–table.insert(newSentences, newS)
end
break
end
end
end
table.insert(newSentences, newS)
end
-- Join the new sentences with periods and return the result
return table.concat(newSentences, ".")
end
function Chat()
if script.Parent.Parent:FindFirstChild(“ChatBox”)~=nil then
script.Parent.Parent:FindFirstChild(“ChatBox”):Destroy()
end
local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Parent = game:GetService("StarterGui")
local Answer="What is you question?"
-- Create a Frame object under the ScreenGui
local Frame = Instance.new("Frame")
Frame.Name="ChatBox"
Frame.Parent = script.Parent.Parent
Frame.Size = UDim2.new(1, 0,0.6, 40)-- Adjust the size as needed
Frame.Position = UDim2.new(0, 0,0, -35) -- Adjust the position as needed
Frame.BackgroundColor3 = Color3.new(1, 1, 1) -- Adjust the color as needed
Frame.BackgroundTransparency=1
-- Create a TextLabel object under the Frame to display the question
local QuestionLabel = script.Parent
QuestionLabel.Text="What is your question?"
local AnswerBox = Instance.new("TextBox")
AnswerBox.Parent = Frame
AnswerBox.Size = UDim2.new(0.74, 0,0.14, 0) -- Adjust the size as needed
AnswerBox.Position = UDim2.new(0.13, 0,0.02, 0) -- Adjust the position as needed
AnswerBox.Text = "" -- Leave the text empty initially
AnswerBox.TextColor3 = script.Parent.TextColor3-- Adjust the text color as needed
AnswerBox.FontFace=script.Parent.FontFace
AnswerBox.PlaceholderText="Type your answer here..."
AnswerBox.ZIndex=11
AnswerBox.TextScaled = true -- Adjust the text scaling as needed
AnswerBox.BackgroundTransparency=1
AnswerBox.TextStrokeTransparency=0
local Box2=script.Parent.Parent.Parent.Box2:Clone()
local Nt2=script.Parent.Parent.Parent.Nametag2:Clone()
Nt2.Text=Player.Name
Nt2.Parent=Frame
Box2.Parent=Frame
Box2.Visible=true
Nt2.Visible=true
--AnswerBox.ClearTextOnFocus=fa
-- Create a TextButton object under the Frame to allow the user to submit their answer
local EnterButton = Instance.new("TextButton")
EnterButton.TextColor3 = script.Parent.TextColor3-- Adjust the text color as needed
EnterButton.FontFace=script.Parent.FontFace
EnterButton.Parent = Frame
EnterButton.Size = UDim2.new(0.12, 0,0.1, 20) -- Adjust the size as needed
EnterButton.Position = UDim2.new(0.875, 0,1.5, -40) -- Adjust the position as needed
EnterButton.Text = "Enter" -- Change the text as needed
EnterButton.TextColor3 = Color3.new(1, 1, 1) -- Adjust the text color as needed
EnterButton.TextScaled = true -- Adjust the text scaling as needed
EnterButton.BackgroundColor3 = Color3.new(0, 0.5, 1) -- Adjust the background color as needed
EnterButton.Style="RobloxButton"
--local CloseButton=EnterButton:Clone()
--CloseButton.Parent=Frame
--CloseButton.Position=UDim2.new(0.08, 0,0.6, 0)
--CloseButton.Text="Back"
-- Define a function to check if the user's answer is correct and display feedback
local function CheckAnswer(answer)
--local answer = AnswerBox.Text -- Get the user's answer from the TextBox
local Result
if answer ~="" then -- Change the correct answer as needed
Result= SearchQuery(answer, Greetings)
-- EnterButton.Text = "" -- Change the feedback text as needed
--EnterButton.BackgroundColor3 = Color3.new(1, 0, 0) -- Change the feedback color as needed
end
if Result==nil then
Result=SearchQuery(Answer,Database)
end
if Result==nil then
Result="Sorry I have no knowledge of that"
end
return randomizeString(Result)
end
EnterButton.MouseButton1Click:Connect(function() QuestionLabel.Text =CheckAnswer(AnswerBox.Text) end)
AnswerBox.FocusLost:Connect(function() QuestionLabel.Text =CheckAnswer(AnswerBox.Text) end)
end