Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
132 lines
4.5 KiB
Python
132 lines
4.5 KiB
Python
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import os
|
||
import sys
|
||
import tempfile
|
||
import uuid
|
||
from pathlib import Path
|
||
from typing import Any
|
||
|
||
import requests
|
||
from dotenv import load_dotenv
|
||
|
||
from .config import AUTO_DRAW_ENDPOINT, AUTO_DRAW_TIMEOUT_SECONDS
|
||
|
||
|
||
def _add_legacy_tw_path() -> None:
|
||
root = os.getenv("LEGACY_TW_ROOT", r"D:\main\sandbox\tw_terminator").strip()
|
||
if not root:
|
||
return
|
||
p = Path(root)
|
||
# 先加载 legacy 项目的 .env,确保 service_tuhui_upload 在 import 时拿到正确账号配置
|
||
legacy_env = p / ".env"
|
||
if legacy_env.exists():
|
||
load_dotenv(legacy_env, override=True)
|
||
if p.exists() and str(p) not in sys.path:
|
||
sys.path.insert(0, str(p))
|
||
|
||
|
||
async def _draw_via_legacy_tw(
|
||
image_url: str,
|
||
customer_id: str,
|
||
requirement: str = "",
|
||
) -> dict[str, Any]:
|
||
# 优先使用当前项目中拷贝过来的 service_gemini
|
||
from services.service_gemini import GeminiExtractV2Service # type: ignore
|
||
|
||
# 上传模块暂时仍走 legacy(你后续可替换为新项目本地上传实现)
|
||
_add_legacy_tw_path()
|
||
from services.service_tuhui_upload import upload_to_tuhui # type: ignore
|
||
|
||
prompt = requirement.strip() or "按原图做高清修复,保留主体细节,输出清晰可用版本"
|
||
|
||
# 1) 下载原图到本地临时文件
|
||
input_path = os.path.join(tempfile.gettempdir(), f"qjcs_in_{uuid.uuid4().hex}.jpg")
|
||
output_path = os.path.join(tempfile.gettempdir(), f"qjcs_out_{uuid.uuid4().hex}.jpg")
|
||
headers = {
|
||
"User-Agent": (
|
||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||
"Chrome/122.0.0.0 Safari/537.36"
|
||
),
|
||
"Referer": "https://www.taobao.com/",
|
||
"Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
|
||
}
|
||
resp = requests.get(image_url, headers=headers, timeout=AUTO_DRAW_TIMEOUT_SECONDS)
|
||
if resp.status_code != 200:
|
||
return {"ok": False, "error": f"download_http_{resp.status_code}"}
|
||
with open(input_path, "wb") as f:
|
||
f.write(resp.content)
|
||
|
||
# 2) 直调你原来的 service_gemini 作图 API
|
||
service = GeminiExtractV2Service()
|
||
ok_extract, msg_extract, _ = await service.extract_pattern(
|
||
input_path=input_path,
|
||
output_path=output_path,
|
||
custom_prompt=prompt,
|
||
aspect_ratio="1:1",
|
||
)
|
||
if not ok_extract:
|
||
return {"ok": False, "error": f"extract_failed:{msg_extract}"}
|
||
if not os.path.exists(output_path):
|
||
return {"ok": False, "error": "extract_no_output_file"}
|
||
|
||
# 3) 上传图绘,返回可外发 URL
|
||
ok, link, _ = await upload_to_tuhui(
|
||
output_path,
|
||
title=f"客户{customer_id[-4:]}-预览图" if customer_id else "预览图",
|
||
description="AI自动作图预览",
|
||
price=1,
|
||
)
|
||
if not ok:
|
||
return {"ok": False, "error": str(link)}
|
||
return {"ok": True, "url": str(link)}
|
||
|
||
|
||
def _draw_via_http_endpoint(image_url: str, customer_id: str, requirement: str = "") -> dict[str, Any]:
|
||
if not AUTO_DRAW_ENDPOINT:
|
||
return {"ok": False, "error": "AUTO_DRAW_ENDPOINT not configured"}
|
||
payload = {
|
||
"image_url": image_url,
|
||
"customer_id": customer_id,
|
||
"requirement": requirement,
|
||
}
|
||
resp = requests.post(AUTO_DRAW_ENDPOINT, json=payload, timeout=AUTO_DRAW_TIMEOUT_SECONDS)
|
||
if resp.status_code != 200:
|
||
return {"ok": False, "error": f"http_{resp.status_code}:{resp.text[:200]}"}
|
||
data = resp.json() if resp.text else {}
|
||
url = str(data.get("url", "") or data.get("preview_url", "") or "")
|
||
if not url:
|
||
return {"ok": False, "error": "missing_preview_url"}
|
||
return {"ok": True, "url": url}
|
||
|
||
|
||
async def auto_draw_preview(
|
||
image_url: str,
|
||
customer_id: str,
|
||
requirement: str = "",
|
||
) -> dict[str, Any]:
|
||
"""
|
||
统一自动作图入口:
|
||
1) 优先走 tw_terminator 的 service_gemini 直调链路
|
||
2) 失败时回退 AUTO_DRAW_ENDPOINT
|
||
"""
|
||
try:
|
||
return await _draw_via_legacy_tw(image_url=image_url, customer_id=customer_id, requirement=requirement)
|
||
except Exception as e:
|
||
legacy_error = str(e)
|
||
|
||
try:
|
||
data = await asyncio.to_thread(
|
||
_draw_via_http_endpoint,
|
||
image_url,
|
||
customer_id,
|
||
requirement,
|
||
)
|
||
if data.get("ok"):
|
||
return data
|
||
return {"ok": False, "error": f"legacy:{legacy_error}; endpoint:{data.get('error','unknown')}"}
|
||
except Exception as e:
|
||
return {"ok": False, "error": f"legacy:{legacy_error}; endpoint:{e}"}
|