add files
This commit is contained in:
1 parent
ab8adbfa12
commit
fbb31409da
8 files changed
+775
No files matched your search
+120
@@ -0,0 +1,120 @@
|
||||
"""Chuẩn hóa câu trả lời Hermes → text thuần cho Zalo (không markdown)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import unicodedata
|
||||
|
||||
_MD_LINK = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
|
||||
_BOLD = re.compile(r"\*\*([^*]+)\*\*")
|
||||
_ITALIC = re.compile(r"(?<!\*)\*([^*]+)\*(?!\*)")
|
||||
_STRIKE = re.compile(r"~~([^~]+)~~")
|
||||
_CODE_FENCE = re.compile(r"```[\s\S]*?```")
|
||||
_INLINE_CODE = re.compile(r"`([^`]+)`")
|
||||
_HEADING = re.compile(r"(?m)^#{1,6}\s+")
|
||||
_BULLET = re.compile(r"(?m)^[\-\*]\s+")
|
||||
_ORDERED = re.compile(r"(?m)^\d+\.\s+")
|
||||
_BLOCKQUOTE = re.compile(r"(?m)^>\s?")
|
||||
_HR = re.compile(r"(?m)^(?:-{3,}|\*{3,}|_{3,})\s*$")
|
||||
_HTML_TAG = re.compile(r"</?[a-zA-Z][^>]*>")
|
||||
_WIKI_OR_REF = re.compile(r"\[\[([^\]|#]+)(?:#[^\]|]*)?(?:\|([^\]]+))?\]\]")
|
||||
_MULTI_NL = re.compile(r"\n{3,}")
|
||||
_MULTI_SPACE = re.compile(r"[ \t]{2,}")
|
||||
_DASHY = re.compile(r"\s*[—–]\s*")
|
||||
|
||||
# Lỗi chính tả / khoảng trắng tiếng Việt thường gặp từ model
|
||||
_TYPO_FIXES: list[tuple[re.Pattern[str], str]] = [
|
||||
(re.compile(r"\s+([,.!?;:…])"), r"\1"),
|
||||
(re.compile(r"([(\[])\s+"), r"\1"),
|
||||
(re.compile(r"\s+([)\]])"), r"\1"),
|
||||
(re.compile(r"(?i)\bko\b"), "không"),
|
||||
(re.compile(r"(?i)\bdc\b"), "được"),
|
||||
(re.compile(r"(?i)\bđc\b"), "được"),
|
||||
(re.compile(r"(?i)\bkq\b"), "kết quả"),
|
||||
(re.compile(r"(?i)\bntn\b"), "như thế nào"),
|
||||
(re.compile(r"(?i)\bntn\b"), "như thế nào"),
|
||||
(re.compile(r"(?i)\bmn\b"), "mọi người"),
|
||||
(re.compile(r"(?i)\bbj\b"), "bây giờ"),
|
||||
(re.compile(r"(?i)\bhqua\b"), "hôm qua"),
|
||||
(re.compile(r"(?i)\bhnay\b"), "hôm nay"),
|
||||
(re.compile(r"(?i)\bsdt\b"), "SĐT"),
|
||||
(re.compile(r"(?i)\bvs\b"), "với"),
|
||||
(re.compile(r"\u00a0"), " "),
|
||||
]
|
||||
|
||||
|
||||
def _nfc(text: str) -> str:
|
||||
return unicodedata.normalize("NFC", text or "")
|
||||
|
||||
|
||||
def _strip_markdown(text: str) -> str:
|
||||
t = text
|
||||
t = _CODE_FENCE.sub(lambda m: "\n".join(
|
||||
line for line in m.group(0).splitlines()[1:-1]
|
||||
), t)
|
||||
t = _HTML_TAG.sub("", t)
|
||||
t = _WIKI_OR_REF.sub(lambda m: (m.group(2) or m.group(1) or "").strip(), t)
|
||||
t = _MD_LINK.sub(lambda m: m.group(1).strip() or m.group(2).strip(), t)
|
||||
t = _BOLD.sub(r"\1", t)
|
||||
t = _ITALIC.sub(r"\1", t)
|
||||
t = _STRIKE.sub(r"\1", t)
|
||||
t = _INLINE_CODE.sub(r"\1", t)
|
||||
t = _HEADING.sub("", t)
|
||||
t = _BLOCKQUOTE.sub("", t)
|
||||
t = _HR.sub("", t)
|
||||
t = _BULLET.sub("• ", t)
|
||||
t = _ORDERED.sub(lambda m: f"{m.group(0).split('.')[0]}. ", t)
|
||||
return t
|
||||
|
||||
|
||||
def _fix_vietnamese_typos(text: str) -> str:
|
||||
t = text
|
||||
for pat, repl in _TYPO_FIXES:
|
||||
t = pat.sub(repl, t)
|
||||
# khoảng trắng quanh dấu tiếng Việt kiểu "ạ ," / "không ?"
|
||||
t = re.sub(r"([^\s])\s+([?!…])", r"\1\2", t)
|
||||
return t
|
||||
|
||||
|
||||
def _tidy_lines(text: str) -> str:
|
||||
lines: list[str] = []
|
||||
for line in text.splitlines():
|
||||
line = _MULTI_SPACE.sub(" ", line).strip()
|
||||
if re.fullmatch(r"[—–\-.…\s]*", line or ""):
|
||||
continue
|
||||
if "—" in line or "–" in line:
|
||||
parts = [p.strip() for p in _DASHY.split(line) if p.strip()]
|
||||
if len(parts) > 1 and any(len(p) > 12 for p in parts):
|
||||
lines.extend(parts)
|
||||
continue
|
||||
line = " ".join(parts)
|
||||
if line:
|
||||
lines.append(line)
|
||||
t = "\n".join(lines)
|
||||
t = _MULTI_NL.sub("\n\n", t).strip()
|
||||
t = re.sub(r"\s+\.\s*$", ".", t)
|
||||
t = re.sub(r"\.{2,}", "…", t)
|
||||
t = re.sub(r"(?m)^[.\s]+$", "", t)
|
||||
return _MULTI_NL.sub("\n\n", t).strip()
|
||||
|
||||
|
||||
def format_for_zalo(text: str, *, max_chars: int = 1800) -> str:
|
||||
"""Bỏ markdown, chuẩn hóa khoảng trắng / lỗi chính tả VN, cắt nếu quá dài."""
|
||||
t = _nfc((text or "").strip())
|
||||
if not t:
|
||||
return t
|
||||
|
||||
t = _strip_markdown(t)
|
||||
t = _fix_vietnamese_typos(t)
|
||||
t = _tidy_lines(t)
|
||||
|
||||
if max_chars and len(t) > max_chars:
|
||||
cut = t.rfind("\n", 0, max_chars)
|
||||
if cut < max_chars // 3:
|
||||
cut = t.rfind(". ", 0, max_chars)
|
||||
if cut > 0:
|
||||
cut += 1
|
||||
if cut < max_chars // 3:
|
||||
cut = max_chars
|
||||
t = t[:cut].rstrip(" ,;:") + "…"
|
||||
|
||||
return t.strip()
|
||||
Reference in new issue
Block a user