模板导出增强 + 模特性别分组 + 三合一提示词精简

1) 模板导出:识别「基码表-胸围」填 sku.bust(多个胸围列都填);申报价格模糊匹配多列统一按加价后价格填写;详情图文不再拼接 img_url_2;SPU 款式来源统一填「现货款」;商品产地国家简称映射(沙特→沙特阿拉伯)
2) 模特性别分组:model_features 按男女分组,按模板类目含男/女固定取对应性别模特(含 Pinterest 模式 pipeline)
3) 三合一提示词:去掉 DESIGN CONTENT 四要素描述(设计已由设计稿提供)
4) 生图尺寸:全部改为读 config 不再硬编码(设计图 compose.design_size / 合成图 compose.size / 种草图 seed_shot.size)
This commit is contained in:
2026-08-26 18:05:11 +08:00
parent e317547b8b
commit b7f429db89
93 changed files with 2708 additions and 583 deletions
+25 -20
View File
@@ -40,16 +40,6 @@ def _plan_seed_shots(comps: List[Dict[str, Any]], count: int) -> List[tuple]:
return plan
def _color_tag(cc: Dict[str, Any], idx: int) -> str:
"""种草图文件名里的颜色标识:优先 sku_code 的颜色段,回退颜色名/序号。"""
sku = str(cc.get("sku_code") or "")
if "-" in sku:
tag = sku.split("-", 1)[1]
else:
tag = str(cc.get("color") or "") or f"c{idx}"
return "".join(ch for ch in tag if ch.isalnum() or ch in "-_") or f"c{idx}"
@with_fallback("seed_shot")
def seed_shot_node(state: Dict[str, Any]) -> Dict[str, Any]:
products: List[Dict[str, Any]] = state.get("product") or []
@@ -95,7 +85,7 @@ def seed_shot_node(state: Dict[str, Any]) -> Dict[str, Any]:
except Exception as e: # noqa: BLE001
print(f"[seed_shot] 材质读取失败(用空): {e}")
from graph.seed_shot import generate_seed_shots
from graph.seed_shot import generate_seed_shots, read_template_category, gender_from_category
from graph.oss_upload import build_oss_key, compress_for_oss, upload_to_oss
from graph.nodes.oss_upload_node import _gen_rand4, MAX_CODE
@@ -104,7 +94,18 @@ def seed_shot_node(state: Dict[str, Any]) -> Dict[str, Any]:
seq = int(state.get("oss_seq") or 0)
oss_cfg = config.get("oss") or {}
oss_enabled = bool(oss_cfg.get("enabled", True)) and bool(oss_cfg.get("oss_bucket"))
size = str(ss_cfg.get("size") or "1504x2000")
size = str(ss_cfg.get("size") or "1536x2048")
# 类目 → 性别:模版「类目」表头值含「男」→ 男模;含「女」→ 女模;都不含 → 全部随机
gender = None
tp = str(((config.get("product") or {}).get("template_path")) or "").strip()
if tp:
category = read_template_category(tp)
gender = gender_from_category(category)
if gender:
print(f"[seed_shot] 类目「{category[:30]}…」含{'' if gender == 'male' else ''} → 固定 {gender} 模特")
elif category:
print(f"[seed_shot] 类目「{category[:30]}…」无男/女 → 男女模特随机")
all_shots: List[Dict[str, Any]] = []
shot_dir = output_dir / "seed_shots"
@@ -128,7 +129,9 @@ def seed_shot_node(state: Dict[str, Any]) -> Dict[str, Any]:
plan = _plan_seed_shots(comps, count)
cn = (r.get("cn_title") or "").strip() or r.get("topic", "")
material = material_map.get(r.get("spu_code", ""), "")
# 按对应货号命名(img_code=货号,如 DG000);无货号时回退 seed
base_prefix = r.get("img_code") or r.get("oss_code") or ""
pfx = base_prefix or "seed"
paths: List[str] = []
for ci, (cc, n) in enumerate(plan, start=1):
@@ -136,23 +139,25 @@ def seed_shot_node(state: Dict[str, Any]) -> Dict[str, Any]:
if not base or not Path(base).exists():
print(f"[seed_shot] {r.get('spu_code', '')} 参考图缺失({base}),跳过该颜色种草图")
continue
tag = _color_tag(cc, ci)
pfx = f"{base_prefix}_{tag}" if base_prefix else f"seed_{tag}"
generated = generate_seed_shots(ib, base, cn, material, n, str(shot_dir),
r.get("composite_negative", ""),
size=size, prefix=pfx)
size=size, prefix=pfx, gender=gender)
paths.extend(generated)
if not paths:
return None
r["seed_shot_paths"] = paths
urls: List[str] = []
for pth in paths:
# OSS key 用对应货号(img_code),不再自增;无货号时回退自增计数
with seq_lock:
if seq >= MAX_CODE:
print(f"[seed_shot] 货号计数达上限 999,停止上传种草图")
break
code = f"{prefix}{seq:03d}"
seq += 1
if not base_prefix:
if seq >= MAX_CODE:
print(f"[seed_shot] 货号计数达上限 999,停止上传种草图")
break
code = f"{prefix}{seq:03d}"
seq += 1
else:
code = base_prefix
if oss_enabled:
try:
compressed = compress_for_oss(pth, str(Path(pth).with_suffix(".oss.jpg")))