Spaces:
Sleeping
Sleeping
Manuel Zafra
commited on
Update app.py
Browse files
app.py
CHANGED
@@ -1,23 +1,15 @@
|
|
1 |
-
from smolagents import CodeAgent,
|
2 |
import datetime
|
3 |
import requests
|
4 |
import pytz
|
5 |
import yaml
|
|
|
|
|
|
|
|
|
6 |
from tools.final_answer import FinalAnswerTool
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
# Below is an example of a tool that does nothing. Amaze us with your creativity !
|
11 |
-
@tool
|
12 |
-
def my_custom_tool(arg1:str, arg2:int)-> str: #it's import to specify the return type
|
13 |
-
#Keep this format for the description / args / args description but feel free to modify the tool
|
14 |
-
"""A tool that does nothing yet
|
15 |
-
Args:
|
16 |
-
arg1: the first argument
|
17 |
-
arg2: the second argument
|
18 |
-
"""
|
19 |
-
return "What magic will you build ?"
|
20 |
-
|
21 |
@tool
|
22 |
def get_current_time_in_timezone(timezone: str) -> str:
|
23 |
"""A tool that fetches the current local time in a specified timezone.
|
@@ -33,30 +25,214 @@ def get_current_time_in_timezone(timezone: str) -> str:
|
|
33 |
except Exception as e:
|
34 |
return f"Error fetching time for timezone '{timezone}': {str(e)}"
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
#
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
|
|
|
|
42 |
model = HfApiModel(
|
43 |
-
max_tokens=2096,
|
44 |
-
temperature=0.5,
|
45 |
-
model_id='Qwen/Qwen2.5-Coder-32B-Instruct'
|
46 |
-
custom_role_conversions=None,
|
47 |
)
|
48 |
|
49 |
-
|
50 |
-
# Import tool from Hub
|
51 |
-
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
|
52 |
-
|
53 |
with open("prompts.yaml", 'r') as stream:
|
54 |
prompt_templates = yaml.safe_load(stream)
|
55 |
-
|
56 |
agent = CodeAgent(
|
57 |
model=model,
|
58 |
-
tools=[
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
verbosity_level=1,
|
61 |
grammar=None,
|
62 |
planning_interval=None,
|
@@ -65,5 +241,57 @@ agent = CodeAgent(
|
|
65 |
prompt_templates=prompt_templates
|
66 |
)
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
-
|
|
|
1 |
+
from smolagents import CodeAgent, HfApiModel, tool
|
2 |
import datetime
|
3 |
import requests
|
4 |
import pytz
|
5 |
import yaml
|
6 |
+
import os
|
7 |
+
import pickle
|
8 |
+
import time
|
9 |
+
import gradio as gr
|
10 |
from tools.final_answer import FinalAnswerTool
|
11 |
|
12 |
+
# Herramienta para obtener la hora actual en una zona horaria
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
@tool
|
14 |
def get_current_time_in_timezone(timezone: str) -> str:
|
15 |
"""A tool that fetches the current local time in a specified timezone.
|
|
|
25 |
except Exception as e:
|
26 |
return f"Error fetching time for timezone '{timezone}': {str(e)}"
|
27 |
|
28 |
+
# Herramienta para reconocer canciones usando AudD
|
29 |
+
@tool
|
30 |
+
def recognize_song(audio_path: str) -> dict:
|
31 |
+
"""Reconoce una canción a partir de un archivo de audio
|
32 |
+
Args:
|
33 |
+
audio_path: ruta al archivo de audio a reconocer
|
34 |
+
"""
|
35 |
+
AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN")
|
36 |
+
|
37 |
+
if not os.path.exists(audio_path):
|
38 |
+
return {"error": "El archivo de audio no existe"}
|
39 |
+
|
40 |
+
try:
|
41 |
+
with open(audio_path, 'rb') as file:
|
42 |
+
data = {
|
43 |
+
'api_token': AUDD_API_TOKEN,
|
44 |
+
'return': 'spotify,apple_music'
|
45 |
+
}
|
46 |
+
files = {
|
47 |
+
'file': file
|
48 |
+
}
|
49 |
+
response = requests.post('https://api.audd.io/', data=data, files=files)
|
50 |
+
|
51 |
+
if response.status_code != 200:
|
52 |
+
return {"error": f"Error en la API: {response.status_code}"}
|
53 |
+
|
54 |
+
result = response.json()
|
55 |
+
|
56 |
+
if result['status'] == 'error':
|
57 |
+
return {"error": result['error']['error_message']}
|
58 |
+
|
59 |
+
if not result.get('result'):
|
60 |
+
return {"error": "No se pudo reconocer la canción"}
|
61 |
+
|
62 |
+
song_info = result['result']
|
63 |
+
|
64 |
+
return {
|
65 |
+
"🎶 Canción": song_info.get('title', 'Desconocido'),
|
66 |
+
"🎤 Artista": song_info.get('artist', 'Desconocido'),
|
67 |
+
"📀 Álbum": song_info.get('album', 'Desconocido'),
|
68 |
+
"🎧 Spotify": song_info.get('spotify', {}).get('external_urls', {}).get('spotify', 'No disponible'),
|
69 |
+
"🍏 Apple Music": song_info.get('apple_music', {}).get('url', 'No disponible')
|
70 |
+
}
|
71 |
+
|
72 |
+
except Exception as e:
|
73 |
+
return {"error": f"Error al procesar el audio: {str(e)}"}
|
74 |
|
75 |
+
# Herramienta para iniciar sesión en Soundeo
|
76 |
+
@tool
|
77 |
+
def login_soundeo() -> str:
|
78 |
+
"""Inicia sesión en Soundeo usando las credenciales almacenadas en secrets"""
|
79 |
+
from selenium import webdriver
|
80 |
+
from selenium.webdriver.chrome.options import Options
|
81 |
+
from selenium.webdriver.common.by import By
|
82 |
+
from selenium.webdriver.support.ui import WebDriverWait
|
83 |
+
from selenium.webdriver.support import expected_conditions as EC
|
84 |
+
|
85 |
+
# Obtener credenciales de los secrets
|
86 |
+
username = os.getenv("SOUNDEO_USERNAME")
|
87 |
+
password = os.getenv("SOUNDEO_PASSWORD")
|
88 |
+
|
89 |
+
if not username or not password:
|
90 |
+
return "❌ No se encontraron las credenciales en los secrets"
|
91 |
+
|
92 |
+
# Configurar opciones de Chrome
|
93 |
+
chrome_options = Options()
|
94 |
+
chrome_options.add_argument("--headless")
|
95 |
+
chrome_options.add_argument("--no-sandbox")
|
96 |
+
chrome_options.add_argument("--disable-dev-shm-usage")
|
97 |
+
chrome_options.add_argument("--disable-gpu")
|
98 |
+
|
99 |
+
try:
|
100 |
+
# Inicializar el driver
|
101 |
+
driver = webdriver.Chrome(options=chrome_options)
|
102 |
+
|
103 |
+
# Navegar a Soundeo
|
104 |
+
driver.get("https://soundeo.com/login")
|
105 |
+
time.sleep(3) # Esperar a que cargue la página
|
106 |
+
|
107 |
+
# Capturar screenshot para debug
|
108 |
+
driver.save_screenshot("pre_login.png")
|
109 |
+
|
110 |
+
# Completar formulario de login
|
111 |
+
username_field = WebDriverWait(driver, 10).until(
|
112 |
+
EC.presence_of_element_located((By.ID, "username"))
|
113 |
+
)
|
114 |
+
username_field.send_keys(username)
|
115 |
+
|
116 |
+
password_field = driver.find_element(By.ID, "password")
|
117 |
+
password_field.send_keys(password)
|
118 |
+
|
119 |
+
# Hacer clic en el botón de login
|
120 |
+
login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
|
121 |
+
login_button.click()
|
122 |
+
|
123 |
+
# Esperar a que se complete el login
|
124 |
+
time.sleep(5)
|
125 |
+
|
126 |
+
# Capturar screenshot para verificar
|
127 |
+
driver.save_screenshot("post_login.png")
|
128 |
+
|
129 |
+
# Guardar cookies para uso futuro
|
130 |
+
pickle.dump(driver.get_cookies(), open("soundeo_cookies.pkl", "wb"))
|
131 |
+
|
132 |
+
# Verificar si el login fue exitoso
|
133 |
+
if "dashboard" in driver.current_url or "account" in driver.current_url:
|
134 |
+
result = "✅ Login exitoso en Soundeo"
|
135 |
+
else:
|
136 |
+
result = "❌ Error al iniciar sesión. Verifica tus credenciales."
|
137 |
+
|
138 |
+
driver.quit()
|
139 |
+
return result
|
140 |
+
|
141 |
+
except Exception as e:
|
142 |
+
return f"❌ Error con Selenium: {str(e)}"
|
143 |
|
144 |
+
# Herramienta para buscar y añadir una canción a la lista de descarga
|
145 |
+
@tool
|
146 |
+
def add_song_to_download_list(song_title: str, artist: str) -> str:
|
147 |
+
"""Busca una canción en Soundeo y la añade a la lista de descarga
|
148 |
+
Args:
|
149 |
+
song_title: título de la canción
|
150 |
+
artist: nombre del artista
|
151 |
+
"""
|
152 |
+
from selenium import webdriver
|
153 |
+
from selenium.webdriver.chrome.options import Options
|
154 |
+
from selenium.webdriver.common.by import By
|
155 |
+
from selenium.webdriver.support.ui import WebDriverWait
|
156 |
+
from selenium.webdriver.support import expected_conditions as EC
|
157 |
+
|
158 |
+
chrome_options = Options()
|
159 |
+
chrome_options.add_argument("--headless")
|
160 |
+
chrome_options.add_argument("--no-sandbox")
|
161 |
+
chrome_options.add_argument("--disable-dev-shm-usage")
|
162 |
+
chrome_options.add_argument("--disable-gpu")
|
163 |
+
|
164 |
+
try:
|
165 |
+
driver = webdriver.Chrome(options=chrome_options)
|
166 |
+
|
167 |
+
# Cargar cookies si existen
|
168 |
+
cookies_file = "soundeo_cookies.pkl"
|
169 |
+
if os.path.exists(cookies_file):
|
170 |
+
driver.get("https://soundeo.com")
|
171 |
+
cookies = pickle.load(open(cookies_file, "rb"))
|
172 |
+
for cookie in cookies:
|
173 |
+
driver.add_cookie(cookie)
|
174 |
+
else:
|
175 |
+
driver.quit()
|
176 |
+
return "❌ No hay cookies de sesión. Primero debes iniciar sesión."
|
177 |
+
|
178 |
+
# Navegar a la búsqueda
|
179 |
+
search_query = f"{song_title} {artist}"
|
180 |
+
search_query = search_query.replace(" ", "+")
|
181 |
+
driver.get(f"https://soundeo.com/search?q={search_query}")
|
182 |
+
time.sleep(5)
|
183 |
+
|
184 |
+
# Capturar screenshot para debug
|
185 |
+
driver.save_screenshot("search_results.png")
|
186 |
+
|
187 |
+
# Buscar el primer resultado
|
188 |
+
try:
|
189 |
+
first_result = WebDriverWait(driver, 10).until(
|
190 |
+
EC.presence_of_element_located((By.CSS_SELECTOR, ".track-item"))
|
191 |
+
)
|
192 |
+
|
193 |
+
# Hacer clic en "Add to Download List"
|
194 |
+
download_button = first_result.find_element(By.CSS_SELECTOR, ".download-button")
|
195 |
+
download_button.click()
|
196 |
+
|
197 |
+
time.sleep(3)
|
198 |
+
driver.save_screenshot("added_to_list.png")
|
199 |
+
|
200 |
+
# Obtener información del track añadido
|
201 |
+
track_info = first_result.find_element(By.CSS_SELECTOR, ".track-title").text
|
202 |
+
artist_info = first_result.find_element(By.CSS_SELECTOR, ".track-artist").text
|
203 |
+
|
204 |
+
driver.quit()
|
205 |
+
return f"✅ Añadida a la lista de descarga: {track_info} - {artist_info}"
|
206 |
+
|
207 |
+
except Exception as e:
|
208 |
+
driver.quit()
|
209 |
+
return f"❌ No se encontraron resultados o no se pudo añadir: {str(e)}"
|
210 |
+
|
211 |
+
except Exception as e:
|
212 |
+
return f"❌ Error con Selenium: {str(e)}"
|
213 |
|
214 |
+
# Configuración del agente
|
215 |
+
final_answer = FinalAnswerTool()
|
216 |
model = HfApiModel(
|
217 |
+
max_tokens=2096,
|
218 |
+
temperature=0.5,
|
219 |
+
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
|
220 |
+
custom_role_conversions=None,
|
221 |
)
|
222 |
|
|
|
|
|
|
|
|
|
223 |
with open("prompts.yaml", 'r') as stream:
|
224 |
prompt_templates = yaml.safe_load(stream)
|
225 |
+
|
226 |
agent = CodeAgent(
|
227 |
model=model,
|
228 |
+
tools=[
|
229 |
+
final_answer,
|
230 |
+
recognize_song,
|
231 |
+
login_soundeo,
|
232 |
+
add_song_to_download_list,
|
233 |
+
get_current_time_in_timezone
|
234 |
+
],
|
235 |
+
max_steps=8,
|
236 |
verbosity_level=1,
|
237 |
grammar=None,
|
238 |
planning_interval=None,
|
|
|
241 |
prompt_templates=prompt_templates
|
242 |
)
|
243 |
|
244 |
+
# Interfaz de usuario con Gradio
|
245 |
+
with gr.Blocks() as demo:
|
246 |
+
gr.Markdown("# 🎵 Asistente Musical - Reconocimiento y Descarga")
|
247 |
+
|
248 |
+
with gr.Tab("Reconocimiento de Música"):
|
249 |
+
with gr.Row():
|
250 |
+
audio_input = gr.Audio(type="filepath", label="Sube o graba un fragmento de audio")
|
251 |
+
|
252 |
+
query_input = gr.Textbox(
|
253 |
+
label="Consulta (opcional)",
|
254 |
+
placeholder="Reconoce esta canción y agrégala a mi lista de descarga"
|
255 |
+
)
|
256 |
+
submit_btn = gr.Button("Procesar")
|
257 |
+
output = gr.Markdown()
|
258 |
+
|
259 |
+
def process_with_agent(audio=None, text_query=""):
|
260 |
+
context = {}
|
261 |
+
|
262 |
+
if audio:
|
263 |
+
context["audio_path"] = audio
|
264 |
+
if not text_query:
|
265 |
+
text_query = "Reconoce esta canción y dame información detallada sobre ella."
|
266 |
+
|
267 |
+
if not text_query:
|
268 |
+
return "❌ Por favor ingresa una consulta o sube un archivo de audio."
|
269 |
+
|
270 |
+
try:
|
271 |
+
result = agent.run(text_query, context=context)
|
272 |
+
return result
|
273 |
+
except Exception as e:
|
274 |
+
return f"❌ Error al procesar la solicitud: {str(e)}"
|
275 |
+
|
276 |
+
submit_btn.click(
|
277 |
+
fn=process_with_agent,
|
278 |
+
inputs=[audio_input, query_input],
|
279 |
+
outputs=output
|
280 |
+
)
|
281 |
+
|
282 |
+
with gr.Tab("Login a Soundeo"):
|
283 |
+
info_text = gr.Markdown("Las credenciales se cargarán automáticamente desde los secrets")
|
284 |
+
login_btn = gr.Button("Iniciar Sesión en Soundeo")
|
285 |
+
login_output = gr.Markdown()
|
286 |
+
|
287 |
+
def login_process():
|
288 |
+
query = "Inicia sesión en Soundeo usando las credenciales almacenadas"
|
289 |
+
return agent.run(query)
|
290 |
+
|
291 |
+
login_btn.click(
|
292 |
+
fn=login_process,
|
293 |
+
inputs=[],
|
294 |
+
outputs=login_output
|
295 |
+
)
|
296 |
|
297 |
+
demo.launch()
|