feat: extract clickable links from email and show as URL buttons
This commit is contained in:
@@ -18,6 +18,7 @@ SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以
|
|||||||
"category": "normal/promotion/notification",
|
"category": "normal/promotion/notification",
|
||||||
"summary": "50字以内的核心摘要",
|
"summary": "50字以内的核心摘要",
|
||||||
"verification_code": "",
|
"verification_code": "",
|
||||||
|
"links": [{"text": "按钮文字", "url": "https://..."}],
|
||||||
"priority": "high/medium/low",
|
"priority": "high/medium/low",
|
||||||
"action_required": true/false,
|
"action_required": true/false,
|
||||||
"action_items": ["待办事项1", "待办事项2"],
|
"action_items": ["待办事项1", "待办事项2"],
|
||||||
@@ -34,6 +35,7 @@ SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以
|
|||||||
- subject 不能照抄原邮件主题,必须是你总结生成的简短标题
|
- subject 不能照抄原邮件主题,必须是你总结生成的简短标题
|
||||||
- category: 邮件类型。推广邮件(营销、促销、广告、 newsletter 推广等)标记为 "promotion";验证码邮件标记为 "notification";普通邮件标记为 "normal"
|
- category: 邮件类型。推广邮件(营销、促销、广告、 newsletter 推广等)标记为 "promotion";验证码邮件标记为 "notification";普通邮件标记为 "normal"
|
||||||
- verification_code: 仅当 category 为 "notification" 且邮件包含验证码时填写,格式为「平台名称 验证码」(如「GitHub 123456」「微信 888888」)。非验证码邮件留空字符串
|
- verification_code: 仅当 category 为 "notification" 且邮件包含验证码时填写,格式为「平台名称 验证码」(如「GitHub 123456」「微信 888888」)。非验证码邮件留空字符串
|
||||||
|
- links: 从邮件正文中提取用户需要点击的链接。只提取有意义的、用户可能需要操作的链接(如确认链接、登录链接、下载链接、账单链接等),不要提取退订链接、追踪像素、邮件头中的无关链接。每条包含简短描述文字和完整 URL。最多 3 条。没有需要点击的链接时为空数组
|
||||||
- 当 category 为 "promotion" 时,summary 直接写成一句话:「[发送方名称] 在推广 [推广的产品/服务/活动]」,例如「腾讯云在推广双十一云服务器折扣」。此时 priority 固定为 "low",action_required 为 false,can_reply 为 false,action_items 和 reply_suggestions 为空数组
|
- 当 category 为 "promotion" 时,summary 直接写成一句话:「[发送方名称] 在推广 [推广的产品/服务/活动]」,例如「腾讯云在推广双十一云服务器折扣」。此时 priority 固定为 "low",action_required 为 false,can_reply 为 false,action_items 和 reply_suggestions 为空数组
|
||||||
- can_reply 为 false 表示无需回复或不适合建议回复(此时忽略 reply_suggestions)
|
- can_reply 为 false 表示无需回复或不适合建议回复(此时忽略 reply_suggestions)
|
||||||
- is_simple 为 true 表示纯确认性回复(如"好的""收到"),用户选择后可直发
|
- is_simple 为 true 表示纯确认性回复(如"好的""收到"),用户选择后可直发
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ def send_summary(tg_cfg: TelegramConfig, chat_id: str, summary_text: str,
|
|||||||
is_promotion = summary_data.get("category") == "promotion"
|
is_promotion = summary_data.get("category") == "promotion"
|
||||||
is_verification = summary_data.get("category") == "notification" and summary_data.get("verification_code")
|
is_verification = summary_data.get("category") == "notification" and summary_data.get("verification_code")
|
||||||
plain_text = is_promotion or is_verification
|
plain_text = is_promotion or is_verification
|
||||||
|
links = summary_data.get("links", [])
|
||||||
result = _tg_req(tg_cfg, "sendMessage", {
|
result = _tg_req(tg_cfg, "sendMessage", {
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
"text": summary_text,
|
"text": summary_text,
|
||||||
"parse_mode": "MarkdownV2" if not plain_text else None,
|
"parse_mode": "MarkdownV2" if not plain_text else None,
|
||||||
"reply_markup": _summary_keyboard(can_reply, is_promotion),
|
"reply_markup": _summary_keyboard(can_reply, is_promotion, links),
|
||||||
})
|
})
|
||||||
msg_id = result["result"]["message_id"]
|
msg_id = result["result"]["message_id"]
|
||||||
_email_contexts[msg_id] = {
|
_email_contexts[msg_id] = {
|
||||||
@@ -164,7 +165,7 @@ CALLBACK_HINT = "h"
|
|||||||
CALLBACK_CANCEL = "c"
|
CALLBACK_CANCEL = "c"
|
||||||
|
|
||||||
|
|
||||||
def _summary_keyboard(can_reply: bool = True, is_promotion: bool = False) -> dict:
|
def _summary_keyboard(can_reply: bool = True, is_promotion: bool = False, links: list = None) -> dict:
|
||||||
if is_promotion:
|
if is_promotion:
|
||||||
return {"inline_keyboard": [[{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}]]}
|
return {"inline_keyboard": [[{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG}]]}
|
||||||
kb = [
|
kb = [
|
||||||
@@ -175,6 +176,11 @@ def _summary_keyboard(can_reply: bool = True, is_promotion: bool = False) -> dic
|
|||||||
]
|
]
|
||||||
if can_reply:
|
if can_reply:
|
||||||
kb.append([{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY}])
|
kb.append([{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY}])
|
||||||
|
for link in (links or []):
|
||||||
|
url = link.get("url", "")
|
||||||
|
text = link.get("text", "打开链接")[:30]
|
||||||
|
if url.startswith("http"):
|
||||||
|
kb.append([{"text": f"🔗 {text}", "url": url}])
|
||||||
return {"inline_keyboard": kb}
|
return {"inline_keyboard": kb}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user