fix: remove duplicated table renderer from Telegram adapter
The PR's original refactor commit only replaced the primitives (regex, is_table_row, split_markdown_table_row) with shared imports but left the verbatim-copied renderer (_render_table_block_for_telegram) and driver (_wrap_markdown_tables) in place. Both are logic-identical to the shared convert_table_to_bullets in gateway/platforms/helpers.py. Replace both with a direct import alias. _TABLE_SEPARATOR_RE is still imported separately because it's used by the rich-message routing logic (lines 1024, 1044) to detect whether content contains tables. Found by 3-agent parallel code-reuse review.
This commit is contained in:
parent
24a4df9cd1
commit
6326d5c6f6
|
|
@ -217,122 +217,15 @@ def _separate_chunk_indicator_from_fence(text: str) -> str:
|
|||
# ---------------------------------------------------------------------------
|
||||
# Telegram's MarkdownV2 has no table syntax — '|' is just an escaped literal,
|
||||
# so pipe tables render as noisy backslash-pipe text with no alignment.
|
||||
# Reformating each row into a bold heading plus bullet list keeps the content
|
||||
# readable on mobile clients while preserving the source data.
|
||||
# The shared convert_table_to_bullets() in gateway.platforms.helpers handles
|
||||
# the full conversion (detection + rendering); Telegram just calls it.
|
||||
|
||||
# Table detection primitives are shared with Discord via gateway.platforms.helpers.
|
||||
from gateway.platforms.helpers import (
|
||||
TABLE_SEPARATOR_RE as _TABLE_SEPARATOR_RE,
|
||||
is_table_row as _is_table_row,
|
||||
split_markdown_table_row as _split_markdown_table_row,
|
||||
convert_table_to_bullets as _wrap_markdown_tables,
|
||||
)
|
||||
|
||||
|
||||
def _render_table_block_for_telegram(table_block: list[str]) -> str:
|
||||
"""Render a detected GFM table as Telegram-friendly row groups."""
|
||||
if len(table_block) < 3:
|
||||
return "\n".join(table_block)
|
||||
|
||||
headers = _split_markdown_table_row(table_block[0])
|
||||
if len(headers) < 2:
|
||||
return "\n".join(table_block)
|
||||
|
||||
# Detect row-label column: present when data rows have one more cell
|
||||
# than the header row (the row-label column carries no header).
|
||||
first_data_row = _split_markdown_table_row(table_block[2]) if len(table_block) > 2 else []
|
||||
has_row_label_col = len(first_data_row) == len(headers) + 1
|
||||
|
||||
rendered_groups: list[str] = []
|
||||
for index, row in enumerate(table_block[2:], start=1):
|
||||
cells = _split_markdown_table_row(row)
|
||||
if has_row_label_col:
|
||||
# First cell is the row-label (heading); remaining cells align with headers.
|
||||
heading = cells[0] if cells and cells[0] else f"Row {index}"
|
||||
data_cells = cells[1:]
|
||||
else:
|
||||
# No row-label column: use first non-empty cell as heading.
|
||||
heading = next((cell for cell in cells if cell), f"Row {index}")
|
||||
data_cells = cells
|
||||
|
||||
# Pad or trim data_cells to match headers length.
|
||||
if len(data_cells) < len(headers):
|
||||
data_cells.extend([""] * (len(headers) - len(data_cells)))
|
||||
elif len(data_cells) > len(headers):
|
||||
data_cells = data_cells[: len(headers)]
|
||||
|
||||
# Build the bulleted lines for this row. Skip any bullet whose value
|
||||
# duplicates the heading text -- when has_row_label_col is False the
|
||||
# heading IS the first data cell, and emitting it twice (once as the
|
||||
# bold heading, once as the first bullet) is visual noise.
|
||||
bullets: list[str] = []
|
||||
for header, value in zip(headers, data_cells):
|
||||
if not has_row_label_col and value == heading:
|
||||
continue
|
||||
bullets.append(f"• {header}: {value}")
|
||||
|
||||
# Within a row-group: single newline between heading and its bullets,
|
||||
# and between successive bullets. This keeps the row visually tight
|
||||
# on Telegram instead of stretching each bullet into its own paragraph.
|
||||
group_lines = [f"**{heading}**", *bullets]
|
||||
rendered_groups.append("\n".join(group_lines))
|
||||
|
||||
# Between row-groups: blank line so each group reads as a distinct block.
|
||||
return "\n\n".join(rendered_groups)
|
||||
|
||||
|
||||
def _wrap_markdown_tables(text: str) -> str:
|
||||
"""Rewrite GFM-style pipe tables into Telegram-friendly bullet groups.
|
||||
|
||||
Detected by a row containing '|' immediately followed by a delimiter
|
||||
row matching :data:`_TABLE_SEPARATOR_RE`. Subsequent pipe-containing
|
||||
non-blank lines are consumed as the table body and rewritten as
|
||||
per-row bullet groups. Tables inside existing fenced code blocks are left
|
||||
alone.
|
||||
"""
|
||||
if '|' not in text or '-' not in text:
|
||||
return text
|
||||
|
||||
lines = text.split('\n')
|
||||
out: list[str] = []
|
||||
in_fence = False
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
stripped = line.lstrip()
|
||||
|
||||
# Track existing fenced code blocks — never touch content inside.
|
||||
if stripped.startswith('```'):
|
||||
in_fence = not in_fence
|
||||
out.append(line)
|
||||
i += 1
|
||||
continue
|
||||
if in_fence:
|
||||
out.append(line)
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Look for a header row (contains '|') immediately followed by a
|
||||
# delimiter row.
|
||||
if (
|
||||
'|' in line
|
||||
and i + 1 < len(lines)
|
||||
and _TABLE_SEPARATOR_RE.match(lines[i + 1])
|
||||
):
|
||||
table_block = [line, lines[i + 1]]
|
||||
j = i + 2
|
||||
while j < len(lines) and _is_table_row(lines[j]):
|
||||
table_block.append(lines[j])
|
||||
j += 1
|
||||
out.append(_render_table_block_for_telegram(table_block))
|
||||
i = j
|
||||
continue
|
||||
|
||||
out.append(line)
|
||||
i += 1
|
||||
|
||||
return '\n'.join(out)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rich-message newline normalization
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in New Issue