QAway-to commited on
Commit
e53a7f3
·
1 Parent(s): 761bd44

New style APP (Tab Changes v1.2)

Browse files
Files changed (1) hide show
  1. core/formatters.py +62 -29
core/formatters.py CHANGED
@@ -1,9 +1,9 @@
1
  """
2
  🇬🇧 Module: formatters.py
3
- Purpose: Converts LLM Markdown output (comparison/analysis) into styled HTML tables.
4
 
5
  🇷🇺 Модуль: formatters.py
6
- Назначение: преобразует Markdown-таблицы и текст отчёта LLM в аккуратное HTML-представление.
7
  """
8
 
9
  import re
@@ -11,66 +11,99 @@ from html import escape
11
 
12
 
13
  def highlight_metrics(text: str) -> str:
14
- """Highlight numeric percentage values in green/red."""
15
  def colorize(match):
16
  val = match.group(0)
17
  try:
18
  num = float(val.replace("%", ""))
19
- color = "#10b981" if num > 0 else "#ef4444" if num < 0 else "#e6edf3"
 
 
 
 
 
20
  return f"<span style='color:{color};font-weight:600;'>{val}</span>"
21
  except ValueError:
22
  return val
 
23
  return re.sub(r"-?\d+\.?\d*%", colorize, text)
24
 
25
 
 
 
 
 
 
 
 
 
 
 
 
26
  def md_table_to_html(md_table: str) -> str:
27
- """Convert a single Markdown table block into HTML."""
28
- lines = [ln.strip() for ln in md_table.strip().splitlines() if "|" in ln]
29
  if len(lines) < 2:
30
  return md_table
31
 
32
- # remove the Markdown alignment line (---|---)
33
  header_line = lines[0]
34
- body_lines = [ln for ln in lines[2:]]
 
35
 
36
- headers = [escape(c.strip()) for c in header_line.split("|")[1:-1]]
37
- html = (
38
  "<table style='width:100%;border-collapse:collapse;"
39
- "margin:10px 0;font-size:14px;font-family:Inter,sans-serif;'>"
40
  "<thead><tr>"
41
  + "".join(
42
- f"<th style='border-bottom:1px solid #30363d;padding:6px;color:#c9d1d9;font-weight:600;text-align:center;'>"
43
- f"{h}</th>" for h in headers
 
44
  )
45
  + "</tr></thead><tbody>"
46
- )
47
- for ln in body_lines:
48
- cols = [highlight_metrics(escape(c.strip())) for c in ln.split("|")[1:-1]]
49
- html += "<tr>" + "".join(
50
- f"<td style='padding:6px 8px;border-bottom:1px solid #30363d;text-align:center;color:#e6edf3;'>"
51
- f"{c}</td>" for c in cols
52
- ) + "</tr>"
53
- html += "</tbody></table>"
54
- return html
 
 
 
 
 
 
 
 
 
 
55
 
56
 
57
  def format_comparison_output(raw: str) -> str:
58
- """Format LLM Markdown response into rich HTML."""
59
  if not raw:
60
  return "<i>No comparison data available.</i>"
61
 
62
  text = raw.strip()
63
 
64
- # Section titles
65
  text = re.sub(r"###\s*1️⃣.*", "<h3 style='color:#93c5fd;margin-top:12px;'>1. Summary Table</h3>", text)
66
  text = re.sub(r"###\s*2️⃣.*", "<h3 style='color:#a78bfa;margin-top:12px;'>2. Comparative Analysis</h3>", text)
67
  text = re.sub(r"###\s*3️⃣.*", "<h3 style='color:#fbbf24;margin-top:12px;'>3. Recommendation</h3>", text)
68
 
69
- # Extract and replace Markdown tables
70
- tables = re.findall(r"(\|[^\n]+\|\n(\|[^\n]+\|\n)+)", text)
71
- for tbl, _ in tables:
72
- html_table = md_table_to_html(tbl)
73
- text = text.replace(tbl, html_table)
 
 
 
 
 
 
74
 
75
  text = highlight_metrics(text)
76
  text = text.replace("**", "")
 
1
  """
2
  🇬🇧 Module: formatters.py
3
+ Purpose: Cleanly format LLM Markdown portfolio comparison output into styled HTML.
4
 
5
  🇷🇺 Модуль: formatters.py
6
+ Назначение: форматирует Markdown-ответ LLM в аккуратную HTML-таблицу без дубликатов и пустых столбцов.
7
  """
