Files
tw/services/service_tuhui_upload.py
ZuoWei a6c42d505a 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
2026-02-28 11:20:40 +08:00

173 lines
6.0 KiB
Python

# -*- coding: utf-8 -*-
"""
图绘平台上传服务
将处理好的图片上传到图绘平台,返回图片 URL
"""
import os
import httpx
import logging
from pathlib import Path
from typing import Optional, Tuple
from dotenv import load_dotenv
logger = logging.getLogger(__name__)
# 图绘平台配置
TUHUI_BASE_URL = os.getenv("TUHUI_BASE_URL", "http://127.0.0.1:8002")
TUHUI_PHONE = os.getenv("TUHUI_PHONE", "17520145271") # 图绘账号手机号
TUHUI_PASSWORD = os.getenv("TUHUI_PASSWORD", "zuowei1216") # 图绘账号密码
TUHUI_DEFAULT_PRICE = int(os.getenv("TUHUI_DEFAULT_PRICE", "20")) # 默认定价(元)
class TuhuiUploadService:
"""图绘平台上传服务"""
def __init__(self):
self.base_url = TUHUI_BASE_URL
self.phone = TUHUI_PHONE
self.password = TUHUI_PASSWORD
self.default_price = TUHUI_DEFAULT_PRICE
self.access_token = None
self.user_id = None
async def login(self) -> bool:
"""登录图绘平台获取 token"""
try:
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/auth/login",
json={
"phone": self.phone,
"password": self.password
},
timeout=10.0
)
if response.status_code == 200:
data = response.json()
self.access_token = data.get("access_token")
user = data.get("user", {})
self.user_id = user.get("id")
logger.info(f"图绘平台登录成功,用户 ID: {self.user_id}")
return True
else:
logger.error(f"图绘平台登录失败:{response.status_code} {response.text}")
return False
except Exception as e:
logger.error(f"图绘平台登录异常:{e}")
return False
async def upload_image(
self,
image_path: str,
title: str,
description: str = "",
price: Optional[int] = None,
category: str = "高清修复"
) -> Tuple[bool, str, int]:
"""
上传图片到图绘平台
Args:
image_path: 图片文件路径
title: 作品标题
description: 作品描述
price: 定价(元),默认使用 TUHUI_DEFAULT_PRICE
category: 分类
Returns:
(success, image_url, work_id)
- success: 是否上传成功
- image_url: 图片 URL
- work_id: 作品 ID
"""
try:
# 如果 token 过期,重新登录
if not self.access_token:
if not await self.login():
return False, "登录失败", 0
# 准备上传数据
price = price or self.default_price
# 读取图片文件
if not os.path.exists(image_path):
logger.error(f"图片文件不存在:{image_path}")
return False, "文件不存在", 0
with open(image_path, "rb") as f:
files = {
"original_image": ("image.jpg", f, "image/jpeg")
}
data = {
"title": title,
"description": description,
"price": str(price),
"category": category
}
headers = {
"Authorization": f"Bearer {self.access_token}"
}
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/works",
files=files,
data=data,
headers=headers,
timeout=30.0
)
if response.status_code in [200, 201]:
work_data = response.json()
work_id = work_data.get("id")
image_url = work_data.get("original_image", "")
logger.info(f"图绘平台上传成功,作品 ID: {work_id}, URL: {image_url}")
return True, image_url, work_id
else:
logger.error(f"图绘平台上传失败:{response.status_code} {response.text}")
# 如果 token 过期,尝试重新登录后再上传
if response.status_code == 401:
logger.info("Token 可能过期,尝试重新登录...")
self.access_token = None
if await self.login():
# 重新上传
return await self.upload_image(
image_path, title, description, price, category
)
return False, f"上传失败:{response.text}", 0
except Exception as e:
logger.error(f"图绘平台上传异常:{e}")
return False, f"上传异常:{e}", 0
# 单例
_tuhui_service: Optional[TuhuiUploadService] = None
def get_tuhui_service() -> TuhuiUploadService:
"""获取图绘上传服务单例"""
global _tuhui_service
if _tuhui_service is None:
_tuhui_service = TuhuiUploadService()
return _tuhui_service
# 便捷函数
async def upload_to_tuhui(
image_path: str,
title: str,
description: str = "",
price: int = 20
) -> Tuple[bool, str, int]:
"""
便捷函数:上传图片到图绘平台
Returns:
(success, image_url, work_id)
"""
service = get_tuhui_service()
return await service.upload_image(image_path, title, description, price)