refactor: merge reply suggestions into single AI request
- Summary prompt now includes can_reply + reply_suggestions fields - Removed separate generate_reply_suggestions function and REPLY_PROMPT - tg_bot reads reply suggestions from cached summary_data - AI Reply button conditionally hidden based on can_reply
This commit is contained in:
@@ -2,7 +2,7 @@ import json
|
||||
import logging
|
||||
import requests
|
||||
from src.config import TelegramConfig, Config
|
||||
from src.ai_client import generate_reply_suggestions
|
||||
# reply suggestions come embedded in summary_data from summarize_email
|
||||
from src.smtp_client import send_reply
|
||||
from src.retry import retry
|
||||
|
||||
@@ -21,11 +21,12 @@ _conversations: dict[int, dict] = {}
|
||||
@retry()
|
||||
def send_summary(tg_cfg: TelegramConfig, chat_id: str, summary_text: str,
|
||||
summary_data: dict, original_body: str, account_idx: int) -> int:
|
||||
can_reply = summary_data.get("can_reply", True)
|
||||
result = _tg_req(tg_cfg, "sendMessage", {
|
||||
"chat_id": chat_id,
|
||||
"text": summary_text,
|
||||
"parse_mode": "MarkdownV2",
|
||||
"reply_markup": _summary_keyboard(),
|
||||
"reply_markup": _summary_keyboard(can_reply),
|
||||
})
|
||||
msg_id = result["result"]["message_id"]
|
||||
_email_contexts[msg_id] = {
|
||||
@@ -35,6 +36,7 @@ def send_summary(tg_cfg: TelegramConfig, chat_id: str, summary_text: str,
|
||||
"account_idx": account_idx,
|
||||
"sender": summary_data.get("sender", ""),
|
||||
"subject": summary_data.get("subject", ""),
|
||||
"can_reply": can_reply,
|
||||
}
|
||||
return msg_id
|
||||
|
||||
@@ -108,32 +110,28 @@ CALLBACK_CONFIRM_REPLY = "cr"
|
||||
CALLBACK_CANCEL = "c"
|
||||
|
||||
|
||||
def _summary_keyboard() -> dict:
|
||||
return {
|
||||
"inline_keyboard": [
|
||||
[
|
||||
{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG},
|
||||
{"text": "回复", "callback_data": CALLBACK_REPLY},
|
||||
],
|
||||
[
|
||||
{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY},
|
||||
],
|
||||
]
|
||||
}
|
||||
def _summary_keyboard(can_reply: bool = True) -> dict:
|
||||
kb = [
|
||||
[
|
||||
{"text": "查看原文", "callback_data": CALLBACK_VIEW_ORIG},
|
||||
{"text": "回复", "callback_data": CALLBACK_REPLY},
|
||||
],
|
||||
]
|
||||
if can_reply:
|
||||
kb.append([{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY}])
|
||||
return {"inline_keyboard": kb}
|
||||
|
||||
|
||||
def _orig_keyboard() -> dict:
|
||||
return {
|
||||
"inline_keyboard": [
|
||||
[
|
||||
{"text": "返回摘要", "callback_data": CALLBACK_VIEW_SUMM},
|
||||
{"text": "回复", "callback_data": CALLBACK_REPLY},
|
||||
],
|
||||
[
|
||||
{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY},
|
||||
],
|
||||
]
|
||||
}
|
||||
def _orig_keyboard(can_reply: bool = True) -> dict:
|
||||
kb = [
|
||||
[
|
||||
{"text": "返回摘要", "callback_data": CALLBACK_VIEW_SUMM},
|
||||
{"text": "回复", "callback_data": CALLBACK_REPLY},
|
||||
],
|
||||
]
|
||||
if can_reply:
|
||||
kb.append([{"text": "AI回复", "callback_data": CALLBACK_AI_REPLY}])
|
||||
return {"inline_keyboard": kb}
|
||||
|
||||
|
||||
def _ai_reply_keyboard(msg_id: int, suggestions: list) -> dict:
|
||||
@@ -191,57 +189,52 @@ def _handle_callback(tg_cfg: TelegramConfig, cfg: Config, cb: dict):
|
||||
ctx = _email_contexts.get(msg_id)
|
||||
|
||||
if action == CALLBACK_VIEW_ORIG and ctx:
|
||||
can_reply = ctx.get("can_reply", True)
|
||||
text = f"*📄 原文 \\- {_escape(ctx['subject'])}*\n\n{_escape(ctx['original_body'][:3500])}"
|
||||
_tg_req(tg_cfg, "editMessageText", {
|
||||
"chat_id": chat_id, "message_id": msg_id,
|
||||
"text": text, "parse_mode": "MarkdownV2",
|
||||
"reply_markup": _orig_keyboard(),
|
||||
"reply_markup": _orig_keyboard(can_reply),
|
||||
})
|
||||
|
||||
elif action == CALLBACK_VIEW_SUMM and ctx:
|
||||
can_reply = ctx.get("can_reply", True)
|
||||
_tg_req(tg_cfg, "editMessageText", {
|
||||
"chat_id": chat_id, "message_id": msg_id,
|
||||
"text": ctx["summary_text"], "parse_mode": "MarkdownV2",
|
||||
"reply_markup": _summary_keyboard(),
|
||||
"reply_markup": _summary_keyboard(can_reply),
|
||||
})
|
||||
|
||||
elif action == CALLBACK_REPLY and ctx:
|
||||
_conversations[chat_id] = {"state": "awaiting_reply", "msg_id": msg_id}
|
||||
can_reply = ctx.get("can_reply", True)
|
||||
_tg_req(tg_cfg, "editMessageText", {
|
||||
"chat_id": chat_id, "message_id": msg_id,
|
||||
"text": ctx["summary_text"], "parse_mode": "MarkdownV2",
|
||||
"reply_markup": _summary_keyboard(),
|
||||
"reply_markup": _summary_keyboard(can_reply),
|
||||
})
|
||||
send_text(tg_cfg, str(chat_id), "请输入你的回复内容:")
|
||||
|
||||
elif action == CALLBACK_AI_REPLY and ctx:
|
||||
try:
|
||||
acct = cfg.email_accounts[ctx["account_idx"]]
|
||||
suggestions = generate_reply_suggestions(
|
||||
cfg.ai, ctx["sender"], ctx["subject"], ctx["original_body"],
|
||||
)
|
||||
except Exception as e:
|
||||
send_text(tg_cfg, str(chat_id), f"AI 生成回复失败: {e}")
|
||||
return
|
||||
|
||||
if not suggestions.get("can_reply") or not suggestions.get("suggestions"):
|
||||
suggestions = ctx["summary_data"].get("reply_suggestions", [])
|
||||
if not suggestions:
|
||||
send_text(tg_cfg, str(chat_id), "此邮件无需回复,已隐藏 AI 回复功能。")
|
||||
return
|
||||
|
||||
_conversations[chat_id] = {
|
||||
"state": "ai_reply_selection",
|
||||
"msg_id": msg_id,
|
||||
"ai_suggestions": suggestions["suggestions"],
|
||||
"ai_suggestions": suggestions,
|
||||
}
|
||||
|
||||
text = "*AI 建议回复,请选择:*\n\n"
|
||||
for i, s in enumerate(suggestions["suggestions"], 1):
|
||||
for i, s in enumerate(suggestions, 1):
|
||||
tag = "✅ 可直接发送" if s.get("is_simple") else "📝 需确认"
|
||||
text += f"{i}\\. {_escape(s['text'])} _{tag}_\n"
|
||||
_tg_req(tg_cfg, "editMessageText", {
|
||||
"chat_id": chat_id, "message_id": msg_id,
|
||||
"text": text, "parse_mode": "MarkdownV2",
|
||||
"reply_markup": _ai_reply_keyboard(msg_id, suggestions["suggestions"]),
|
||||
"reply_markup": _ai_reply_keyboard(msg_id, suggestions),
|
||||
})
|
||||
|
||||
elif action == CALLBACK_SELECT_REPLY and ctx:
|
||||
@@ -282,10 +275,11 @@ def _handle_callback(tg_cfg: TelegramConfig, cfg: Config, cb: dict):
|
||||
elif action == CALLBACK_CANCEL:
|
||||
_conversations.pop(chat_id, None)
|
||||
if ctx:
|
||||
can_reply = ctx.get("can_reply", True)
|
||||
_tg_req(tg_cfg, "editMessageText", {
|
||||
"chat_id": chat_id, "message_id": msg_id,
|
||||
"text": ctx["summary_text"], "parse_mode": "MarkdownV2",
|
||||
"reply_markup": _summary_keyboard(),
|
||||
"reply_markup": _summary_keyboard(can_reply),
|
||||
})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user