feat(p2.4): Telegram 中間態推播 — 分析中佔位卡 + 完成後自動刪除
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
P2.4 實作 2026-04-24 ogt + Claude Sonnet 4.6 問題: LLM 分析耗時 10-30s,期間 Telegram 無任何回應,使用者不知系統在處理 修復: - telegram_gateway.py: 新增 send_analyzing_placeholder() — 發送「AI 正在分析中...」佔位卡 - telegram_gateway.py: 新增 delete_message() — 刪除佔位卡 - webhooks.py: LLM 分析前 3s 內送出佔位卡(超時不阻塞主流程) - webhooks.py: _push_to_telegram_background 收到 placeholder_message_id → 完整卡發出後刪除佔位卡 - webhooks.py: import asyncio(補缺漏) 效果: 使用者在告警到達 <3s 內即看到「分析中...」訊息,完整卡出現後自動清除 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ Endpoints:
|
||||
8. 前端戰情室即時顯示聚合次數
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import hmac
|
||||
import uuid
|
||||
@@ -314,6 +315,8 @@ async def _push_to_telegram_background(
|
||||
alert_category: str = "",
|
||||
# 2026-04-20 ogt: ADR-092 tg_sent Redis 標記(防收斂靜默)
|
||||
fingerprint: str = "",
|
||||
# P2.4 中間態清理 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
placeholder_message_id: int | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
背景任務: 推送待簽核卡片到 Telegram (v7.0 含 SignOz 整合)
|
||||
@@ -423,6 +426,10 @@ async def _push_to_telegram_background(
|
||||
if fingerprint:
|
||||
await get_approval_service().mark_telegram_confirmed(fingerprint)
|
||||
|
||||
# P2.4 中間態清理 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
if placeholder_message_id:
|
||||
await gateway.delete_message(placeholder_message_id)
|
||||
|
||||
# 2026-04-08 Claude Code: 記錄 Telegram 推送事件
|
||||
try:
|
||||
from src.repositories.alert_operation_log_repository import get_alert_operation_log_repository
|
||||
@@ -848,6 +855,22 @@ async def receive_alert(
|
||||
"labels": alert.labels or {},
|
||||
}
|
||||
|
||||
# P2.4 中間態推播 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
# LLM 分析前先送佔位卡,讓使用者知道系統已收到告警並正在處理
|
||||
_placeholder_msg_id: int | None = None
|
||||
try:
|
||||
_tg_gw = get_telegram_gateway()
|
||||
_placeholder_msg_id = await asyncio.wait_for(
|
||||
_tg_gw.send_analyzing_placeholder(
|
||||
alert_type=alert.alert_type or "unknown",
|
||||
resource_name=alert.target_resource or "",
|
||||
severity=alert.severity or "medium",
|
||||
),
|
||||
timeout=3.0, # 最多等 3s,不阻塞主流程
|
||||
)
|
||||
except Exception:
|
||||
pass # 佔位卡失敗不影響主流程
|
||||
|
||||
# 呼叫 OpenClaw LLM 分析 (v7.0 含 SignOz 整合)
|
||||
# 2026-03-29 ogt: 加入 Token/Cost 追蹤
|
||||
openclaw = get_openclaw()
|
||||
@@ -1010,6 +1033,8 @@ async def receive_alert(
|
||||
"ssl_expiry": "ssl_cert",
|
||||
}.get(alert.alert_type, "general"),
|
||||
fingerprint=fingerprint,
|
||||
# P2.4 中間態清理 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
placeholder_message_id=_placeholder_msg_id,
|
||||
)
|
||||
|
||||
return AlertResponse(
|
||||
|
||||
@@ -1525,6 +1525,62 @@ class TelegramGateway:
|
||||
|
||||
return {"inline_keyboard": buttons}
|
||||
|
||||
async def send_analyzing_placeholder(
|
||||
self,
|
||||
alert_type: str,
|
||||
resource_name: str,
|
||||
severity: str = "medium",
|
||||
) -> int | None:
|
||||
"""
|
||||
P2.4 中間態推播 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
在 LLM 分析開始前送出佔位卡,讓使用者知道系統正在處理。
|
||||
分析完成後用 delete_message() 刪除,再由 send_approval_card 補上完整卡。
|
||||
Returns: Telegram message_id 或 None(Bot 未設定 / API 失敗)
|
||||
"""
|
||||
if not self.bot_token:
|
||||
return None
|
||||
emoji = {"critical": "🔴", "medium": "🟡", "low": "🟢"}.get(severity.lower(), "⚠️")
|
||||
text = (
|
||||
f"{emoji} <b>告警收到,AI 正在分析中...</b>\n\n"
|
||||
f"資源: <code>{html.escape(resource_name or 'unknown')}</code>\n"
|
||||
f"類型: <code>{html.escape(alert_type or 'unknown')}</code>\n\n"
|
||||
f"<i>預計 10-30 秒完成,請稍候...</i>"
|
||||
)
|
||||
try:
|
||||
result = await self._send_request("sendMessage", {
|
||||
"chat_id": self.chat_id,
|
||||
"text": text,
|
||||
"parse_mode": "HTML",
|
||||
"disable_web_page_preview": True,
|
||||
})
|
||||
msg_id: int | None = None
|
||||
result_val = result.get("result")
|
||||
if isinstance(result_val, dict):
|
||||
msg_id = result_val.get("message_id")
|
||||
logger.info("analyzing_placeholder_sent", message_id=msg_id, resource=resource_name)
|
||||
return msg_id
|
||||
except Exception as e:
|
||||
logger.warning("analyzing_placeholder_failed", error=str(e))
|
||||
return None
|
||||
|
||||
async def delete_message(self, message_id: int) -> bool:
|
||||
"""
|
||||
P2.4 中間態清理 2026-04-24 ogt + Claude Sonnet 4.6
|
||||
刪除佔位卡(分析完成、完整卡已發出後呼叫)。
|
||||
"""
|
||||
if not self.bot_token or not message_id:
|
||||
return False
|
||||
try:
|
||||
await self._send_request("deleteMessage", {
|
||||
"chat_id": self.chat_id,
|
||||
"message_id": message_id,
|
||||
})
|
||||
logger.info("placeholder_deleted", message_id=message_id)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning("placeholder_delete_failed", message_id=message_id, error=str(e))
|
||||
return False
|
||||
|
||||
async def send_approval_card(
|
||||
self,
|
||||
approval_id: str,
|
||||
|
||||
Reference in New Issue
Block a user