Digest was attributing forwarded emails to the person who forwarded them. Now Claude is instructed to identify the original sender from the forwarded headers and ignore the forwarder entirely. Also drops pleasantries/apologies from the summary — facts only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
131 lines
4.2 KiB
Python
131 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Email digest: procesează emailuri necitite și trimite rezumate pe WhatsApp.
|
|
|
|
Usage:
|
|
python3 tools/email_digest.py # Run digest
|
|
python3 tools/email_digest.py --dry-run # Afișează rezumatele fără a trimite
|
|
"""
|
|
|
|
import sys
|
|
import subprocess
|
|
import requests
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from tools.email_process import save_unread_emails
|
|
from src.config import Config
|
|
|
|
BRIDGE_URL = "http://127.0.0.1:8098"
|
|
DRY_RUN = "--dry-run" in sys.argv
|
|
|
|
|
|
def get_owner_jid() -> str:
|
|
config = Config(PROJECT_ROOT / "config.json")
|
|
owner = config.get("whatsapp.owner", "")
|
|
return f"{owner}@s.whatsapp.net"
|
|
|
|
|
|
def generate_summary(filepath: str, subject: str, from_full: str, date: str) -> str:
|
|
"""Citește conținutul emailului și generează rezumat via Claude CLI."""
|
|
try:
|
|
email_content = Path(filepath).read_text(encoding="utf-8")
|
|
except Exception as e:
|
|
return f"[Eroare la citirea fișierului: {e}]"
|
|
|
|
prompt = f"""Mai jos este conținutul unui email. Scrie un rezumat factual pentru WhatsApp.
|
|
|
|
EMAIL:
|
|
{email_content}
|
|
|
|
Instrucțiuni:
|
|
- Începe cu header-ul fix (fără modificări):
|
|
SUBIECT: {subject}
|
|
De la: {from_full}
|
|
Primit: {date}
|
|
---
|
|
- Dacă emailul este un forward (subiect începe cu Fwd:/Fw: sau conține "---------- Forwarded message"):
|
|
* Ignoră complet persoana care a forwardat. Nu o menționez în rezumat.
|
|
* Identifică expeditorul original din corpul emailului (câmpurile From/De la din headerul forwarded).
|
|
* Rezumatul trebuie să fie despre mesajul original, ca și cum ar fi fost primit direct de la acel expeditor.
|
|
- Scrie rezumatul în stil briefing: factual, clar, persoana a 3-a.
|
|
* Prima propoziție: cine a trimis mesajul original, ce, cui.
|
|
* Ce conține mesajul — concret și direct. Omite politețuri, scuze și amabilități; include doar faptele.
|
|
* Dacă există termene, date, locuri sau acțiuni cerute — menționează-le explicit.
|
|
* Dacă există atașamente — listează-le la final: "Atașat: ..."
|
|
* Dacă există linkuri acționabile (formulare, documente), adaugă o secțiune LINKURI la final.
|
|
- Nu adăuga secțiuni goale sau care nu se aplică emailului.
|
|
- Plain text, fără markdown. Fără emoji.
|
|
- Răspunde DOAR cu rezumatul, nimic altceva."""
|
|
|
|
result = subprocess.run(
|
|
["claude", "--print", prompt],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
stdin=subprocess.DEVNULL,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
return f"[Eroare la generarea rezumatului pentru: {subject}]\n{result.stderr.strip()[:200]}"
|
|
|
|
return result.stdout.strip()
|
|
|
|
|
|
def send_whatsapp(to: str, text: str) -> bool:
|
|
"""Trimite mesaj pe WhatsApp prin bridge."""
|
|
try:
|
|
resp = requests.post(
|
|
f"{BRIDGE_URL}/send",
|
|
json={"to": to, "text": text},
|
|
timeout=15,
|
|
)
|
|
data = resp.json()
|
|
return data.get("ok", False)
|
|
except Exception as e:
|
|
print(f"[eroare send] {e}", file=sys.stderr)
|
|
return False
|
|
|
|
|
|
def run_digest():
|
|
print("📬 Verific emailuri necitite...")
|
|
saved = save_unread_emails()
|
|
|
|
owner_jid = get_owner_jid()
|
|
|
|
if not saved:
|
|
print("Niciun email nou de procesat.")
|
|
if not DRY_RUN:
|
|
send_whatsapp(owner_jid, "📭 Nu sunt emailuri noi.")
|
|
return
|
|
|
|
for result in saved:
|
|
if not result.get("ok"):
|
|
print(f"⚠️ Sărit: {result.get('error')}")
|
|
continue
|
|
|
|
filepath = result["file"]
|
|
subject = result["subject"]
|
|
from_full = result.get("from_full", result.get("from", ""))
|
|
date = result.get("date", "")
|
|
print(f"📧 Procesez: {subject}")
|
|
|
|
summary = generate_summary(filepath, subject, from_full, date)
|
|
|
|
if DRY_RUN:
|
|
print("\n--- REZUMAT (dry-run) ---")
|
|
print(summary)
|
|
print("------------------------\n")
|
|
else:
|
|
ok = send_whatsapp(owner_jid, summary)
|
|
if ok:
|
|
print(f"✅ Trimis pe WhatsApp: {subject}")
|
|
else:
|
|
print(f"❌ Trimitere eșuată: {subject}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run_digest()
|