From 9991e4ef17d1bc4c35824fb94b59739dde3354ad Mon Sep 17 00:00:00 2001 From: Zichao Lin Date: Wed, 8 Jul 2026 16:13:54 +0800 Subject: [PATCH] feat: promotional emails summarized as who promotes what --- src/ai_client.py | 3 +++ src/tg_bot.py | 25 ++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ai_client.py b/src/ai_client.py index d28c9c0..c7c8d90 100644 --- a/src/ai_client.py +++ b/src/ai_client.py @@ -15,6 +15,7 @@ SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以 "subject": "你概括的简短标题(10字以内)", "recipient": "收件邮箱地址", "sender": "发件人", + "category": "normal/promotion/notification", "summary": "50字以内的核心摘要", "priority": "high/medium/low", "action_required": true/false, @@ -30,6 +31,8 @@ SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以 其中: - subject 不能照抄原邮件主题,必须是你总结生成的简短标题 +- category: 邮件类型。推广邮件(营销、促销、广告、 newsletter 推广等)标记为 "promotion";系统通知类(账单、验证码、订阅提醒等)标记为 "notification";普通邮件标记为 "normal" +- 当 category 为 "promotion" 时,summary 直接写成一句话:「[发送方名称] 在推广 [推广的产品/服务/活动]」,例如「腾讯云在推广双十一云服务器折扣」。此时 priority 固定为 "low",action_required 为 false,can_reply 为 false,action_items 和 reply_suggestions 为空数组 - can_reply 为 false 表示无需回复或不适合建议回复(此时忽略 reply_suggestions) - is_simple 为 true 表示纯确认性回复(如"好的""收到"),用户选择后可直发 - is_simple 为 false 表示涉及实质内容,需要用户确认再发送 diff --git a/src/tg_bot.py b/src/tg_bot.py index 239bba1..083cc13 100644 --- a/src/tg_bot.py +++ b/src/tg_bot.py @@ -25,11 +25,12 @@ def send_summary(tg_cfg: TelegramConfig, chat_id: str, summary_text: str, original_sender: str = "", original_recipient: str = "", original_reply_to: str = "", account_email: str = "") -> int: can_reply = summary_data.get("can_reply", True) + is_promotion = summary_data.get("category") == "promotion" result = _tg_req(tg_cfg, "sendMessage", { "chat_id": chat_id, "text": summary_text, - "parse_mode": "MarkdownV2", - "reply_markup": _summary_keyboard(can_reply), + "parse_mode": "MarkdownV2" if not is_promotion else None, + "reply_markup": _summary_keyboard(can_reply, is_promotion), }) msg_id = result["result"]["message_id"] _email_contexts[msg_id] = { @@ -93,6 +94,22 @@ def poll_telegram(tg_cfg: TelegramConfig, cfg: Config, last_update_id: int) -> i # ── Formatting ────────────────────────────────────────── def format_summary(data: dict, account_email: str = "") -> str: + category = data.get("category", "normal") + if category == "promotion": + return _format_promotion(data, account_email) + return _format_normal(data, account_email) + + +def _format_promotion(data: dict, account_email: str = "") -> str: + summary = data.get("summary", "") + lines = [ + f"📢 {_escape(summary)}", + f"账户: {_escape(account_email)}", + ] + return "\n".join(lines) + + +def _format_normal(data: dict, account_email: str = "") -> str: priority = data.get("priority", "medium") icon = _priority_icon.get(priority, "⚪") lines = [ @@ -134,7 +151,9 @@ CALLBACK_HINT = "h" CALLBACK_CANCEL = "c" -def _summary_keyboard(can_reply: bool = True) -> dict: +def _summary_keyboard(can_reply: bool = True, is_promotion: bool = False) -> dict: + if is_promotion: + return {"inline_keyboard": [[{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}]]} kb = [ [ {"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG},