POD 趋势感知 Agent:缓存热点模式 + 三图合成 + 热点去重/风格去重 + review 兜底
- 缓存热点批量流程(有采集缓存不触发 Google) - 简报不足直接从采集缓存生成(轻量补齐) - 三图合成(模特/印花/底图)+ 底图压缩 <2MB - 热点去重→风格去重自动切换 + 不适合类目 review 兜底 - 透明背景(background=transparent)+ 提示词清洗(敏感词/背景描述) - 任务前 basemap 校验 + 模板国家校验 + 模特任务级分配
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
"""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 find_basemap(basemap_root, spu_code: str, sku_code: str) -> Optional[Path]:
|
||||
"""basemap/<款号>/<SKU.code>/ 下第一张图片;无返回 None。"""
|
||||
d = Path(basemap_root) / spu_code / sku_code
|
||||
if not d.exists():
|
||||
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
|
||||
Reference in New Issue
Block a user