Jeremy Live commited on
Commit
9f4148c
·
1 Parent(s): 70c3587
Files changed (1) hide show
  1. app.py +39 -32
app.py CHANGED
@@ -482,6 +482,30 @@ def is_db_intent(question: str) -> bool:
482
  except Exception:
483
  return False
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  def generate_plot(data, x_col, y_col, title, x_label, y_label):
486
  """Generate a plot from data and return the file path."""
487
  plt.figure(figsize=(10, 6))
@@ -746,44 +770,21 @@ async def stream_agent_response(question: str, chat_history: List[List[str]], se
746
  logger.error(f"Second-pass SQL synthesis failed: {e}")
747
 
748
  # Fallback: if user asked for a chart and we didn't get SQL or chart yet,
749
- # parse the most recent assistant text for lines like "LABEL: NUMBER" (bulleted or plain).
750
  if chart_fig is None:
751
  wants_chart, desired_type = detect_chart_preferences(question)
752
  if wants_chart:
753
- # Find the most recent assistant message with usable numeric pairs
754
  candidate_text = ""
755
- if chat_history:
 
 
 
 
756
  for pair in reversed(chat_history):
757
  if len(pair) >= 2 and isinstance(pair[1], str) and pair[1].strip():
758
  candidate_text = pair[1]
759
  break
760
- # Also consider current response_text as a data source
761
- if not candidate_text and isinstance(response_text, str) and response_text.strip():
762
- candidate_text = response_text
763
- if candidate_text:
764
- raw_lines = candidate_text.split('\n')
765
- # Normalize lines: strip bullets and markdown symbols
766
- norm_lines = []
767
- for l in raw_lines:
768
- s = l.strip()
769
- if not s:
770
- continue
771
- s = s.lstrip("•*-\t ")
772
- # Remove surrounding markdown emphasis from labels later
773
- norm_lines.append(s)
774
- data = []
775
- for l in norm_lines:
776
- # Accept patterns like "**LABEL**: 123" or "LABEL: 1,234"
777
- m = re.match(r"^(.+?):\s*([0-9][0-9.,]*)$", l)
778
- if m:
779
- label = m.group(1).strip()
780
- # Strip common markdown emphasis
781
- label = re.sub(r"[*_`]+", "", label).strip()
782
- try:
783
- val = float(m.group(2).replace(',', ''))
784
- except Exception:
785
- continue
786
- data.append({"label": label, "value": val})
787
  logger.info(f"Fallback parse from text: extracted {len(data)} items for potential chart")
788
  if len(data) >= 2:
789
  chart_fig = generate_chart(
@@ -793,8 +794,14 @@ async def stream_agent_response(question: str, chat_history: List[List[str]], se
793
  y="value",
794
  title="Distribución"
795
  )
796
- if chart_fig is not None:
797
- logger.info(f"Chart generated from text fallback: type={desired_type}, items={len(data)}")
 
 
 
 
 
 
798
 
799
  # Update the assistant's message with the response
800
  assistant_message["content"] = response_text
 
482
  except Exception:
483
  return False
484
 
485
+ def extract_label_value_pairs(text: str) -> List[Dict[str, Union[str, float]]]:
486
+ """Extract pairs like 'LABEL: NUMBER' from free text."""
487
+ pairs: List[Dict[str, Union[str, float]]] = []
488
+ if not text:
489
+ return pairs
490
+ try:
491
+ raw_lines = text.split('\n')
492
+ for line in raw_lines:
493
+ s = line.strip()
494
+ if not s:
495
+ continue
496
+ s = s.lstrip('•*\t -')
497
+ m = re.match(r"^(.+?):\s*([0-9][0-9.,]*)$", s)
498
+ if m:
499
+ label = re.sub(r"[*_`]+", "", m.group(1)).strip()
500
+ try:
501
+ value = float(m.group(2).replace(',', ''))
502
+ pairs.append({"label": label, "value": value})
503
+ except Exception:
504
+ continue
505
+ return pairs
506
+ except Exception:
507
+ return pairs
508
+
509
  def generate_plot(data, x_col, y_col, title, x_label, y_label):
510
  """Generate a plot from data and return the file path."""
511
  plt.figure(figsize=(10, 6))
 
770
  logger.error(f"Second-pass SQL synthesis failed: {e}")
771
 
772
  # Fallback: if user asked for a chart and we didn't get SQL or chart yet,
773
+ # use the MOST RECENT bot text (this turn or previous) and parse label:value pairs.
774
  if chart_fig is None:
775
  wants_chart, desired_type = detect_chart_preferences(question)
776
  if wants_chart:
 
777
  candidate_text = ""
778
+ # Prefer THIS TURN's response_text if it's non-empty
779
+ if isinstance(response_text, str) and response_text.strip():
780
+ candidate_text = response_text
781
+ # Otherwise look back at the latest assistant turn in history
782
+ if not candidate_text and chat_history:
783
  for pair in reversed(chat_history):
784
  if len(pair) >= 2 and isinstance(pair[1], str) and pair[1].strip():
785
  candidate_text = pair[1]
786
  break
787
+ data = extract_label_value_pairs(candidate_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
  logger.info(f"Fallback parse from text: extracted {len(data)} items for potential chart")
789
  if len(data) >= 2:
790
  chart_fig = generate_chart(
 
794
  y="value",
795
  title="Distribución"
796
  )
797
+ if chart_fig is not None and not response_text.strip():
798
+ # Provide a helpful text if the agent didn't produce one
799
+ response_text = (
800
+ f"Gráfico {('de barras' if desired_type=='bar' else desired_type)} "
801
+ f"con {len(data)} categorías basado en los datos previos."
802
+ )
803
+ if chart_fig is not None:
804
+ logger.info(f"Chart generated from text fallback: type={desired_type}, items={len(data)}")
805
 
806
  # Update the assistant's message with the response
807
  assistant_message["content"] = response_text