feat: 审核体系全面改造 — 多维度评分 + 卖点优先级 + AI 语义匹配 + 品牌方 AI 状态通知

后端:
- 审核结果拆分为 4 个独立维度 (法规合规/平台规则/品牌安全/Brief匹配度)
- 卖点优先级从 required:bool 改为三级 (core/recommended/reference)
- AI 语义匹配卖点覆盖 + AI 整体 Brief 匹配度分析
- BriefMatchDetail 评分详情 (覆盖率+亮点+问题点)
- min_selling_points 代理商可配置最少卖点数 + Alembic 迁移
- AI 语境复核过滤误报
- Brief AI 解析 + 规则 AI 解析
- AI 未配置/异常时通知品牌方
- 种子数据更新 (新格式审核结果+brief_match_detail)

前端:
- 三端审核页面展示四维度评分卡片
- 卖点编辑改为三级优先级选择器
- BriefMatchDetail 展示 (覆盖率进度条+亮点+问题)
- min_selling_points 配置 UI
- AI 配置页未配置时静默处理
- 文件预览/下载/签名 URL 优化

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-11 19:11:54 +08:00
co-authored by Claude Opus 4.6
parent 0c59797d5b
commit 0ef7650c09
43 changed files with 3909 additions and 1316 deletions
+12 -1
View File
@@ -1,5 +1,10 @@
"""
Brief 相关 Schema
卖点格式 (selling_points: List[dict]):
新格式: {"content": "卖点内容", "priority": "core|recommended|reference"}
旧格式: {"content": "卖点内容", "required": true|false}
兼容规则: required=true → priority="core", required=false → priority="recommended"
"""
from typing import Optional, List
from datetime import datetime
@@ -39,8 +44,13 @@ class BriefUpdateRequest(BaseModel):
class AgencyBriefUpdateRequest(BaseModel):
"""代理商更新 Brief 请求(允许更新 agency_attachments"""
"""代理商更新 Brief 请求(允许更新代理商附件 + 卖点 + 违禁词 + AI解析内容"""
agency_attachments: Optional[List[dict]] = None
selling_points: Optional[List[dict]] = None
min_selling_points: Optional[int] = None
blacklist_words: Optional[List[dict]] = None
brand_tone: Optional[str] = None
other_requirements: Optional[str] = None
# ===== 响应 =====
@@ -53,6 +63,7 @@ class BriefResponse(BaseModel):
file_url: Optional[str] = None
file_name: Optional[str] = None
selling_points: Optional[List[dict]] = None
min_selling_points: Optional[int] = None
blacklist_words: Optional[List[dict]] = None
competitors: Optional[List[str]] = None
brand_tone: Optional[str] = None
+55 -6
View File
@@ -91,6 +91,7 @@ class Violation(BaseModel):
content: str = Field(..., description="违规内容")
severity: RiskLevel = Field(..., description="严重程度")
suggestion: str = Field(..., description="修改建议")
dimension: Optional[str] = Field(None, description="所属维度: legal/platform/brand_safety/brief_match")
# 文本审核字段
position: Optional[Position] = Field(None, description="文本位置(脚本审核)")
@@ -101,6 +102,45 @@ class Violation(BaseModel):
source: Optional[ViolationSource] = Field(None, description="违规来源(视频审核)")
# ==================== 多维度审核 ====================
class ReviewDimension(BaseModel):
"""审核维度评分"""
score: int = Field(..., ge=0, le=100)
passed: bool
issue_count: int = 0
class ReviewDimensions(BaseModel):
"""四维度审核结果"""
legal: ReviewDimension # 法规合规(违禁词、功效词、Brief黑名单词)
platform: ReviewDimension # 平台规则
brand_safety: ReviewDimension # 品牌安全(竞品、其他品牌词)
brief_match: ReviewDimension # Brief 匹配度(卖点覆盖)
class SellingPointMatch(BaseModel):
"""卖点匹配结果"""
content: str
priority: str # "core" | "recommended" | "reference"
matched: bool
evidence: Optional[str] = None # AI 给出的匹配依据
class BriefMatchDetail(BaseModel):
"""Brief 匹配度评分详情"""
# 卖点覆盖
total_points: int = Field(0, description="需要检查的卖点总数(core + recommended")
matched_points: int = Field(0, description="实际匹配的卖点数")
required_points: int = Field(0, description="代理商要求至少体现的卖点条数(min_selling_points")
coverage_score: int = Field(0, ge=0, le=100, description="卖点覆盖率得分")
# AI 整体匹配分析
overall_score: int = Field(0, ge=0, le=100, description="整体 Brief 匹配度得分")
highlights: list[str] = Field(default_factory=list, description="内容亮点(AI 分析)")
issues: list[str] = Field(default_factory=list, description="问题点(AI 分析)")
explanation: str = Field("", description="评分说明(一句话总结)")
# ==================== 脚本预审 ====================
class ScriptReviewRequest(BaseModel):
@@ -108,9 +148,12 @@ class ScriptReviewRequest(BaseModel):
content: str = Field(..., min_length=1, description="脚本内容")
platform: Platform = Field(..., description="投放平台")
brand_id: str = Field(..., description="品牌 ID")
required_points: Optional[list[str]] = Field(None, description="必要卖点列表")
selling_points: Optional[list[dict]] = Field(None, description="卖点列表 [{content, priority}]")
min_selling_points: Optional[int] = Field(None, ge=0, description="代理商要求至少体现的卖点条数")
blacklist_words: Optional[list[dict]] = Field(None, description="Brief 黑名单词 [{word, reason}]")
soft_risk_context: Optional[SoftRiskContext] = Field(None, description="软性风控上下文")
file_url: Optional[str] = Field(None, description="脚本文件 URL(用于自动解析文本和提取图片)")
file_name: Optional[str] = Field(None, description="原始文件名(用于判断格式)")
class ScriptReviewResponse(BaseModel):
@@ -118,16 +161,22 @@ class ScriptReviewResponse(BaseModel):
脚本预审响应
结构:
- score: 合规分数 0-100
- score: 加权总分(向后兼容)
- summary: 整体摘要
- violations: 违规项列表,每项包含 suggestion
- missing_points: 遗漏的卖点(可选)
- dimensions: 四维度评分(法规/平台/品牌安全/Brief匹配)
- selling_point_matches: 卖点匹配详情
- violations: 违规项列表,每项带 dimension 标签
- missing_points: 遗漏的核心卖点(向后兼容)
"""
score: int = Field(..., ge=0, le=100, description="合规分数")
score: int = Field(..., ge=0, le=100, description="加权总分")
summary: str = Field(..., description="审核摘要")
dimensions: ReviewDimensions = Field(..., description="四维度评分")
selling_point_matches: list[SellingPointMatch] = Field(default_factory=list, description="卖点匹配详情")
brief_match_detail: Optional[BriefMatchDetail] = Field(None, description="Brief 匹配度评分详情")
violations: list[Violation] = Field(default_factory=list, description="违规项列表")
missing_points: Optional[list[str]] = Field(None, description="遗漏的卖点")
missing_points: Optional[list[str]] = Field(None, description="遗漏的核心卖点")
soft_warnings: list[SoftRiskWarning] = Field(default_factory=list, description="软性风控提示")
ai_available: bool = Field(True, description="AI 服务是否可用(False 表示降级为纯关键词检测)")
# ==================== 视频审核 ====================