File size: 10,509 Bytes
412755c
9b5b26a
 
 
c19d193
412755c
 
 
 
6aae614
8fe992b
412755c
9b5b26a
 
 
 
 
 
 
 
 
 
 
 
 
 
8c01ffb
412755c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8c01ffb
412755c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae7a494
412755c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae7a494
412755c
 
e121372
412755c
 
 
 
13d500a
8c01ffb
861422e
 
412755c
8c01ffb
8fe992b
412755c
 
 
 
 
 
 
 
8c01ffb
 
 
 
 
861422e
8fe992b
 
412755c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b5b26a
412755c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
from smolagents import CodeAgent, HfApiModel, tool
import datetime
import requests
import pytz
import yaml
import os
import pickle
import time
import gradio as gr
from tools.final_answer import FinalAnswerTool

# Herramienta para obtener la hora actual en una zona horaria
@tool
def get_current_time_in_timezone(timezone: str) -> str:
    """A tool that fetches the current local time in a specified timezone.
    Args:
        timezone: A string representing a valid timezone (e.g., 'America/New_York').
    """
    try:
        # Create timezone object
        tz = pytz.timezone(timezone)
        # Get current time in that timezone
        local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
        return f"The current local time in {timezone} is: {local_time}"
    except Exception as e:
        return f"Error fetching time for timezone '{timezone}': {str(e)}"

# Herramienta para reconocer canciones usando AudD
@tool
def recognize_song(audio_path: str) -> dict:
    """Reconoce una canción a partir de un archivo de audio
    Args:
        audio_path: ruta al archivo de audio a reconocer
    """
    AUDD_API_TOKEN = os.getenv("AUDD_API_TOKEN")
    
    if not os.path.exists(audio_path):
        return {"error": "El archivo de audio no existe"}
    
    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"Error en la API: {response.status_code}"}
            
        result = response.json()
        
        if result['status'] == 'error':
            return {"error": result['error']['error_message']}
            
        if not result.get('result'):
            return {"error": "No se pudo reconocer la canción"}
            
        song_info = result['result']
        
        return {
            "🎶 Canción": song_info.get('title', 'Desconocido'),
            "🎤 Artista": song_info.get('artist', 'Desconocido'),
            "📀 Álbum": song_info.get('album', 'Desconocido'),
            "🎧 Spotify": song_info.get('spotify', {}).get('external_urls', {}).get('spotify', 'No disponible'),
            "🍏 Apple Music": song_info.get('apple_music', {}).get('url', 'No disponible')
        }
        
    except Exception as e:
        return {"error": f"Error al procesar el audio: {str(e)}"}

# Herramienta para iniciar sesión en Soundeo
@tool
def login_soundeo() -> str:
    """Inicia sesión en Soundeo usando las credenciales almacenadas en secrets"""
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    # Obtener credenciales de los secrets
    username = os.getenv("SOUNDEO_USERNAME")
    password = os.getenv("SOUNDEO_PASSWORD")
    
    if not username or not password:
        return "❌ No se encontraron las credenciales en los secrets"
    
    # Configurar opciones de Chrome
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--disable-gpu")
    
    try:
        # Inicializar el driver
        driver = webdriver.Chrome(options=chrome_options)
        
        # Navegar a Soundeo
        driver.get("https://soundeo.com/login")
        time.sleep(3)  # Esperar a que cargue la página
        
        # Capturar screenshot para debug
        driver.save_screenshot("pre_login.png")
        
        # Completar formulario de login
        username_field = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "username"))
        )
        username_field.send_keys(username)
        
        password_field = driver.find_element(By.ID, "password")
        password_field.send_keys(password)
        
        # Hacer clic en el botón de login
        login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
        login_button.click()
        
        # Esperar a que se complete el login
        time.sleep(5)
        
        # Capturar screenshot para verificar
        driver.save_screenshot("post_login.png")
        
        # Guardar cookies para uso futuro
        pickle.dump(driver.get_cookies(), open("soundeo_cookies.pkl", "wb"))
        
        # Verificar si el login fue exitoso
        if "dashboard" in driver.current_url or "account" in driver.current_url:
            result = "✅ Login exitoso en Soundeo"
        else:
            result = "❌ Error al iniciar sesión. Verifica tus credenciales."
        
        driver.quit()
        return result
        
    except Exception as e:
        return f"❌ Error con Selenium: {str(e)}"

