RicardoDataScience36 commited on
Commit
87fd7b2
·
verified ·
1 Parent(s): 90fbbdc

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +299 -0
app.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from pydantic_ai import Agent
4
+ from pydantic import BaseModel
5
+ import yfinance as yf
6
+ import asyncio
7
+ from datetime import datetime
8
+ import pandas as pd
9
+ from typing import List
10
+ from openai import OpenAI
11
+ import json
12
+
13
+ # Modelo para resultados de precios de acciones individuales
14
+ class ResultadoPrecioAccion(BaseModel):
15
+ simbolo: str
16
+ precio: float
17
+ moneda: str = "USD"
18
+ company_name: str
19
+ previous_close: float
20
+ percentage_change: float
21
+ timestamp: str
22
+
23
+ # Modelo para agrupar los resultados de múltiples acciones
24
+ class ResultadosPreciosAcciones(BaseModel):
25
+ resultados: List[ResultadoPrecioAccion]
26
+
27
+ # Función para ejecutar la herramienta de obtención de precio de acción
28
+ async def obtener_precio_accion_async(simbolo: str) -> dict:
29
+ ticker = yf.Ticker(simbolo)
30
+ try:
31
+ info = ticker.fast_info
32
+ precio = info.last_price
33
+ if precio is None:
34
+ raise ValueError(f"No se encontró información para el símbolo '{simbolo}'.")
35
+ company_name = ticker.info.get('shortName', 'N/A')
36
+ previous_close = info.previous_close
37
+ percentage_change = ((precio - previous_close) / previous_close) * 100 if previous_close != 0 else 0
38
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
39
+ return {
40
+ "simbolo": simbolo,
41
+ "precio": round(precio, 2),
42
+ "moneda": "USD",
43
+ "company_name": company_name,
44
+ "previous_close": round(previous_close, 2),
45
+ "percentage_change": round(percentage_change, 2),
46
+ "timestamp": timestamp
47
+ }
48
+ except Exception as e:
49
+ raise ValueError(f"Error al obtener datos para '{simbolo}': {str(e)}")
50
+
51
+ # Función para llamar a la API de Grok (síncrona)
52
+ def call_grok_api(api_key, consulta):
53
+ client = OpenAI(
54
+ api_key=api_key,
55
+ base_url="https://api.x.ai/v1",
56
+ )
57
+
58
+ functions = [
59
+ {
60
+ "name": "obtener_info_accion",
61
+ "description": "Obtiene información sobre el precio de una o varias acciones.",
62
+ "parameters": {
63
+ "type": "object",
64
+ "properties": {
65
+ "consulta": {
66
+ "type": "string",
67
+ "description": "La consulta del usuario sobre el precio de las acciones.",
68
+ },
69
+ },
70
+ "required": ["consulta"],
71
+ },
72
+ }
73
+ ]
74
+
75
+ tools = [{"type": "function", "function": f} for f in functions]
76
+
77
+ messages = [
78
+ {"role": "system", "content": "Eres un asistente financiero útil."},
79
+ {"role": "user", "content": consulta}
80
+ ]
81
+
82
+ try:
83
+ # Llama a la API
84
+ response = client.chat.completions.create(
85
+ model="grok-beta", # Asegúrate de que el modelo es correcto
86
+ messages=messages,
87
+ tools=tools,
88
+ )
89
+
90
+ # Verifica si la respuesta tiene contenido esperado
91
+ if hasattr(response, "choices") and len(response.choices) > 0:
92
+ response_message = response.choices[0].message
93
+ if hasattr(response_message, "tool_calls") and response_message.tool_calls:
94
+ tool_call = response_message.tool_calls[0]
95
+ function_name = tool_call.function.name
96
+ function_args = json.loads(tool_call.function.arguments)
97
+
98
+ if function_name == "obtener_info_accion":
99
+ # Ejecutar la función asíncrona usando asyncio.run
100
+ loop = asyncio.new_event_loop()
101
+ asyncio.set_event_loop(loop)
102
+ try:
103
+ resultados = loop.run_until_complete(
104
+ obtener_info_accion(
105
+ function_args["consulta"],
106
+ os.environ.get("GROQ_API_KEY"),
107
+ api_key, True, False
108
+ )
109
+ )
110
+ finally:
111
+ loop.close()
112
+ return resultados
113
+
114
+ else:
115
+ return f"Función desconocida: {function_name}"
116
+ else:
117
+ return response_message.content
118
+ else:
119
+ return "La API no devolvió una respuesta válida."
120
+
121
+ except Exception as e:
122
+ return f"Error al llamar a la API de Grok: {e}"
123
+
124
+ # Función principal para obtener información de acciones (asíncrona)
125
+ async def obtener_info_accion(consulta: str, groq_api_key: str, grok_api_key: str, use_groq: bool, use_grok: bool) -> str:
126
+ try:
127
+ if use_groq:
128
+ # Usar Groq AI
129
+ os.environ["GROQ_API_KEY"] = groq_api_key
130
+
131
+ # Inicializa el agente de Pydantic AI
132
+ agente_acciones = Agent(
133
+ "groq:llama3-groq-70b-8192-tool-use-preview",
134
+ result_type=ResultadosPreciosAcciones,
135
+ system_prompt="Eres un asistente financiero útil que puede consultar precios de acciones. Usa la herramienta obtener_precio_accion para obtener datos actuales y devuelve la información en el formato especificado. Debes proporcionar información para todas las acciones solicitadas."
136
+ )
137
+
138
+ # Herramienta para obtener el precio de una acción
139
+ @agente_acciones.tool_plain
140
+ async def obtener_precio_accion_tool(simbolo: str) -> dict:
141
+ return await obtener_precio_accion_async(simbolo)
142
+
143
+ # Ejecutar la consulta
144
+ response = await agente_acciones.run(consulta)
145
+
146
+ # Procesar los resultados
147
+ data_frames = []
148
+ errores = []
149
+ for resultado in response.data.resultados:
150
+ try:
151
+ data_frames.append(pd.DataFrame([{
152
+ 'Símbolo': resultado.simbolo,
153
+ 'Nombre de la Empresa': resultado.company_name,
154
+ 'Precio Actual': f"${resultado.precio:.2f} {resultado.moneda}",
155
+ 'Última Actualización': resultado.timestamp,
156
+ 'Cambio en Precio': f"{resultado.percentage_change:.2f}%",
157
+ 'Tendencia': '📈' if resultado.percentage_change >= 0 else '📉'
158
+ }]))
159
+ except Exception as e:
160
+ errores.append(pd.DataFrame([{'Símbolo': resultado.simbolo, 'Error': str(e)}]))
161
+
162
+ # Concatena todos los DataFrames
163
+ if data_frames:
164
+ data_df = pd.concat(data_frames, ignore_index=True)
165
+ else:
166
+ data_df = pd.DataFrame()
167
+
168
+ if errores:
169
+ error_df = pd.concat(errores, ignore_index=True)
170
+ else:
171
+ error_df = pd.DataFrame()
172
+
173
+ respuesta = "📈 Información de las Acciones\n\n"
174
+ if not data_df.empty:
175
+ respuesta += data_df.to_string(index=False) + "\n\n"
176
+ if not error_df.empty:
177
+ respuesta += "### Errores:\n" + error_df.to_string(index=False) + "\n\n"
178
+ if not data_df.empty:
179
+ respuesta += "### Análisis Comparativo:\n"
180
+ respuesta += f"- **Máximo Precio:** {data_df['Precio Actual'].max()}\n"
181
+ respuesta += f"- **Mínimo Precio:** {data_df['Precio Actual'].min()}\n"
182
+
183
+ return respuesta
184
+
185
+ elif use_grok:
186
+ # Usar Grok API (llamada asíncrona a call_grok_api)
187
+ # return await asyncio.to_thread(call_grok_api, grok_api_key, consulta)
188
+ return await asyncio.get_event_loop().run_in_executor(None, call_grok_api, grok_api_key, consulta)
189
+
190
+ else:
191
+ return "⚠️ Por favor, selecciona al menos un modelo para usar."
192
+
193
+ except Exception as e:
194
+ return f"⚠️ **Error:** {str(e)}\nPor favor, ingresa una consulta válida."
195
+
196
+ # Tema personalizado con tonos claros
197
+ tema_personalizado = gr.themes.Soft(
198
+ primary_hue=gr.themes.Color(
199
+ c50='#e6f2ff',
200
+ c100='#b3dcff',
201
+ c200='#4dabf7',
202
+ c300='#2196f3',
203
+ c400='#1e88e5',
204
+ c500='#1976d2',
205
+ c600='#1565c0',
206
+ c700='#0b3d91',
207
+ c800='#082963',
208
+ c900='#051839',
209
+ c950='#030c1f'
210
+ ),
211
+ neutral_hue=gr.themes.Color(
212
+ c50='#f5f5f5',
213
+ c100='#e0e0e0',
214
+ c200='#bdbdbd',
215
+ c300='#9e9e9e',
216
+ c400='#757575',
217
+ c500='#616161',
218
+ c600='#424242',
219
+ c700='#212121',
220
+ c800='#121212',
221
+ c900='#010101',
222
+ c950='#000000'
223
+ )
224
+ )
225
+
226
+ # Crear la interfaz de Gradio con el tema personalizado
227
+ with gr.Blocks(title="Asistente Financiero AI", theme=tema_personalizado) as demo:
228
+ # Encabezado con markdown
229
+ gr.Markdown(
230
+ """
231
+ # 💹 Asistente de Precios de Acciones AI
232
+ ## Consulta Instantánea de Información Bursátil
233
+ """
234
+ )
235
+
236
+ # Sección de instrucciones
237
+ gr.Markdown(
238
+ """
239
+ ### 🎯 Guía Rápida
240
+ - Ingresa una consulta en lenguaje coloquial (ej. "¿Cuál es el precio de Apple y Microsoft?")
241
+ - Obtén información de precio en tiempo real
242
+ - Soporta mercados de valores globales
243
+ """
244
+ )
245
+
246
+ # Diseño de entrada y salida
247
+ with gr.Column():
248
+ consulta = gr.Textbox(
249
+ label="Ingrese la consulta",
250
+ placeholder="Ingrese una consulta en lenguaje coloquial",
251
+ lines=1,
252
+ elem_id="input-textbox"
253
+ )
254
+ groq_api_key = gr.Textbox(
255
+ label="Groq AI API Key",
256
+ placeholder="Ingrese su API Key de Groq AI (opcional si no usa Groq)",
257
+ type="password",
258
+ value=os.environ.get("GROQ_API_KEY", "")
259
+ )
260
+ grok_api_key = gr.Textbox(
261
+ label="Grok API Key",
262
+ placeholder="Ingrese su API Key de Grok (opcional si no usa Grok)",
263
+ type="password",
264
+ value=os.environ.get("GROK_API_KEY", "")
265
+ )
266
+ with gr.Row():
267
+ use_groq = gr.Checkbox(label="Usar Groq AI", value=True)
268
+ use_grok = gr.Checkbox(label="Usar Grok", value=False)
269
+ boton = gr.Button("Consultar Precio 🔍", variant="primary", elem_id="consultar-button")
270
+
271
+ # Sección de salida
272
+ salida = gr.Textbox(
273
+ label="Resultados",
274
+ placeholder="La información de la acción aparecerá aquí...",
275
+ lines=10,
276
+ interactive=False,
277
+ elem_id="output-textbox"
278
+ )
279
+
280
+ # Pie de página con autor
281
+ gr.Markdown(
282
+ """
283
+ ---
284
+ ### 🚀 Potenciado por Tecnología AI
285
+ Desarrollado con ❤️ usando Python, Gradio, Groq y Grok
286
+ **Creado por: Ricardo Fernández**
287
+ """
288
+ )
289
+
290
+ # Conectar evento de clic del botón
291
+ boton.click(
292
+ obtener_info_accion,
293
+ inputs=[consulta, groq_api_key, grok_api_key, use_groq, use_grok],
294
+ outputs=salida
295
+ )
296
+
297
+ # Lanzar la aplicación
298
+ if __name__ == "__main__":
299
+ demo.launch(share=True)