POD 趋势感知 Agent:缓存热点模式 + 三图合成 + 热点去重/风格去重 + review 兜底
- 缓存热点批量流程(有采集缓存不触发 Google) - 简报不足直接从采集缓存生成(轻量补齐) - 三图合成(模特/印花/底图)+ 底图压缩 <2MB - 热点去重→风格去重自动切换 + 不适合类目 review 兜底 - 透明背景(background=transparent)+ 提示词清洗(敏感词/背景描述) - 任务前 basemap 校验 + 模板国家校验 + 模特任务级分配
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""用 v3 国家化纯印花模板重新生成各国提示词产物。
|
||||
|
||||
- 模板来源:config.yaml 的 prompt_templates(countries.<CODE> 按国家覆盖,resolve_templates 解析),
|
||||
与流水线 prompt_node 完全一致,保证产物=实际生图提示词。
|
||||
- 数据源优先 output/<c>/llm_verified_prompts.json(含 verdict),
|
||||
否则 output/<c>/design_briefs.json(risk_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()
|
||||
Reference in New Issue
Block a user