# -*- 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)