import html import re MAX_SSML_CHARS = 8000 VOICE_FRIENDLY_MAX = 1000 class MarkdownToSSML: def __init__(self, max_chars: int = VOICE_FRIENDLY_MAX): self._max_chars = max_chars def convert(self, markdown_text: str) -> str: if not markdown_text: return "" text = self._strip_markdown(markdown_text) text = html.escape(text, quote=False) text = self._restore_placeholders(text) text = self._truncate_if_needed(text) return f"{text}" def _strip_markdown(self, md: str) -> str: self._placeholders = [] p = self._ph md = re.sub(r'```[\s\S]*?```', p('此处有代码,请在手机 App 中查看。'), md) md = re.sub(r'`([^`]+)`', r'\1', md) md = re.sub(r'!\[.*?\]\(.*?\)', p('此处有图片。'), md) md = re.sub(r'\*\*(.+?)\*\*', lambda m: p(f'{m.group(1)}'), md) md = re.sub(r'\*([^*]+)\*', lambda m: p(f'{m.group(1)}'), md) md = re.sub(r'__([^_]+)__', r'\1', md) md = re.sub(r'_([^_]+)_', r'\1', md) md = re.sub(r'~~(.+?)~~', r'\1', md) md = re.sub(r'\[(.+?)\]\(.+?\)', r'\1', md) md = re.sub(r'^#{1,6}\s+', '', md, flags=re.MULTILINE) md = re.sub(r'^[\-\*\+]\s+', '', md, flags=re.MULTILINE) md = re.sub(r'^\d+\.\s+', '', md, flags=re.MULTILINE) md = re.sub(r'^>\s+', '', md, flags=re.MULTILINE) md = md.replace('---', p('')) md = md.replace('***', p('')) md = re.sub(r'\|.*\|', p('表格内容请在手机 App 中查看。'), md) md = re.sub(r'https?://\S+', '', md) return md.strip() def _ph(self, s: str) -> str: placeholder = f"\x00SSML{len(self._placeholders)}\x00" self._placeholders.append(s) return placeholder def _restore_placeholders(self, text: str) -> str: for i, val in enumerate(self._placeholders): text = text.replace(f"\x00SSML{i}\x00", val) return text def _truncate_if_needed(self, text: str) -> str: if len(text) <= self._max_chars: return text truncated = text[:self._max_chars] delimiters = ['。', '.', '\n', ';', ';', ','] best_pos = -1 for delim in delimiters: pos = truncated.rfind(delim) if pos > best_pos: best_pos = pos if best_pos > 0: truncated = truncated[:best_pos + 1] truncated += '以上为部分回答,完整内容请在手机 App 中查看。' return truncated def ssml_safe(text: str) -> str: if not text: return "" text = html.escape(text, quote=False) return f"{text}"