Jeremy Live commited on
Commit
0369200
1 Parent(s): eed8b79

INFO:__main__:Database connection successful INFO:__main__:Response generation complete

Browse files
Files changed (1) hide show
  1. app.py +40 -15
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 usando expresiones regulares."""
 
 
324
  if not text:
325
  return None
326
-
327
- # Buscar c贸digo SQL entre backticks
328
- sql_match = re.search(r'```(?:sql)?\s*(.*?)```', text, re.DOTALL)
329
- if sql_match:
330
- return sql_match.group(1).strip()
331
-
332
- # Si no hay backticks, buscar una consulta SQL simple
333
- sql_match = re.search(r'(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE).*?;', text, re.IGNORECASE | re.DOTALL)
334
- if sql_match:
335
- return sql_match.group(0).strip()
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
- result = connection.execute(query)
 
 
 
 
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).