v92-v105 多国适配 + 模板导出增强 + 生图可靠性优化

- 新增韩国(KR)适配:countries/pinterest 种子词、K-pop 提示词、UI 国家列表
- 爬虫跨运行持久化已采集 URL(.collected_urls.json),同关键词重复搜索采新图
- 模板导出增强:SPU 商品属性列名前缀剥离匹配、尺码下拉框 INDIRECT 动态引用、
  SPU 字段映射(袖长/门襟/胸垫等)、季节/印花图案女装映射、建议售价统一必填、
  SKU 分类/数量/单位直接填默认值
- 自定义模式:多模态提示词独立(custom_analyze_*)、生图提示词模板可配置
- Pinterest:空选品守卫、连续空分析保护(max_empty_analyze)、flat_prompt 配置覆盖
- 生图可靠性:开始/完成进度日志、异步任务轮询超时 60s→300s
This commit is contained in:
2026-08-31 18:35:51 +08:00
parent 71a48e4ed5
commit 3dc594cf57
29 changed files with 1369 additions and 321 deletions
+19 -8
View File
@@ -74,7 +74,6 @@ def _enrich_briefs(raw_briefs: List[Dict[str, Any]], country: str,
"suitable_for_print": True,
"design_category": classify(term),
"concept": f"围绕「{term}」的原创印花设计",
"negative_prompt": str(b.get("negative_prompt") or "").strip(),
"image_prompt": str(b.get("image_prompt") or "").strip(),
"ref_images": [str(p) for p in (b.get("ref_images") or []) if str(p)],
"source_md5": str(b.get("source_md5") or "").strip().lower(),
@@ -114,11 +113,11 @@ def pinterest_analyze_node(state: Dict[str, Any]) -> Dict[str, Any]:
if batch_size <= 0:
batch_size = max_designs # 自动:一次最多分析 max_designs 张(每张图→1条简报)
need = batch_size
# 自定义模式:本地图池是唯一且有限的图源,最多分析选品清单总数」张即可
# 避免多余分析(超出的图源在简报达标后由自定义路由结束,不浪费配额)。
if bool(state.get("custom_mode")):
_t = int(state.get("pinterest_target") or 1) or 1
need = max(0, min(need, _t))
# 按目标简报数收敛:最多分析到满足选品清单所需的简报数即可(target=spu_tasks,每款一个设计)
# 普通与自定义模式一致——避免单一产品任务也把整池未消费图片全部分析成冗余简报、浪费配额
# 分析出的简报若不适合可丢弃,缺口不足时再由路由补分析/search。
_t = int(state.get("pinterest_target") or 1) or 1
need = max(1, min(need, _t))
# 1) 图池取未消费图片(md5 不在 used_images);无 → 返回空,路由触发搜索
pool = load_image_pool(output_dir, country)
@@ -204,7 +203,8 @@ def pinterest_analyze_node(state: Dict[str, Any]) -> Dict[str, Any]:
if pipe is not None and hasattr(pipe, "record_400"):
if pipe.record_400():
pipe._abort_current_term()
res = llm.analyze_pinterest_images(paths, term, country, on_400=_on_400) or []
res = llm.analyze_pinterest_images(paths, term, country, on_400=_on_400,
custom_mode=bool(state.get("custom_mode"))) or []
# 把每条简报的来源图路径回填为原始图(压缩图仅用于分析,参考图用原图)
return _assign_refs(res, chunk)
except Exception as e: # noqa: BLE001
@@ -269,6 +269,16 @@ def pinterest_analyze_node(state: Dict[str, Any]) -> Dict[str, Any]:
accumulated = list(state.get("briefs") or [])
accumulated.extend(new_briefs)
# 连续无产出计数器:本次无新增简报 → 递增(防"逐一取下一张参考图"空转);
# 有新增简报 → 重置为 0
empty_rounds = int(state.get("pinterest_empty_rounds") or 0)
if new_briefs:
empty_rounds = 0
else:
empty_rounds += 1
print(f"[pinterest_analyze] 本轮无新增简报(连续 {empty_rounds} 轮无产出),"
f"超过上限后将自动结束")
# 推送实际新增且保留的简报到并发生成流水线(简报池):边分析边生成设计/三合一/种草图
pushed = accumulated[old_count:]
pipe = state.get("pinterest_pipeline")
@@ -293,4 +303,5 @@ def pinterest_analyze_node(state: Dict[str, Any]) -> Dict[str, Any]:
}
print(f"[pinterest_analyze] 本轮分析 {len(batch)} 张图 → 简报 {len(new_briefs)} 条,"
f"累计 {len(accumulated)} 条({country}")
return {"pinterest_briefs": kept, "briefs": accumulated, "stats": stats, "errors": errors}
return {"pinterest_briefs": kept, "briefs": accumulated, "stats": stats, "errors": errors,
"pinterest_empty_rounds": empty_rounds}