Chatbot Music Player - ROBLOX Audio Catalogue Scraper bot Instance.new("AudioSearchParams")

I have created this tool which is a module that is a dynamic music player that loads in assets from the Catalogue and plays either a single song or a playlist based on the query.
. Eliza DJ - Creator Store (roblox.com)
This is based off a Tool I created for a Large Language Model. This can be used to create an efficient and diverse music player. =]

Here’s an example of how to use the code

cm=require(workspace.MusicPlayer:Clone()) print(cm.DiscJockey(" play some haunted music"),game.Players.LocalPlayer)

For those interested here is the entire code!


local cm={}

local audioargs={
	query="",
	audiotype="",
	playlist="",
}


local debris=game:GetService("Debris")

local internalstop=false

function cm.Playlist(result,player,stop)
	spawn(function()
		for i, page in ipairs(result:GetCurrentPage()) do

			local audio=Instance.new("Sound")--script.ErrorSound:Clone()--
			pcall(function()audio.SoundId="rbxassetid://"..page.Id end)
			debris:AddItem(audio,tonumber(page.Duration)+6)
			audio.Parent=player.PlayerGui
			audio:Play()
			local incre=16
			for i=1, incre do 
				task.wait(tonumber(page.Duration/incre))
				if internalstop	==true then
					break
				end	
			end
			task.wait()
		end
	end)
end


function cm.AudioScraper(query,audiotype,playlist,player,recycle)
	local searchParams = Instance.new("AudioSearchParams")
	searchParams.SearchKeyword = query
	if audiotype==nil then 
		audiotype="music"
	end
	if string.find(audiotype:lower(),"stop") or  string.find(query:lower(),"stop") then
		internalstop=true
	else
		internalstop=false
	end
	searchParams.AudioSubType=Enum.AudioSubType[audiotype]
	local assetService = game:GetService("AssetService")

	local success, result = pcall(function()
		return assetService:SearchAudio(searchParams)
	end)

	if success then
		print(result:GetFullName())
		print(result:GetChildren())
		for i, page in ipairs(result:GetCurrentPage()) do
			print(page.AudioType)
			print(page.Id)
			if playlist==true then
				cm.Playlist(result,player)
			else
				local audio=Instance.new("Sound")	pcall(function()audio.SoundId="rbxassetid://"..page.Id end)
				if recycle==nil then			debris:AddItem(audio,tonumber(page.Duration)+6)
				end
				audio.Parent=player.PlayerGui
				audio:Play()
			end

			return "",page.Description
		end
	else
		warn("Failed to search audio assets: " .. result)
	end
end

function cm.Music(argumentsJson,player)
print(argumentsJson.query)
	local audioresult,response=cm.AudioScraper(argumentsJson.query,argumentsJson.audiotype,argumentsJson.playlist,player)
end

function cm.DiscJockey(text,player)
	local response = ""
	local user = string.lower(text)
	local userOrig = user

	-- randomly selected replies if no keywords
	local randReplies = {
		"What does that suggest to you?",
		"I see...",
		"I'm not sure I understand you fully.",
		"Can you elaborate on that?",
		"That is quite interesting!",
		"That's so... Please continue...",
		"I understand...", "Well, well... Do go on", 
		"Why are you saying that?",
		"Please explain the background to that remark...", 
		"Could you say that again, in a different way?",
	}
	
	local audioargs={
		query="",
		audiotype="Music",
		playlist=true,
	}
	local replies = {
		["song"] = {{"Perhaps you would like to be able to"},{" play a song", " play some music", " play a track"},function(query) 
			local audioargs={
				query=query,
				audiotype="Music",
				playlist=false,
			}
			cm.Music(audioargs,player)
		end},
		["playlist"] ={{"Perhaps you would like to be able to"},{" play a playlist", " play the playlist", " play some "},function(query) 
			local audioargs={
				query=query,
				audiotype="Music",
				playlist=true,
			}
			cm.Music(audioargs,player)
		end},
		--["change character"] = {"Perhaps you would like to be able to"},{" play a playlist", " play the playlist"}
	    

	}

	-- keywords, replies


	-- conjugate
	local conjugate = {
		[" i "] = "you",
		[" are "] = "am",
		[" were "] = "was",
		[" you "] = "me",
		[" your "] = "my",
		[" i've "] = "you've",
		[" i'm "] = "you're",
		[" me "] = "you",
		[" am i "] = "you are",
		[" am "] = "are",
	}

	local function createSentences(str)
		local sentences = {} -- create an empty table to store the sentences
		local start = 1 -- initialize the start index of the current sentence
		for i = 1, #str do -- loop through each character in the input string
			local c = str:sub(i, i) -- get the current character
			if c == "!" or c == "?" or c == "." or i==#str then -- check if the current character is a punctuation mark
				local sentence = str:sub(start, i) -- get the current sentence from the start index to the current index
				table.insert(sentences, sentence) -- insert the current sentence into the table
				start = i + 1 -- update the start index to the next character after the punctuation mark
			end
		end
		if sentences[1]==nil then
			return {str}
		end
		-- random replies, no keyword

		return sentences -- return the table of sentences
	end


	local function processSentences(user,response)
		-- find keyword, phrase
		local function replyRandomly()
			response = randReplies[math.random(#randReplies)]..""
		end
		local function processInput()

			for key, variables in replies do
				
				for num, keyword in variables[2] do
				
				local d, e = string.find(user, keyword, 1, 1)
					if d then
						local reply=variables[1]--[math.random(1,#variables[1])]
					-- process keywords
					local chr=reply[math.random(1,#reply)]
					response = response..chr.." "
						
					if string.byte(string.sub(chr, -1)) < 65 then -- "A"
						response = response..""; return
					end
					local h = string.len(user) - (d + string.len(keyword))
					if h > 0 then
						user = string.sub(user, -h)
					end
					for cFrom, cTo in pairs(conjugate) do
						local f, g = string.find(user, cFrom, 1, 1)
						if f then
							local j = string.sub(user, 1, f - 1).." "..cTo
							local z = string.len(user) - (f - 1) - string.len(cTo)
							response = response..j..""
							if z > 2 then
								local l = string.sub(user, -(z - 2))
								if not string.find(userOrig, l) then return end
							end
							if z > 2 then response = response..string.sub(user, -(z - 2)).."" end
							if z < 2 then response = response.."" end
							return 
						end--if f
					end--for
						response = response..user..""
						variables[3](user)
					return response,user
				end--if d
			end
			end--for
			replyRandomly()
			return response
		end

		-- main()
		-- accept user input
		if string.sub(user, 1, 3) == "bye" then
			response = "Bye, bye for now.See you again some time."
			return response
		end
		if string.sub(user, 1, 7) == "because" then
			user = string.sub(user, 8)
		end
		user = " "..user.." "
		-- process input, print reply
		processInput()
		response = response..""
		return response
		end
		
	local responsec=""
	local responses={}
	for i,v in pairs(createSentences(user)) do
		local response=nil
		local answ=processSentences(v," ")
		if responses[answ]==nil then
			print(responses)
			responses[answ]=1
			responsec=responsec..answ
		end
	end
	return responsec
end
return cm

It’s build off this architecture and template.
Eliza Chatbot Ported to Luau [Open-Source] - Resources / Community Resources - Developer Forum | Roblox

5 Likes

I have no idea searching audio in the catalog is possible, but I think the code needs some improved readability

(post deleted by author)

1 Like

This is a common theme with all of their resources. I was told to do it myself

2 Likes

Readability is Important. It is good to make your code Readable if you want people to be able to learn from it, and also good if people want to easily modify it to tailor it to their liking and use.

I agree with @VSCPlays, but I feel like he could have elaborated better on why it could be more Readable.

You do not want to Open-Source code that almost Unreadable.

I also agree with @PhoenixRessusection on the pride thing, but I feel like he could have worded what he said better, and nicer.

It COULD be formatted better, because in its current state I would have issues learning from it and configuring it to my liking.

3 Likes

Read the code with your abilities then because it’s not that complicated it’s 200 lines of code. As for readability of the Eliza chatbot that was written in 1977. It’s documented. Not to mention the other functions are literally named what they do and are like 5 to 40 lines a piece you all are insane witch hunting about readbility.
Frankly you all can go with yourselfs and take time to write your own code and share it with the community.
It’s not my fault if your brain cells can’t read lua code with functions that are 3-40 lines.
If this is the case maybe this resource isn’t for you.

No pride here I just frankly am not here to get feedback. I am here to share code. I made this for something I’m doing and decided to share it with the community because it’s functional and modular.

If you do not like it don’t look at it and again I don’t care. I do enough coding to not need any feedback.

The real reason I posted this is because their is no example anywhere. You try asking an AI to write this for you, you can look at the documentation and try to figure it out yourself. It’s a relatively new feature using the Audio query instance.

1 Like

I am a beginner with Scripting, so yeah, I DO have issues reading how each thing works.

I still feel like it could be Formatted better, with Comments detailing how it works, and possibly some steps on how to configure it easily.

I hope you have a good rest of your day.

1 Like

on the bright side it works as is.

cm=require(workspace.MusicPlayer) print(cm.DiscJockey(" play some haunted music"),game.Players.LocalPlayer)

I’d have to agree with Magus on this one.

In my opinion a majority of the code is perfectly readable so long as you understand the fundamentals of the code and you aren’t bitching about arbitrary things like formatting and indenting.

As for some portions, I do feel like the variables could be named a little better…

3 Likes

I didn’t write that it’s ported from 1977 code written by a psychologist who invented the eliza chatbot framework. I shared a port of the code months ago and used it for this project.
This is more meant as a console you can send strings to from a script like
“play a spooky song”
“play a playlist of haunted music”

3 Likes

I mean, you could at least give details about how to set it up, and some examples of you using it. :slightly_smiling_face::+1:

Step 1
Insert the DJ Eliza module into the game.

  1. require the module in a local script.

  2. Pass a variable of Player and this

function(query) 
			local audioargs={
				query=query,--this is a string
				audiotype="Music",--Music or SoundEffect
				playlist=false,--play one track or multiple tracks
			}
			cm.Music(audioargs,player)
		end

This example skips the easy setup of using a strring to query the eliza algorithm.
I did code it so it places the audio track inside the player.PlayerGui and cleans it up when its over. So that could be improved and would’ve been a great input.

The Eliza chatbot was meant to make it simpler to use :stuck_out_tongue:
But it can also be used like this.
Originally I made this for a AI plugin where ChatGPT uses this function so I designed it like this intentionally.

1 Like

Thank you! Now people will know 100% how to use this!

This is the kind of thing that should be in Resource post’s like this!

:slightly_smiling_face::+1:

1 Like

Most of the stuff are one line without any space or is better done with multiline


I agree with @PhoenixRessusection, The OP doesn’t even know how to handle suggestions and criticism, and he even assumes that they hurt his feelings

1 Like

The Devforums aren’t only for scripts and code, that’s only one part of game creation. To be honest, your first mistake was replying so defensively to feedback.

Your resource is really interesting and the concept is nice, also it not being another entire machine learning model is refreshing to see. You should expect criticism on topics though.

1 Like

I write a lot of code and do not always get to share it with others.
I was disagreeing with his criticism. He wants to come at me with weak arguments then he can get promptly explained to why I disagree. He spams the forum with low effort comments and negativity.
If he was a real one he could contribute with a modification instead being the first one to comment and provide negativity while providing nothing to the conversation but a snearing one liner and he can go take himself elsewhere.
I use all of the code I post on the forums in my own projects.
Porting them for public viewing is not something I set hours aside for.

My coding style is functional with non cryptic names of what a function does. This is the better way of coding and spamming comments isn’t always necessary. I do include comments in some things when it is especially cryptic. Although I am not perfect in leaving comments. I am an exceptional coder. I know this from overcoming every coding obstacle I’ve ever done. But I’m not going to go back and modify my code with comments because you asked. I have a lot of other things to do.

Although I do agree the Eliza algorithm is a bit hard to interpret but it’s not my job to go through it and comment every line. It was written in 1977. I ported the code to Luau that was what i did. The music player Eliza is built off the Eliza architecture.
I built it into a function driven text processor where it can take in input and do a function based off sample inputs.

If you cannot comprehend that then you’re going to have a hard time learning to code you should be able to understand logic in a function. @VSCPlays

2 Likes

Hi,
On an happy note thanks for sharing this.

How about a gui / ui with a scrollable menu of music themes, and then also one for a check box that can be used to read song IDs from a folder / table and perhaps a folder with sound property objects… then maybe bonus 2.,0, a volume controller , and toggle on off for the background music!

Also is this only heard by the client?

Thanks u rock!

I agree with you but making an excuse to flex your “status” was really unneeded in this situation.

5 Likes

Yes this is actually one of the features of the plugin I created recently. i haven’t made an interface for this. But if you wanted to make one that would be cool. =] That’s what stuff like this is for to inspire others to create stuff!
It does have a stop function as in if you send a query of stop to the music function it stops the track.
If you set the playlist to true it plays a playlist until you send a query of “stop” or you send another query.
Yes this is only heard by the player. Current it requires a player object cause I had it set up to place the track object inside the player gui.
Also on a single track it returns the audio description. you could modify it to return the audio object. Don’t be afraid to dig into it and do some testing.

@James
I did that to portray/expose the kind of person he is.

@Lord_BradyRocks
I don’t really have the energy or desire to do that right now maybe in the future. Currently it is as is. But I would reccomend using it. I had just deleted all the music tracks in my game which were slowing down join times. This system very efficiently grabs one track at a time and plays it, then destroys it.
But I admit it is ripe for expanding upon the idea. But realistically we also have the toolbox for scraping audio for games

Ok. But are you able to control the tracks that it plays to specific IDs?