baodan/api/insurance/poster/render_document_builder.py
wsb1224 e1770be4cc 现在选择“长图海报”后,在“海报尺寸”下方可以切换:
自动高度
自定义高度:1920–30000px,默认 4500px
自定义高度会同步影响画布预览、任务快照、renderDocument、历史恢复和最终 PNG。若内容超过指定高度,系统会阻止导出并提示最低所需高度,不会静默裁掉底部内容。
关键修改:
[PosterCreativePanel.vue (line 51)](D:/work/code/python/coding/baodanagent/frontend/src/components/poster/workspace/PosterCreativePanel.vue:51)
[PosterHtmlCanvas.vue (line 1)](D:/work/code/python/coding/baodanagent/frontend/src/components/poster/long/PosterHtmlCanvas.vue:1)
[poster-exporter.ts (line 95)](D:/work/code/python/coding/baodanagent/frontend/src/utils/poster-exporter.ts:95)
[format_registry.py (line 17)](D:/work/code/python/coding/baodanagent/api/insurance/poster/format_registry.py:17)
[render_validation.py (line 13)](D:/work/code/python/coding/baodanagent/api/insurance/poster/render_validation.py:13)
验证结果:33 项海报测试通过、Vue 类型检查通过、生产构建通过、UI 静态检查通过
2026-07-31 22:05:57 +08:00

110 lines
3.7 KiB
Python

"""构建海报预览、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,
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}"
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,
"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