模板导出增强 + 模特性别分组 + 三合一提示词精简
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:
+56
-9
@@ -44,15 +44,55 @@ def load_templates() -> List[Dict[str, str]]:
|
||||
for t in tpls if t.get("prompt")]
|
||||
|
||||
|
||||
def load_model_features() -> List[str]:
|
||||
"""模特特征列表(无配置时给内置兜底)。"""
|
||||
def load_model_features(gender: Optional[str] = None) -> List[str]:
|
||||
"""模特特征列表(无配置时给内置兜底)。
|
||||
gender: "male"/"female" 时只返回对应性别;None/其他 返回全部(指定性别组为空时回退全部)。"""
|
||||
data = _load_yaml("configs/model_features.yaml")
|
||||
feats = [str(f) for f in (data.get("model_features") or []) if str(f).strip()]
|
||||
mf = data.get("model_features") or []
|
||||
feats: List[str] = []
|
||||
if isinstance(mf, dict):
|
||||
if gender and gender in mf:
|
||||
feats = [str(f) for f in mf[gender] if str(f).strip()]
|
||||
if not feats:
|
||||
feats = [str(f) for g in mf.values() for f in g if str(f).strip()]
|
||||
else:
|
||||
feats = [str(f) for f in mf if str(f).strip()]
|
||||
if not feats:
|
||||
feats = ["20岁清新少女,素颜通透感", "25岁都市职场女性,干练气质"]
|
||||
return feats
|
||||
|
||||
|
||||
def read_template_category(template_path: str) -> str:
|
||||
"""读取模版「类目」表头对应的值(如 服装、鞋靴和珠宝饰品>男士时尚>男装>男装上衣、T恤、衬衫>男装T恤)。
|
||||
遍历所有 sheet(类目表头可能在「模版」等 sheet),找到即返回其下一行同列值。"""
|
||||
try:
|
||||
import openpyxl
|
||||
wb = openpyxl.load_workbook(template_path, data_only=True, read_only=True)
|
||||
try:
|
||||
for ws in wb.worksheets:
|
||||
rows = [r for r in ws.iter_rows(min_row=1, max_row=5, values_only=True)]
|
||||
for ri, row in enumerate(rows):
|
||||
for ci, v in enumerate(row):
|
||||
if v is not None and str(v).strip() == "类目":
|
||||
if ri + 1 < len(rows):
|
||||
val = rows[ri + 1][ci]
|
||||
return str(val or "").strip()
|
||||
finally:
|
||||
wb.close()
|
||||
except Exception as e: # noqa: BLE001
|
||||
print(f"[seed_shot] 读取模版类目失败: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def gender_from_category(category: str) -> Optional[str]:
|
||||
"""类目含「男」→ male;含「女」→ female;都不含 → None(全部随机)。"""
|
||||
if "男" in category:
|
||||
return "male"
|
||||
if "女" in category:
|
||||
return "female"
|
||||
return None
|
||||
|
||||
|
||||
def load_style_features() -> List[str]:
|
||||
"""服装风格列表(style_features.yaml,随机取一条替换 [服装风格];无配置时内置兜底)。"""
|
||||
data = _load_yaml("configs/style_features.yaml")
|
||||
@@ -75,13 +115,15 @@ def render_prompt(template_prompt: str, cn_title: str, material: str, model_feat
|
||||
|
||||
def generate_seed_shots(image_backend, base_image: str, cn_title: str, material: str,
|
||||
count: int, out_dir: str, negative: str = "",
|
||||
size: str = "1504x2000", prefix: str = "") -> List[str]:
|
||||
size: str = "1536x2048", prefix: str = "",
|
||||
gender: Optional[str] = None) -> List[str]:
|
||||
"""生成 count 张种草图(img2img,图1=合成图)。返回产物路径列表。
|
||||
size: 种草图统一 1504x2000。
|
||||
prefix: 货号前缀(对应产品货号,命名 {prefix}_seedshot_{n}.png,不覆盖旧文件)。
|
||||
size: 种草图统一 1536x2048(与合成图一致)。
|
||||
prefix: 货号前缀(对应产品货号,命名 {prefix}_{随机4位}.png,不覆盖旧文件)。
|
||||
gender: "male"/"female" 时只从对应性别模特特征随机;None 全部随机。
|
||||
占位符 [商品名称]/[材质]/[模特特征]/[服装风格] 均随机组合(模板/模特/服装风格各随机取一条)。"""
|
||||
templates = load_templates()
|
||||
features = load_model_features()
|
||||
features = load_model_features(gender=gender)
|
||||
style_features = load_style_features()
|
||||
out = Path(out_dir)
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
@@ -91,8 +133,13 @@ def generate_seed_shots(image_backend, base_image: str, cn_title: str, material:
|
||||
feat = random.choice(features)
|
||||
style_feat = random.choice(style_features)
|
||||
prompt = render_prompt(tpl["prompt"], cn_title, material, feat, style_feat)
|
||||
out_path = str(out / f"{prefix}_seedshot_{i + 1:02d}.png" if prefix
|
||||
else out / f"seed_shot_{i + 1:02d}.png")
|
||||
# 命名:{货号}_{随机4位}.png(按货号命名,随机4位避免自增序号/覆盖)
|
||||
while True:
|
||||
rand4 = f"{random.randint(0, 9999):04d}"
|
||||
out_path = str(out / f"{prefix}_{rand4}.png" if prefix
|
||||
else out / f"seed_{rand4}.png")
|
||||
if not Path(out_path).exists():
|
||||
break
|
||||
try:
|
||||
image_backend.print(prompt, base_image, out_path, negative, size=size)
|
||||
paths.append(out_path)
|
||||
|
||||
Reference in New Issue
Block a user