Jeremy Live commited on
Commit
f639c56
·
1 Parent(s): 5c3160e
Files changed (3) hide show
  1. README.md +104 -13
  2. app.py +517 -0
  3. requirements.txt +9 -0
README.md CHANGED
@@ -1,13 +1,104 @@
1
- ---
2
- title: ChatbotAgentGraphSQLgemini V2 Etheroi
3
- emoji: 🐨
4
- colorFrom: pink
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 5.41.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Chatbot Agent with SQL and Gemini Integration
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![Python 3.8+](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://www.python.org/downloads/)
5
+ [![Gradio](https://img.shields.io/badge/Interface-Gradio-FF4B4B.svg)](https://gradio.app/)
6
+
7
+ A powerful chatbot agent that integrates Google's Gemini language model with SQL database connectivity, enabling natural language to SQL query conversion and data visualization.
8
+
9
+ ## 🌟 Features
10
+
11
+ - **Natural Language to SQL**: Convert natural language questions into SQL queries
12
+ - **Database Integration**: Connect to MySQL databases seamlessly
13
+ - **Interactive Chat Interface**: User-friendly Gradio-based web interface
14
+ - **Data Visualization**: Generate visualizations from query results
15
+ - **Environment Configuration**: Easy setup with environment variables
16
+
17
+ ## 🚀 Quick Start
18
+
19
+ ### Prerequisites
20
+
21
+ - Python 3.8 or higher
22
+ - MySQL database (or compatible database)
23
+ - Google API key for Gemini
24
+
25
+ ### Installation
26
+
27
+ 1. Clone the repository:
28
+ ```bash
29
+ git clone https://github.com/yourusername/chatbot-agent-sql-gemini.git
30
+ cd chatbot-agent-sql-gemini
31
+ ```
32
+
33
+ 2. Install dependencies:
34
+ ```bash
35
+ pip install -r requirements.txt
36
+ ```
37
+
38
+ 3. Create a `.env` file in the project root with your configuration:
39
+ ```env
40
+ DB_USER=your_db_username
41
+ DB_PASSWORD=your_db_password
42
+ DB_HOST=your_db_host
43
+ DB_NAME=your_database_name
44
+ GOOGLE_API_KEY=your_google_api_key
45
+ ```
46
+
47
+ ### Running the Application
48
+
49
+ 1. Start the application:
50
+ ```bash
51
+ python app.py
52
+ ```
53
+
54
+ 2. Open your web browser and navigate to `http://localhost:7860`
55
+
56
+ ## 🛠️ Configuration
57
+
58
+ The application can be configured using the following environment variables:
59
+
60
+ | Variable | Description | Required |
61
+ |----------|-------------|----------|
62
+ | `DB_USER` | Database username | ✅ |
63
+ | `DB_PASSWORD` | Database password | ✅ |
64
+ | `DB_HOST` | Database host | ✅ |
65
+ | `DB_NAME` | Database name | ✅ |
66
+ | `GOOGLE_API_KEY` | Google API key for Gemini | ✅ |
67
+
68
+ ## 📦 Dependencies
69
+
70
+ - gradio >= 3.0.0
71
+ - langchain >= 0.1.0
72
+ - langchain-community >= 0.0.10
73
+ - langchain-google-genai >= 0.1.0
74
+ - langgraph >= 0.0.0
75
+ - matplotlib >= 3.7.0
76
+ - pandas >= 2.0.0
77
+ - sqlalchemy >= 2.0.0
78
+ - python-dotenv >= 1.0.0
79
+
80
+ ## 🤖 How It Works
81
+
82
+ 1. The application connects to your SQL database using the provided credentials
83
+ 2. Users input natural language questions through the Gradio interface
84
+ 3. The Gemini model converts these questions into SQL queries
85
+ 4. Queries are executed against the database
86
+ 5. Results are formatted and displayed to the user
87
+ 6. For appropriate data, visualizations are automatically generated
88
+
89
+ ## 📝 Example Queries
90
+
91
+ - "Show me the top 10 customers by total purchases"
92
+ - "What were our total sales last month?"
93
+ - "List all products with stock below minimum levels"
94
+ - "Generate a bar chart of monthly sales for the past year"
95
+
96
+ ## 📄 License
97
+
98
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
99
+
100
+ ## 🙏 Acknowledgments
101
+
102
+ - [Gradio](https://gradio.app/) for the web interface
103
+ - [Google Gemini](https://ai.google.dev/) for the language model
104
+ - [LangChain](https://www.langchain.com/) for the agent framework
app.py ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import json
4
+ from typing import List, Dict, Any, Optional, Tuple
5
+ import logging
6
+
7
+ try:
8
+ # Intentar importar dependencias opcionales
9
+ from langchain_community.agent_toolkits import create_sql_agent
10
+ from langchain_community.utilities import SQLDatabase
11
+ from langchain_google_genai import ChatGoogleGenerativeAI
12
+ from langchain.agents.agent_types import AgentType
13
+ import pymysql
14
+ from dotenv import load_dotenv
15
+
16
+ DEPENDENCIES_AVAILABLE = True
17
+ except ImportError:
18
+ # Si faltan dependencias, la aplicación funcionará en modo demo
19
+ DEPENDENCIES_AVAILABLE = False
20
+
21
+ # Configuración de logging
22
+ logging.basicConfig(level=logging.INFO)
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Configure logging
26
+ logging.basicConfig(level=logging.INFO)
27
+ logger = logging.getLogger(__name__)
28
+
29
+ def check_environment():
30
+ """Verifica si el entorno está configurado correctamente."""
31
+ if not DEPENDENCIES_AVAILABLE:
32
+ return False, "Missing required Python packages. Please install them with: pip install -r requirements.txt"
33
+
34
+ # Verificar si estamos en un entorno con variables de entorno
35
+ required_vars = ["DB_USER", "DB_PASSWORD", "DB_HOST", "DB_NAME", "GOOGLE_API_KEY"]
36
+ missing_vars = [var for var in required_vars if not os.getenv(var)]
37
+
38
+ if missing_vars:
39
+ return False, f"Missing required environment variables: {', '.join(missing_vars)}"
40
+
41
+ return True, "Environment is properly configured"
42
+
43
+ def setup_database_connection():
44
+ """Intenta establecer una conexión a la base de datos."""
45
+ if not DEPENDENCIES_AVAILABLE:
46
+ return None, "Dependencies not available"
47
+
48
+ try:
49
+ load_dotenv(override=True)
50
+
51
+ db_user = os.getenv("DB_USER")
52
+ db_password = os.getenv("DB_PASSWORD")
53
+ db_host = os.getenv("DB_HOST")
54
+ db_name = os.getenv("DB_NAME")
55
+
56
+ if not all([db_user, db_password, db_host, db_name]):
57
+ return None, "Missing database configuration"
58
+
59
+ logger.info(f"Connecting to database: {db_user}@{db_host}/{db_name}")
60
+
61
+ # Probar conexión
62
+ connection = pymysql.connect(
63
+ host=db_host,
64
+ user=db_user,
65
+ password=db_password,
66
+ database=db_name,
67
+ connect_timeout=5,
68
+ cursorclass=pymysql.cursors.DictCursor
69
+ )
70
+ connection.close()
71
+
72
+ # Si la conexión es exitosa, crear motor SQLAlchemy
73
+ db_uri = f"mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}"
74
+ logger.info("Database connection successful")
75
+ return SQLDatabase.from_uri(db_uri), ""
76
+
77
+ except Exception as e:
78
+ error_msg = f"Error connecting to database: {str(e)}"
79
+ logger.error(error_msg)
80
+ return None, error_msg
81
+
82
+ def initialize_llm():
83
+ """Inicializa el modelo de lenguaje."""
84
+ if not DEPENDENCIES_AVAILABLE:
85
+ return None, "Dependencies not available"
86
+
87
+ google_api_key = os.getenv("GOOGLE_API_KEY")
88
+ if not google_api_key:
89
+ return None, "GOOGLE_API_KEY not found in environment variables"
90
+
91
+ try:
92
+ llm = ChatGoogleGenerativeAI(
93
+ model="gemini-2.0-flash",
94
+ temperature=0,
95
+ google_api_key=google_api_key
96
+ )
97
+ logger.info("Google Generative AI initialized successfully")
98
+ return llm, ""
99
+ except Exception as e:
100
+ error_msg = f"Error initializing Google Generative AI: {str(e)}"
101
+ logger.error(error_msg)
102
+ return None, error_msg
103
+
104
+ def create_agent():
105
+ """Crea el agente SQL si es posible."""
106
+ if not DEPENDENCIES_AVAILABLE:
107
+ return None, "Dependencies not available"
108
+
109
+ db, db_error = setup_database_connection()
110
+ llm, llm_error = initialize_llm()
111
+
112
+ if not db or not llm:
113
+ error_msg = " | ".join(filter(None, [db_error, llm_error]))
114
+ return None, f"Cannot create agent: {error_msg}"
115
+
116
+ try:
117
+ logger.info("Creating SQL agent...")
118
+ agent = create_sql_agent(
119
+ llm=llm,
120
+ db=db,
121
+ agent_type=AgentType.OPENAI_FUNCTIONS,
122
+ verbose=True
123
+ )
124
+ logger.info("SQL agent created successfully")
125
+ return agent, ""
126
+ except Exception as e:
127
+ error_msg = f"Error creating SQL agent: {str(e)}"
128
+ logger.error(error_msg)
129
+ return None, error_msg
130
+
131
+ # Inicializar el agente
132
+ agent, agent_error = create_agent()
133
+ db_connected = agent is not None
134
+
135
+ def extract_sql_query(text):
136
+ """Extrae consultas SQL del texto usando expresiones regulares."""
137
+ if not text:
138
+ return None
139
+
140
+ # Buscar código SQL entre backticks
141
+ sql_match = re.search(r'```(?:sql)?\s*(.*?)```', text, re.DOTALL)
142
+ if sql_match:
143
+ return sql_match.group(1).strip()
144
+
145
+ # Si no hay backticks, buscar una consulta SQL simple
146
+ sql_match = re.search(r'(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE).*?;', text, re.IGNORECASE | re.DOTALL)
147
+ if sql_match:
148
+ return sql_match.group(0).strip()
149
+
150
+ return None
151
+
152
+ def execute_sql_query(query, db_connection):
153
+ """Ejecuta una consulta SQL y devuelve los resultados como una cadena."""
154
+ if not db_connection:
155
+ return "Error: No hay conexión a la base de datos"
156
+
157
+ try:
158
+ with db_connection._engine.connect() as connection:
159
+ result = connection.execute(query)
160
+ rows = result.fetchall()
161
+
162
+ # Convertir los resultados a un formato legible
163
+ if not rows:
164
+ return "La consulta no devolvió resultados"
165
+
166
+ # Si es un solo resultado, devolverlo directamente
167
+ if len(rows) == 1 and len(rows[0]) == 1:
168
+ return str(rows[0][0])
169
+
170
+ # Si hay múltiples filas, formatear como tabla
171
+ try:
172
+ import pandas as pd
173
+ df = pd.DataFrame(rows)
174
+ return df.to_markdown(index=False)
175
+ except ImportError:
176
+ # Si pandas no está disponible, usar formato simple
177
+ return "\n".join([str(row) for row in rows])
178
+
179
+ except Exception as e:
180
+ return f"Error ejecutando la consulta: {str(e)}"
181
+
182
+ def generate_plot(data, x_col, y_col, title, x_label, y_label):
183
+ """Generate a plot from data and return the file path."""
184
+ plt.figure(figsize=(10, 6))
185
+ plt.bar(data[x_col], data[y_col])
186
+ plt.title(title)
187
+ plt.xlabel(x_label)
188
+ plt.ylabel(y_label)
189
+ plt.xticks(rotation=45)
190
+ plt.tight_layout()
191
+
192
+ # Save to a temporary file
193
+ temp_dir = tempfile.mkdtemp()
194
+ plot_path = os.path.join(temp_dir, "plot.png")
195
+ plt.savefig(plot_path)
196
+ plt.close()
197
+
198
+ return plot_path
199
+
200
+ async def stream_agent_response(question: str, chat_history: List) -> Tuple[List, Dict]:
201
+ """Procesa la pregunta del usuario y devuelve la respuesta del agente."""
202
+ if not agent:
203
+ error_msg = (
204
+ "## ⚠️ Error: Agente no inicializado\n\n"
205
+ "No se pudo inicializar el agente de base de datos. Por favor, verifica que:\n"
206
+ "1. Todas las variables de entorno estén configuradas correctamente\n"
207
+ "2. La base de datos esté accesible\n"
208
+ f"3. El modelo de lenguaje esté disponible\n\n"
209
+ f"Error: {agent_error}"
210
+ )
211
+ return chat_history + [[question, error_msg]], gr.update(visible=False)
212
+
213
+ try:
214
+ # Agregar un mensaje de "pensando"
215
+ chat_history = chat_history + [[question, None]]
216
+ yield chat_history, gr.update(visible=False)
217
+
218
+ # Ejecutar el agente
219
+ response = await agent.ainvoke({"input": question, "chat_history": chat_history[:-1]})
220
+
221
+ # Procesar la respuesta
222
+ if hasattr(response, 'output'):
223
+ response_text = response.output
224
+
225
+ # Verificar si la respuesta contiene una consulta SQL
226
+ sql_query = extract_sql_query(response_text)
227
+ if sql_query:
228
+ # Ejecutar la consulta y actualizar la respuesta
229
+ db_connection, _ = setup_database_connection()
230
+ query_result = execute_sql_query(sql_query, db_connection)
231
+ response_text += f"\n\n### 🔍 Resultado de la consulta:\n```sql\n{sql_query}\n```\n\n{query_result}"
232
+ else:
233
+ response_text = "Error: No se recibió respuesta del agente."
234
+
235
+ # Actualizar el historial con la respuesta completa
236
+ chat_history[-1][1] = response_text
237
+ return chat_history, gr.update(visible=False)
238
+
239
+ except Exception as e:
240
+ error_msg = f"## ❌ Error\n\nOcurrió un error al procesar tu solicitud:\n\n```\n{str(e)}\n```"
241
+ chat_history[-1][1] = error_msg
242
+ return chat_history, gr.update(visible=False)
243
+
244
+ # Custom CSS for the app
245
+ custom_css = """
246
+ .gradio-container {
247
+ max-width: 1200px !important;
248
+ margin: 0 auto !important;
249
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
250
+ }
251
+
252
+ #chatbot {
253
+ min-height: 500px;
254
+ border: 1px solid #e0e0e0;
255
+ border-radius: 8px;
256
+ margin-bottom: 20px;
257
+ padding: 20px;
258
+ background-color: #f9f9f9;
259
+ }
260
+
261
+ .user-message, .bot-message {
262
+ padding: 12px 16px;
263
+ border-radius: 18px;
264
+ margin: 8px 0;
265
+ max-width: 80%;
266
+ line-height: 1.5;
267
+ }
268
+
269
+ .user-message {
270
+ background-color: #007bff;
271
+ color: white;
272
+ margin-left: auto;
273
+ border-bottom-right-radius: 4px;
274
+ }
275
+
276
+ .bot-message {
277
+ background-color: #f1f1f1;
278
+ color: #333;
279
+ margin-right: auto;
280
+ border-bottom-left-radius: 4px;
281
+ }
282
+
283
+ #question-input textarea {
284
+ min-height: 50px !important;
285
+ border-radius: 8px !important;
286
+ padding: 12px !important;
287
+ font-size: 16px !important;
288
+ }
289
+
290
+ #send-button {
291
+ height: 100%;
292
+ background-color: #007bff !important;
293
+ color: white !important;
294
+ border: none !important;
295
+ border-radius: 8px !important;
296
+ font-weight: 500 !important;
297
+ transition: background-color 0.2s !important;
298
+ }
299
+
300
+ #send-button:hover {
301
+ background-color: #0056b3 !important;
302
+ }
303
+
304
+ .status-message {
305
+ text-align: center;
306
+ color: #666;
307
+ font-style: italic;
308
+ margin: 10px 0;
309
+ }
310
+ """
311
+
312
+ def create_ui():
313
+ """Crea y devuelve los componentes de la interfaz de usuario de Gradio."""
314
+ # Verificar el estado del entorno
315
+ env_ok, env_message = check_environment()
316
+
317
+ # Crear el tema personalizado
318
+ theme = gr.themes.Soft(
319
+ primary_hue="blue",
320
+ secondary_hue="indigo",
321
+ neutral_hue="slate"
322
+ )
323
+
324
+ with gr.Blocks(
325
+ css=custom_css,
326
+ title="Asistente de Base de Datos SQL",
327
+ theme=theme
328
+ ) as demo:
329
+ # Encabezado
330
+ gr.Markdown("""
331
+ # 🤖 Asistente de Base de Datos SQL
332
+
333
+ Haz preguntas en lenguaje natural sobre tu base de datos y obtén resultados de consultas SQL.
334
+ """)
335
+
336
+ # Mensaje de estado
337
+ if not env_ok:
338
+ gr.Warning("⚠️ " + env_message)
339
+
340
+ with gr.Accordion("ℹ️ Estado del sistema", open=not env_ok):
341
+ if not DEPENDENCIES_AVAILABLE:
342
+ gr.Markdown("""
343
+ ## ❌ Dependencias faltantes
344
+
345
+ Para ejecutar esta aplicación localmente, necesitas instalar las dependencias:
346
+
347
+ ```bash
348
+ pip install -r requirements.txt
349
+ ```
350
+ """)
351
+ else:
352
+ if not agent:
353
+ gr.Markdown(f"""
354
+ ## ⚠️ Configuración incompleta
355
+
356
+ No se pudo inicializar el agente de base de datos. Por favor, verifica que:
357
+
358
+ 1. Todas las variables de entorno estén configuradas correctamente
359
+ 2. La base de datos esté accesible
360
+ 3. La API de Google Gemini esté configurada
361
+
362
+ **Error:** {agent_error if agent_error else 'No se pudo determinar el error'}
363
+
364
+ ### Configuración local
365
+
366
+ Crea un archivo `.env` en la raíz del proyecto con las siguientes variables:
367
+
368
+ ```
369
+ DB_USER=tu_usuario
370
+ DB_PASSWORD=tu_contraseña
371
+ DB_HOST=tu_servidor
372
+ DB_NAME=tu_base_de_datos
373
+ GOOGLE_API_KEY=tu_api_key_de_google
374
+ ```
375
+ """)
376
+ else:
377
+ gr.Markdown("""
378
+ ## ✅ Sistema listo
379
+
380
+ El asistente está listo para responder tus preguntas sobre la base de datos.
381
+ """)
382
+
383
+ # Interfaz de chat
384
+ chatbot = gr.Chatbot(
385
+ elem_id="chatbot",
386
+ show_label=False,
387
+ height=500,
388
+ bubble_full_width=False,
389
+ avatar_images=(
390
+ "https://i.imgur.com/8O1mCJx.png", # User avatar
391
+ "https://i.imgur.com/7I12Ybh.png" # Bot avatar
392
+ ),
393
+ render_markdown=True,
394
+ show_copy_button=True,
395
+ show_share_button=True,
396
+ likeable=True
397
+ )
398
+
399
+ # Área de entrada
400
+ with gr.Row():
401
+ question_input = gr.Textbox(
402
+ label="",
403
+ placeholder="Escribe tu pregunta sobre la base de datos...",
404
+ elem_id="question-input",
405
+ container=False,
406
+ scale=5,
407
+ min_width=300,
408
+ max_lines=3,
409
+ autofocus=True
410
+ )
411
+ submit_button = gr.Button(
412
+ "Enviar",
413
+ elem_id="send-button",
414
+ min_width=100,
415
+ scale=1,
416
+ variant="primary"
417
+ )
418
+
419
+ # Información del sistema (solo para depuración)
420
+ with gr.Accordion("🔍 Información de depuración", open=False):
421
+ gr.Markdown("""
422
+ ### Estado del sistema
423
+ - **Base de datos**: {}
424
+ - **Modelo**: {}
425
+ - **Modo**: {}
426
+ """.format(
427
+ f"Conectado a {os.getenv('DB_HOST')}/{os.getenv('DB_NAME')}" if db_connected else "No conectado",
428
+ "gemini-2.0-flash" if agent else "No disponible",
429
+ "Completo" if agent else "Demo (sin conexión a base de datos)"
430
+ ))
431
+
432
+ # Mostrar variables de entorno (solo para depuración)
433
+ if os.getenv("SHOW_ENV_DEBUG", "false").lower() == "true":
434
+ env_vars = {k: "***" if "PASS" in k or "KEY" in k else v
435
+ for k, v in os.environ.items()
436
+ if k.startswith(('DB_', 'GOOGLE_'))}
437
+ gr.Code(
438
+ json.dumps(env_vars, indent=2, ensure_ascii=False),
439
+ language="json",
440
+ label="Variables de entorno"
441
+ )
442
+
443
+ # Hidden component for streaming output
444
+ streaming_output_display = gr.Textbox(visible=False)
445
+
446
+ return demo, chatbot, question_input, submit_button, streaming_output_display
447
+
448
+ # Create the UI components
449
+ demo, chatbot, question_input, submit_button, streaming_output_display = create_ui()
450
+
451
+ def user_message(user_input: str, chat_history: List) -> Tuple[str, List]:
452
+ """Add user message to chat history and clear input."""
453
+ if not user_input.strip():
454
+ return "", chat_history
455
+ logger.info(f"User message: {user_input}")
456
+ return "", chat_history + [[user_input, None]]
457
+
458
+ def bot_response(chat_history: List) -> Tuple[List, Dict]:
459
+ """Get bot response and update chat history."""
460
+ if not chat_history or not chat_history[-1][0]:
461
+ return chat_history, gr.update(visible=False)
462
+
463
+ question = chat_history[-1][0]
464
+ logger.info(f"Processing question: {question}")
465
+ return stream_agent_response(question, chat_history[:-1])
466
+
467
+ # Event handlers
468
+ submit_click = submit_button.click(
469
+ fn=user_message,
470
+ inputs=[question_input, chatbot],
471
+ outputs=[question_input, chatbot],
472
+ queue=True
473
+ ).then(
474
+ fn=bot_response,
475
+ inputs=[chatbot],
476
+ outputs=[chatbot, streaming_output_display],
477
+ api_name="ask"
478
+ )
479
+
480
+ question_input.submit(
481
+ fn=user_message,
482
+ inputs=[question_input, chatbot],
483
+ outputs=[question_input, chatbot],
484
+ queue=True
485
+ ).then(
486
+ fn=bot_response,
487
+ inputs=[chatbot],
488
+ outputs=[chatbot, streaming_output_display]
489
+ )
490
+
491
+ # Configuración para Hugging Face Spaces
492
+ def get_app():
493
+ """Obtiene la instancia de la aplicación Gradio para Hugging Face Spaces."""
494
+ # Verificar si estamos en un entorno de Hugging Face Spaces
495
+ if os.getenv('SPACE_ID'):
496
+ # Configuración específica para Spaces
497
+ demo.title = "🤖 Asistente de Base de Datos SQL (Demo)"
498
+ demo.description = """
499
+ Este es un demo del asistente de base de datos SQL.
500
+ Para usar la versión completa con conexión a base de datos, clona este espacio y configura las variables de entorno.
501
+ """
502
+
503
+ return demo
504
+
505
+ # Para desarrollo local
506
+ if __name__ == "__main__":
507
+ # Configuración para desarrollo local
508
+ demo.queue(concurrency_count=5).launch(
509
+ server_name="0.0.0.0",
510
+ server_port=7860,
511
+ debug=True,
512
+ share=False,
513
+ show_api=True,
514
+ favicon_path=None,
515
+ show_error=True,
516
+ show_tips=True
517
+ )
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=3.0.0
2
+ langchain>=0.1.0
3
+ langchain-community>=0.0.10
4
+ langchain-google-genai>=0.1.0
5
+ langgraph>=0.0.0
6
+ matplotlib>=3.7.0
7
+ pandas>=2.0.0
8
+ sqlalchemy>=2.0.0
9
+ python-dotenv>=1.0.0