Jeremy Live commited on
Commit
f2961b7
·
1 Parent(s): 8bb4446
Files changed (1) hide show
  1. app.py +71 -19
app.py CHANGED
@@ -417,6 +417,40 @@ def execute_sql_query(query, db_connection):
417
  except Exception as e:
418
  return f"Error ejecutando la consulta: {str(e)}"
419
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  def generate_plot(data, x_col, y_col, title, x_label, y_label):
421
  """Generate a plot from data and return the file path."""
422
  plt.figure(figsize=(10, 6))
@@ -563,18 +597,8 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
563
  data.append(dict(zip(columns, values)))
564
 
565
  if data and len(columns) >= 2:
566
- # Determine chart type from user's question (supports pie chart)
567
- q_lower = question.lower()
568
- if any(k in q_lower for k in ["gráfico circular", "grafico circular", "pie", "pastel"]):
569
- desired_type = 'pie'
570
- elif any(k in q_lower for k in ["línea", "linea", "line"]):
571
- desired_type = 'line'
572
- elif any(k in q_lower for k in ["dispersión", "dispersion", "scatter"]):
573
- desired_type = 'scatter'
574
- elif any(k in q_lower for k in ["histograma", "histogram"]):
575
- desired_type = 'histogram'
576
- else:
577
- desired_type = 'bar'
578
 
579
  # Choose x/y columns (assume first is category, second numeric)
580
  x_col = columns[0]
@@ -608,8 +632,7 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
608
  # If we still have no chart but the user clearly wants one,
609
  # try a second pass to get ONLY a SQL query from the agent and execute it.
610
  if chart_fig is None:
611
- q_lower = question.lower()
612
- wants_chart = any(k in q_lower for k in ["gráfico", "grafico", "chart", "graph", "pastel", "pie"])
613
  if wants_chart:
614
  try:
615
  logger.info("Second pass: asking agent for ONLY SQL query in fenced block.")
@@ -648,7 +671,7 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
648
  except Exception:
649
  continue
650
  if y_col:
