feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
94
apps/etl/connectors/feiqiu/utils/ai_trigger.py
Normal file
94
apps/etl/connectors/feiqiu/utils/ai_trigger.py
Normal file
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AI 触发工具 — DWS 任务完成后通知后端 AI 模块。
|
||||
|
||||
通过 POST /api/internal/ai/trigger 发送事件,
|
||||
后端异步执行 AI 调用链(App2 预生成、消费事件链等)。
|
||||
|
||||
失败时仅记录日志,不中断 ETL 流程。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 超时设置(秒):连接 5s,读取 10s
|
||||
_TIMEOUT = (5, 10)
|
||||
|
||||
|
||||
def trigger_ai_event(
|
||||
event_type: str,
|
||||
site_id: int,
|
||||
member_id: int | None = None,
|
||||
payload: dict[str, Any] | None = None,
|
||||
connector_type: str = "feiqiu",
|
||||
) -> bool:
|
||||
"""向后端 AI 模块发送触发事件。
|
||||
|
||||
Args:
|
||||
event_type: 事件类型(dws_completed / consumption / note_created / task_assigned)
|
||||
site_id: 门店 ID
|
||||
member_id: 会员 ID(可选)
|
||||
payload: 附加数据(可选)
|
||||
connector_type: 连接器类型,默认 feiqiu
|
||||
|
||||
Returns:
|
||||
True 表示发送成功,False 表示失败(已记录日志)
|
||||
"""
|
||||
backend_url = os.environ.get("BACKEND_API_URL", "").rstrip("/")
|
||||
token = os.environ.get("INTERNAL_API_TOKEN", "")
|
||||
|
||||
if not backend_url:
|
||||
logger.warning("AI 触发跳过:BACKEND_API_URL 未配置")
|
||||
return False
|
||||
if not token:
|
||||
logger.warning("AI 触发跳过:INTERNAL_API_TOKEN 未配置")
|
||||
return False
|
||||
|
||||
url = f"{backend_url}/api/internal/ai/trigger"
|
||||
headers = {
|
||||
"Authorization": f"Internal-Token {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
body = {
|
||||
"event_type": event_type,
|
||||
"connector_type": connector_type,
|
||||
"site_id": site_id,
|
||||
"member_id": member_id,
|
||||
"payload": payload or {},
|
||||
}
|
||||
|
||||
try:
|
||||
resp = requests.post(url, json=body, headers=headers, timeout=_TIMEOUT)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
logger.info(
|
||||
"AI 触发成功:event=%s site=%s job_id=%s",
|
||||
event_type,
|
||||
site_id,
|
||||
data.get("trigger_job_id"),
|
||||
)
|
||||
return True
|
||||
else:
|
||||
logger.warning(
|
||||
"AI 触发失败:event=%s site=%s status=%s body=%s",
|
||||
event_type,
|
||||
site_id,
|
||||
resp.status_code,
|
||||
resp.text[:200],
|
||||
)
|
||||
return False
|
||||
except requests.RequestException as exc:
|
||||
logger.warning(
|
||||
"AI 触发异常:event=%s site=%s error=%s",
|
||||
event_type,
|
||||
site_id,
|
||||
exc,
|
||||
)
|
||||
return False
|
||||
Reference in New Issue
Block a user