feat: 完整功能部署 v1.0

新增功能:
- 天网协作系统 (HTTP API 端口 6060)
- 三种工作流 (查找图片/处理图片/转人工派单)
- 图片任务数据库 (支持客户后续增加需求)
- 图绘派单系统集成 (API: 8005)
- 文字检测与加价 (60-80 元高价值订单)
- 风险评估与接单判断
- 作图失败自动转人工

新增文档:
- 项目功能汇总.md
- 三种工作流功能说明.md
- 文字加价功能说明.md
- 风险评估功能说明.md
- 图片任务数据库功能说明.md
- 图绘派单系统集成说明.md
- 作图失败转接人工说明.md
- DEPLOYMENT.md
- TIANWANG_INTEGRATION.md

核心修改:
- core/pydantic_ai_agent.py
- core/workflow.py
- core/websocket_client.py
- image/image_analyzer.py
- services/service_tuhui_dispatch.py
- db/image_tasks_db.py

版本:v1.0
日期:2026-02-28
This commit is contained in:
2026-02-28 11:20:40 +08:00
parent 5aedf1665d
commit a6c42d505a
171 changed files with 7979 additions and 328 deletions

116
core/websocket_client.py Normal file → Executable file
View File

@@ -95,6 +95,15 @@ class QingjianAPIClient:
self._pending_images: dict = {}
self._pending_image_tasks: dict = {}
# 延迟加载任务模块(避免循环导入)
self.task_scheduler = None
self.task_manager = None
self.trigger_engine = None
# 多进程分片支持
self.shard_keys: set = set() # 本进程负责的客户 key 集合
self.worker_id = int(os.getenv('AI_CS_WORKER_ID', '0'))
# 初始化 Agent
if self.enable_agent:
try:
@@ -108,6 +117,7 @@ class QingjianAPIClient:
if workflow:
workflow.register_send_callback(self._workflow_send)
workflow.register_agent_notify_callback(self._workflow_agent_notify)
async def connect(self):
"""连接WebSocket服务器"""
@@ -190,11 +200,18 @@ class QingjianAPIClient:
async def handle_message(self, message):
"""处理接收到的消息"""
timestamp = self.get_time()
try:
data = json.loads(message)
# 多进程分片检查:只处理分配给本进程的客户
if self.shard_keys:
customer_key = self._customer_key(data)
if customer_key not in self.shard_keys:
# 不属于本进程的客户,跳过
return
timestamp = self.get_time()
# 保存最后一条消息用于回复
self.last_msg = data
@@ -517,7 +534,7 @@ class QingjianAPIClient:
urls = self._extract_image_urls(msg_text)
key = self._customer_key(data)
self._add_pending_images(key, urls)
await self.send_reply(data, "图片收到了,说下要求(尺寸/要做什么)")
await self.send_reply(data, "收到,我看看哈")
old = self._pending_image_tasks.get(key)
if old and not old.done():
old.cancel()
@@ -546,7 +563,7 @@ class QingjianAPIClient:
if len(urls) == 1:
key = self._customer_key(data)
self._add_pending_images(key, urls)
await self.send_reply(data, "图片收到了,说下要求(尺寸/要做什么)")
await self.send_reply(data, "收到,我看看哈")
else:
if self._msg_requests_external_contact(msg_text):
reply = "这里沟通就可以哦,其他联系方式不方便"
@@ -1303,3 +1320,94 @@ if __name__ == "__main__":
asyncio.run(client.run())
except KeyboardInterrupt:
print("\n已停止")
async def _load_task_modules(self):
"""延迟加载任务模块,避免循环导入"""
from core.task_scheduler import get_task_scheduler
from core.task_trigger import get_trigger_engine
from db.task_db.task_model import get_task_manager
self.trigger_engine = get_trigger_engine()
async def check_and_trigger_tasks(self, data: dict):
"""检查并触发匹配的任务"""
try:
customer_key = self._customer_key(data)
customer_id = data.get('from_id')
message = data.get('content', '')
# 获取该客户的待触发任务
pending_tasks = self.task_manager.get_pending_tasks(customer_id)
for task in pending_tasks:
trigger = {
'type': task['trigger_type'],
'keyword': task['trigger_keyword'],
'keywords': task['trigger_keywords']
}
# 检查是否匹配触发条件
if self.task_scheduler.check_trigger_match(message, trigger):
logger.info(f"任务触发条件匹配:{task['task_id']}")
# 异步执行任务
asyncio.create_task(self.task_scheduler.execute_task(task))
except Exception as e:
logger.error(f"检查任务触发失败:{e}")
async def _load_task_modules(self):
"""延迟加载任务模块,避免循环导入"""
from core.task_scheduler import get_task_scheduler
from core.task_trigger import get_trigger_engine
from db.task_db.task_model import get_task_manager
self.trigger_engine = get_trigger_engine()
async def _load_task_modules(self):
"""延迟加载任务模块"""
if self.task_scheduler is None:
from core.task_scheduler import get_task_scheduler
from core.task_trigger import get_trigger_engine
from db.task_db.task_model import get_task_manager
self.trigger_engine = get_trigger_engine()
async def check_and_trigger_tasks_v2(self, data: dict):
"""增强版:检查并触发匹配的任务(支持指定客户)"""
# 确保任务模块已加载
await self._load_task_modules()
try:
customer_key = self._customer_key(data)
customer_id = data.get('from_id')
customer_name = data.get('from_name')
message = data.get('content', '')
# 准备上下文
context = {
'customer_id': customer_id,
'customer_name': customer_name,
'acc_id': data.get('acc_id')
}
# 获取该客户的待触发任务
pending_tasks = self.task_manager.get_pending_tasks(customer_id)
for task in pending_tasks:
trigger = {
'type': task['trigger_type'],
'keyword': task['trigger_keyword'],
'keywords': task['trigger_keywords'],
# 指定客户相关字段
'customer_id': task.get('specified_customer_id'),
'customer_name': task.get('specified_customer_name')
}
# 使用触发引擎检查是否匹配
if self.trigger_engine.check_trigger(message, trigger, context):
logger.info(f"任务触发条件匹配:{task['task_id']} (客户:{customer_name}/{customer_id})")
# 异步执行任务
asyncio.create_task(self.task_scheduler.execute_task(task))
except Exception as e:
logger.error(f"检查任务触发失败:{e}")