Files
pod_trend_agent/graph/product.py
T
3218485270 b7f429db89 模板导出增强 + 模特性别分组 + 三合一提示词精简
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)
2026-08-26 18:05:11 +08:00

123 lines
4.5 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""SPU/SKU 数据库查询 + 底图/模特图资源查找(产品图生成流水线的数据层)。
数据关系(已核实 spu_sku.db):
- SPU.code = 款号(如 DG004
- SKU.code = "款号-颜色编码"(如 DG004-BL01),SKU.color = 中文色名(黑/灰/...
- basemap 目录 = basemap/<款号>/<SKU.code>/xxx.jpg
- material_library/<品类>/ 存放模特图
- SKU.img_url_2~5 = CDN 图 URL(底图/细节/模特图,仅作参考字段)
"""
import sqlite3
from pathlib import Path
from typing import Any, Dict, List, Optional
# 支持的图片格式:模特图/底图均按此识别(png/jpg 等常见格式全覆盖;AVIF/GIF/TIFF 亦支持)
IMG_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".avif", ".gif", ".tiff", ".tif"}
def _connect(db_path) -> sqlite3.Connection:
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
return conn
def list_spus(db_path, country: Optional[str] = None) -> List[Dict[str, Any]]:
"""全部 SPU(可选按国家过滤)。"""
conn = _connect(db_path)
sql = "SELECT id, code, style, material, printing_type, target_audience, pattern, country, mark FROM SPU"
params: list = []
if country:
sql += " WHERE country = ?"
params.append(country)
sql += " ORDER BY code"
rows = conn.execute(sql, params).fetchall()
conn.close()
return [dict(r) for r in rows]
def list_colors(db_path, spu_code: str) -> List[Dict[str, Any]]:
"""款号 → 颜色列表(SKU.code 去重,附中文色名、CDN 底图 URL、最低价)。"""
conn = _connect(db_path)
rows = conn.execute(
"""SELECT s.code AS sku_code, s.color, s.img_url_2 AS img_url, MIN(s.price) AS price
FROM SKU s JOIN SPU p ON s.spu_id = p.id
WHERE p.code = ?
GROUP BY s.code, s.color ORDER BY s.code""", (spu_code,)).fetchall()
conn.close()
return [dict(r) for r in rows]
def _norm_name(s: str) -> str:
"""去空格(半角+全角)+ 小写,用于 SKU code 与文件夹名比较。"""
return str(s or "").replace(" ", "").replace(" ", "").strip().lower()
def find_basemap(basemap_root, spu_code: str, sku_code: str) -> Optional[Path]:
"""basemap/<款号>/<SKU.code>/ 下第一张图片;无返回 None。
SKU code 与文件夹名比较时两边都去空格(兼容 db code 或文件夹名带空格)。
"""
root = Path(basemap_root) / spu_code
if not root.exists():
return None
target = _norm_name(sku_code)
if not target:
return None
d = root / sku_code
if not (d.exists() and d.is_dir()):
d = None
for cand in sorted(root.iterdir()):
if cand.is_dir() and _norm_name(cand.name) == target:
d = cand
break
if d is None:
return None
for f in sorted(d.iterdir()):
if f.is_file() and f.suffix.lower() in IMG_EXTS:
return f
return None
def list_model_images(material_root, category: str = "T-shirt") -> List[Path]:
"""material_library/<品类>/ 下所有图片;无返回空列表。"""
d = Path(material_root) / category
if not d.exists():
return []
return [f for f in sorted(d.iterdir()) if f.is_file() and f.suffix.lower() in IMG_EXTS]
def find_first_model_folder(material_root, preferred: Optional[str] = None):
"""material_library 下「第一个有图片的子目录」及其图片列表。
- preferred(如 config 的 model_category)优先:该目录有图就直接用;
- 否则按子目录名排序,取第一个有图的目录;
- 全空返回 (None, [])。
返回 (dir_name or None, images: List[Path])。
"""
root = Path(material_root)
if not root.exists():
return None, []
candidates = []
if preferred:
d = root / preferred
if d.is_dir():
candidates.append(d)
candidates += [d for d in sorted(root.iterdir()) if d.is_dir()]
seen = set()
for d in candidates:
if d in seen:
continue
seen.add(d)
imgs = [f for f in sorted(d.iterdir()) if f.is_file() and f.suffix.lower() in IMG_EXTS]
if imgs:
return d.name, imgs
return None, []
def first_available_sku(db_path, basemap_root, spu_code: str) -> Optional[str]:
"""返回该款号下第一个「本地有底图」的 SKU.code;无则 None。"""
for c in list_colors(db_path, spu_code):
if find_basemap(basemap_root, spu_code, c["sku_code"]) is not None:
return c["sku_code"]
return None