Musify / app.py
solinm's picture
Update app.py
fcdc0b6 verified
raw
history blame
20.4 kB
import gradio as gr
import os
from groq import Groq
api_key = os.getenv("GROQ_API_KEY")
client = Groq(api_key=api_key)
# TODO for solin: add new translations
def chat_with_bot_stream(user_input, conversation_history):
if conversation_history is None:
conversation_history = []
conversation_history.append({"role": "user", "content": user_input})
# Provide an engaging system message and introduce the chatbot with example questions
if len(conversation_history) == 1:
conversation_history.insert(0, {
"role": "system",
"content": (
"You are a music and genre recommendation bot designed to help users discover new music "
"based on their preferences, mood, or activity.\n\n"
"Your responses should be engaging, personalized, and insightful. You can recommend:\n\n"
"- Specific songs, albums, or artists\n"
"- Genres based on mood, activity, or past preferences\n"
"- Hidden gems and deep cuts for music enthusiasts\n"
"- Trending or classic hits based on user taste\n\n"
"Be conversational, suggest multiple options when possible, and encourage users to explore new sounds. "
"If requested, provide brief descriptions of artists or genres, and explain why a recommendation might suit the user.\n\n"
"If asked about visibility on the website, such as font sizing and themes (dark or light mode ONLY), "
"direct them to the settings tab at the top of the chatbot.\n\n"
"If asked about the languages you speak, you can say that you speak English, Spanish, and French ONLY. "
"Direct the user to the settings tab to change the language.\n\n"
"Limit your responses to music-related inquiries only. Limit your responses to 15 lines or less.\n\n"
"If you do not recognize an artist/genre/album/song name, try to clarify further, and if you still don't recognize it let the user know that you're not familiar with said artist/genre/album/song.\n\n"
"Encourage users to continue the conversation. If you suggest music, offer to refine your recommendations further, "
"such as recommending more similar artists, making a mini playlist, or adjusting based on user feedback.\n\n"
)
})
completion = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=conversation_history,
temperature=0.95,
max_tokens=1024,
top_p=0.9,
stream=True,
)
response_content = ""
for chunk in completion:
response_content += chunk.choices[0].delta.content or ""
conversation_history.append({"role": "assistant", "content": response_content})
return [
(msg["content"] if msg["role"] == "user" else None,
msg["content"] if msg["role"] == "assistant" else None)
for msg in conversation_history
], conversation_history
# word translation
translations = {
"English": {
"header_description": "Your own personal music discovery assistant!",
"user_input_placeholder": "Enter your music-related questions here!",
"send_button": "↗️ Send",
"settings_tab_item": "⚙️ Settings",
"settings_markdown": "### Settings",
"apply_settings_button": "Apply Settings",
"select_language_label": "🌐 Language",
"theme_label": "🌗 Theme",
"theme_choices": ["Dark", "Light"],
"font_size_label": "🗛 Font Size",
"font_size_choices": ["Small", "Medium", "Large"],
"language_choices": ["English", "Español", "Français"]
},
"Spanish": {
"header_description": "¡Tu asistente personal para descubrir música!",
"user_input_placeholder": "¡Introduce tus preguntas relacionadas con la música!",
"send_button": "↗️ Enviar",
"settings_tab_item": "⚙️ Configuración",
"settings_markdown": "### Configuración",
"apply_settings_button": "Aplicar Configuración",
"select_language_label": "🌐 Idioma",
"theme_label": "🌗 Tema",
"theme_choices": ["Oscuro", "Claro"],
"font_size_label": "🗛 Tamaño de Fuente",
"font_size_choices": ["Pequeño", "Mediano", "Grande"],
"language_choices": ["English", "Español", "Français"]
},
"French": {
"header_description": "Votre assistant personnel pour découvrir de la musique !",
"user_input_placeholder": "Entrez vos questions sur la musique ici !",
"send_button": "↗️ Envoyer",
"settings_tab_item": "⚙️ Paramètres",
"settings_markdown": "### Paramètres",
"apply_settings_button": "Appliquer les paramètres",
"select_language_label": "🌐 Langue",
"theme_label": "🌗 Thème",
"theme_choices": ["Sombre", "Clair"],
"font_size_label": "🗛 Taille de police",
"font_size_choices": ["Petit", "Moyen", "Grand"],
"language_choices": ["English", "Español", "Français"]
}
}
# translations for theme
english_to_spanish_theme = {"Dark": "Oscuro", "Light": "Claro"}
spanish_to_english_theme = {"Oscuro": "Dark", "Claro": "Light"}
english_to_french_theme = {"Dark": "Sombre", "Light": "Clair"}
french_to_english_theme = {"Sombre": "Dark", "Clair": "Light"}
english_to_spanish_font = {"Small": "Pequeño", "Medium": "Mediano", "Large": "Grande"}
spanish_to_english_font = {"Pequeño": "Small", "Mediano": "Medium", "Grande": "Large"}
english_to_french_font = {"Small": "Petit", "Medium": "Moyen", "Large": "Grand"}
french_to_english_font = {"Petit": "Small", "Moyen": "Medium", "Grand": "Large"}
# I wanted to include the c in Fraincais and the spanish e and n in Spanish
def normalize_language(lang):
if lang in ["English", "Inglés", "Anglais"]:
return "English"
elif lang in ["Spanish", "Español", "Espagnol"]:
return "Spanish"
elif lang in ["French", "Français"]:
return "French"
else:
return "English"
def update_all_settings(theme, font_size, language):
target_lang = normalize_language(language)
t = translations[target_lang]
if target_lang == "Spanish":
theme_for_ui = english_to_spanish_theme.get(theme, theme) if theme in english_to_spanish_theme else theme if theme in spanish_to_english_theme else "Oscuro"
elif target_lang == "French":
theme_for_ui = english_to_french_theme.get(theme, theme) if theme in english_to_french_theme else theme if theme in french_to_english_theme else "Sombre"
else: # target is English
theme_for_ui = spanish_to_english_theme.get(theme, theme) if theme in spanish_to_english_theme else theme if theme in english_to_spanish_theme else "Dark"
if target_lang == "Spanish":
font_for_ui = english_to_spanish_font.get(font_size, font_size) if font_size in english_to_spanish_font else font_size if font_size in spanish_to_english_font else "Mediano"
elif target_lang == "French":
font_for_ui = english_to_french_font.get(font_size, font_size) if font_size in english_to_french_font else font_size if font_size in french_to_english_font else "Moyen"
else:
font_for_ui = spanish_to_english_font.get(font_size, font_size) if font_size in spanish_to_english_font else font_size if theme in english_to_spanish_font else "Medium"
if theme in ["Dark", "Light"]:
theme_for_style = theme
elif theme in spanish_to_english_theme:
theme_for_style = spanish_to_english_theme.get(theme, "Dark")
elif theme in french_to_english_theme:
theme_for_style = french_to_english_theme.get(theme, "Dark")
else:
theme_for_style = "Dark"
if font_size in ["Small", "Medium", "Large"]:
font_for_style = font_size
elif font_size in spanish_to_english_font:
font_for_style = spanish_to_english_font.get(font_size, "Medium")
elif font_size in french_to_english_font:
font_for_style = french_to_english_font.get(font_size, "Medium")
else:
font_for_style = "Medium"
dynamic_style = update_styles(theme_for_style, font_for_style)
#Languages
if target_lang == "English":
language_value = "English"
elif target_lang == "Spanish":
language_value = "Español"
elif target_lang == "French":
language_value = "Français"
header_html = f'<p id="header_description">{t["header_description"]}</p>'
return (
dynamic_style,
gr.update(value=header_html),
gr.update(placeholder=t["user_input_placeholder"]),
gr.update(value=t["send_button"]),
gr.update(value=t["settings_markdown"]),
gr.update(value=t["apply_settings_button"]),
gr.update(label=t["theme_label"], choices=t["theme_choices"], value=theme_for_ui),
gr.update(label=t["font_size_label"], choices=t["font_size_choices"], value=font_for_ui),
gr.update(label=t["select_language_label"], choices=t["language_choices"], value=language_value)
)
def update_styles(theme, font_size):
if theme == "Dark":
bg = "#18181B"
text_color = "#EAEAEA"
button_bg = "#56246B"
radio_bg = "#444444"
border_color = "#444444"
placeholder_color = "#e8e8e8"
button_text_color = "#ffffff"
chatbot_bg = "#212125"
settings_box_bg = chatbot_bg
chatbot_text_color = "#ffffff"
purple="#56246B"
light_purple="#795699"
settings_heading_color = text_color
user_msg_bg_color="#333333"
bot_msg_bg_color="#1F1F1F"
msg_text_color="#FFFFFF"
else:
bg = "#F2F2F2"
text_color = "#1C1C1C"
button_bg = "#56246B"
radio_bg = "#CCCCCC"
border_color = "#B0B0B0"
placeholder_color = "#EAEAEA"
button_text_color = "#ffffff"
chatbot_bg = "#fcfcfc"
settings_box_bg = chatbot_bg
chatbot_text_color = "#000000"
purple="#56246B"
light_purple="#795699"
settings_heading_color = "#333333"
user_msg_bg_color="#e0e0e0"
bot_msg_bg_color="#cccccc"
msg_text_color="#000000"
if font_size == "Small":
fsize = "0.8rem"
tab_padding = "4px 8px"
elif font_size == "Medium":
fsize = "1.2rem"
tab_padding = "6px 12px"
elif font_size == "Large":
fsize = "1.8rem"
tab_padding = "8px 16px"
else:
fsize = "1rem"
tab_padding = "5px 10px"
style = f"""
<style id="dynamic_styles">
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');
body, .gradio-container {{
background-color: {bg} !important;
color: {text_color} !important;
font-size: {fsize} !important;
font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
}}
#header_section {{
width: 400px;
height: 100px;
background: url("https://huggingface.co/spaces/MusifyLTD/Musify/resolve/main/logo.png")
no-repeat center center;
background-size: contain;
margin: 0px auto;
margin-bottom: -10px;
}}
#header_description {{
text-align: center;
color: {text_color} !important;
font-size: {fsize} !important;
margin-top: -10px;
margin-bottom: 10px;
}}
#chatbot {{
background-color: {chatbot_bg} !important;
color: {chatbot_text_color} !important;
font-size: {fsize} !important;
border: {border_color} solid 0.5px;
}}
fieldset {{
background-color: {settings_box_bg} !important;
color: {text_color} !important;
border: none;
margin: 0;
}}
div[role="log"] {{
border: none;
background-color: {chatbot_bg} !important;
color: {chatbot_text_color} !important;
font-size: {fsize} !important;
}}
#user_input {{
background-color: {purple} !important;
border: none;
height: 65px;
}}
#user_input textarea {{
background-color: {light_purple} !important;
color: {button_text_color} !important;
font-size: {fsize} !important;
border: 0.5px solid {light_purple} !important;
padding: 10px;
}}
#user_input textarea::placeholder {{
background-color: {light_purple} !important;
color: {placeholder_color} !important;
font-size: {fsize} !important;
opacity: 0.73;
}}
#send_button {{
background-color: {button_bg} !important;
color: {button_text_color} !important;
font-size: {fsize} !important;
border: none;
border-radius: 6px;
margin-left: 1px;
font-family: 'Inter', sans-serif;
height: 65px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 10px;
transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out;
}}
#send_button:hover {{
background-color: {light_purple} !important;
}}
#apply_button {{
background-color: {button_bg} !important;
color: {button_text_color} !important;
font-size: {fsize} !important;
border: none;
border-radius: 6px;
width: 20%;
align-self: center;
font-family: 'Inter', sans-serif;
transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out;
}}
#apply_button:hover {{
background-color: {light_purple} !important;
}}
#settings_box {{
background-color: {settings_box_bg} !important;
color: {text_color} !important;
font-size: {fsize} !important;
border: {border_color} solid 0.5px;
border-radius: 6px;
padding: 10px;
margin: 10px;
}}
h3 {{
color: {text_color} !important;
font-weight: 600;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-size: {fsize} !important;
}}
.form.svelte-633qhp {{
border: {border_color} solid 0.5px;
border-radius: 6px;
}}
label[data-testid] {{
background-color: {bg} !important;
color: {text_color} !important;
}}
[data-testid="block-info"] {{
color: {text_color} !important;
}}
div[role="tablist"] {{
border: 1px;
border-radius: 8px;
padding: {tab_padding} !important;
height: auto !important;
min-height: 0 !important;
}}
div[role="tab"] {{
font-size: {fsize} !important;
padding: {tab_padding} !important;
color: {text_color} !important;
}}
button[role="tab"][aria-selected="true"]::after {{
background-color:{light_purple} !important;
}}
button[role="tab"][aria-selected="true"] {{
color: {text_color} !important;
}}
button[role="tab"][aria-selected="false"] {{
background-color:transparent !important;
color: #616161 !important;
}}
input[type="radio"] {{
background-color: #795699 !important;
}}
input[type="radio"]:checked {{
background-color: #56246B !important;
border-color: #795699 !important;
}}
.user.svelte-pcjl1g.message {{
background-color: {user_msg_bg_color} !important;
color: {msg_text_color} !important;
}}
.bot.svelte-pcjl1g.message {{
background-color: {bot_msg_bg_color} !important;
color: {msg_text_color} !important;
}}
.md.svelte-7ddecg.chatbot.prose > p {{
color: {msg_text_color} !important;
font-size: {fsize} !important;
}}
#example_questions {{
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 10px;
text-align: center;
}}
#example_questions .wrap.svelte-1kzox3m {{
display: contents;
}}
</style>
"""
return style
# Gradio build stuff actually starts here
with gr.Blocks(css=None) as demo:
dynamic_styles = gr.HTML(value=update_styles("Dark", "Medium"))
with gr.Tabs():
with gr.TabItem("💬 Chatbot"):
gr.HTML('<div id="header_section"></div>')
header_desc = gr.HTML('<p id="header_description">' + translations["English"]["header_description"] + '</p>')
chatbot = gr.Chatbot(label="", height=500, show_label=False, elem_id="chatbot")
with gr.Row():
user_input = gr.Textbox(
show_label=False,
lines=1,
placeholder=translations["English"]["user_input_placeholder"],
interactive=True,
elem_id="user_input",
scale=15
)
send_button = gr.Button(
value=translations["English"]["send_button"],
elem_id="send_button",
scale=1
)
conversation_state = gr.State(value=[])
gr.HTML("<br>")
gr.HTML("<h3 style='text-align: center; color: {text_color};'>Need inspiration? Try asking about one of these topics:</h3>")
example_questions = gr.Radio(
choices=[
"🎵 What's some good background music for studying?",
"🔥 Which indie artists are blowing up right now?",
"🎷 Can you recommend iconic jazz albums?",
"🎶 I need a workout playlist—any suggestions?",
"💿 What classic rock albums should I listen to?",
"🎧 Who’s an underrated artist I should check out?"
],
label="",
interactive=True,
elem_id="example_questions"
)
example_questions.change(
fn=lambda x: chat_with_bot_stream(x, conversation_state.value),
inputs=example_questions,
outputs=[chatbot, conversation_state]
)
send_button.click(
fn=chat_with_bot_stream,
inputs=[user_input, conversation_state],
outputs=[chatbot, conversation_state]
).then(
fn=lambda: "",
inputs=None,
outputs=user_input
)
# SETTINGS PAGE
with gr.TabItem(translations["English"]["settings_tab_item"]):
with gr.Column(elem_id="settings_box"):
settings_md = gr.Markdown(translations["English"]["settings_markdown"])
theme_radio = gr.Radio(
choices=translations["English"]["theme_choices"],
value="Dark",
label=translations["English"]["theme_label"],
)
font_radio = gr.Radio(
choices=translations["English"]["font_size_choices"],
value="Medium",
label=translations["English"]["font_size_label"],
)
language_radio = gr.Radio(
choices=translations["English"]["language_choices"],
value="English",
label=translations["English"]["select_language_label"],
)
apply_button = gr.Button(
translations["English"]["apply_settings_button"],
elem_id="apply_button",
)
apply_button.click(
fn=update_all_settings,
inputs=[theme_radio, font_radio, language_radio],
outputs=[
dynamic_styles,
header_desc,
user_input,
send_button,
settings_md,
apply_button,
theme_radio,
font_radio,
language_radio
]
)
demo.launch()