baodan/api/insurance/poster/content_builder.py

110 lines
4.2 KiB
Python
Raw Normal View History

2026-07-31 09:00:39 +08:00
"""海报内容构建器 — 将计划书和小册子数据组装为单图/长图模块。"""
import logging
logger = logging.getLogger(__name__)
def build_poster_content(parsed_data: dict, product_rules: dict, output_mode: str = "single") -> dict:
"""组装海报内容模块。
参数:
parsed_data: 计划书解析数据 benefit_table
product_rules: 产品小册子解析数据 features 来源页
output_mode: 'single' 'long'
返回:
结构化的海报内容 dict供前端 PosterHtmlCanvas 使用
"""
content = {
"summary": _build_summary(parsed_data),
"features": _build_features(product_rules),
"benefit_table": _build_benefit_table(parsed_data),
"bonus_mechanism": product_rules.get("bonus_mechanism", ""),
"flexible_options": product_rules.get("flexible_options", []),
"risk_warnings": product_rules.get("risk_warnings", []),
"investment_rules": product_rules.get("investment_rules", {}),
"currency_options": product_rules.get("currency_options", []),
"data_completeness": _assess_completeness(parsed_data, product_rules),
}
return content
def _build_summary(parsed_data: dict) -> dict:
"""构建客户摘要卡片数据。"""
return {
"age": parsed_data.get("age"),
"gender": parsed_data.get("gender"),
"currency": parsed_data.get("currency"),
"sum_assured": parsed_data.get("sum_assured"),
"annual_premium": parsed_data.get("annual_premium"),
"premium_term": parsed_data.get("premium_term"),
"coverage_period": parsed_data.get("coverage_period"),
}
def _build_features(product_rules: dict) -> list:
"""构建产品亮点列表,保留来源页码。
优先使用小册子提取的 features source_page
如果小册子无数据回退到计划书的 key_benefits
"""
features = product_rules.get("features", [])
if features:
result = []
for f in features[:8]:
item = {
"title": f.get("title", ""),
"summary": f.get("summary", ""),
"source_page": f.get("source_page"),
}
if item["title"]:
result.append(item)
return result
# 回退:使用计划书的 key_benefits
return [] # 由调用方从 parsed_data.key_benefits 补充
def _build_benefit_table(parsed_data: dict) -> list:
"""构建利益演示表数据(供图表组件使用)。"""
table = (
parsed_data.get("benefit_table")
or parsed_data.get("benefit_illustration")
or []
)
if not table:
return []
result = []
for row in table:
entry = {
"year": row.get("year") or row.get("policy_year") or row.get("policyYear") or 0,
"guaranteed": row.get("guaranteed_csv") or row.get("guaranteedCashValue") or row.get("guaranteed") or 0,
"nonGuaranteed": row.get("non_guaranteed") or row.get("nonGuaranteed") or 0,
"totalSurrender": row.get("total_surrender") or row.get("totalSurrenderValue") or row.get("total") or 0,
"deathBenefit": row.get("death_benefit") or row.get("deathBenefit") or 0,
}
if entry["year"] > 0:
result.append(entry)
return result
def _assess_completeness(parsed_data: dict, product_rules: dict) -> dict:
"""评估数据完整度,决定哪些模块应显示。
返回:
{field: bool} 表示各模块是否有足够数据
"""
has_benefit_table = bool(parsed_data.get("benefit_table") or parsed_data.get("benefit_illustration"))
benefit_rows = parsed_data.get("benefit_table") or parsed_data.get("benefit_illustration") or []
return {
"has_summary": bool(parsed_data.get("age") or parsed_data.get("sum_assured")),
"has_benefit_chart": has_benefit_table and len(benefit_rows) >= 3,
"has_features": bool(product_rules.get("features")),
"has_currency_options": bool(product_rules.get("currency_options")),
"has_bonus": bool(product_rules.get("bonus_mechanism")),
"has_flexible_options": bool(product_rules.get("flexible_options")),
"has_risk_warnings": bool(product_rules.get("risk_warnings")),
}