# Herramienta para buscar y añadir una canción a la lista de descarga
@tool
def add_song_to_download_list(song_title: str, artist: str) -> str:
    """Busca una canción en Soundeo y la añade a la lista de descarga
    Args:
        song_title: título de la canción
        artist: nombre del artista
    """
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--disable-gpu")
    
    try:
        driver = webdriver.Chrome(options=chrome_options)
        
        # Cargar cookies si existen
        cookies_file = "soundeo_cookies.pkl"
        if os.path.exists(cookies_file):
            driver.get("https://soundeo.com")
            cookies = pickle.load(open(cookies_file, "rb"))
            for cookie in cookies:
                driver.add_cookie(cookie)
        else:
            driver.quit()
            return "❌ No hay cookies de sesión. Primero debes iniciar sesión."
        
        # Navegar a la búsqueda
        search_query = f"{song_title} {artist}"
        search_query = search_query.replace(" ", "+")
        driver.get(f"https://soundeo.com/search?q={search_query}")
        time.sleep(5)
        
        # Capturar screenshot para debug
        driver.save_screenshot("search_results.png")
        
        # Buscar el primer resultado
        try:
            first_result = WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".track-item"))
            )
            
            # Hacer clic en "Add to Download List"
            download_button = first_result.find_element(By.CSS_SELECTOR, ".download-button")
            download_button.click()
            
            time.sleep(3)
            driver.save_screenshot("added_to_list.png")
            
            # Obtener información del track añadido
            track_info = first_result.find_element(By.CSS_SELECTOR, ".track-title").text
            artist_info = first_result.find_element(By.CSS_SELECTOR, ".track-artist").text
            
            driver.quit()
            return f"✅ Añadida a la lista de descarga: {track_info} - {artist_info}"
            
        except Exception as e:
            driver.quit()
            return f"❌ No se encontraron resultados o no se pudo añadir: {str(e)}"
            
    except Exception as e:
        return f"❌ Error con Selenium: {str(e)}"

# Configuración del agente
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,
        login_soundeo,
        add_song_to_download_list,
        get_current_time_in_timezone
    ],
    max_steps=8,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name=None,
    description=None,
    prompt_templates=prompt_templates
)

# Interfaz de usuario con Gradio
with gr.Blocks() as demo:
    gr.Markdown("# 🎵 Asistente Musical - Reconocimiento y Descarga")
    
    with gr.Tab("Reconocimiento de Música"):
        with gr.Row():
            audio_input = gr.Audio(type="filepath", label="Sube o graba un fragmento de audio")
        
        query_input = gr.Textbox(
            label="Consulta (opcional)", 
            placeholder="Reconoce esta canción y agrégala a mi lista de descarga"
        )
        submit_btn = gr.Button("Procesar")
        output = gr.Markdown()
        
        def process_with_agent(audio=None, text_query=""):
            context = {}
            
            if audio:
                context["audio_path"] = audio
                if not text_query:
                    text_query = "Reconoce esta canción y dame información detallada sobre ella."
            
            if not text_query:
                return "❌ Por favor ingresa una consulta o sube un archivo de audio."
            
            try:
                result = agent.run(text_query, context=context)
                return result
            except Exception as e:
                return f"❌ Error al procesar la solicitud: {str(e)}"
        
        submit_btn.click(
            fn=process_with_agent,
            inputs=[audio_input, query_input],
            outputs=output
        )
    
    with gr.Tab("Login a Soundeo"):
        info_text = gr.Markdown("Las credenciales se cargarán automáticamente desde los secrets")
        login_btn = gr.Button("Iniciar Sesión en Soundeo")
        login_output = gr.Markdown()
        
        def login_process():
            query = "Inicia sesión en Soundeo usando las credenciales almacenadas"
            return agent.run(query)
        
        login_btn.click(
            fn=login_process,
            inputs=[],
            outputs=login_output
        )

demo.launch()