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:通过
89 lines
3.0 KiB
Python
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,
|
|
}
|