POD 趋势感知 Agent:缓存热点模式 + 三图合成 + 热点去重/风格去重 + review 兜底

- 缓存热点批量流程(有采集缓存不触发 Google)
- 简报不足直接从采集缓存生成(轻量补齐)
- 三图合成(模特/印花/底图)+ 底图压缩 <2MB
- 热点去重→风格去重自动切换 + 不适合类目 review 兜底
- 透明背景(background=transparent)+ 提示词清洗(敏感词/背景描述)
- 任务前 basemap 校验 + 模板国家校验 + 模特任务级分配
This commit is contained in:
2026-08-22 14:14:01 +08:00
commit f493bde8a9
98 changed files with 10280 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
# -*- coding: utf-8 -*-
"""用 v3 国家化纯印花模板重新生成各国提示词产物。
- 模板来源:config.yaml 的 prompt_templatescountries.<CODE> 按国家覆盖,resolve_templates 解析),
与流水线 prompt_node 完全一致,保证产物=实际生图提示词。
- 数据源优先 output/<c>/llm_verified_prompts.json(含 verdict),
否则 output/<c>/design_briefs.jsonrisk_level 全 safe 时视作 verdict=safe)。
- 输出:output/<c>/pure_print_prompts.{json,md}
"""
import argparse
import datetime
import json
import os
import sys
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE)
from graph.templates import resolve_templates # noqa: E402
COUNTRY_NAMES = {"US": "美国", "GB": "英国", "JP": "日本", "AU": "澳大利亚"}
STATUS = {"safe": "✅ 可直接用", "review": "⚠️ 需人工复核", "blocked": "🚫 已拦截"}
def load_briefs(country: str):
"""优先 llm_verified_prompts.json,否则 design_briefs.json。"""
verified = os.path.join(BASE, "output", country, "llm_verified_prompts.json")
briefs_path = os.path.join(BASE, "output", country, "design_briefs.json")
if os.path.exists(verified):
with open(verified, "r", encoding="utf-8") as f:
data = json.load(f)
items = data.get("design_briefs", [])
# 归一化 verdict 字段名
for b in items:
if "verdict" not in b and "risk_level" in b:
b["verdict"] = b["risk_level"]
return [b for b in items if b.get("motif")]
if os.path.exists(briefs_path):
with open(briefs_path, "r", encoding="utf-8") as f:
data = json.load(f)
items = data.get("design_briefs", [])
for b in items:
if "verdict" not in b:
b["verdict"] = b.get("risk_level") or ("safe" if b.get("safe_for_print") else "review")
return [b for b in items if b.get("motif")]
return []
def gen_country(country: str):
briefs = load_briefs(country)
if not briefs:
print(f"[{country}] 无简报数据(output/{country}/llm_verified_prompts.json 或 design_briefs.json 缺失/无 motif),跳过")
return False
with open(os.path.join(BASE, "config.yaml"), "r", encoding="utf-8") as f:
import yaml
tpls = yaml.safe_load(f).get("prompt_templates") or {}
t = resolve_templates(tpls, country)
image_tpl = t["image_prompt"]
out_items = []
for b in briefs:
out_items.append({
"topic": b.get("topic"),
"category": b.get("design_category") or b.get("category"),
"score": round(float(b.get("score") or 0), 3),
"verdict": b.get("verdict"),
"compliance_note": b.get("compliance_note") or b.get("concept") or b.get("risk_reasons"),
"motif": b.get("motif"),
"art_style": b.get("art_style"),
"color_palette": b.get("color_palette"),
"composition": b.get("composition"),
"pure_print_prompt": image_tpl.format(
motif=b.get("motif"), art_style=b.get("art_style"),
color_palette=b.get("color_palette"), composition=b.get("composition")),
})
result = {
"country": country,
"country_name": COUNTRY_NAMES.get(country, country),
"template": "pure_print_15x18cm_to_26x32cm_v3",
"template_source": "config.yaml prompt_templates.countries." + country,
"generated_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"total": len(out_items),
"safe": sum(1 for i in out_items if i["verdict"] == "safe"),
"review": sum(1 for i in out_items if i["verdict"] in ("review", "blocked")),
"items": out_items,
}
out_dir = os.path.join(BASE, "output", country)
os.makedirs(out_dir, exist_ok=True)
json_path = os.path.join(out_dir, "pure_print_prompts.json")
with open(json_path, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
lines = [
f"# {result['country_name']}{country})纯印花设计提示词产物(15×18cm ~ 26×32cm · v3 国家化模板)\n",
f"- 生成时间:{result['generated_at']}",
f"- 模板版本:`pure_print_15x18cm_to_26x32cm_v3`,来源:config.yaml → prompt_templates.countries.{country}",
"- 规则:尺寸在**约 15×18cm ~ 26×32cm 区间内自由选择**(防默认出满幅大图,不拉伸、不铺满、留边距);英文**可加可不加**,与印花适配即可;**任何文字严禁政治/宗教/仇恨/暴力/性/品牌/商标/真实人物等敏感内容**",
f"- 总数 {result['total']} 条:✅ safe {result['safe']} 条(可直接生成) / ⚠️ review {result['review']} 条(需人工复核)\n",
]
for i, it in enumerate(result["items"], 1):
verdict = it["verdict"]
tag = STATUS.get(verdict, verdict)
lines.append(f"## {i}. {it['topic']} [{it['category'] or 'N/A'}] (score {it['score']}) {tag}\n")
note = it["compliance_note"]
lines.append(f"- **合规/说明**{note if note else '(无)'}")
lines.append(f"- **motif**{it['motif']}")
lines.append(f"- **art_style**{it['art_style']}")
lines.append(f"- **color_palette**{it['color_palette']}")
lines.append(f"- **composition**{it['composition']}\n")
lines.append("```text")
lines.append(it["pure_print_prompt"])
lines.append("```\n")
md_path = os.path.join(out_dir, "pure_print_prompts.md")
with open(md_path, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
# 校验
with open(json_path, "r", encoding="utf-8") as f:
chk = json.load(f)
bad = [i["topic"] for i in chk["items"] if "choose freely between a MINIMUM print area of about 15x18 cm" not in i["pure_print_prompt"]]
print(f"[{country}] 生成完成: {len(chk['items'])} 条 (safe {chk['safe']} / review {chk['review']}) | "
f"新模板未命中: {bad or ''} | 旧模板残留: {sum(1 for i in chk['items'] if 'designed to fit a maximum print area' in i['pure_print_prompt'])}")
return True
def main():
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--country", default="all",
help="国家代码 US/GB/JP/AU,或 all(默认,处理所有有数据的国家)")
args = ap.parse_args()
if args.country == "all":
countries = [c for c in ("US", "GB", "JP", "AU")]
else:
countries = [args.country.upper()]
for cc in countries:
try:
gen_country(cc)
except Exception as e: # noqa: BLE001
print(f"[{cc}] 失败: {e}")
if __name__ == "__main__":
main()