Jeremy Live
commited on
Commit
路
0369200
1
Parent(s):
eed8b79
INFO:__main__:Database connection successful INFO:__main__:Response generation complete
Browse files
app.py
CHANGED
@@ -12,6 +12,10 @@ import pandas as pd
|
|
12 |
import plotly.express as px
|
13 |
import plotly.graph_objects as go
|
14 |
from plotly.subplots import make_subplots
|
|
|
|
|
|
|
|
|
15 |
|
16 |
try:
|
17 |
# Intentar importar dependencias opcionales
|
@@ -319,21 +323,36 @@ else:
|
|
319 |
|
320 |
logger.info("="*50)
|
321 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
def extract_sql_query(text):
|
323 |
-
"""Extrae consultas SQL del texto
|
|
|
|
|
324 |
if not text:
|
325 |
return None
|
326 |
-
|
327 |
-
# Buscar
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
|
|
|
|
|
|
|
|
337 |
return None
|
338 |
|
339 |
def execute_sql_query(query, db_connection):
|
@@ -343,7 +362,11 @@ def execute_sql_query(query, db_connection):
|
|
343 |
|
344 |
try:
|
345 |
with db_connection._engine.connect() as connection:
|
346 |
-
|
|
|
|
|
|
|
|
|
347 |
rows = result.fetchall()
|
348 |
|
349 |
# Convertir los resultados a un formato legible
|
@@ -481,9 +504,9 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
|
|
481 |
|
482 |
logger.info(f"Extracted response text: {response_text[:200]}...")
|
483 |
|
484 |
-
# Check if the response contains an SQL query
|
485 |
sql_query = extract_sql_query(response_text)
|
486 |
-
if sql_query:
|
487 |
logger.info(f"Detected SQL query: {sql_query}")
|
488 |
# Execute the query and update the response
|
489 |
db_connection, _ = setup_database_connection()
|
@@ -551,6 +574,8 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
|
|
551 |
response_text += "\n\n鈿狅笍 No se pudo generar la visualizaci贸n de los datos."
|
552 |
else:
|
553 |
response_text += "\n\n鈿狅笍 No se pudo conectar a la base de datos para ejecutar la consulta."
|
|
|
|
|
554 |
|
555 |
# Fallback: if user asked for a chart (e.g., pie) and we didn't get SQL or chart yet,
|
556 |
# parse the most recent assistant text for lines like "LABEL: NUMBER" (bulleted or plain).
|
|
|
12 |
import plotly.express as px
|
13 |
import plotly.graph_objects as go
|
14 |
from plotly.subplots import make_subplots
|
15 |
+
try:
|
16 |
+
from sqlalchemy import text as sa_text
|
17 |
+
except Exception:
|
18 |
+
sa_text = None
|
19 |
|
20 |
try:
|
21 |
# Intentar importar dependencias opcionales
|
|
|
323 |
|
324 |
logger.info("="*50)
|
325 |
|
326 |
+
def looks_like_sql(s: str) -> bool:
|
327 |
+
"""Heuristic to check if a string looks like an executable SQL statement."""
|
328 |
+
if not s:
|
329 |
+
return False
|
330 |
+
s_strip = s.strip().lstrip("-- ")
|
331 |
+
# common starters
|
332 |
+
return bool(re.match(r"^(WITH|SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE)\b", s_strip, re.IGNORECASE))
|
333 |
+
|
334 |
+
|
335 |
def extract_sql_query(text):
|
336 |
+
"""Extrae consultas SQL del texto. Acepta solo bloques etiquetados como ```sql
|
337 |
+
o cadenas que claramente parezcan SQL. Evita ejecutar texto gen茅rico.
|
338 |
+
"""
|
339 |
if not text:
|
340 |
return None
|
341 |
+
|
342 |
+
# Buscar TODOS los bloques en backticks y elegir los que sean 'sql'
|
343 |
+
for m in re.finditer(r"```(\w+)?\s*(.*?)```", text, re.DOTALL | re.IGNORECASE):
|
344 |
+
lang = (m.group(1) or '').lower()
|
345 |
+
body = (m.group(2) or '').strip()
|
346 |
+
if lang in {"sql", "postgresql", "mysql"} and looks_like_sql(body):
|
347 |
+
return body
|
348 |
+
|
349 |
+
# Si no hay bloques etiquetados, buscar una consulta SQL simple con palabras clave
|
350 |
+
simple = re.search(r"(WITH|SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE)[\s\S]*?;", text, re.IGNORECASE)
|
351 |
+
if simple:
|
352 |
+
candidate = simple.group(0).strip()
|
353 |
+
if looks_like_sql(candidate):
|
354 |
+
return candidate
|
355 |
+
|
356 |
return None
|
357 |
|
358 |
def execute_sql_query(query, db_connection):
|
|
|
362 |
|
363 |
try:
|
364 |
with db_connection._engine.connect() as connection:
|
365 |
+
# Ensure SQLAlchemy receives a SQL expression
|
366 |
+
if sa_text is not None and isinstance(query, str):
|
367 |
+
result = connection.execute(sa_text(query))
|
368 |
+
else:
|
369 |
+
result = connection.execute(query)
|
370 |
rows = result.fetchall()
|
371 |
|
372 |
# Convertir los resultados a un formato legible
|
|
|
504 |
|
505 |
logger.info(f"Extracted response text: {response_text[:200]}...")
|
506 |
|
507 |
+
# Check if the response contains an SQL query and it truly looks like SQL
|
508 |
sql_query = extract_sql_query(response_text)
|
509 |
+
if sql_query and looks_like_sql(sql_query):
|
510 |
logger.info(f"Detected SQL query: {sql_query}")
|
511 |
# Execute the query and update the response
|
512 |
db_connection, _ = setup_database_connection()
|
|
|
574 |
response_text += "\n\n鈿狅笍 No se pudo generar la visualizaci贸n de los datos."
|
575 |
else:
|
576 |
response_text += "\n\n鈿狅笍 No se pudo conectar a la base de datos para ejecutar la consulta."
|
577 |
+
elif sql_query and not looks_like_sql(sql_query):
|
578 |
+
logger.info("Detected code block but it does not look like SQL; skipping execution.")
|
579 |
|
580 |
# Fallback: if user asked for a chart (e.g., pie) and we didn't get SQL or chart yet,
|
581 |
# parse the most recent assistant text for lines like "LABEL: NUMBER" (bulleted or plain).
|