- persona_prompts OPENER RULE: never open with dots/ellipsis and never end
an opener by dismissing/belittling the product (but ไม่คิดจะซื้อ, แค่มาดูเล่น,
ก็แค่มาเมิน, ไม่ได้จะซื้อ...) — Thai openers stay politely interested
- fix_openers.py: strip leading dots("..") and remove trailing dismissive
clauses ('ตามไม่คิดจะซื้อหรอกนะ' etc.) so existing personas are normalized
to a natural interest opener; update docstring
110 lines
4.5 KiB
Python
110 lines
4.5 KiB
Python
"""One-time data fix (run in the EasyPanel container console):
|
|
Rewrite existing personas' openers (opener) to natural Thai.
|
|
|
|
Only rewords openers that:
|
|
- open with a casual interjection/filler (เฮ้ / เอ้ / เอ่อ / hey / hi / yo ...),
|
|
- open with ellipsis/dots ("..", "..."), or
|
|
- end with a dismissive clause Thais would not say first
|
|
("แต่ไม่คิดจะซื้อหรอกนะ", "ไม่ได้จะซื้อ", "แค่มาดูเล่น", "ก็แค่มาเมิน"...).
|
|
Everyone else is left untouched (safe & reversible). Prints before -> after.
|
|
|
|
Usage:
|
|
cd /app/backend
|
|
python3 scripts/fix_openers.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Make `app` importable no matter what directory the script is invoked from.
|
|
# The repo layout is <backend>/app ; this script lives in <backend>/scripts/.
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from app.config import Config
|
|
from app.services.groups import GroupStore
|
|
|
|
# Leading casual interjections/filler that make a Thai opener sound unnatural.
|
|
FILLER = re.compile(
|
|
r"^(?:เฮ้|เอ้|เอ่อ|เอ๊ะ|อืม|เออ|นี่ๆ|นี่|ว่าไง|เฮย์|hey|hiya|hi|hello|yo)"
|
|
r"[\s:,\-–—]*",
|
|
re.IGNORECASE,
|
|
)
|
|
BARE_POLITE = re.compile(r"^(ครับ|ค่ะ)(\s|$)")
|
|
THAI_CHAR = re.compile(r"[\u0E00-\u0E7F]")
|
|
# Leading punctuation/dots ("..", "...") that look unfinished/un-natural.
|
|
LEAD_DOTS = re.compile(r"^[\.…\s]*")
|
|
# Trailing dismissive clauses Thais would not say in an opener
|
|
# ("แต่ไม่คิดจะซื้อหรอกนะ", "ไม่ได้จะซื้อ", "แค่มาดูเล่น", "ก็แค่มาเมิน"...).
|
|
DISMISS_TAIL = re.compile(
|
|
r"\s*(?:แต่(?:ก็)?(?:ไม่(?:ได้)?คิดจะซื้อ|ไม่รู้จะซื้อ|ไม่ได้จะซื้อ|ไม่ตั้งใจซื้อ)|"
|
|
r"แค่(?:มา)?ดู(?:เล่น)?|ก็แค่(?:มา)?ดู(?:เล่น)?|ก็แค่มาเมิน|"
|
|
r"แต่กะแค่ลองดู|ก็แค่ลองดู)(?:หรอกนะ|หรอก|นะ|ล่ะ)?$"
|
|
)
|
|
|
|
|
|
def fix_opener(existing: str) -> str | None:
|
|
"""Return the rewritten opener, or None when nothing needs changing."""
|
|
if not isinstance(existing, str) or not existing.strip():
|
|
return None
|
|
s = existing.strip()
|
|
# Only target Thai openers; leave English ones untouched.
|
|
if not THAI_CHAR.search(s):
|
|
return None
|
|
|
|
# 0) Strip leading dots/ellipsis and any casual filler.
|
|
new = LEAD_DOTS.sub("", s)
|
|
m = FILLER.match(new)
|
|
if m:
|
|
new = new[m.end():]
|
|
new = new.strip(" .…,:-–—;")
|
|
|
|
# 1) Remove a trailing dismissive clause ("แต่ไม่คิดจะซื้อหรอกนะ" etc.),
|
|
# so the opener stays politely interested instead of pre-dismissing.
|
|
new = DISMISS_TAIL.sub("", new).strip(" .…,:-–—;")
|
|
|
|
# 2) If it now opens with a bare politeness word, prepend the greeting:
|
|
# "ครับ สนใจ..." -> "สวัสดีครับ สนใจ..."
|
|
bp = BARE_POLITE.match(new)
|
|
if bp:
|
|
polite = new[: len(bp.group(1))]
|
|
new = new[len(polite):].strip(" .…,:-–—;") or ""
|
|
new = "สวัสดี" + polite + ((" " + new) if new else "")
|
|
|
|
cleaned = " ".join(new.split())
|
|
if not cleaned or cleaned == s:
|
|
return None # nothing meaningful changed (or was empty)
|
|
return cleaned[:400]
|
|
|
|
|
|
def main() -> None:
|
|
store = GroupStore(Config.DATA_DIR)
|
|
groups = store.groups.all()
|
|
fixed = skipped = 0
|
|
seen: set[str] = set()
|
|
for group in groups:
|
|
gid = group.get("id") or group.get("_id")
|
|
if not gid or gid in seen:
|
|
continue
|
|
seen.add(gid)
|
|
raw = group.get("personas") or []
|
|
personas = [p for p in raw if isinstance(p, dict) and p.get("id")]
|
|
for p in personas:
|
|
oid = p.get("id")
|
|
old = p.get("opener") or ""
|
|
new = fix_opener(old)
|
|
if new is None:
|
|
skipped += 1
|
|
continue
|
|
print(f"[{gid}] persona={oid!r}")
|
|
print(f" before: {old!r}")
|
|
print(f" after : {new!r}")
|
|
store.update_persona(gid, oid, {"opener": new})
|
|
fixed += 1
|
|
print(f"\nDONE — fixed: {fixed}, left-as-is: {skipped}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|