# -*- coding: utf-8 -*- """用 v3 国家化纯印花模板重新生成各国提示词产物。 - 模板来源:config.yaml 的 prompt_templates(countries. 按国家覆盖,resolve_templates 解析), 与流水线 prompt_node 完全一致,保证产物=实际生图提示词。 - 数据源优先 output//llm_verified_prompts.json(含 verdict), 否则 output//design_briefs.json(risk_level 全 safe 时视作 verdict=safe)。 - 输出:output//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()