import html as html_mod import re from time import time as _time ALLOWED_TAGS = { "p", "br", "b", "strong", "i", "em", "u", "s", "del", "ul", "ol", "li", "a", "img", "table", "tr", "td", "th", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "blockquote", "code", "pre", "span", } ALLOWED_ATTRS = { "a": {"href", "rel", "target"}, "img": {"src", "alt", "width", "height"}, "td": {"colspan", "rowspan"}, "th": {"colspan", "rowspan"}, } FORBIDDEN_TAGS = {"script", "style", "iframe", "object", "embed", "form", "input"} def sanitize_html(html_body: str) -> str: for tag in FORBIDDEN_TAGS: html_body = re.sub( rf"<\s*{tag}[^>]*>.*?<\s*/\s*{tag}\s*>", "", html_body, flags=re.DOTALL | re.IGNORECASE, ) html_body = re.sub( rf"<\s*{tag}[^>]*/?\s*>", "", html_body, flags=re.IGNORECASE, ) return html_body def markdown_to_html(md_text: str) -> str: text = html_mod.escape(md_text) text = re.sub(r"```(\w+)?\n?(.*?)```", r"
\2
", text, flags=re.DOTALL) text = re.sub(r"`([^`]+)`", r"\1", text) text = re.sub(r"\*\*(.+?)\*\*", r"\1", text) text = re.sub(r"\*(.+?)\*", r"\1", text) text = re.sub(r"~~(.+?)~~", r"\1", text) text = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', text) text = re.sub(r"^[\-\*]\s+(.+)$", r"
  • \1
  • ", text, flags=re.MULTILINE) text = re.sub(r"(
  • .*?
  • (\n?
  • .*?
  • )*)", r"", text) text = re.sub(r"^\d+\.\s+(.+)$", r"
  • \1
  • ", text, flags=re.MULTILINE) text = re.sub(r"(
  • .*?
  • (\n?
  • .*?
  • )*)", r"
      \1
    ", text) lines = text.split("\n") result_lines = [] in_table = False table_rows = [] for line in lines: if line.strip().startswith("|") and line.strip().endswith("|"): cells = [c.strip() for c in line.strip().strip("|").split("|")] if all(c.startswith("-") and len(c) > 1 for c in cells): continue table_rows.append("" + "".join(f"{c}" for c in cells) + "") in_table = True else: if in_table and table_rows: result_lines.append("" + "".join(table_rows) + "
    ") table_rows = [] in_table = False result_lines.append(line) if in_table and table_rows: result_lines.append("" + "".join(table_rows) + "
    ") text = "\n".join(result_lines) text = re.sub(r"^>\s+(.+)$", r"
    \1
    ", text, flags=re.MULTILINE) text = re.sub(r"^---+$", r"
    ", text, flags=re.MULTILINE) text = re.sub(r"^#{1,2}\s+(.+)$", r"

    \1

    ", text, flags=re.MULTILINE) text = re.sub(r"^#{3,6}\s+(.+)$", r"

    \1

    ", text, flags=re.MULTILINE) lines = text.split("\n") result = [] for line in lines: stripped = line.strip() if not stripped: result.append("
    ") elif stripped.startswith("<") and not stripped.startswith("{stripped}

    ") return "\n".join(result) def message_parts_to_text(parts: list[dict]) -> str: texts = [] for part in parts: if "text" in part: texts.append(part["text"].get("content", "")) elif "image" in part: img = part["image"] texts.append(f"[图片: {img.get('name', img.get('url', ''))}]") elif "file" in part: f = part["file"] texts.append(f"[文件: {f.get('name', f.get('url', ''))}]") elif "card" in part: card = part["card"] texts.append(f"[卡片: {card.get('title', '')}]") return "\n".join(texts) def get_agent_prompt_rules(mode: str = "both") -> list[str]: rules = [ "Your response will be sent to Freshdesk/Freshworks as an AI agent reply.", ] if mode in ("freshdesk", "both"): rules.extend( [ "--- Freshdesk (Ticket System) Format Rules ---", "The message body is HTML. Use for bold, for italic.", 'Use text for links.', "Use
    • item
    for unordered lists.", "Use
    1. item
    for ordered lists.", "Use for inline code and
     for code blocks.",
                    "Use 
    text
    for quotations.", "Use

    or

    for headings.", "Use
    ...
    for tables.", "Do NOT use