8
 
9
  import re
 
11
 
12
 
13
  def highlight_metrics(text: str) -> str:
14
+ """Color numeric values depending on sign."""
15
  def colorize(match):
16
  val = match.group(0)
17
  try:
18
  num = float(val.replace("%", ""))
19
+ if num > 0:
20
+ color = "#10b981" # green
21
+ elif num < 0:
22
+ color = "#ef4444" # red
23
+ else:
24
+ color = "#e6edf3"
25
  return f"<span style='color:{color};font-weight:600;'>{val}</span>"
26
  except ValueError:
27
  return val
28
+
29
  return re.sub(r"-?\d+\.?\d*%", colorize, text)
30
 
31
 
32
+ def clean_table_lines(lines):
33
+ """Remove invalid / empty Markdown table lines."""
34
+ result = []
35
+ for ln in lines:
36
+ if not ln.strip():
37
+ continue
38
+ if ln.strip().startswith("|") and len(ln.split("|")) > 3:
39
+ result.append(ln)
40
+ return result
41
+
42
+
43
  def md_table_to_html(md_table: str) -> str:
44
+ """Convert one Markdown table to HTML safely."""
45
+ lines = clean_table_lines(md_table.strip().splitlines())
46
  if len(lines) < 2:
47
  return md_table
48
 
 
49
  header_line = lines[0]
50
+ data_lines = lines[2:] # skip the ---|--- line
51
+ headers = [escape(c.strip()) for c in header_line.split("|")[1:-1] if c.strip()]
52
 
53
+ html = [
 
54
  "<table style='width:100%;border-collapse:collapse;"
55
+ "margin:10px 0;font-size:14px;font-family:Inter,sans-serif;'>",
56
  "<thead><tr>"
57
  + "".join(
58
+ f"<th style='border-bottom:1px solid #30363d;padding:6px;color:#c9d1d9;"
59
+ f"font-weight:600;text-align:center;'>{h}</th>"
60
+ for h in headers
61
  )
62
  + "</tr></thead><tbody>"
63
+ ]
64
+
65
+ for ln in data_lines:
66
+ cols = [c.strip() for c in ln.split("|")[1:-1] if c.strip()]
67
+ if len(cols) != len(headers):
68
+ continue # skip malformed rows
69
+ html.append(
70
+ "<tr>"
71
+ + "".join(
72
+ f"<td style='padding:6px 8px;border-bottom:1px solid #30363d;"
73
+ f"text-align:center;color:#e6edf3;'>"
74
+ f"{highlight_metrics(escape(c))}</td>"
75
+ for c in cols
76
+ )
77
+ + "</tr>"
78
+ )
79
+
80
+ html.append("</tbody></table>")
81
+ return "".join(html)
82
 
83
 
84
  def format_comparison_output(raw: str) -> str:
85
+ """Transform Markdown to HTML with correct table parsing."""
86
  if not raw:
87
  return "<i>No comparison data available.</i>"
88
 
89
  text = raw.strip()
90
 
91
+ # Section headers
92
  text = re.sub(r"###\s*1️⃣.*", "<h3 style='color:#93c5fd;margin-top:12px;'>1. Summary Table</h3>", text)
93
  text = re.sub(r"###\s*2️⃣.*", "<h3 style='color:#a78bfa;margin-top:12px;'>2. Comparative Analysis</h3>", text)
94
  text = re.sub(r"###\s*3️⃣.*", "<h3 style='color:#fbbf24;margin-top:12px;'>3. Recommendation</h3>", text)
95
 
96
+ # Extract Markdown tables only once
97
+ table_blocks = re.findall(r"((?:\|[^\n]+\n)+)", text)
98
+ used_blocks = set()
99
+
100
+ for tbl in table_blocks:
101
+ tbl_clean = tbl.strip()
102
+ if tbl_clean in used_blocks:
103
+ continue
104
+ used_blocks.add(tbl_clean)
105
+ html_table = md_table_to_html(tbl_clean)
106
+ text = text.replace(tbl_clean, html_table)
107
 
108
  text = highlight_metrics(text)
109
  text = text.replace("**", "")