From 13b76c00abea541b3ceb969ad6e2d273d61e627d Mon Sep 17 00:00:00 2001 From: Zichao Lin Date: Sat, 11 Jul 2026 22:17:10 +0800 Subject: [PATCH] feat: add tell me more button for promotion emails with AI-generated details --- src/ai_client.py | 22 ++++++++++++++++++++++ src/tg_bot.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/ai_client.py b/src/ai_client.py index 2dce0fd..ceaa693 100644 --- a/src/ai_client.py +++ b/src/ai_client.py @@ -61,6 +61,28 @@ def summarize_email(ai_cfg: AIConfig, recipient: str, subject: str, sender: str, return _call_deepseek(ai_cfg, payload) +PROMO_DETAIL_PROMPT = """你是一个邮件分析助手。用户想了解更多关于这封推广邮件的详情。 +请根据邮件原文,输出 3-5 条关键信息,每条一句话,简洁明了。包括:优惠力度、适用条件、截止时间、核心卖点等用户做决策需要知道的信息。 +只返回一个 JSON: {"details": ["信息1", "信息2", ...]} +只返回 JSON,不要包含任何其他文字。""" + + +@retry() +def expand_promo_detail(ai_cfg: AIConfig, sender: str, subject: str, body: str) -> list[str]: + logger.info("AI 推广详情请求: sender=%s subject=%s", sender, subject) + content = f"发件人: {sender}\n主题: {subject}\n正文:\n{body[:4000]}" + payload = { + "model": ai_cfg.model, + "messages": [ + {"role": "system", "content": PROMO_DETAIL_PROMPT}, + {"role": "user", "content": content}, + ], + "response_format": {"type": "json_object"}, + } + result = _call_deepseek(ai_cfg, payload) + return result.get("details", []) + + MORE_REPLIES_PROMPT = """你是一个邮件回复助手。根据以下邮件内容生成3个完全不同的建议回复。 以下是一些已经生成过的回复,请生成全新的回复,不要与已有回复重复。 diff --git a/src/tg_bot.py b/src/tg_bot.py index e6e4dcb..b0db106 100644 --- a/src/tg_bot.py +++ b/src/tg_bot.py @@ -3,7 +3,7 @@ import logging from email.utils import parseaddr import requests from src.config import TelegramConfig, Config -from src.ai_client import generate_more_replies +from src.ai_client import generate_more_replies, expand_promo_detail from src.smtp_client import send_reply from src.retry import retry @@ -154,11 +154,15 @@ CALLBACK_SELECT_REPLY = "sr" CALLBACK_REGEN = "rg" CALLBACK_HINT = "h" CALLBACK_CANCEL = "c" +CALLBACK_PROMO_DETAIL = "pd" def _summary_keyboard(can_reply: bool = True, is_promotion: bool = False, links: list = None) -> dict: if is_promotion: - return {"inline_keyboard": [[{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}]]} + return {"inline_keyboard": [ + [{"text": "告诉我更多", "callback_data": CALLBACK_PROMO_DETAIL}], + [{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}], + ]} kb = [ [ {"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}, @@ -360,6 +364,33 @@ def _handle_callback(tg_cfg: TelegramConfig, cfg: Config, cb: dict): delete_message(tg_cfg, str(chat_id), msg_id) logger.info(" 取消, 删除提示消息") + elif action == CALLBACK_PROMO_DETAIL and ctx: + try: + details = expand_promo_detail( + cfg.ai, ctx["sender"], ctx["subject"], ctx["original_body"], + ) + except Exception as e: + send_text(tg_cfg, str(chat_id), f"获取详情失败: {e}") + return + summary = ctx["summary_data"].get("summary", "") + detail_lines = "\n".join(f"\\- {_escape(d)}" for d in details) if details else "暂无更多详情" + expanded = ( + f"📢 *推广*\n" + f"━━━━━━━━━━━━━━━━━━\n" + f"*收件账户:* {_escape(ctx.get('account_email', ''))}\n" + f"\n{_escape(summary)}\n" + f"\n*📋 详情:*\n{detail_lines}" + ) + _tg_req(tg_cfg, "editMessageText", { + "chat_id": chat_id, "message_id": msg_id, + "text": expanded, "parse_mode": "MarkdownV2", + "reply_markup": {"inline_keyboard": [ + [{"text": "收起", "callback_data": CALLBACK_VIEW_SUMM}], + [{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}], + ]}, + }) + logger.info(" 显示推广详情") + def _handle_message(tg_cfg: TelegramConfig, cfg: Config, msg: dict): chat_id = msg["chat"]["id"]