Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
106 lines
3.8 KiB
Python
106 lines
3.8 KiB
Python
from lavalink import LoadType
|
|
import re
|
|
|
|
from utils.config import AI_CLIENT, AI_MODEL
|
|
|
|
|
|
async def add_song_recommendations(
|
|
bot_user, player, number, inputs, retries: int = 1
|
|
):
|
|
input_list = [f'"{song} by {artist}"' for song, artist in inputs.items()]
|
|
|
|
completion = (
|
|
AI_CLIENT.chat.completions.create(
|
|
messages=[
|
|
{
|
|
"role": "system",
|
|
"content": f"""
|
|
Given an input list of songs formatted as ["song_name
|
|
by artist_name", "song_name by artist_name", ...], generate
|
|
a list of 5 new songs that the user may enjoy based on
|
|
the input.
|
|
|
|
Thoroughly analyze each song in the input list, considering
|
|
factors such as tempo, beat, mood, genre, lyrical themes,
|
|
instrumentation, and overall meaning. Use this analysis to
|
|
recommend 5 songs that closely align with the user's musical
|
|
preferences.
|
|
|
|
The output must be formatted in the exact same way:
|
|
["song_name by artist_name", "song_name by artist_name", ...].
|
|
|
|
If you are unable to find 5 new songs or encounter any issues,
|
|
return the following list instead: ["NOTHING_FOUND"]. Do
|
|
not return partial results—either provide 5 songs or return
|
|
["NOTHING_FOUND"]. Ensure accuracy in song and artist names.
|
|
|
|
DO NOT include any additional information or text in the
|
|
output, it should STRICTLY be either a list of the songs
|
|
or ["NOTHING_FOUND"].
|
|
""",
|
|
},
|
|
{
|
|
"role": "user",
|
|
"content": f"""
|
|
{input_list}
|
|
""",
|
|
},
|
|
],
|
|
model=AI_MODEL,
|
|
)
|
|
.choices[0]
|
|
.message.content.strip()
|
|
.strip('"')
|
|
)
|
|
|
|
# Sometimes ChatGPT will return `["NOTHING FOUND"]` even if it should
|
|
# have found something, so we check each prompt up to 3 times before
|
|
# giving up.
|
|
if completion == '["NOTHING FOUND"]':
|
|
if retries <= 3:
|
|
await add_song_recommendations(
|
|
bot_user, player, number, inputs, retries + 1
|
|
)
|
|
else:
|
|
return False
|
|
|
|
else:
|
|
# Clean up the completion string to remove any potential issues
|
|
# with the eval function (e.g. OUTPUT: prefix, escaped quotes, etc.)
|
|
completion = re.sub(r"[\\\'\[\]\n]+|OUTPUT: ", "", completion)
|
|
|
|
for entry in eval(completion):
|
|
song, artist = entry.split(" by ")
|
|
ytsearch = f"ytsearch:{song} by {artist} audio"
|
|
results = await player.node.get_tracks(ytsearch)
|
|
|
|
if (
|
|
not results
|
|
or not results.tracks
|
|
or not results.load_type
|
|
or results.load_type
|
|
in (
|
|
LoadType.EMPTY,
|
|
LoadType.ERROR,
|
|
)
|
|
):
|
|
dzsearch = f"dzsearch:{song}"
|
|
results = await player.node.get_tracks(dzsearch)
|
|
|
|
if (
|
|
not results
|
|
or not results.tracks
|
|
or not results.load_type
|
|
or results.load_type
|
|
in (
|
|
LoadType.EMPTY,
|
|
LoadType.ERROR,
|
|
)
|
|
):
|
|
continue
|
|
|
|
track = results.tracks[0]
|
|
player.add(requester=bot_user, track=track)
|
|
|
|
return True
|