Spaces:
Sleeping
Sleeping
from smolagents import CodeAgent, HfApiModel, tool | |
import datetime | |
import requests | |
import yaml | |
import os | |
import json | |
import gradio as gr | |
from tools.final_answer import FinalAnswerTool | |
# File to save the history of recognized songs | |
HISTORY_FILE = "song_history.json" | |
# Supported languages | |
LANGUAGES = { | |
"English": "en", | |
"Español": "es", | |
"Français": "fr" | |
} | |
# Language-specific messages | |
MESSAGES = { | |
"en": { | |
"title": "# 🎵 Music Recognition & Fun Facts", | |
"subtitle": "Identify songs, learn interesting facts about artists, and chat about music", | |
"language_label": "Choose your language", | |
"rec_button": "REC FOR 10 SECONDS", | |
"recognize_button": "RECOGNIZE SONG", | |
"no_audio": "Please record an audio clip", | |
"loading": "Recording... Click Stop when done (10 seconds max)", | |
"audio_loaded": "✅ Audio loaded! Ready to recognize", | |
"uploading": "Please wait while the audio is being uploaded...", | |
"searching": "Searching your song in the sonic multiverse, please wait to discover amazing facts about your artist. This is a beta version, it might be a bit slow, please be patient...", | |
"recognized": "✅ Song successfully recognized!", | |
"error": "❌ Error recognizing the song: {error}", | |
"artist_info_title": "### 🌟 About the Artist", | |
"history_title": "### Song History", | |
"history_button": "View History", | |
"history_limit_label": "Number of songs to show", | |
"no_history": "📋 No song recognition history yet", | |
"empty_history": "📋 Song history is empty", | |
"history_error": "❌ Error loading song history: {error}", | |
"chat_title": "### Ask me more about this artist or music in general", | |
"chat_placeholder": "Ask about the artist, song, or anything music related...", | |
"chat_button": "Send" | |
}, | |
"es": { | |
"title": "# 🎵 Reconocimiento Musical y Datos Curiosos", | |
"subtitle": "Identifica canciones, aprende datos interesantes sobre artistas y chatea sobre música", | |
"language_label": "Elige tu idioma", | |
"rec_button": "GRABAR POR 10 SEGUNDOS", | |
"recognize_button": "RECONOCER CANCIÓN", | |
"no_audio": "Por favor graba un clip de audio", | |
"loading": "Grabando... Haz clic en Detener cuando termines (máximo 10 segundos)", | |
"audio_loaded": "✅ ¡Audio cargado! Listo para reconocer", | |
"uploading": "Por favor espera mientras se carga el audio...", | |
"searching": "Buscando tu canción en el multiverso sónico, por favor espera para descubrir datos increíbles sobre tu artista. Esta es una versión beta, puede ser un poco lenta, por favor ten paciencia...", | |
"recognized": "✅ ¡Canción reconocida con éxito!", | |
"error": "❌ Error al reconocer la canción: {error}", | |
"artist_info_title": "### 🌟 Sobre el Artista", | |
"history_title": "### Historial de Canciones", | |
"history_button": "Ver Historial", | |
"history_limit_label": "Número de canciones a mostrar", | |
"no_history": "📋 No hay historial de canciones reconocidas todavía", | |
"empty_history": "📋 El historial de canciones está vacío", | |
"history_error": "❌ Error al cargar el historial: {error}", | |
"chat_title": "### Pregúntame más sobre este artista o música en general", | |
"chat_placeholder": "Pregunta sobre el artista, la canción o cualquier tema musical...", | |
"chat_button": "Enviar" | |
}, | |
"fr": { | |
"title": "# 🎵 Reconnaissance Musicale et Anecdotes", | |
"subtitle": "Identifiez des chansons, découvrez des faits intéressants sur les artistes et discutez de musique", | |
"language_label": "Choisissez votre langue", | |
"rec_button": "ENREGISTRER PENDANT 10 SECONDES", | |
"recognize_button": "RECONNAÎTRE LA CHANSON", | |
"no_audio": "Veuillez enregistrer un clip audio", | |
"loading": "Enregistrement... Cliquez sur Arrêter quand c'est fini (10 secondes maximum)", | |
"audio_loaded": "✅ Audio chargé ! Prêt à reconnaître", | |
"uploading": "Veuillez patienter pendant le chargement de l'audio...", | |
"searching": "Recherche de votre chanson dans le multivers sonore, veuillez patienter pour découvrir des faits incroyables sur votre artiste. Ceci est une version bêta, cela peut être un peu lent, soyez patient...", | |
"recognized": "✅ Chanson reconnue avec succès !", | |
"error": "❌ Erreur lors de la reconnaissance de la chanson : {error}", | |
"artist_info_title": "### 🌟 À propos de l'Artiste", | |
"history_title": "### Historique des Chansons", | |
"history_button": "Voir l'Historique", | |
"history_limit_label": "Nombre de chansons à afficher", | |
"no_history": "📋 Aucun historique de reconnaissance de chansons pour l'instant", | |
"empty_history": "📋 L'historique des chansons est vide", | |
"history_error": "❌ Erreur lors du chargement de l'historique : {error}", | |
"chat_title": "### Posez-moi des questions sur cet artiste ou la musique en général", | |
"chat_placeholder": "Posez des questions sur l'artiste, la chanson ou tout sujet musical...", | |
"chat_button": "Envoyer" | |
} | |
} | |
def recognize_song(audio_path: str) -> dict: | |
"""Recognizes a song from an audio file | |
Args: | |
audio_path: path to the audio file to recognize | |
""" | |
AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN") | |
if not os.path.exists(audio_path): | |
return {"error": "The audio file does not exist"} | |
try: | |
with open(audio_path, 'rb') as file: | |
data = {'api_token': AUDD_API_TOKEN, 'return': 'spotify,apple_music'} | |
files = {'file': file} | |
response = requests.post('https://api.audd.io/', data=data, files=files) | |
if response.status_code != 200: | |
return {"error": f"API Error: {response.status_code}"} | |
result = response.json() | |
if result['status'] == 'error': | |
return {"error": result['error']['error_message']} | |
if not result.get('result'): | |
return {"error": "Could not recognize the song"} | |
song_info = result['result'] | |
song_data = { | |
"Song": song_info.get('title', 'Unknown'), | |
"Artist": song_info.get('artist', 'Unknown'), | |
"Album": song_info.get('album', 'Unknown'), | |
"Spotify": song_info.get('spotify', {}).get('external_urls', {}).get('spotify', 'Not available'), | |
"Apple Music": song_info.get('apple_music', {}).get('url', 'Not available'), | |
"Recognition Date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
} | |
save_to_history(song_data) | |
return song_data | |
except Exception as e: | |
return {"error": f"Error processing audio: {str(e)}"} | |
def save_to_history(song_data): | |
"""Saves a song to the history""" | |
try: | |
if os.path.exists(HISTORY_FILE): | |
with open(HISTORY_FILE, 'r') as f: | |
try: | |
history = json.load(f) | |
except json.JSONDecodeError: | |
history = [] | |
else: | |
history = [] | |
history.insert(0, song_data) | |
if len(history) > 50: | |
history = history[:50] | |
with open(HISTORY_FILE, 'w') as f: | |
json.dump(history, f, indent=2) | |
except Exception as e: | |
print(f"Error saving to history: {str(e)}") | |
def view_song_history(limit: int = 10, language: str = "en") -> str: | |
"""Shows the history of recognized songs | |
Args: | |
limit: maximum number of songs to display (default 10) | |
language: language code (en, es, fr) | |
""" | |
lang = language | |
try: | |
if not os.path.exists(HISTORY_FILE): | |
return f"📋 {MESSAGES[lang]['no_history']}" | |
with open(HISTORY_FILE, 'r') as f: | |
try: | |
history = json.load(f) | |
except json.JSONDecodeError: | |
return f"📋 Error loading song history." | |
if not history: | |
return f"📋 {MESSAGES[lang]['empty_history']}" | |
history = history[:min(limit, len(history))] | |
result = f"📋 **{MESSAGES[lang]['history_title']}:**\n\n" | |
for i, song in enumerate(history, 1): | |
result += f"{i}. **{song.get('Song', 'Unknown')}** - *{song.get('Artist', 'Unknown')}*\n" | |
result += f" 📀 Album: {song.get('Album', 'Unknown')}\n" | |
if song.get('Spotify', 'Not available') != 'Not available': | |
result += f" 🎧 [Spotify]({song.get('Spotify')})\n" | |
if song.get('Apple Music', 'Not available') != 'Not available': | |
result += f" 🍏 [Apple Music]({song.get('Apple Music')})\n" | |
result += f" 🕒 Recognized on: {song.get('Recognition Date', 'Unknown date')}\n\n" | |
return result | |
except Exception as e: | |
return f"❌ {MESSAGES[lang]['history_error'].format(error=str(e))}" | |
def get_artist_info(artist_name: str, song_title: str, language: str = "en") -> dict: | |
"""Gets detailed artist info including anecdotes and song creation facts | |
Args: | |
artist_name: name of the artist | |
song_title: title of the song | |
language: language code (en, es, fr) | |
""" | |
prompts = { | |
"en": f"Provide a detailed overview of the music artist '{artist_name}' including general information about their career, anecdotes, fun facts about the group, and specific details about the creation of their song '{song_title}' if available. Include an image URL if possible. Keep it engaging and positive.", | |
"es": f"Proporciona una visión detallada del artista musical '{artist_name}' incluyendo información general sobre su carrera, anécdotas, datos curiosos sobre el grupo y detalles específicos sobre la creación de su canción '{song_title}' si están disponibles. Incluye una URL de imagen si es posible. Mantenlo atractivo y positivo.", | |
"fr": f"Fournissez un aperçu détaillé de l'artiste musical '{artist_name}' incluant des informations générales sur sa carrière, des anecdotes, des faits amusants sur le groupe et des détails spécifiques sur la création de sa chanson '{song_title}' si disponibles. Incluez une URL d'image si possible. Gardez-le engageant et positif." | |
} | |
if language not in prompts: | |
language = "en" | |
messages = [{"role": "user", "content": prompts[language]}] | |
try: | |
response = model(messages) | |
content = response.content | |
image_url = None | |
if "[Image:" in content: | |
start = content.find("[Image:") + 7 | |
end = content.find("]", start) | |
image_url = content[start:end].strip() | |
content = content[:start-7] + content[end+1:] | |
return {"text": content.strip(), "image": image_url} | |
except Exception as e: | |
return {"text": f"Could not retrieve information about {artist_name}: {str(e)}", "image": None} | |
# Agent configuration | |
final_answer = FinalAnswerTool() | |
model = HfApiModel( | |
max_tokens=2096, | |
temperature=0.5, | |
model_id='Qwen/Qwen2.5-Coder-32B-Instruct', | |
custom_role_conversions=None, | |
) | |
with open("prompts.yaml", 'r') as stream: | |
prompt_templates = yaml.safe_load(stream) | |
agent = CodeAgent( | |
model=model, | |
tools=[final_answer, recognize_song, view_song_history, get_artist_info], | |
max_steps=8, | |
verbosity_level=1, | |
) | |
with gr.Blocks(title="Music Recognition & Fun Facts", css=".large-text {font-size: 1.5em !important;} .big-button {font-size: 1.2em; padding: 15px 30px;}") as demo: | |
selected_language = gr.State("en") # Cambiado a "en" en lugar de "English" | |
song_info_state = gr.State(None) | |
audio_status = gr.State("no_audio") | |
gr.Markdown(lambda: MESSAGES[selected_language.value]["title"]) | |
gr.Markdown(lambda: MESSAGES[selected_language.value]["subtitle"]) | |
with gr.Row(): | |
language_dropdown = gr.Dropdown( | |
choices=[("English", "en"), ("Español", "es"), ("Français", "fr")], # Tuplas (label, value) | |
value="en", # Valor inicial es el código | |
label=lambda: MESSAGES[selected_language.value]["language_label"] | |
) | |
with gr.Tab("Song Recognition"): | |
audio_status_msg = gr.Markdown(lambda: MESSAGES[selected_language.value]["no_audio"]) | |
with gr.Row(): | |
with gr.Column(scale=1): | |
audio_input = gr.Audio(type="filepath", visible=False, source="microphone") | |
record_btn = gr.Button( | |
lambda: MESSAGES[selected_language.value]["rec_button"], | |
elem_classes="big-button", | |
variant="primary" | |
) | |
audio_loaded_msg = gr.Markdown("", elem_classes="large-text") | |
recognize_btn = gr.Button( | |
lambda: MESSAGES[selected_language.value]["recognize_button"], | |
variant="secondary" | |
) | |
recognition_results = gr.Markdown("") | |
artist_info_text = gr.Markdown("") | |
artist_info_image = gr.Image(type="url", label="Artist Image") | |
gr.Markdown(lambda: MESSAGES[selected_language.value]["chat_title"]) | |
chat_history = gr.Chatbot(label="Music Chat") | |
with gr.Row(): | |
chat_input = gr.Textbox( | |
placeholder=lambda: MESSAGES[selected_language.value]["chat_placeholder"], | |
label="Your question" | |
) | |
chat_btn = gr.Button( | |
lambda: MESSAGES[selected_language.value]["chat_button"], | |
variant="primary" | |
) | |
with gr.Row(): | |
history_limit = gr.Slider( | |
minimum=5, maximum=50, value=10, step=5, | |
label=lambda: MESSAGES[selected_language.value]["history_limit_label"] | |
) | |
view_history_btn = gr.Button( | |
lambda: MESSAGES[selected_language.value]["history_button"] | |
) | |
history_output = gr.Markdown("") | |
def toggle_audio_widget(): | |
lang = selected_language.value | |
return gr.update(visible=True), "loading", MESSAGES[lang]["loading"] | |
def update_audio_status(audio_path): | |
lang = selected_language.value | |
if audio_path: | |
return "ready", MESSAGES[lang]["audio_loaded"] | |
return "no_audio", MESSAGES[lang]["no_audio"] | |
def process_audio(audio_path, language_name, status): | |
lang = language_name | |
if not audio_path or status != "ready": | |
return None, "", "", MESSAGES[lang]["no_audio"], "" | |
yield None, "", "", MESSAGES[lang]["uploading"], "" | |
yield None, "", "", MESSAGES[lang]["searching"], "" | |
result = recognize_song(audio_path) | |
if "error" in result: | |
return None, "", "", MESSAGES[lang]["error"].format(error=result['error']), "" | |
recognition_msg = f"### 🎵 {result['Song']}\n\n" | |
recognition_msg += f"**🎤 Artist:** {result['Artist']}\n" | |
recognition_msg += f"**📀 Album:** {result['Album']}\n" | |
if result['Spotify'] != "Not available": | |
recognition_msg += f"**🎧 [Spotify]({result['Spotify']})**\n" | |
if result['Apple Music'] != "Not available": | |
recognition_msg += f"**🍏 [Apple Music]({result['Apple Music']})**\n" | |
artist_info = get_artist_info(result['Artist'], result['Song'], lang) | |
artist_info_content = f"{MESSAGES[lang]['artist_info_title']}\n\n{artist_info['text']}" | |
return result, recognition_msg, artist_info_content, MESSAGES[lang]["recognized"], artist_info['image'] or "" | |
def process_chat(query, language_name, song_info): | |
lang = language_name | |
if not query or not song_info: | |
return [] | |
try: | |
response = chat_with_assistant(query, "", lang) | |
return [(query, response)] | |
except Exception as e: | |
return [(query, f"Sorry, I couldn't process your request: {str(e)}")] | |
def view_history_process(limit, language_name): | |
return view_song_history(int(limit), language_name) | |
def update_language(language_name): | |
lang = language_name | |
return ( | |
MESSAGES[lang]["title"], | |
MESSAGES[lang]["subtitle"], | |
gr.update(label=MESSAGES[lang]["language_label"]), | |
MESSAGES[lang]["rec_button"], | |
MESSAGES[lang]["recognize_button"], | |
MESSAGES[lang]["chat_title"], | |
gr.update(placeholder=MESSAGES[lang]["chat_placeholder"]), | |
MESSAGES[lang]["chat_button"], | |
gr.update(label=MESSAGES[lang]["history_limit_label"]), | |
MESSAGES[lang]["history_button"] | |
) | |
language_dropdown.change( | |
fn=update_language, | |
inputs=[language_dropdown], | |
outputs=[demo.get_component(0), demo.get_component(1), language_dropdown, record_btn, recognize_btn, demo.get_component(8), chat_input, chat_btn, history_limit, view_history_btn] | |
) | |
record_btn.click( | |
fn=toggle_audio_widget, | |
inputs=[], | |
outputs=[audio_input, audio_status, audio_status_msg] | |
) | |
audio_input.change( | |
fn=update_audio_status, | |
inputs=[audio_input], | |
outputs=[audio_status, audio_loaded_msg] | |
) | |
recognize_btn.click( | |
fn=process_audio, | |
inputs=[audio_input, language_dropdown, audio_status], | |
outputs=[song_info_state, recognition_results, artist_info_text, audio_status_msg, artist_info_image] | |
) | |
chat_btn.click( | |
fn=process_chat, | |
inputs=[chat_input, language_dropdown, song_info_state], | |
outputs=[chat_history] | |
).then( | |
fn=lambda: "", | |
inputs=[], | |
outputs=[chat_input] | |
) | |
view_history_btn.click( | |
fn=view_history_process, | |
inputs=[history_limit, language_dropdown], | |
outputs=[history_output] | |
) | |
demo.launch() |