chore: harden runtime checks and split websocket inbound/outbound flows
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import asyncio
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, date, timedelta
|
||||
from typing import Optional
|
||||
|
||||
@@ -16,6 +17,7 @@ import httpx
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
logger = logging.getLogger("cs_agent")
|
||||
|
||||
WECHAT_WEBHOOK = os.getenv("WECHAT_WEBHOOK", "")
|
||||
SUMMARY_EMAIL = os.getenv("SUMMARY_EMAIL", "") # 收摘要的邮箱
|
||||
@@ -130,7 +132,7 @@ async def _ai_summary(raw_text: str) -> str:
|
||||
async def _send_wechat(content: str):
|
||||
"""推送到企业微信群机器人(markdown 格式,单条 ≤4096 字节自动分段)"""
|
||||
if not WECHAT_WEBHOOK:
|
||||
print("[DailySummary] 未配置 WECHAT_WEBHOOK,跳过推送")
|
||||
logger.info("[DailySummary] 未配置 WECHAT_WEBHOOK,跳过推送")
|
||||
return
|
||||
|
||||
# 企业微信单条 markdown 限 4096 字节,超长自动分段
|
||||
@@ -148,11 +150,11 @@ async def _send_wechat(content: str):
|
||||
resp = await client.post(WECHAT_WEBHOOK, json=payload)
|
||||
data = resp.json()
|
||||
if data.get("errcode") == 0:
|
||||
print(f"[DailySummary] 企业微信推送成功(第{i+1}段)")
|
||||
logger.info("[DailySummary] 企业微信推送成功(第%s段)", i + 1)
|
||||
else:
|
||||
print(f"[DailySummary] 企业微信推送失败: {data}")
|
||||
logger.warning("[DailySummary] 企业微信推送失败: %s", data)
|
||||
except Exception as e:
|
||||
print(f"[DailySummary] 企业微信推送异常: {e}")
|
||||
logger.exception("[DailySummary] 企业微信推送异常: %s", e)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
@@ -178,9 +180,9 @@ def _send_email(subject: str, body: str):
|
||||
s.starttls()
|
||||
s.login(email_sender.smtp_user, email_sender.smtp_password)
|
||||
s.sendmail(email_sender.smtp_user, [SUMMARY_EMAIL], msg.as_string())
|
||||
print(f"[DailySummary] 日报邮件已发送至 {SUMMARY_EMAIL}")
|
||||
logger.info("[DailySummary] 日报邮件已发送至 %s", SUMMARY_EMAIL)
|
||||
except Exception as e:
|
||||
print(f"[DailySummary] 日报邮件发送失败: {e}")
|
||||
logger.exception("[DailySummary] 日报邮件发送失败: %s", e)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
@@ -244,7 +246,7 @@ async def send_daily_summary(target_date: str = ""):
|
||||
if not target_date:
|
||||
target_date = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
print(f"[DailySummary] 开始生成 {target_date} 日报...")
|
||||
logger.info("[DailySummary] 开始生成 %s 日报...", target_date)
|
||||
|
||||
raw_text = _build_stats_text(target_date)
|
||||
ai_text = await _ai_summary(raw_text)
|
||||
@@ -258,7 +260,7 @@ async def send_daily_summary(target_date: str = ""):
|
||||
email_body = f"{ai_text}\n\n{'='*40}\n\n{raw_text}"
|
||||
_send_email(title, email_body)
|
||||
|
||||
print(f"[DailySummary] 日报推送完成")
|
||||
logger.info("[DailySummary] 日报推送完成")
|
||||
return ai_text
|
||||
|
||||
|
||||
@@ -268,7 +270,7 @@ async def send_daily_summary(target_date: str = ""):
|
||||
|
||||
async def scheduler():
|
||||
"""每天 SEND_HOUR:SEND_MINUTE 触发日报"""
|
||||
print(f"[DailySummary] 定时日报已启动,发送时间 {SEND_HOUR:02d}:{SEND_MINUTE:02d}")
|
||||
logger.info("[DailySummary] 定时日报已启动,发送时间 %02d:%02d", SEND_HOUR, SEND_MINUTE)
|
||||
sent_today: Optional[str] = None # 记录已发日期,防重复
|
||||
|
||||
while True:
|
||||
@@ -280,7 +282,7 @@ async def scheduler():
|
||||
try:
|
||||
await send_daily_summary(today)
|
||||
except Exception as e:
|
||||
print(f"[DailySummary] 日报生成出错: {e}")
|
||||
logger.exception("[DailySummary] 日报生成出错: %s", e)
|
||||
|
||||
# 每 30 秒检查一次
|
||||
await asyncio.sleep(30)
|
||||
@@ -294,5 +296,5 @@ if __name__ == "__main__":
|
||||
import sys
|
||||
target = sys.argv[1] if len(sys.argv) > 1 else ""
|
||||
result = asyncio.run(send_daily_summary(target))
|
||||
print("\n=== AI 摘要 ===")
|
||||
print(result)
|
||||
logger.info("\n=== AI 摘要 ===")
|
||||
logger.info(result)
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
import httpx
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
logger = logging.getLogger("cs_agent")
|
||||
|
||||
_last_push: dict[tuple[str, str], tuple[str, str, float]] = {}
|
||||
|
||||
@@ -38,6 +40,7 @@ def _get_recent_conversation(customer_id: str, acc_id: str, last_n: int = 8) ->
|
||||
from db.chat_log_db import get_recent_conversation
|
||||
return get_recent_conversation(customer_id, acc_id, limit=last_n)
|
||||
except Exception:
|
||||
logger.debug("[WechatChatLog] 获取近期对话失败,返回空列表", exc_info=True)
|
||||
return []
|
||||
|
||||
|
||||
@@ -68,7 +71,7 @@ async def push_chat_to_wechat(
|
||||
return
|
||||
_last_push[key] = ((customer_msg or ""), (reply_msg or ""), now)
|
||||
except Exception:
|
||||
pass
|
||||
logger.debug("[WechatChatLog] 去重检查异常,忽略本次去重", exc_info=True)
|
||||
reply_msg = _truncate(reply_msg, 300)
|
||||
ts = datetime.now().strftime("%H:%M")
|
||||
shop = acc_id or "未知店铺"
|
||||
@@ -109,11 +112,11 @@ async def push_chat_to_wechat(
|
||||
)
|
||||
data = resp.json()
|
||||
if data.get("errcode") == 0:
|
||||
pass # 成功静默
|
||||
return
|
||||
else:
|
||||
print(f"[WechatChatLog] 推送失败: {data}")
|
||||
logger.warning("[WechatChatLog] 推送失败: %s", data)
|
||||
except Exception as e:
|
||||
print(f"[WechatChatLog] 推送异常: {e}")
|
||||
logger.exception("[WechatChatLog] 推送异常: %s", e)
|
||||
|
||||
|
||||
async def send_morning_startup():
|
||||
@@ -129,14 +132,14 @@ async def send_morning_startup():
|
||||
webhook,
|
||||
json={"msgtype": "markdown", "markdown": {"content": content}},
|
||||
)
|
||||
print(f"[WechatChatLog] 早8点启动消息已发送")
|
||||
logger.info("[WechatChatLog] 早8点启动消息已发送")
|
||||
except Exception as e:
|
||||
print(f"[WechatChatLog] 启动消息发送失败: {e}")
|
||||
logger.exception("[WechatChatLog] 启动消息发送失败: %s", e)
|
||||
|
||||
|
||||
async def morning_startup_scheduler():
|
||||
"""每天 8:00 发送启动消息"""
|
||||
print("[WechatChatLog] 早8点启动消息定时任务已启动")
|
||||
logger.info("[WechatChatLog] 早8点启动消息定时任务已启动")
|
||||
sent_today = None
|
||||
while True:
|
||||
now = datetime.now()
|
||||
|
||||
Reference in New Issue
Block a user