baodan/api/insurance/poster/compliance.py
wsb1224 cf77d40569 本轮新增:
PPT 对象选择和绿色选中框。
双击编辑文本框、表格单元格。
文字字体、字号、加粗、颜色、对齐属性。
Ctrl/Cmd+Z、Ctrl/Cmd+Shift+Z 撤销重做。
PPT 缩略图/网格总览切换。
历史版本只读查看。
历史版本“恢复为新版本”,不覆盖旧文件。
海报区块显示/隐藏。
长图区块上移、下移排序。
新背景候选确认,可选择使用新背景或保留原背景。
合规问题“一键采用建议”。
新增 warn 合规级别。
解析失败人工填写入口。
展示解析方法和低质量页诊断。
同步更新了[API 接口文档](/D:/work/code/python/coding/baodanagent/docs/保险智能客服系统_API接口文档.md)。
验证结果:
相关后端测试:28 passed, 1 skipped
Python 编译检查:通过
前端生产构建:通过
git diff --check:通过
2026-07-31 15:41:58 +08:00

89 lines
3.0 KiB
Python

"""海报文案合规规则与字符定位。"""
import hashlib
import json
RULES = (
{
"ruleId": "RETURN_GUARANTEE",
"terms": ("保证", "稳赚", "保底"),
"severity": "block",
"message": "不得使用确定性收益承诺",
"suggestion": "改为“利益以正式计划书为准”",
"replacement": "相关利益",
},
{
"ruleId": "RISK_FREE_CLAIM",
"terms": ("无风险", "零风险"),
"severity": "block",
"message": "不得宣称保险或投资安排不存在风险",
"suggestion": "删除绝对化表述,并补充必要的风险提示",
"replacement": "存在一定风险",
},
{
"ruleId": "EXAGGERATED_RETURN",
"terms": ("最高收益", "回报率"),
"severity": "block",
"message": "收益表述必须有正式计划书依据且不得夸大",
"suggestion": "引用已确认的计划书数据并注明非保证利益",
"replacement": "演示利益",
},
{
"ruleId": "UNSUPPORTED_SUPERLATIVE",
"terms": ("行业领先", "最佳"),
"severity": "warn",
"message": "比较性或最高级表述需要可核验依据",
"suggestion": "改为客观描述产品特点,或补充权威依据",
"replacement": "具有特色",
},
)
FIELDS = ("headline", "body", "call_to_action")
def copy_revision(copy_content: dict) -> str:
"""生成与字段顺序无关的文案版本摘要。"""
normalized = {
field: str((copy_content or {}).get(field) or "")
for field in FIELDS
}
payload = json.dumps(normalized, ensure_ascii=False, sort_keys=True)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
def check_copy_compliance(copy_content: dict) -> dict:
"""返回合规状态、文案版本和可定位的问题列表。"""
issues = []
for field in FIELDS:
text = str((copy_content or {}).get(field) or "")
for rule in RULES:
for term in rule["terms"]:
start = 0
while True:
index = text.find(term, start)
if index < 0:
break
issues.append({
"ruleId": rule["ruleId"],
"severity": rule["severity"],
"field": field,
"start": index,
"end": index + len(term),
"text": term,
"message": rule["message"],
"suggestion": rule["suggestion"],
"replacement": rule["replacement"],
})
start = index + len(term)
severity_order = {"pass": 0, "warn": 1, "block": 2}
status = "pass"
for issue in issues:
if severity_order[issue["severity"]] > severity_order[status]:
status = issue["severity"]
return {
"status": status,
"revision": copy_revision(copy_content),
"issues": issues,
}