Manuel Zafra commited on
Commit
42d0179
·
verified ·
1 Parent(s): 3868e5f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -322
app.py CHANGED
@@ -9,17 +9,15 @@ from tools.final_answer import FinalAnswerTool
9
  import tempfile
10
  import shutil
11
 
12
- # File to save the history of recognized songs
13
  HISTORY_FILE = "song_history.json"
14
 
15
- # Supported languages
16
  LANGUAGES = {
17
  "English": "en",
18
  "Español": "es",
19
  "Français": "fr"
20
  }
21
 
22
- # Language-specific messages
23
  MESSAGES = {
24
  "en": {
25
  "title": "# 🎵 Music Recognition & Fun Facts",
@@ -95,43 +93,25 @@ MESSAGES = {
95
  }
96
  }
97
 
98
- # Tool to recognize songs using AudD
99
  @tool
100
  def recognize_song(audio_path: str) -> dict:
101
- """Recognizes a song from an audio file
102
- Args:
103
- audio_path: path to the audio file to recognize
104
- """
105
  AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN")
106
-
107
  if not os.path.exists(audio_path):
108
  return {"error": "The audio file does not exist"}
109
-
110
  try:
111
  with open(audio_path, 'rb') as file:
112
- data = {
113
- 'api_token': AUDD_API_TOKEN,
114
- 'return': 'spotify,apple_music'
115
- }
116
- files = {
117
- 'file': file
118
- }
119
  response = requests.post('https://api.audd.io/', data=data, files=files)
120
-
121
  if response.status_code != 200:
122
  return {"error": f"API Error: {response.status_code}"}
123
-
124
  result = response.json()
125
-
126
  if result['status'] == 'error':
127
  return {"error": result['error']['error_message']}
128
-
129
  if not result.get('result'):
130
  return {"error": "Could not recognize the song"}
131
-
132
  song_info = result['result']
133
-
134
- # Create object with song information
135
  song_data = {
136
  "Song": song_info.get('title', 'Unknown'),
137
  "Artist": song_info.get('artist', 'Unknown'),
@@ -140,115 +120,60 @@ def recognize_song(audio_path: str) -> dict:
140
  "Apple Music": song_info.get('apple_music', {}).get('url', 'Not available'),
141
  "Recognition Date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
142
  }
143
-
144
- # Save to history
145
  save_to_history(song_data)
146
-
147
  return song_data
148
-
149
  except Exception as e:
150
  return {"error": f"Error processing audio: {str(e)}"}
151
 
152
- # Function to save song to history
153
  def save_to_history(song_data):
154
- """Saves a song to the history"""
155
  try:
156
- # Load existing history or create new
157
  if os.path.exists(HISTORY_FILE):
158
  with open(HISTORY_FILE, 'r') as f:
159
- try:
160
- history = json.load(f)
161
- except json.JSONDecodeError:
162
- history = []
163
  else:
164
  history = []
165
-
166
- # Add song to the beginning of history (most recent first)
167
  history.insert(0, song_data)
168
-
169
- # Limit history to the 50 most recent songs
170
  if len(history) > 50:
171
  history = history[:50]
172
-
173
- # Save updated history
174
  with open(HISTORY_FILE, 'w') as f:
175
  json.dump(history, f, indent=2)
176
-
177
  except Exception as e:
178
  print(f"Error saving to history: {str(e)}")
179
 
180
- # Tool to view song history
181
  @tool
182
  def view_song_history(limit: int = 10, language: str = "en") -> str:
183
- """Shows the history of recognized songs
184
- Args:
185
- limit: maximum number of songs to display (default 10)
186
- language: language code (en, es, fr)
187
- """
188
  lang = LANGUAGES.get(language, "en")
189
  try:
190
  if not os.path.exists(HISTORY_FILE):
191
  return f"📋 {MESSAGES[lang]['no_history']}"
192
-
193
  with open(HISTORY_FILE, 'r') as f:
194
- try:
195
- history = json.load(f)
196
- except json.JSONDecodeError:
197
- return "📋 Error loading song history."
198
-
199
  if not history:
200
  return f"📋 {MESSAGES[lang]['empty_history']}"
201
-
202
- # Limit the number of songs to display
203
  history = history[:min(limit, len(history))]
204
-
205
- # Format output
206
  result = f"📋 **{MESSAGES[lang]['history_title']}:**\n\n"
207
-
208
  for i, song in enumerate(history, 1):
209
  result += f"{i}. **{song.get('Song', 'Unknown')}** - *{song.get('Artist', 'Unknown')}*\n"
210
  result += f" 📀 Album: {song.get('Album', 'Unknown')}\n"
211
-
212
  if song.get('Spotify', 'Not available') != 'Not available':
213
  result += f" 🎧 [Spotify]({song.get('Spotify')})\n"
214
-
215
  if song.get('Apple Music', 'Not available') != 'Not available':
216
  result += f" 🍏 [Apple Music]({song.get('Apple Music')})\n"
217
-
218
  result += f" 🕒 Recognized on: {song.get('Recognition Date', 'Unknown date')}\n\n"
219
-
220
  return result
221
-
222
  except Exception as e:
223
  return f"❌ {MESSAGES[lang]['history_error'].format(error=str(e))}"
224
 
225
- # Tool to get artist information in selected language
226
  @tool
227
  def get_artist_info(artist_name: str, song_title: str, language: str = "en") -> dict:
228
- """Gets background information and fun facts about a music artist in the specified language
229
- Args:
230
- artist_name: name of the artist to get information about
231
- song_title: title of the song
232
- language: language code (en, es, fr)
233
- """
234
- # Language-specific prompts
235
  prompts = {
236
  "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 song '{song_title}' was created if known, or surprising facts about their life. Include an image URL if possible. Focus on highlighting their contributions to music and anything that makes them unique as an artist. Keep it engaging and positive.",
237
  "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 creó su canción '{song_title}' si se sabe, o datos sorprendentes sobre su vida. Incluye una URL de imagen si es posible. Céntrate en destacar sus contribuciones a la música y cualquier cosa que les haga únicos como artistas. Mantenlo atractivo y positivo.",
238
  "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 leur chanson '{song_title}' a été créée si connu, ou des faits surprenants sur leur vie. Incluez une URL d'image si possible. 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.",
239
  }
240
-
241
- # Default to English if language not supported
242
- if language not in prompts:
243
- language = "en"
244
-
245
- # Create messages for the model
246
- messages = [
247
- {"role": "user", "content": prompts[language]}
248
- ]
249
-
250
  try:
251
- # Using the same model that powers our agent
252
  response = model(messages)
253
  content = response.content
254
  image_url = None
@@ -261,45 +186,26 @@ def get_artist_info(artist_name: str, song_title: str, language: str = "en") ->
261
  except Exception as e:
262
  return {"text": f"Could not retrieve information about {artist_name}: {str(e)}", "image": None}
263
 
264
- # Chat with LLM tool
265
  @tool
266
  def chat_with_assistant(query: str, artist_info: str = "", language: str = "en") -> str:
267
- """Chat with the AI assistant about any music related topic in the specified language
268
- Args:
269
- query: user's question or request
270
- artist_info: previous artist info to provide context
271
- language: language code (en, es, fr)
272
- """
273
- # Language-specific system messages
274
  system_messages = {
275
  "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.",
276
  "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.",
277
  "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.",
278
  }
279
-
280
- # Default to English if language not supported
281
- if language not in system_messages:
282
- language = "en"
283
-
284
- # Create context
285
- context = ""
286
- if artist_info:
287
- context = f"Previous context about the artist: {artist_info}\n\n"
288
-
289
- # Create messages for the model
290
  messages = [
291
  {"role": "system", "content": system_messages[language]},
292
  {"role": "user", "content": context + query}
293
  ]
294
-
295
  try:
296
- # Using the model to generate a response
297
  response = model(messages)
298
  return response.content
299
  except Exception as e:
300
  return f"Sorry, I couldn't process your request: {str(e)}"
301
 
302
- # Agent configuration
303
  final_answer = FinalAnswerTool()
304
  model = HfApiModel(
305
  max_tokens=2096,
@@ -311,16 +217,9 @@ model = HfApiModel(
311
  with open("prompts.yaml", 'r') as stream:
312
  prompt_templates = yaml.safe_load(stream)
313
 
314
- # Agent definition
315
  agent = CodeAgent(
316
  model=model,
317
- tools=[
318
- final_answer,
319
- recognize_song,
320
- view_song_history,
321
- get_artist_info,
322
- chat_with_assistant
323
- ],
324
  max_steps=8,
325
  verbosity_level=1,
326
  grammar=None,
@@ -330,240 +229,177 @@ agent = CodeAgent(
330
  prompt_templates=prompt_templates
331
  )
332
 
333
- # Gradio user interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  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:
335
- # State variables
336
  selected_language = gr.State("en")
337
  song_info_state = gr.State(None)
338
  artist_info_state = gr.State("")
339
- audio_status = gr.State("no_audio") # States: no_audio, loading, ready
340
-
341
- # Title and intro
342
- gr.Markdown(value=lambda: MESSAGES[selected_language.value]["title"])
343
- gr.Markdown(value=lambda: MESSAGES[selected_language.value]["subtitle"])
344
-
345
- # Language selection
346
  with gr.Row():
347
  language_dropdown = gr.Dropdown(
348
  choices=[("English", "en"), ("Español", "es"), ("Français", "fr")],
349
  value="en",
350
- label=lambda: MESSAGES[selected_language.value]["language_label"]
351
  )
352
-
353
- # Combined recognition and chat interface
354
  with gr.Tab("Song Recognition & Chat"):
355
- # Audio status message
356
- audio_status_msg = gr.Markdown(value=lambda: MESSAGES[selected_language.value]["no_audio"])
357
-
358
- # Song recognition section
359
  with gr.Row():
360
  with gr.Column(scale=1):
361
- # Replacing the standard audio widget with a custom button approach
362
- # First, keep the actual audio input but make it less visible
363
- audio_input = gr.Audio(type="filepath", visible=False) # Removed source="microphone"
364
-
365
- # Add a big, prominent record button
366
- record_btn = gr.Button(value=lambda: MESSAGES[selected_language.value]["rec_button"], elem_classes="big-button", variant="primary")
367
  audio_loaded_msg = gr.Markdown("", elem_classes="large-text")
368
- # Add the recognize button
369
- recognize_btn = gr.Button(value=lambda: MESSAGES[selected_language.value]["recognize_button"], variant="secondary")
370
-
371
- # Recognition results section (separate from chat)
372
  with gr.Row():
373
  recognition_results = gr.Markdown("")
374
-
375
- # Artist info section
376
  with gr.Row():
377
  artist_info_text = gr.Markdown("")
378
- artist_info_image = gr.Image(type="filepath") # Changed from type="url" to type="filepath"
 
 
 
379
 
380
- gr.Markdown(value=lambda: MESSAGES[selected_language.value]["chat_title"])
381
- chat_history = gr.Chatbot(label="Music Chat")
382
-
383
  with gr.Row():
384
  chat_input = gr.Textbox(
385
- placeholder=lambda: MESSAGES[selected_language.value]["chat_placeholder"],
386
- label="Your question"
387
- )
388
- chat_btn = gr.Button(value=lambda: MESSAGES[selected_language.value]["chat_button"], variant="primary")
389
-
390
- # Function to handle audio recording/uploading
391
- def toggle_audio_widget(language_name):
392
- lang = LANGUAGES.get(language_name, "en")
393
- # This function triggers the audio widget's recording functionality
394
- return gr.update(visible=True), "loading", MESSAGES[lang]["loading"]
395
-
396
- # Function to update status when audio is uploaded
397
- def update_audio_status(audio_path, language_name):
398
- lang = LANGUAGES.get(language_name, "en")
399
- if audio_path:
400
- return "ready", MESSAGES[lang]["audio_loaded"]
401
- else:
402
- return "no_audio", MESSAGES[lang]["no_audio"]
403
-
404
- # Function to download image from URL and return a local filepath
405
- def download_image(url):
406
- if not url:
407
- return None
408
- try:
409
- response = requests.get(url, stream=True)
410
- response.raise_for_status()
411
- # Create a temporary file
412
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
413
- shutil.copyfileobj(response.raw, temp_file)
414
- temp_file.close()
415
- return temp_file.name
416
- except Exception as e:
417
- print(f"Error downloading image: {str(e)}")
418
- return None
419
-
420
- # Recognition function
421
- def process_audio(audio_path, language_name, status):
422
- lang = LANGUAGES.get(language_name, "en")
423
- if not audio_path or status != "ready":
424
- return None, "", "", MESSAGES[lang]["no_audio"], ""
425
-
426
- yield None, "", "", MESSAGES[lang]["uploading"], ""
427
- yield None, "", "", MESSAGES[lang]["searching"], ""
428
- try:
429
- result = recognize_song(audio_path)
430
-
431
- if "error" in result:
432
- return None, "", "", MESSAGES[lang]["error"].format(error=result['error']), ""
433
-
434
- # Get artist information in selected language
435
- artist_info = get_artist_info(result['Artist'], result['Song'], lang)
436
-
437
- # Format recognition result based on language
438
- if lang == "en":
439
- recognition_msg = f"### 🎵 Recognized Song: {result['Song']}\n\n"
440
- recognition_msg += f"**🎤 Artist:** {result['Artist']}\n"
441
- recognition_msg += f"**📀 Album:** {result['Album']}\n\n"
442
-
443
- if result['Spotify'] != "Not available":
444
- recognition_msg += f"**🎧 [Listen on Spotify]({result['Spotify']})**\n"
445
- if result['Apple Music'] != "Not available":
446
- recognition_msg += f"**🍏 [Listen on Apple Music]({result['Apple Music']})**\n"
447
-
448
- elif lang == "es":
449
- recognition_msg = f"### 🎵 Canción Reconocida: {result['Song']}\n\n"
450
- recognition_msg += f"**🎤 Artista:** {result['Artist']}\n"
451
- recognition_msg += f"**📀 Álbum:** {result['Album']}\n\n"
452
-
453
- if result['Spotify'] != "Not available":
454
- recognition_msg += f"**🎧 [Escuchar en Spotify]({result['Spotify']})**\n"
455
- if result['Apple Music'] != "Not available":
456
- recognition_msg += f"**🍏 [Escuchar en Apple Music]({result['Apple Music']})**\n"
457
-
458
- elif lang == "fr":
459
- recognition_msg = f"### 🎵 Chanson Reconnue: {result['Song']}\n\n"
460
- recognition_msg += f"**🎤 Artiste:** {result['Artist']}\n"
461
- recognition_msg += f"**📀 Album:** {result['Album']}\n\n"
462
-
463
- if result['Spotify'] != "Not available":
464
- recognition_msg += f"**🎧 [Écouter sur Spotify]({result['Spotify']})**\n"
465
- if result['Apple Music'] != "Not available":
466
- recognition_msg += f"**🍏 [Écouter sur Apple Music]({result['Apple Music']})**\n"
467
-
468
- # Artist info section title based on language
469
- artist_facts_content = f"{MESSAGES[lang]['artist_info_title']}\n\n{artist_info['text']}"
470
-
471
- # Download the image if URL exists
472
- image_filepath = download_image(artist_info['image']) if artist_info['image'] else ""
473
-
474
- # Update status message
475
- status_msg = MESSAGES[lang]["recognized"]
476
-
477
- return result, recognition_msg, artist_facts_content, status_msg, image_filepath
478
-
479
- except Exception as e:
480
- return None, "", "", MESSAGES[lang]["error"].format(error=str(e)), ""
481
-
482
- # Chat function
483
- def process_chat(query, language_name, song_info, artist_info):
484
- lang = LANGUAGES.get(language_name, "en")
485
- if not query:
486
- return []
487
-
488
- try:
489
- # Get response
490
- response = chat_with_assistant(query, artist_info, lang)
491
-
492
- return [(query, response)]
493
- except Exception as e:
494
- return [(query, f"Sorry, I couldn't process your request: {str(e)}")]
495
-
496
- def view_history_process(limit, language_name):
497
- lang = LANGUAGES.get(language_name, "en")
498
- return view_song_history(int(limit), lang)
499
-
500
- def update_ui(language_name):
501
- lang = LANGUAGES.get(language_name, "en")
502
- return (
503
- MESSAGES[lang]["title"],
504
- MESSAGES[lang]["subtitle"],
505
- gr.Markdown(value=MESSAGES[lang]["no_audio"]),
506
- gr.Button(value=MESSAGES[lang]["rec_button"], elem_classes="big-button", variant="primary"),
507
- gr.Button(value=MESSAGES[lang]["recognize_button"], variant="secondary"),
508
- gr.Markdown(value=MESSAGES[lang]["chat_title"]),
509
- gr.Textbox(placeholder=MESSAGES[lang]["chat_placeholder"], label="Your question"),
510
- gr.Button(value=MESSAGES[lang]["chat_button"], variant="primary"),
511
- gr.Slider(minimum=5, maximum=50, value=10, step=5, label=MESSAGES[lang]["history_limit_label"]),
512
- gr.Button(value=MESSAGES[lang]["history_button"])
513
  )
 
514
 
515
- # Event handlers
516
- language_dropdown.change(
517
- fn=update_ui,
518
- inputs=[language_dropdown],
519
- outputs=[demo.get_component(0), demo.get_component(1), audio_status_msg, record_btn, recognize_btn, demo.get_component(8), chat_input, chat_btn, history_limit, view_history_btn]
520
- )
521
-
522
- record_btn.click(
523
- fn=toggle_audio_widget,
524
- inputs=[language_dropdown],
525
- outputs=[audio_input, audio_status, audio_status_msg]
526
- )
527
-
528
- audio_input.change(
529
- fn=update_audio_status,
530
- inputs=[audio_input, language_dropdown],
531
- outputs=[audio_status, audio_loaded_msg]
532
- )
533
-
534
- recognize_btn.click(
535
- fn=process_audio,
536
- inputs=[audio_input, language_dropdown, audio_status],
537
- outputs=[song_info_state, recognition_results, artist_info_text, audio_status_msg, artist_info_image]
538
- ).then(
539
- fn=lambda a: a,
540
- inputs=[artist_info_text],
541
- outputs=[artist_info_state]
542
- )
543
-
544
- chat_btn.click(
545
- fn=process_chat,
546
- inputs=[chat_input, language_dropdown, song_info_state, artist_info_state],
547
- outputs=[chat_history]
548
- ).then(
549
- fn=lambda: "", # Clear input after sending
550
- inputs=[],
551
- outputs=[chat_input]
552
- )
553
-
554
  with gr.Tab("Song History"):
555
- gr.Markdown(value=lambda: MESSAGES[selected_language.value]["history_title"])
556
-
557
  with gr.Row():
558
- history_limit = gr.Slider(minimum=5, maximum=50, value=10, step=5, label=lambda: MESSAGES[selected_language.value]["history_limit_label"])
559
- view_history_btn = gr.Button(value=lambda: MESSAGES[selected_language.value]["history_button"])
560
-
561
  history_output = gr.Markdown()
562
-
563
- view_history_btn.click(
564
- fn=view_history_process,
565
- inputs=[history_limit, language_dropdown],
566
- outputs=[history_output]
 
 
 
 
 
 
 
 
 
567
  )
568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  demo.launch()
 
9
  import tempfile
10
  import shutil
11
 
12
+ # Constantes
13
  HISTORY_FILE = "song_history.json"
14
 
 
15
  LANGUAGES = {
16
  "English": "en",
17
  "Español": "es",
18
  "Français": "fr"
19
  }
20
 
 
21
  MESSAGES = {
22
  "en": {
23
  "title": "# 🎵 Music Recognition & Fun Facts",
 
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 = {'api_token': AUDD_API_TOKEN, 'return': 'spotify,apple_music'}
105
+ files = {'file': file}
 
 
 
 
 
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
  "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
+ history = json.load(f) if f.read().strip() else []
 
 
 
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, language: str = "en") -> str:
 
 
 
 
 
145
  lang = LANGUAGES.get(language, "en")
146
  try:
147
  if not os.path.exists(HISTORY_FILE):
148
  return f"📋 {MESSAGES[lang]['no_history']}"
 
149
  with open(HISTORY_FILE, 'r') as f:
150
+ history = json.load(f)
 
 
 
 
151
  if not history:
152
  return f"📋 {MESSAGES[lang]['empty_history']}"
 
 
153
  history = history[:min(limit, len(history))]
 
 
154
  result = f"📋 **{MESSAGES[lang]['history_title']}:**\n\n"
 
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"❌ {MESSAGES[lang]['history_error'].format(error=str(e))}"
166
 
 
167
  @tool
168
  def get_artist_info(artist_name: str, song_title: str, language: str = "en") -> dict:
 
 
 
 
 
 
 
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 song '{song_title}' was created if known, or surprising facts about their life. Include an image URL if possible. Focus on highlighting their contributions to music and anything that makes them unique as an artist. Keep it engaging and positive.",
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 creó su canción '{song_title}' si se sabe, o datos sorprendentes sobre su vida. Incluye una URL de imagen si es posible. Céntrate en destacar sus contribuciones a la música y cualquier cosa que les haga únicos como artistas. Mantenlo atractivo y positivo.",
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 leur chanson '{song_title}' a été créée si connu, ou des faits surprenants sur leur vie. Incluez une URL d'image si possible. 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.",
173
  }
174
+ language = language if language in prompts else "en"
175
+ messages = [{"role": "user", "content": prompts[language]}]
 
 
 
 
 
 
 
 
176
  try:
 
177
  response = model(messages)
178
  content = response.content
179
  image_url = None
 
186
  except Exception as e:
187
  return {"text": f"Could not retrieve information about {artist_name}: {str(e)}", "image": None}
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
+ language = language if language in system_messages else "en"
197
+ context = f"Previous context about the artist: {artist_info}\n\n" if artist_info else ""
 
 
 
 
 
 
 
 
 
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
+ # Configuración del agente
209
  final_answer = FinalAnswerTool()
210
  model = HfApiModel(
211
  max_tokens=2096,
 
217
  with open("prompts.yaml", 'r') as stream:
218
  prompt_templates = yaml.safe_load(stream)
219
 
 
220
  agent = CodeAgent(
221
  model=model,
222
+ tools=[final_answer, recognize_song, view_song_history, get_artist_info, chat_with_assistant],
 
 
 
 
 
 
223
  max_steps=8,
224
  verbosity_level=1,
225
  grammar=None,
 
229
  prompt_templates=prompt_templates
230
  )
231
 
232
+ # Descargar imagen (función auxiliar)
233
+ def download_image(image_url):
234
+ if not image_url:
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
+ title = gr.Markdown(value=MESSAGES["en"]["title"], elem_id="title")
255
+ subtitle = gr.Markdown(value=MESSAGES["en"]["subtitle"], elem_id="subtitle")
256
+
 
 
257
  with gr.Row():
258
  language_dropdown = gr.Dropdown(
259
  choices=[("English", "en"), ("Español", "es"), ("Français", "fr")],
260
  value="en",
261
+ label=MESSAGES["en"]["language_label"]
262
  )
263
+
 
264
  with gr.Tab("Song Recognition & Chat"):
265
+ audio_status_msg = gr.Markdown(value=MESSAGES["en"]["no_audio"], elem_id="audio_status_msg")
 
 
 
266
  with gr.Row():
267
  with gr.Column(scale=1):
268
+ audio_input = gr.Audio(type="filepath", visible=False)
269
+ record_btn = gr.Button(value=MESSAGES["en"]["rec_button"], elem_classes="big-button", variant="primary", elem_id="record_btn")
 
 
 
 
270
  audio_loaded_msg = gr.Markdown("", elem_classes="large-text")
271
+ recognize_btn = gr.Button(value=MESSAGES["en"]["recognize_button"], variant="secondary", elem_id="recognize_btn")
272
+
 
 
273
  with gr.Row():
274
  recognition_results = gr.Markdown("")
275
+
 
276
  with gr.Row():
277
  artist_info_text = gr.Markdown("")
278
+ artist_info_image = gr.Image(type="filepath")
279
+
280
+ chat_title = gr.Markdown(value=MESSAGES["en"]["chat_title"], elem_id="chat_title")
281
+ chat_history = gr.Chatbot(label="Music Chat", type="messages")
282
 
 
 
 
283
  with gr.Row():
284
  chat_input = gr.Textbox(
285
+ placeholder=MESSAGES["en"]["chat_placeholder"],
286
+ label="Your question",
287
+ elem_id="chat_input"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  )
289
+ chat_btn = gr.Button(value=MESSAGES["en"]["chat_button"], variant="primary", elem_id="chat_btn")
290
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  with gr.Tab("Song History"):
292
+ gr.Markdown(value=MESSAGES["en"]["history_title"])
 
293
  with gr.Row():
294
+ history_limit = gr.Slider(minimum=5, maximum=50, value=10, step=5, label=MESSAGES["en"]["history_limit_label"], elem_id="history_limit")
295
+ view_history_btn = gr.Button(value=MESSAGES["en"]["history_button"], elem_id="view_history_btn")
 
296
  history_output = gr.Markdown()
297
+
298
+ def update_ui(language_name):
299
+ lang = LANGUAGES.get(language_name, "en")
300
+ return (
301
+ MESSAGES[lang]["title"],
302
+ MESSAGES[lang]["subtitle"],
303
+ MESSAGES[lang]["no_audio"],
304
+ MESSAGES[lang]["rec_button"],
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()