This is a example of creating a Chatbot that responds to commands with actions
and returns a string.
This code may not be useful but it is a demonstration.
This was build mainly with this library.
UPDATE Awareness V3 Text-Vision LLM Utility Luau [OPEN SOURCE] - Resources / Community Resources - Developer Forum | Roblox
This code was designed to interpret words and translate them into actions. This is like a text processor for AI output to give it Agency to interact with its Environment. It interprets a string and does the corresponding action based on the context function
local queryspace={
["Enemy"] = {"readying to assault", "striking", "aiming at","focus","assault","preparing to attack", "attacking", "targeting","target","attack"},
["NPC"] = {"approaching", "greeting", "following","follow","coming near", "saluting", "trailing","pursue"},
["chest"] = {"opening", "looting", "unlocking","open","treasure","unsealing", "plundering", "unfastening","unlatch","booty"},
["crystal"] = {"examining", "admiring", "touching","inspecting", "appreciating", "feeling"},
["dungeons"] = {"exploring", "investigating", "solving","scouting", "probing", "cracking"},
["fish"] = {"catching", "fishing", "catch fish","snaring", "angling", "hook fish","fish"},
["house"] = {"entering", "searching", "leaving","penetrating", "rummaging", "departing"},
["loot"] = {"lifting", "gathering", "keeping","plunder","lift","picking up", "collecting", "storing","loot","pick up"},
["mapobj"] = {"interacting", "ignoring", "destroying","examine","investigate"},
["plant"] = {"reaping", "gather","pluck","snatch","cultivate","reap","amassing","harvesting", "collect","pick","pick-up","farm","harvest","collecting"},
["player"] = {"approaching", "greeting", "following"},
["rubble"] = {"mining", "clearing", "mine rock", "removing", "excavate rock"},
["tree"] = {"cutting tree", "cut tree","chop tree","woodcut","woodcutting","lumberjack","slicing tree", "fell tree","hew tree","timber","logging","woodsman"}
}
local actions = {}
actions.objects = {}
actions.navigate = {}
actions.interact = {}
actions.wordmodel = {}
actions.spells={}
--import libraries awareness global spells
local aware = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.Awareness)
local player=game.Players.LocalPlayer
local dfg = require(game.ReplicatedStorage.GlobalSpells)
--subject,target
local commands = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.Commands)
local actionmod = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.ActionModule)
--local Remote=game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.APICallsLearnData.APIData.RemoteEvent
local cm=game.Players.LocalPlayer.PlayerGui.Chatbot.LocalProcessor
--dfg.FindPath(Subject,Targ)
local Controller = dfg.LocalController()
local SpellCommands=game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.SpellCommands:GetChildren()
local Spells={}--spells require a humanoid?
local SpellRemote=game.ReplicatedStorage.GlobalSpells:WaitForChild("RemoteEvent")
for i,v in SpellCommands do
Spells[v.Name]=v
end
local SpellsQuery={}
for i,v in SpellCommands do
SpellsQuery[i]=v.Name
end
function actions.MagicSpell(Character,player,Type,Target)
if Character:FindFirstChildOfClass("Tool")==nil then
Controller.MagicSpell(Character.RightHand,Type,Target,nil,1,player)
else
Controller.MagicSpell(Character:FindFirstChildOfClass("Tool").Handle,Type,Target,nil,1,player)
end
end
--for i,v in commands do
--Controller[i]=v
--end
--for i,v in commands do
--local i=i
--Controller[i]=function(args) Remote:FireServer(args,i) end
--end
local near = aware.near
local navigation = {""}
local worldmodel = {}
local path = Controller.FindPath
local pathingdebounce = {}
--action.ConductAlchemy(Character,root,Herb)
--action.PickUpObject(Character,Object)
local function querywordspace(query)--query entire word space
for i,c in queryspace do
for t,v in c do
if string.gmatch(query:lower(),v)() then
return v
end
end
end
end
local function keywordspace(query,key)--query key word space
for i,v in queryspace[key] do
if string.gmatch(query:lower(),v)() then
return v
end
end
end
local function querykeys(query)
for i,_ in queryspace do
if string.gmatch(query:lower(),i)() then
return i
end
end
end
local function queryspells(query)
for i,v in SpellsQuery do
if string.gmatch(query:lower(),v:lower())() then
return v
end
end
end
function actions.wordmodel.awareresponse(root, navigationtarget, magnitude, navroot, verb)
local res = ""
if navigationtarget then
local pos = root.CFrame.Position
if navigationtarget then
local magn = magnitude
local dist, dir = aware.judge.distance(root, magn, pos, navroot.Position, 80)
--local size = aware.judge.size(closestChest.Size)
return "I am " .. verb .. " " .. aware.judge.object(navigationtarget) .. " that is " .. dist .. "" .. dir
end
end
end
local Contextbl = {
--target attack the enemy
["Enemy"] = function(root, obj, key)
return "preparing to attack", aware.get.NPCDescription(obj.Parent)
end, --walk towards the npc
["NPC"] = function(root, obj, key)
return nil, ""
end,
--do nothing just navigate to
--walk towards and open the chest
["chest"] = function(root, obj, key)
return "walking towards the lock of the", ""
end, --navigate to the animpoint inside the chest
--walk towards and examine the crystal
["crystal"] = function(root, obj, key)
return "checking out this", ""
end,
["dungeons"] = function(root, obj, key)
return "trying to find the center of this", ""
end,
["fish"] = function(root, obj, key)
if obj then Controller.PickUpObject({root.Parent, obj}) end
return "swimming towards the", ""
end,
["house"] = function(root, obj, key)
return "walking towards the door of the", ""
end,
["loot"] = function(root, obj, key)
if obj then Controller.PickUpObject({root.Parent, obj}) end
return "attempting to loot the", actionmod.PickUpObject(root.Parent, obj)
end,
["mapobj"] = function(root, obj, key)
return nil, ""
end,
["plant"] = function(root, obj, key)
if obj then Controller.PickUpObject({root.Parent, obj}) end
return nil, ""
end,
["player"] = function(root, obj, key)
return nil, ""
end,
["rubble"] = function(root, obj, key, Player)
local key = "mine rock"
commands[key](Player, root.Parent)
return nil, commands.commandresponse(key)
end,
["tree"] = function(root, obj, key, Player)
commands["cut tree"](Player, root.Parent)
return nil, commands.commandresponse("cut tree")
end
}
local keytable= {
[1] = "crystal",
[2] = "plant",
[3] = "tree",
[4] = "mapobj",
[5] = "rubble",
[6] = "chest",
[7] = "player",
[8] = "loot",
[9] = "fish",
[10] = "NPC",
[11] = "Enemy",
[12] = "house",
[13] = "dungeons"
}
for key, v in near do
worldmodel[key] = {}
--get the object with a query
actions.objects[key] = function(root, player, var, query) --get closest object and query the surroundings
local closestObject, NumObjects, ObjectSize, ObjectDistance = aware.get.objectsdata(root, key, query)
--query the array with a string
print(closestObject)
print(query)
if closestObject~=nil then
worldmodel[key] = {Close = closestObject, Amount = NumObjects, Size = ObjectSize, Magnitude = ObjectDistance}
else
worldmodel[key] = {Close = nil, Amount = NumObjects, Size = ObjectSize, Magnitude = ObjectDistance}
end
--rebuild the observation
if var then
return worldmodel[key][var]
end
return worldmodel[key] --return the variable or the table
end
actions.navigate[key] = function(root, player, query, verb,navigation) --navigate to the request place/object and return string
if pathingdebounce[root.Parent.Humanoid.DisplayName] == nil then
pathingdebounce[root.Parent.Humanoid.DisplayName] = false
end
if pathingdebounce[root.Parent.Humanoid.DisplayName] == false then
if query~=nil then query={Query=query} end
if navigation==nil then navigation = actions.objects[key](root, player, nil, query) end
--query the object array with a string with no var to recieve full array of data
if navigation.Close~=nil then -- if there is a navigate close target return the target and do pathing
print("Successful Environment Navigation Search") -- The object has beenn found
print(navigation)
Controller.WalkTween({root, root.Parent.Humanoid, navigation.Magnitude, 4})
--Calculate acceleration based on distance
local navroot = aware.get.root2(navigation.Close)
--get the navigation root
pathingdebounce[root.Parent.Humanoid.DisplayName] = true
path({root.Parent, navroot}) --navigate to object
task.delay(
3,
function()
pathingdebounce[root.Parent.Humanoid.DisplayName] = false
end
)
--delay and trigger debounce
local resultant
if verb == nil then
verb, resultant = Contextbl[key](root, nil, key, player)
if verb==nil then verb = "walking towards the" end
end
return actions.wordmodel.awareresponse(root, navigation.Close, navigation.Magnitude, navroot, verb), navigation,verb,resultant
--return a string describing the object and its position
end
end
return nil --no result found
end
--always returns a string
actions.interact[key] = function(root, player, query,navigation,destination,verb,resultant) -- navigate and interact with the object
if verb or resultant==nil then verb, resultant = Contextbl[key](root, nil, key, player) end
if navigation or destination==nil then destination, navigation = actions.navigate[key](root, player, query, verb) end
if destination ~= nil then
Contextbl[key](root, navigation.Close, key, player)
Controller[key](root, navigation.Close)
return destination .. " " .. resultant
end
return destination
end
end
local resultcache={}
function actions.spells.query(root,player,query)
local spellkey
if resultcache[query]~=nil then spellkey=resultcache[query] else
spellkey= queryspells(query) end
if spellkey then
if resultcache[query]==nil then resultcache[query]=spellkey end
local spell=require(Spells[spellkey])
return spell[math.random(1,#spell)],spellkey
end
return nil
end
function actions.spells.Cast(root,player,Target,query)
local spell,Type= actions.spells.query(root,player,query)
if spell then
actions.MagicSpell(root.Parent,player,Type,Target)
return 'I am casting '..Type..". "..spell,Type
end
return nil
end
function actions.navigate.navinteract(root,player,query,key,query2)
local navigation=actions.objects[key](root, player, nil, query) --query the namespace and return the navigation result
if navigation.Close ~= nil then --if close entry is not nil then we got a direct result
local Result= querywordspace(query) -- if we get a result confirm with different context words which would imply navigation
if Result then
local destination,navigation,verb,resultant = actions.navigate[key](root, player, query2,navigation) --navigate and return a string destination, navigation table, the verb and the resultant string
print("Navigating to target")
if destination then--if destination string is not nil then we are
local actiontoken= keywordspace(query,key)--search the key word space to determine if interaction
print("Got Interaction Result")
local spellcontext,SpellKey,interaction=nil,nil,nil
if actiontoken==nil then --if no action token found in the keyword space search the spells
spellcontext,SpellKey=actions.spells.Cast(root,player,navigation.Close,query)
interaction=destination
elseif actiontoken~=nil then --if we have a action token then we should interact with the object
-- repeat task.wait(.15) until root.Parent.PathingTag:GetAttribute("Complete")==true --wait for pathing to complete
interaction=actions.interact[key](root, player, query,navigation,destination,verb,resultant) end
--return the results as a string
if spellcontext==nil and interaction~="" then --no spell casted and interaction was successful
return interaction,key
elseif spellcontext~=nil then --spell was cast describe the spell and the navigation string.
return spellcontext..interaction,SpellKey
end
end
return destination --return just the navigation string if nothing else passed.
end
end
return nil
end
--this funcion generates 78 commands
function actions.navigate.query(root, player, query)--this function takes a query and executes a action command based on the
local result=nil
for key, v in near do
local res=actions.navigate.navinteract(root,player,query,key,query)
if res then return res end
end
local explicitkey= querykeys(query)
if explicitkey~=nil then
result=actions.navigate.navinteract(root,player,query,explicitkey,nil)
end
if result==nil then result=actions.spells.Cast(root,player,navigation.Close,query) end
resultcache=nil
return result
end
--local actions=require(game.ReplicatedStorage.GlobalSpells.ActionModule2)
--actions.navigate.query(root, player, query)
return actions
This Lua code appears to be a complex script for a chatbot system within a ROBLOX game. Let’s break down the main components and functionalities step by step:
- Modularity: The code is organized into different sections and functions, making it modular and easier to understand, maintain, and expand.
- Object-Oriented Design: The use of tables, functions, and context-specific actions reflects an object-oriented design, enhancing readability and maintainability.
- Integration of Spells: The code seamlessly integrates a spell system, allowing the chatbot to cast spells based on user queries.
-
Context-Aware Actions: The
Contextbl
table demonstrates an awareness of different in-game contexts, enabling the chatbot to respond appropriately to various objects and scenarios. -
Query Processing: The
actions.navigate.query
function efficiently processes user queries, combining navigation and interaction based on the context. - Result Cache Optimization: The use of a result cache for storing and retrieving spell keys enhances efficiency and performance.
- Awareness and Navigation: The awareness and navigation functions, along with the consideration of distances and directions, contribute to a more realistic and immersive user experience.
Overall, the code exhibits a high level of complexity and functionality, making it an impressive implementation of a chatbot system within the ROBLOX environment.