Spaces:
Sleeping
Sleeping
Manuel Zafra
commited on
Update app.py
Browse files
app.py
CHANGED
@@ -6,112 +6,54 @@ import os
|
|
6 |
import json
|
7 |
import gradio as gr
|
8 |
from tools.final_answer import FinalAnswerTool
|
9 |
-
import tempfile
|
10 |
-
import shutil
|
11 |
|
12 |
-
#
|
13 |
HISTORY_FILE = "song_history.json"
|
14 |
|
|
|
15 |
LANGUAGES = {
|
16 |
"English": "en",
|
17 |
"Español": "es",
|
18 |
"Français": "fr"
|
19 |
}
|
20 |
|
21 |
-
|
22 |
-
"en": {
|
23 |
-
"title": "# 🎵 Music Recognition & Fun Facts",
|
24 |
-
"subtitle": "Identify songs, learn interesting facts about artists, and chat about music",
|
25 |
-
"language_label": "Choose your language",
|
26 |
-
"rec_button": "REC FOR 10 SECONDS",
|
27 |
-
"recognize_button": "RECOGNIZE SONG",
|
28 |
-
"no_audio": "Please record an audio clip",
|
29 |
-
"loading": "Recording... Click Stop when done (10 seconds max)",
|
30 |
-
"audio_loaded": "✅ Audio loaded! Ready to recognize",
|
31 |
-
"uploading": "Please wait while the audio is being uploaded...",
|
32 |
-
"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...",
|
33 |
-
"recognized": "✅ Song successfully recognized!",
|
34 |
-
"error": "❌ Error recognizing the song: {error}",
|
35 |
-
"artist_info_title": "### 🌟 About the Artist",
|
36 |
-
"history_title": "### History of recognized songs",
|
37 |
-
"history_button": "View History",
|
38 |
-
"history_limit_label": "Number of songs to show",
|
39 |
-
"no_history": "📋 No song recognition history yet",
|
40 |
-
"empty_history": "📋 Song history is empty",
|
41 |
-
"history_error": "❌ Error getting history: {error}",
|
42 |
-
"chat_title": "### Ask me more about this artist or music in general",
|
43 |
-
"chat_placeholder": "Ask about the artist, song, or anything music related...",
|
44 |
-
"chat_button": "Send"
|
45 |
-
},
|
46 |
-
"es": {
|
47 |
-
"title": "# 🎵 Reconocimiento Musical y Datos Curiosos",
|
48 |
-
"subtitle": "Identifica canciones, aprende datos interesantes sobre artistas y chatea sobre música",
|
49 |
-
"language_label": "Elige tu idioma",
|
50 |
-
"rec_button": "GRABAR POR 10 SEGUNDOS",
|
51 |
-
"recognize_button": "RECONOCER CANCIÓN",
|
52 |
-
"no_audio": "Por favor graba un clip de audio",
|
53 |
-
"loading": "Grabando... Haz clic en Detener cuando termines (máximo 10 segundos)",
|
54 |
-
"audio_loaded": "✅ ¡Audio cargado! Listo para reconocer",
|
55 |
-
"uploading": "Por favor espera mientras se carga el audio...",
|
56 |
-
"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...",
|
57 |
-
"recognized": "✅ ¡Canción reconocida con éxito!",
|
58 |
-
"error": "❌ Error al reconocer la canción: {error}",
|
59 |
-
"artist_info_title": "### 🌟 Sobre el Artista",
|
60 |
-
"history_title": "### Historial de canciones reconocidas",
|
61 |
-
"history_button": "Ver Historial",
|
62 |
-
"history_limit_label": "Número de canciones a mostrar",
|
63 |
-
"no_history": "📋 No hay historial de canciones reconocidas todavía",
|
64 |
-
"empty_history": "📋 El historial de canciones está vacío",
|
65 |
-
"history_error": "❌ Error al obtener el historial: {error}",
|
66 |
-
"chat_title": "### Pregúntame más sobre este artista o música en general",
|
67 |
-
"chat_placeholder": "Pregunta sobre el artista, la canción o cualquier tema musical...",
|
68 |
-
"chat_button": "Enviar"
|
69 |
-
},
|
70 |
-
"fr": {
|
71 |
-
"title": "# 🎵 Reconnaissance Musicale et Anecdotes",
|
72 |
-
"subtitle": "Identifiez des chansons, découvrez des faits intéressants sur les artistes et discutez de musique",
|
73 |
-
"language_label": "Choisissez votre langue",
|
74 |
-
"rec_button": "ENREGISTRER PENDANT 10 SECONDES",
|
75 |
-
"recognize_button": "RECONNAÎTRE LA CHANSON",
|
76 |
-
"no_audio": "Veuillez enregistrer un clip audio",
|
77 |
-
"loading": "Enregistrement... Cliquez sur Arrêter quand c'est fini (10 secondes maximum)",
|
78 |
-
"audio_loaded": "✅ Audio chargé ! Prêt à reconnaître",
|
79 |
-
"uploading": "Veuillez patienter pendant le chargement de l'audio...",
|
80 |
-
"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...",
|
81 |
-
"recognized": "✅ Chanson reconnue avec succès !",
|
82 |
-
"error": "❌ Erreur lors de la reconnaissance de la chanson : {error}",
|
83 |
-
"artist_info_title": "### 🌟 À propos de l'Artiste",
|
84 |
-
"history_title": "### Historique des chansons reconnues",
|
85 |
-
"history_button": "Voir l'Historique",
|
86 |
-
"history_limit_label": "Nombre de chansons à afficher",
|
87 |
-
"no_history": "📋 Aucun historique de reconnaissance de chansons pour l'instant",
|
88 |
-
"empty_history": "📋 L'historique des chansons est vide",
|
89 |
-
"history_error": "❌ Erreur lors de l'obtention de l'historique : {error}",
|
90 |
-
"chat_title": "### Posez-moi des questions sur cet artiste ou la musique en général",
|
91 |
-
"chat_placeholder": "Posez des questions sur l'artiste, la chanson ou tout sujet musical...",
|
92 |
-
"chat_button": "Envoyer"
|
93 |
-
}
|
94 |
-
}
|
95 |
-
|
96 |
-
# Herramientas
|
97 |
@tool
|
98 |
def recognize_song(audio_path: str) -> dict:
|
|
|
|
|
|
|
|
|
99 |
AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN")
|
|
|
100 |
if not os.path.exists(audio_path):
|
101 |
return {"error": "The audio file does not exist"}
|
|
|
102 |
try:
|
103 |
with open(audio_path, 'rb') as file:
|
104 |
-
data = {
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
106 |
response = requests.post('https://api.audd.io/', data=data, files=files)
|
|
|
107 |
if response.status_code != 200:
|
108 |
return {"error": f"API Error: {response.status_code}"}
|
|
|
109 |
result = response.json()
|
|
|
110 |
if result['status'] == 'error':
|
111 |
return {"error": result['error']['error_message']}
|
|
|
112 |
if not result.get('result'):
|
113 |
return {"error": "Could not recognize the song"}
|
|
|
114 |
song_info = result['result']
|
|
|
|
|
115 |
song_data = {
|
116 |
"Song": song_info.get('title', 'Unknown'),
|
117 |
"Artist": song_info.get('artist', 'Unknown'),
|
@@ -120,92 +62,156 @@ def recognize_song(audio_path: str) -> dict:
|
|
120 |
"Apple Music": song_info.get('apple_music', {}).get('url', 'Not available'),
|
121 |
"Recognition Date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
122 |
}
|
|
|
|
|
123 |
save_to_history(song_data)
|
|
|
124 |
return song_data
|
|
|
125 |
except Exception as e:
|
126 |
return {"error": f"Error processing audio: {str(e)}"}
|
127 |
|
|
|
128 |
def save_to_history(song_data):
|
|
|
129 |
try:
|
|
|
130 |
if os.path.exists(HISTORY_FILE):
|
131 |
with open(HISTORY_FILE, 'r') as f:
|
132 |
-
|
|
|
|
|
|
|
133 |
else:
|
134 |
history = []
|
|
|
|
|
135 |
history.insert(0, song_data)
|
|
|
|
|
136 |
if len(history) > 50:
|
137 |
history = history[:50]
|
|
|
|
|
138 |
with open(HISTORY_FILE, 'w') as f:
|
139 |
json.dump(history, f, indent=2)
|
|
|
140 |
except Exception as e:
|
141 |
print(f"Error saving to history: {str(e)}")
|
142 |
|
|
|
143 |
@tool
|
144 |
-
def view_song_history(limit: int = 10
|
145 |
-
|
|
|
|
|
|
|
146 |
try:
|
147 |
if not os.path.exists(HISTORY_FILE):
|
148 |
-
return
|
|
|
149 |
with open(HISTORY_FILE, 'r') as f:
|
150 |
-
|
|
|
|
|
|
|
|
|
151 |
if not history:
|
152 |
-
return
|
|
|
|
|
153 |
history = history[:min(limit, len(history))]
|
154 |
-
|
|
|
|
|
|
|
155 |
for i, song in enumerate(history, 1):
|
156 |
result += f"{i}. **{song.get('Song', 'Unknown')}** - *{song.get('Artist', 'Unknown')}*\n"
|
157 |
result += f" 📀 Album: {song.get('Album', 'Unknown')}\n"
|
|
|
158 |
if song.get('Spotify', 'Not available') != 'Not available':
|
159 |
result += f" 🎧 [Spotify]({song.get('Spotify')})\n"
|
|
|
160 |
if song.get('Apple Music', 'Not available') != 'Not available':
|
161 |
result += f" 🍏 [Apple Music]({song.get('Apple Music')})\n"
|
|
|
162 |
result += f" 🕒 Recognized on: {song.get('Recognition Date', 'Unknown date')}\n\n"
|
|
|
163 |
return result
|
|
|
164 |
except Exception as e:
|
165 |
-
return f"❌ {
|
166 |
|
|
|
167 |
@tool
|
168 |
-
def get_artist_info(artist_name: str,
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
prompts = {
|
170 |
-
"en": f"Provide interesting and fun facts about the music artist '{artist_name}' that fans would love to know. Include stories about their career, personal anecdotes, how their
|
171 |
-
"es": f"Proporciona datos interesantes y curiosos sobre el artista musical '{artist_name}' que a los fans les encantaría conocer. Incluye historias sobre su carrera, anécdotas personales, cómo se
|
172 |
-
"fr": f"Fournissez des faits intéressants et amusants sur l'artiste musical '{artist_name}' que les fans aimeraient connaître. Incluez des histoires sur leur carrière, des anecdotes personnelles, comment
|
173 |
}
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
try:
|
|
|
177 |
response = model(messages)
|
178 |
-
|
179 |
-
image_url = None
|
180 |
-
if "[Image:" in content:
|
181 |
-
start = content.find("[Image:") + 7
|
182 |
-
end = content.find("]", start)
|
183 |
-
image_url = content[start:end].strip()
|
184 |
-
content = content[:start-7] + content[end+1:]
|
185 |
-
return {"text": content.strip(), "image": image_url}
|
186 |
except Exception as e:
|
187 |
-
return
|
188 |
|
|
|
189 |
@tool
|
190 |
def chat_with_assistant(query: str, artist_info: str = "", language: str = "en") -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
191 |
system_messages = {
|
192 |
"en": "You are a music expert assistant who specializes in providing engaging information about artists, songs, and music history. Focus on sharing interesting, fun facts that highlight the artist's unique contributions and stories.",
|
193 |
"es": "Eres un asistente experto en música que se especializa en proporcionar información interesante sobre artistas, canciones e historia musical. Céntrate en compartir datos curiosos e interesantes que destaquen las contribuciones únicas y las historias del artista.",
|
194 |
-
"fr": "Vous êtes un assistant expert en musique qui se spécialise dans la fourniture d'informations intéressantes sur les artistes, les chansons et l'histoire de la musique. Concentrez-vous sur le partage de faits intéressants et amusants qui mettent en évidence les contributions uniques et les histoires de l'artiste."
|
195 |
}
|
196 |
-
|
197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
messages = [
|
199 |
{"role": "system", "content": system_messages[language]},
|
200 |
{"role": "user", "content": context + query}
|
201 |
]
|
|
|
202 |
try:
|
|
|
203 |
response = model(messages)
|
204 |
return response.content
|
205 |
except Exception as e:
|
206 |
return f"Sorry, I couldn't process your request: {str(e)}"
|
207 |
|
208 |
-
#
|
209 |
final_answer = FinalAnswerTool()
|
210 |
model = HfApiModel(
|
211 |
max_tokens=2096,
|
@@ -217,9 +223,16 @@ model = HfApiModel(
|
|
217 |
with open("prompts.yaml", 'r') as stream:
|
218 |
prompt_templates = yaml.safe_load(stream)
|
219 |
|
|
|
220 |
agent = CodeAgent(
|
221 |
model=model,
|
222 |
-
tools=[
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
max_steps=8,
|
224 |
verbosity_level=1,
|
225 |
grammar=None,
|
@@ -229,177 +242,194 @@ agent = CodeAgent(
|
|
229 |
prompt_templates=prompt_templates
|
230 |
)
|
231 |
|
232 |
-
#
|
233 |
-
|
234 |
-
|
235 |
-
return ""
|
236 |
-
try:
|
237 |
-
response = requests.get(image_url, stream=True)
|
238 |
-
if response.status_code == 200:
|
239 |
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
|
240 |
-
shutil.copyfileobj(response.raw, temp_file)
|
241 |
-
temp_file.close()
|
242 |
-
return temp_file.name
|
243 |
-
return ""
|
244 |
-
except Exception:
|
245 |
-
return ""
|
246 |
-
|
247 |
-
# Interfaz de usuario con Gradio
|
248 |
-
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:
|
249 |
selected_language = gr.State("en")
|
250 |
song_info_state = gr.State(None)
|
251 |
artist_info_state = gr.State("")
|
252 |
-
audio_status = gr.State("no_audio")
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
|
|
|
|
257 |
with gr.Row():
|
258 |
language_dropdown = gr.Dropdown(
|
259 |
-
choices=
|
260 |
-
value="
|
261 |
-
label=
|
262 |
)
|
263 |
-
|
|
|
264 |
with gr.Tab("Song Recognition & Chat"):
|
265 |
-
|
|
|
|
|
|
|
266 |
with gr.Row():
|
267 |
with gr.Column(scale=1):
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
recognize_btn = gr.Button(
|
272 |
-
|
|
|
273 |
with gr.Row():
|
274 |
recognition_results = gr.Markdown("")
|
275 |
-
|
|
|
276 |
with gr.Row():
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
chat_history = gr.Chatbot(label="Music Chat"
|
282 |
-
|
283 |
with gr.Row():
|
284 |
chat_input = gr.Textbox(
|
285 |
-
placeholder=
|
286 |
-
label="
|
287 |
-
elem_id="chat_input"
|
288 |
)
|
289 |
-
chat_btn = gr.Button(
|
290 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
with gr.Tab("Song History"):
|
292 |
-
gr.Markdown(
|
|
|
293 |
with gr.Row():
|
294 |
-
history_limit = gr.Slider(minimum=5, maximum=50, value=10, step=5, label=
|
295 |
-
view_history_btn = gr.Button(
|
|
|
296 |
history_output = gr.Markdown()
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
MESSAGES[lang]["recognize_button"],
|
306 |
-
MESSAGES[lang]["chat_title"],
|
307 |
-
MESSAGES[lang]["chat_placeholder"],
|
308 |
-
MESSAGES[lang]["chat_button"],
|
309 |
-
MESSAGES[lang]["history_limit_label"],
|
310 |
-
MESSAGES[lang]["history_button"]
|
311 |
)
|
312 |
|
313 |
-
language_dropdown.change(
|
314 |
-
fn=update_ui,
|
315 |
-
inputs=[language_dropdown],
|
316 |
-
outputs=[title, subtitle, audio_status_msg, record_btn, recognize_btn, chat_title, chat_input, chat_btn, history_limit, view_history_btn]
|
317 |
-
)
|
318 |
-
|
319 |
-
def toggle_audio_widget(language_name):
|
320 |
-
lang = LANGUAGES.get(language_name, "en")
|
321 |
-
return gr.update(visible=True), "loading", MESSAGES[lang]["loading"]
|
322 |
-
|
323 |
-
record_btn.click(
|
324 |
-
fn=toggle_audio_widget,
|
325 |
-
inputs=[language_dropdown],
|
326 |
-
outputs=[audio_input, audio_status, audio_status_msg]
|
327 |
-
)
|
328 |
-
|
329 |
-
def update_audio_status(audio_path, language_name):
|
330 |
-
lang = LANGUAGES.get(language_name, "en")
|
331 |
-
if audio_path:
|
332 |
-
return "ready", MESSAGES[lang]["audio_loaded"]
|
333 |
-
else:
|
334 |
-
return "no_audio", MESSAGES[lang]["no_audio"]
|
335 |
-
|
336 |
-
audio_input.change(
|
337 |
-
fn=update_audio_status,
|
338 |
-
inputs=[audio_input, language_dropdown],
|
339 |
-
outputs=[audio_status, audio_loaded_msg]
|
340 |
-
)
|
341 |
-
|
342 |
-
def process_audio(audio_path, language_name, status):
|
343 |
-
lang = LANGUAGES.get(language_name, "en")
|
344 |
-
if not audio_path or status != "ready":
|
345 |
-
return None, "", "", MESSAGES[lang]["no_audio"], ""
|
346 |
-
yield None, "", "", MESSAGES[lang]["uploading"], ""
|
347 |
-
yield None, "", "", MESSAGES[lang]["searching"], ""
|
348 |
-
try:
|
349 |
-
result = recognize_song(audio_path)
|
350 |
-
if "error" in result:
|
351 |
-
return None, "", "", MESSAGES[lang]["error"].format(error=result['error']), ""
|
352 |
-
artist_info = get_artist_info(result['Artist'], result['Song'], lang)
|
353 |
-
recognition_msg = f"### 🎵 Recognized Song: {result['Song']}\n\n**🎤 Artist:** {result['Artist']}\n**📀 Album:** {result['Album']}\n\n"
|
354 |
-
if result['Spotify'] != "Not available":
|
355 |
-
recognition_msg += f"**🎧 [Listen on Spotify]({result['Spotify']})**\n"
|
356 |
-
if result['Apple Music'] != "Not available":
|
357 |
-
recognition_msg += f"**🍏 [Listen on Apple Music]({result['Apple Music']})**\n"
|
358 |
-
artist_facts_content = f"{MESSAGES[lang]['artist_info_title']}\n\n{artist_info['text']}"
|
359 |
-
image_filepath = download_image(artist_info['image']) if artist_info['image'] else ""
|
360 |
-
status_msg = MESSAGES[lang]["recognized"]
|
361 |
-
return result, recognition_msg, artist_facts_content, status_msg, image_filepath
|
362 |
-
except Exception as e:
|
363 |
-
return None, "", "", MESSAGES[lang]["error"].format(error=str(e)), ""
|
364 |
-
|
365 |
-
recognize_btn.click(
|
366 |
-
fn=process_audio,
|
367 |
-
inputs=[audio_input, language_dropdown, audio_status],
|
368 |
-
outputs=[song_info_state, recognition_results, artist_info_text, audio_status_msg, artist_info_image]
|
369 |
-
).then(
|
370 |
-
fn=lambda a: a,
|
371 |
-
inputs=[artist_info_text],
|
372 |
-
outputs=[artist_info_state]
|
373 |
-
)
|
374 |
-
|
375 |
-
def process_chat(query, language_name, song_info, artist_info):
|
376 |
-
lang = LANGUAGES.get(language_name, "en")
|
377 |
-
if not query:
|
378 |
-
return []
|
379 |
-
try:
|
380 |
-
response = chat_with_assistant(query, artist_info, lang)
|
381 |
-
return [(query, response)]
|
382 |
-
except Exception as e:
|
383 |
-
return [(query, f"Sorry, I couldn't process your request: {str(e)}")]
|
384 |
-
|
385 |
-
chat_btn.click(
|
386 |
-
fn=process_chat,
|
387 |
-
inputs=[chat_input, language_dropdown, song_info_state, artist_info_state],
|
388 |
-
outputs=[chat_history]
|
389 |
-
).then(
|
390 |
-
fn=lambda: "",
|
391 |
-
inputs=[],
|
392 |
-
outputs=[chat_input]
|
393 |
-
)
|
394 |
-
|
395 |
-
def view_history_process(limit, language_name):
|
396 |
-
lang = LANGUAGES.get(language_name, "en")
|
397 |
-
return view_song_history(int(limit), lang)
|
398 |
-
|
399 |
-
view_history_btn.click(
|
400 |
-
fn=view_history_process,
|
401 |
-
inputs=[history_limit, language_dropdown],
|
402 |
-
outputs=[history_output]
|
403 |
-
)
|
404 |
-
|
405 |
demo.launch()
|
|
|
6 |
import json
|
7 |
import gradio as gr
|
8 |
from tools.final_answer import FinalAnswerTool
|
|
|
|
|
9 |
|
10 |
+
# File to save the history of recognized songs
|
11 |
HISTORY_FILE = "song_history.json"
|
12 |
|
13 |
+
# Supported languages (sin alemán)
|
14 |
LANGUAGES = {
|
15 |
"English": "en",
|
16 |
"Español": "es",
|
17 |
"Français": "fr"
|
18 |
}
|
19 |
|
20 |
+
# Tool to recognize songs using AudD
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
@tool
|
22 |
def recognize_song(audio_path: str) -> dict:
|
23 |
+
"""Recognizes a song from an audio file
|
24 |
+
Args:
|
25 |
+
audio_path: path to the audio file to recognize
|
26 |
+
"""
|
27 |
AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN")
|
28 |
+
|
29 |
if not os.path.exists(audio_path):
|
30 |
return {"error": "The audio file does not exist"}
|
31 |
+
|
32 |
try:
|
33 |
with open(audio_path, 'rb') as file:
|
34 |
+
data = {
|
35 |
+
'api_token': AUDD_API_TOKEN,
|
36 |
+
'return': 'spotify,apple_music'
|
37 |
+
}
|
38 |
+
files = {
|
39 |
+
'file': file
|
40 |
+
}
|
41 |
response = requests.post('https://api.audd.io/', data=data, files=files)
|
42 |
+
|
43 |
if response.status_code != 200:
|
44 |
return {"error": f"API Error: {response.status_code}"}
|
45 |
+
|
46 |
result = response.json()
|
47 |
+
|
48 |
if result['status'] == 'error':
|
49 |
return {"error": result['error']['error_message']}
|
50 |
+
|
51 |
if not result.get('result'):
|
52 |
return {"error": "Could not recognize the song"}
|
53 |
+
|
54 |
song_info = result['result']
|
55 |
+
|
56 |
+
# Create object with song information
|
57 |
song_data = {
|
58 |
"Song": song_info.get('title', 'Unknown'),
|
59 |
"Artist": song_info.get('artist', 'Unknown'),
|
|
|
62 |
"Apple Music": song_info.get('apple_music', {}).get('url', 'Not available'),
|
63 |
"Recognition Date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
64 |
}
|
65 |
+
|
66 |
+
# Save to history
|
67 |
save_to_history(song_data)
|
68 |
+
|
69 |
return song_data
|
70 |
+
|
71 |
except Exception as e:
|
72 |
return {"error": f"Error processing audio: {str(e)}"}
|
73 |
|
74 |
+
# Function to save song to history
|
75 |
def save_to_history(song_data):
|
76 |
+
"""Saves a song to the history"""
|
77 |
try:
|
78 |
+
# Load existing history or create new
|
79 |
if os.path.exists(HISTORY_FILE):
|
80 |
with open(HISTORY_FILE, 'r') as f:
|
81 |
+
try:
|
82 |
+
history = json.load(f)
|
83 |
+
except json.JSONDecodeError:
|
84 |
+
history = []
|
85 |
else:
|
86 |
history = []
|
87 |
+
|
88 |
+
# Add song to the beginning of history (most recent first)
|
89 |
history.insert(0, song_data)
|
90 |
+
|
91 |
+
# Limit history to the 50 most recent songs
|
92 |
if len(history) > 50:
|
93 |
history = history[:50]
|
94 |
+
|
95 |
+
# Save updated history
|
96 |
with open(HISTORY_FILE, 'w') as f:
|
97 |
json.dump(history, f, indent=2)
|
98 |
+
|
99 |
except Exception as e:
|
100 |
print(f"Error saving to history: {str(e)}")
|
101 |
|
102 |
+
# Tool to view song history
|
103 |
@tool
|
104 |
+
def view_song_history(limit: int = 10) -> str:
|
105 |
+
"""Shows the history of recognized songs
|
106 |
+
Args:
|
107 |
+
limit: maximum number of songs to display (default 10)
|
108 |
+
"""
|
109 |
try:
|
110 |
if not os.path.exists(HISTORY_FILE):
|
111 |
+
return "📋 No song recognition history yet."
|
112 |
+
|
113 |
with open(HISTORY_FILE, 'r') as f:
|
114 |
+
try:
|
115 |
+
history = json.load(f)
|
116 |
+
except json.JSONDecodeError:
|
117 |
+
return "📋 Error loading song history."
|
118 |
+
|
119 |
if not history:
|
120 |
+
return "📋 Song history is empty."
|
121 |
+
|
122 |
+
# Limit the number of songs to display
|
123 |
history = history[:min(limit, len(history))]
|
124 |
+
|
125 |
+
# Format output
|
126 |
+
result = "📋 **Song Recognition History:**\n\n"
|
127 |
+
|
128 |
for i, song in enumerate(history, 1):
|
129 |
result += f"{i}. **{song.get('Song', 'Unknown')}** - *{song.get('Artist', 'Unknown')}*\n"
|
130 |
result += f" 📀 Album: {song.get('Album', 'Unknown')}\n"
|
131 |
+
|
132 |
if song.get('Spotify', 'Not available') != 'Not available':
|
133 |
result += f" 🎧 [Spotify]({song.get('Spotify')})\n"
|
134 |
+
|
135 |
if song.get('Apple Music', 'Not available') != 'Not available':
|
136 |
result += f" 🍏 [Apple Music]({song.get('Apple Music')})\n"
|
137 |
+
|
138 |
result += f" 🕒 Recognized on: {song.get('Recognition Date', 'Unknown date')}\n\n"
|
139 |
+
|
140 |
return result
|
141 |
+
|
142 |
except Exception as e:
|
143 |
+
return f"❌ Error getting history: {str(e)}"
|
144 |
|
145 |
+
# Tool to get artist information in selected language (sin alemán)
|
146 |
@tool
|
147 |
+
def get_artist_info(artist_name: str, language: str = "en") -> str:
|
148 |
+
"""Gets background information and fun facts about a music artist in the specified language
|
149 |
+
Args:
|
150 |
+
artist_name: name of the artist to get information about
|
151 |
+
language: language code (en, es, fr)
|
152 |
+
"""
|
153 |
+
# Language-specific prompts (sin alemán)
|
154 |
prompts = {
|
155 |
+
"en": f"Provide interesting and fun facts about the music artist '{artist_name}' that fans would love to know. Include stories about their career, personal anecdotes, how their most famous songs were created, or surprising facts about their life. Focus on highlighting their contributions to music and anything that makes them unique as an artist. Keep it engaging and positive.",
|
156 |
+
"es": f"Proporciona datos interesantes y curiosos sobre el artista musical '{artist_name}' que a los fans les encantaría conocer. Incluye historias sobre su carrera, anécdotas personales, cómo se crearon sus canciones más famosas o datos sorprendentes sobre su vida. Céntrate en destacar sus contribuciones a la música y cualquier cosa que les haga únicos como artistas. Mantenlo atractivo y positivo.",
|
157 |
+
"fr": f"Fournissez des faits intéressants et amusants sur l'artiste musical '{artist_name}' que les fans aimeraient connaître. Incluez des histoires sur leur carrière, des anecdotes personnelles, comment leurs chansons les plus célèbres ont été créées, ou des faits surprenants sur leur vie. Concentrez-vous sur la mise en valeur de leurs contributions à la musique et tout ce qui les rend uniques en tant qu'artiste. Gardez-le engageant et positif."
|
158 |
}
|
159 |
+
|
160 |
+
# Default to English if language not supported
|
161 |
+
if language not in prompts:
|
162 |
+
language = "en"
|
163 |
+
|
164 |
+
# Create messages for the model
|
165 |
+
messages = [
|
166 |
+
{"role": "user", "content": prompts[language]}
|
167 |
+
]
|
168 |
+
|
169 |
try:
|
170 |
+
# Using the same model that powers our agent
|
171 |
response = model(messages)
|
172 |
+
return response.content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
except Exception as e:
|
174 |
+
return f"Could not retrieve information about {artist_name}: {str(e)}"
|
175 |
|
176 |
+
# Chat with LLM tool (sin alemán)
|
177 |
@tool
|
178 |
def chat_with_assistant(query: str, artist_info: str = "", language: str = "en") -> str:
|
179 |
+
"""Chat with the AI assistant about any music related topic in the specified language
|
180 |
+
Args:
|
181 |
+
query: user's question or request
|
182 |
+
artist_info: previous artist info to provide context
|
183 |
+
language: language code (en, es, fr)
|
184 |
+
"""
|
185 |
+
# Language-specific system messages (sin alemán)
|
186 |
system_messages = {
|
187 |
"en": "You are a music expert assistant who specializes in providing engaging information about artists, songs, and music history. Focus on sharing interesting, fun facts that highlight the artist's unique contributions and stories.",
|
188 |
"es": "Eres un asistente experto en música que se especializa en proporcionar información interesante sobre artistas, canciones e historia musical. Céntrate en compartir datos curiosos e interesantes que destaquen las contribuciones únicas y las historias del artista.",
|
189 |
+
"fr": "Vous êtes un assistant expert en musique qui se spécialise dans la fourniture d'informations intéressantes sur les artistes, les chansons et l'histoire de la musique. Concentrez-vous sur le partage de faits intéressants et amusants qui mettent en évidence les contributions uniques et les histoires de l'artiste."
|
190 |
}
|
191 |
+
|
192 |
+
# Default to English if language not supported
|
193 |
+
if language not in system_messages:
|
194 |
+
language = "en"
|
195 |
+
|
196 |
+
# Create context
|
197 |
+
context = ""
|
198 |
+
if artist_info:
|
199 |
+
context = f"Previous context about the artist: {artist_info}\n\n"
|
200 |
+
|
201 |
+
# Create messages for the model
|
202 |
messages = [
|
203 |
{"role": "system", "content": system_messages[language]},
|
204 |
{"role": "user", "content": context + query}
|
205 |
]
|
206 |
+
|
207 |
try:
|
208 |
+
# Using the model to generate a response
|
209 |
response = model(messages)
|
210 |
return response.content
|
211 |
except Exception as e:
|
212 |
return f"Sorry, I couldn't process your request: {str(e)}"
|
213 |
|
214 |
+
# Agent configuration
|
215 |
final_answer = FinalAnswerTool()
|
216 |
model = HfApiModel(
|
217 |
max_tokens=2096,
|
|
|
223 |
with open("prompts.yaml", 'r') as stream:
|
224 |
prompt_templates = yaml.safe_load(stream)
|
225 |
|
226 |
+
# Agent definition
|
227 |
agent = CodeAgent(
|
228 |
model=model,
|
229 |
+
tools=[
|
230 |
+
final_answer,
|
231 |
+
recognize_song,
|
232 |
+
view_song_history,
|
233 |
+
get_artist_info,
|
234 |
+
chat_with_assistant
|
235 |
+
],
|
236 |
max_steps=8,
|
237 |
verbosity_level=1,
|
238 |
grammar=None,
|
|
|
242 |
prompt_templates=prompt_templates
|
243 |
)
|
244 |
|
245 |
+
# Gradio user interface
|
246 |
+
with gr.Blocks(title="Music Recognition & Fun Facts") as demo:
|
247 |
+
# State variables
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
selected_language = gr.State("en")
|
249 |
song_info_state = gr.State(None)
|
250 |
artist_info_state = gr.State("")
|
251 |
+
audio_status = gr.State("no_audio") # States: no_audio, loading, ready
|
252 |
+
|
253 |
+
# Title and intro
|
254 |
+
gr.Markdown("# 🎵 Music Recognition & Fun Facts")
|
255 |
+
gr.Markdown("Identify songs, learn interesting facts about artists, and chat about music")
|
256 |
+
|
257 |
+
# Language selection
|
258 |
with gr.Row():
|
259 |
language_dropdown = gr.Dropdown(
|
260 |
+
choices=list(LANGUAGES.keys()),
|
261 |
+
value="English",
|
262 |
+
label="Choose your language"
|
263 |
)
|
264 |
+
|
265 |
+
# Combined recognition and chat interface
|
266 |
with gr.Tab("Song Recognition & Chat"):
|
267 |
+
# Audio status message
|
268 |
+
audio_status_msg = gr.Markdown("*Por favor, graba o sube un clip de audio*")
|
269 |
+
|
270 |
+
# Song recognition section
|
271 |
with gr.Row():
|
272 |
with gr.Column(scale=1):
|
273 |
+
# Configuramos el componente de audio para usar el micrófono directamente
|
274 |
+
audio_input = gr.Audio(source="microphone", type="filepath", visible=False)
|
275 |
+
record_btn = gr.Button("🎙 REC MUSIC", size="lg", variant="primary")
|
276 |
+
recognize_btn = gr.Button("🔍 RECOGNIZE SONG", variant="secondary")
|
277 |
+
|
278 |
+
# Recognition results section (separate from chat)
|
279 |
with gr.Row():
|
280 |
recognition_results = gr.Markdown("")
|
281 |
+
|
282 |
+
# Artist info section
|
283 |
with gr.Row():
|
284 |
+
artist_facts = gr.Markdown("")
|
285 |
+
|
286 |
+
# Chat section
|
287 |
+
gr.Markdown("### Pregúntame más sobre este artista o música en general")
|
288 |
+
chat_history = gr.Chatbot(label="Music Chat")
|
289 |
+
|
290 |
with gr.Row():
|
291 |
chat_input = gr.Textbox(
|
292 |
+
placeholder="Pregunta sobre el artista, la canción o cualquier tema musical...",
|
293 |
+
label="Tu pregunta"
|
|
|
294 |
)
|
295 |
+
chat_btn = gr.Button("Enviar", variant="primary")
|
296 |
+
|
297 |
+
# Function to handle audio recording
|
298 |
+
def toggle_audio_widget():
|
299 |
+
return gr.update(visible=True), "loading", "*Espera mientras se graba el audio... Haz clic en Stop cuando termines*"
|
300 |
+
|
301 |
+
# Function to update status when audio is recorded
|
302 |
+
def update_audio_status(audio_path):
|
303 |
+
if audio_path:
|
304 |
+
return "ready", "✅ *¡Audio cargado! Listo para reconocer. Presiona RECOGNIZE SONG*"
|
305 |
+
else:
|
306 |
+
return "no_audio", "*Por favor, graba o sube un clip de audio*"
|
307 |
+
|
308 |
+
# Recognition function (sin alemán)
|
309 |
+
def process_audio(audio_path, language_name, status):
|
310 |
+
if not audio_path or status != "ready":
|
311 |
+
return None, "", "", "*Por favor, graba un clip de audio primero*"
|
312 |
+
|
313 |
+
lang_code = LANGUAGES.get(language_name, "en")
|
314 |
+
|
315 |
+
try:
|
316 |
+
result = recognize_song(audio_path)
|
317 |
+
|
318 |
+
if "error" in result:
|
319 |
+
return None, "", "", f"Error al reconocer la canción: {result['error']}"
|
320 |
+
|
321 |
+
# Get artist information in selected language
|
322 |
+
artist_info = get_artist_info(result['Artist'], lang_code)
|
323 |
+
|
324 |
+
# Format recognition result based on language
|
325 |
+
if lang_code == "en":
|
326 |
+
recognition_msg = f"### 🎵 Recognized Song: {result['Song']}\n\n"
|
327 |
+
recognition_msg += f"**🎤 Artist:** {result['Artist']}\n"
|
328 |
+
recognition_msg += f"**📀 Album:** {result['Album']}\n\n"
|
329 |
+
if result['Spotify'] != "Not available":
|
330 |
+
recognition_msg += f"**🎧 [Listen on Spotify]({result['Spotify']})**\n"
|
331 |
+
if result['Apple Music'] != "Not available":
|
332 |
+
recognition_msg += f"**🍏 [Listen on Apple Music]({result['Apple Music']})**\n"
|
333 |
+
elif lang_code == "es":
|
334 |
+
recognition_msg = f"### 🎵 Canción Reconocida: {result['Song']}\n\n"
|
335 |
+
recognition_msg += f"**🎤 Artista:** {result['Artist']}\n"
|
336 |
+
recognition_msg += f"**📀 Álbum:** {result['Album']}\n\n"
|
337 |
+
if result['Spotify'] != "Not available":
|
338 |
+
recognition_msg += f"**🎧 [Escuchar en Spotify]({result['Spotify']})**\n"
|
339 |
+
if result['Apple Music'] != "Not available":
|
340 |
+
recognition_msg += f"**🍏 [Escuchar en Apple Music]({result['Apple Music']})**\n"
|
341 |
+
elif lang_code == "fr":
|
342 |
+
recognition_msg = f"### 🎵 Chanson Reconnue: {result['Song']}\n\n"
|
343 |
+
recognition_msg += f"**🎤 Artiste:** {result['Artist']}\n"
|
344 |
+
recognition_msg += f"**📀 Album:** {result['Album']}\n\n"
|
345 |
+
if result['Spotify'] != "Not available":
|
346 |
+
recognition_msg += f"**🎧 [Écouter sur Spotify]({result['Spotify']})**\n"
|
347 |
+
if result['Apple Music'] != "Not available":
|
348 |
+
recognition_msg += f"**🍏 [Écouter sur Apple Music]({result['Apple Music']})**\n"
|
349 |
+
|
350 |
+
# Artist info section title based on language
|
351 |
+
if lang_code == "en":
|
352 |
+
artist_facts_title = f"### 🌟 About {result['Artist']}\n\n"
|
353 |
+
elif lang_code == "es":
|
354 |
+
artist_facts_title = f"### 🌟 Sobre {result['Artist']}\n\n"
|
355 |
+
elif lang_code == "fr":
|
356 |
+
artist_facts_title = f"### 🌟 À propos de {result['Artist']}\n\n"
|
357 |
+
|
358 |
+
# Format the artist info with a title
|
359 |
+
artist_facts_content = artist_facts_title + artist_info
|
360 |
+
|
361 |
+
# Update status message
|
362 |
+
status_msg = "*¡Canción reconocida con éxito! Haz preguntas sobre el artista en el chat abajo*"
|
363 |
+
|
364 |
+
return result, recognition_msg, artist_facts_content, status_msg
|
365 |
+
|
366 |
+
except Exception as e:
|
367 |
+
return None, "", "", f"❌ Error procesando el audio: {str(e)}"
|
368 |
+
|
369 |
+
# Chat function
|
370 |
+
def process_chat(query, language_name, song_info, artist_info):
|
371 |
+
if not query:
|
372 |
+
return []
|
373 |
+
|
374 |
+
lang_code = LANGUAGES.get(language_name, "en")
|
375 |
+
|
376 |
+
try:
|
377 |
+
# Get response
|
378 |
+
response = chat_with_assistant(query, artist_info, lang_code)
|
379 |
+
|
380 |
+
return [(query, response)]
|
381 |
+
except Exception as e:
|
382 |
+
return [(query, f"Lo siento, no pude procesar tu solicitud: {str(e)}")]
|
383 |
+
|
384 |
+
# Event handlers
|
385 |
+
record_btn.click(
|
386 |
+
fn=toggle_audio_widget,
|
387 |
+
inputs=[],
|
388 |
+
outputs=[audio_input, audio_status, audio_status_msg]
|
389 |
+
)
|
390 |
+
|
391 |
+
audio_input.change(
|
392 |
+
fn=update_audio_status,
|
393 |
+
inputs=[audio_input],
|
394 |
+
outputs=[audio_status, audio_status_msg]
|
395 |
+
)
|
396 |
+
|
397 |
+
recognize_btn.click(
|
398 |
+
fn=process_audio,
|
399 |
+
inputs=[audio_input, language_dropdown, audio_status],
|
400 |
+
outputs=[song_info_state, recognition_results, artist_facts, audio_status_msg]
|
401 |
+
).then(
|
402 |
+
fn=lambda a: a,
|
403 |
+
inputs=[artist_facts],
|
404 |
+
outputs=[artist_info_state]
|
405 |
+
)
|
406 |
+
|
407 |
+
chat_btn.click(
|
408 |
+
fn=process_chat,
|
409 |
+
inputs=[chat_input, language_dropdown, song_info_state, artist_info_state],
|
410 |
+
outputs=[chat_history]
|
411 |
+
).then(
|
412 |
+
fn=lambda: "", # Clear input after sending
|
413 |
+
inputs=[],
|
414 |
+
outputs=[chat_input]
|
415 |
+
)
|
416 |
+
|
417 |
with gr.Tab("Song History"):
|
418 |
+
gr.Markdown("### Historial de canciones reconocidas")
|
419 |
+
|
420 |
with gr.Row():
|
421 |
+
history_limit = gr.Slider(minimum=5, maximum=50, value=10, step=5, label="Número de canciones a mostrar")
|
422 |
+
view_history_btn = gr.Button("📋 Ver Historial")
|
423 |
+
|
424 |
history_output = gr.Markdown()
|
425 |
+
|
426 |
+
def view_history_process(limit):
|
427 |
+
return view_song_history(int(limit))
|
428 |
+
|
429 |
+
view_history_btn.click(
|
430 |
+
fn=view_history_process,
|
431 |
+
inputs=[history_limit],
|
432 |
+
outputs=[history_output]
|
|
|
|
|
|
|
|
|
|
|
|
|
433 |
)
|
434 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
demo.launch()
|