Track the source-of-truth code, skills, bootstrap rules, docs, and packaging files before adding new features. Exclude local vault config, generated skill mirrors, temporary exports, virtual environments, and business data files from version control. Validation: inspected staged file list and git ignored status before commit.
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
EMAIL_RE = re.compile(r"[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}")
|
|
PHONE_RE = re.compile(r"(?<!\d)(?:\+?\d[\d -]{6,}\d)(?!\d)")
|
|
PRICE_RE = re.compile(r"(?i)(?:rmb|usd|eur|cny|¥|\$)?\s*\d+(?:\.\d+)?\s*(?:元|块|usd|rmb|eur|cny|/pcs|/pc|/k|pcs)?")
|
|
|
|
|
|
def redact(text: str) -> str:
|
|
text = EMAIL_RE.sub("[email]", text)
|
|
text = PHONE_RE.sub("[number]", text)
|
|
text = PRICE_RE.sub("[number]", text)
|
|
return text
|
|
|
|
|
|
def main() -> int:
|
|
if len(sys.argv) < 3:
|
|
print("usage: extract_email_thread_snippets.py file.jsonl thread_id...", file=sys.stderr)
|
|
return 2
|
|
path = Path(sys.argv[1])
|
|
wanted = set(sys.argv[2:])
|
|
with path.open(encoding="utf-8", errors="replace") as fh:
|
|
for line in fh:
|
|
obj = json.loads(line)
|
|
if obj.get("thread_id") not in wanted:
|
|
continue
|
|
print("=" * 80)
|
|
print("thread_id:", obj.get("thread_id"))
|
|
print("subject:", redact(obj.get("suggested_title_from_subject", "")))
|
|
print("date:", obj.get("date_start"), "->", obj.get("date_end"))
|
|
print("messages:", len(obj.get("messages", [])), "attachments:", len(obj.get("attachments", [])))
|
|
for i, msg in enumerate(obj.get("messages", [])[:8], 1):
|
|
body = redact(msg.get("body_text") or "")
|
|
body = re.sub(r"\n{3,}", "\n\n", body).strip()
|
|
if len(body) > 1400:
|
|
body = body[:1400] + "\n[...truncated...]"
|
|
print("-" * 40)
|
|
print("message", i, "date", msg.get("date", ""))
|
|
print("subject:", redact(msg.get("subject", "")))
|
|
print(body)
|
|
if len(obj.get("messages", [])) > 8:
|
|
print("[remaining messages omitted]")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|