baodan/api/insurance/poster/render_document_builder.py

110 lines
3.7 KiB
Python
Raw Normal View History

2026-07-31 21:42:32 +08:00
"""构建海报预览、Prompt 与导出共同使用的 renderDocument v2。"""
from copy import deepcopy
from insurance.poster.content_builder import build_poster_content
DEFAULT_SECTIONS = (
"hero",
"summary",
"benefits",
"features",
"cta",
"disclaimer",
)
def build_render_document(
*,
format_spec: dict,
template: dict | None,
copy_content: dict,
case_facts: dict,
product_rules: dict,
plan_type: str,
compliance_revision: str,
custom_height: int | None = None,
2026-07-31 21:42:32 +08:00
sections: list[dict] | None = None,
brand: dict | None = None,
) -> dict:
"""按固定优先级组装唯一渲染文档。"""
template = template or {}
facts = deepcopy(case_facts or product_rules.get("facts") or {})
rules = deepcopy(product_rules or {})
if not rules.get("features") and facts.get("key_benefits"):
rules["features"] = [
{"title": item, "summary": ""} if isinstance(item, str) else item
for item in facts["key_benefits"]
]
content = build_poster_content(
parsed_data=facts,
product_rules=rules,
output_mode=format_spec["outputMode"],
plan_type=plan_type or "other",
)
theme = _build_theme(template.get("colorScheme") or {})
normalized_sections = _normalize_sections(sections, format_spec["outputMode"], content)
requested_output = deepcopy(format_spec["output"])
export_size = format_spec["exportSize"]
if custom_height is not None:
requested_output["height"] = custom_height
export_size = f"{requested_output['width']}x{custom_height}"
2026-07-31 21:42:32 +08:00
return {
"schemaVersion": 2,
"revision": 1,
"formatId": format_spec["id"],
"outputMode": format_spec["outputMode"],
"layoutKey": template.get("layoutKey") or (
"long_complete" if format_spec["outputMode"] == "long" else "single_hero_data"
),
"templateId": template.get("id"),
"layout": deepcopy(format_spec["layout"]),
"requestedOutput": requested_output,
"exportSize": export_size,
2026-07-31 21:42:32 +08:00
"copy": deepcopy(copy_content or {}),
"facts": facts,
"summary": content["summary"],
"features": content["features"],
"benefits": content["benefit_table"],
"theme": theme,
"style": theme,
"sections": normalized_sections,
"background": {},
"brand": deepcopy(brand or {}),
"fieldProfile": content["field_profile"],
"warnings": content["warnings"],
"complianceRevision": compliance_revision or "",
}
def _build_theme(color_scheme: dict) -> dict:
return {
"primary": color_scheme.get("primary") or "#173f35",
"accent": color_scheme.get("accent") or "#c99a4b",
"surface": color_scheme.get("surface") or "#f7f4ed",
"text": color_scheme.get("text") or "#17231f",
"muted": color_scheme.get("muted") or "#64716d",
}
def _normalize_sections(sections: list[dict] | None, output_mode: str, content: dict) -> list[dict]:
current = {
item.get("id"): item.get("visible", True)
for item in (sections or [])
if isinstance(item, dict) and item.get("id") in DEFAULT_SECTIONS
}
result = []
for section_id in DEFAULT_SECTIONS:
visible = current.get(section_id, True)
if section_id == "benefits":
visible = visible and output_mode == "long" and len(content["benefit_table"]) >= 3
elif section_id == "features":
visible = visible and bool(content["features"])
elif section_id == "summary":
visible = visible and any(content["summary"].values())
result.append({"id": section_id, "visible": visible})
return result