651
- desired_type = 'pie' if any(k in q_lower for k in ["gráfico circular", "grafico circular", "pie", "pastel"]) else 'bar'
652
  chart_fig = generate_chart(
653
  data=data,
654
  chart_type=desired_type,
@@ -663,11 +686,10 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
663
  except Exception as e:
664
  logger.error(f"Second-pass SQL synthesis failed: {e}")
665
 
666
- # Fallback: if user asked for a chart (e.g., pie) and we didn't get SQL or chart yet,
667
  # parse the most recent assistant text for lines like "LABEL: NUMBER" (bulleted or plain).
668
  if chart_fig is None:
669
- q_lower = question.lower()
670
- wants_chart = any(k in q_lower for k in ["gráfico", "grafico", "chart", "graph", "pastel", "pie"])
671
  if wants_chart:
672
  # Find the most recent assistant message with usable numeric pairs
673
  candidate_text = ""
@@ -705,7 +727,6 @@ async def stream_agent_response(question: str, chat_history: List[List[str]]) ->
705
  data.append({"label": label, "value": val})
706
  logger.info(f"Fallback parse from text: extracted {len(data)} items for potential chart")
707
  if len(data) >= 2:
708
- desired_type = 'pie' if any(k in q_lower for k in ["gráfico circular", "grafico circular", "pie", "pastel"]) else 'bar'
709
  chart_fig = generate_chart(
710
  data=data,
711
  chart_type=desired_type,
@@ -1013,6 +1034,37 @@ def create_application():
1013
  # Append assistant message back into messages history
1014
  chat_history.append({"role": "assistant", "content": assistant_message})
1015
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1016
  logger.info("Response generation complete")
1017
  return chat_history, chart_fig
1018
 
 
417
  except Exception as e:
418
  return f"Error ejecutando la consulta: {str(e)}"
419
 
420
+ def detect_chart_preferences(question: str) -> Tuple[bool, str]:
421
+ """Detect whether the user is asking for a chart and infer desired type.
422
+
423
+ Returns (wants_chart, chart_type) where chart_type is one of
424
+ {'bar', 'pie', 'line', 'scatter', 'histogram'}.
425
+ Defaults to 'bar' when ambiguous.
426
+ """
427
+ try:
428
+ q = (question or "").lower()
429
+
430
+ # Broad triggers indicating any chart request
431
+ chart_triggers = [
432
+ "grafico", "gráfico", "grafica", "gráfica", "chart", "graph",
433
+ "visualizacion", "visualización", "plot", "plotly", "diagrama"
434
+ ]
435
+ wants_chart = any(k in q for k in chart_triggers)
436
+
437
+ # Specific type hints
438
+ if any(k in q for k in ["pastel", "pie", "circular", "donut", "dona", "anillo"]):
439
+ return wants_chart or True, "pie"
440
+ if any(k in q for k in ["linea", "línea", "line", "tendencia"]):
441
+ return wants_chart or True, "line"
442
+ if any(k in q for k in ["dispersión", "dispersion", "scatter", "puntos"]):
443
+ return wants_chart or True, "scatter"
444
+ if any(k in q for k in ["histograma", "histogram"]):
445
+ return wants_chart or True, "histogram"
446
+ if any(k in q for k in ["barra", "barras", "columnas", "column"]):
447
+ return wants_chart or True, "bar"
448
+
449
+ # Default
450
+ return wants_chart, "bar"
451
+ except Exception:
452
+ return False, "bar"
453
+
454
  def generate_plot(data, x_col, y_col, title, x_label, y_label):
455
  """Generate a plot from data and return the file path."""
456
  plt.figure(figsize=(10, 6))
 
597
  data.append(dict(zip(columns, values)))
598
 
599
  if data and len(columns) >= 2:
600
+ # Determine chart type from user's question
601
+ _, desired_type = detect_chart_preferences(question)
 
 
 
 
 
 
 
 
 
 
602
 
603
  # Choose x/y columns (assume first is category, second numeric)
604
  x_col = columns[0]
 
632
  # If we still have no chart but the user clearly wants one,
633
  # try a second pass to get ONLY a SQL query from the agent and execute it.
634
  if chart_fig is None:
635
+ wants_chart, default_type = detect_chart_preferences(question)
 
636
  if wants_chart:
637
  try:
638
  logger.info("Second pass: asking agent for ONLY SQL query in fenced block.")
 
671
  except Exception:
672
  continue
673
  if y_col:
674
+ desired_type = default_type
675
  chart_fig = generate_chart(
676
  data=data,
677
  chart_type=desired_type,
 
686
  except Exception as e:
687
  logger.error(f"Second-pass SQL synthesis failed: {e}")
688
 
689
+ # Fallback: if user asked for a chart and we didn't get SQL or chart yet,
690
  # parse the most recent assistant text for lines like "LABEL: NUMBER" (bulleted or plain).
691
  if chart_fig is None:
692
+ wants_chart, desired_type = detect_chart_preferences(question)
 
693
  if wants_chart:
694
  # Find the most recent assistant message with usable numeric pairs
695
  candidate_text = ""
 
727
  data.append({"label": label, "value": val})
728
  logger.info(f"Fallback parse from text: extracted {len(data)} items for potential chart")
729
  if len(data) >= 2:
 
730
  chart_fig = generate_chart(
731
  data=data,
732
  chart_type=desired_type,
 
1034
  # Append assistant message back into messages history
1035
  chat_history.append({"role": "assistant", "content": assistant_message})
1036
 
1037
+ # If user asked for a chart but none was produced, try to build one
1038
+ # from the latest assistant text using the same fallback logic.
1039
+ if chart_fig is None:
1040
+ wants_chart, desired_type = detect_chart_preferences(question)
1041
+ if wants_chart and isinstance(assistant_message, str):
1042
+ candidate_text = assistant_message
1043
+ raw_lines = candidate_text.split('\n')
1044
+ norm_lines = []
1045
+ for l in raw_lines:
1046
+ s = l.strip().lstrip("•*\t -")
1047
+ if s:
1048
+ norm_lines.append(s)
1049
+ data = []
1050
+ for l in norm_lines:
1051
+ m = re.match(r"^(.+?):\s*([0-9][0-9.,]*)$", l)
1052
+ if m:
1053
+ label = re.sub(r"[*_`]+", "", m.group(1)).strip()
1054
+ try:
1055
+ val = float(m.group(2).replace(',', ''))
1056
+ except Exception:
1057
+ continue
1058
+ data.append({"label": label, "value": val})
1059
+ if len(data) >= 2:
1060
+ chart_fig = generate_chart(
1061
+ data=data,
1062
+ chart_type=desired_type,
1063
+ x="label",
1064
+ y="value",
1065
+ title="Distribución"
1066
+ )
1067
+
1068
  logger.info("Response generation complete")
1069
  return chat_history, chart_fig
1070