feat: AI 审核自动驳回 + 功效词可配置 + UI 修复
- AI 自动驳回:法规/品牌安全 HIGH 违规或总分<40 自动打回上传阶段 - 功效词可配置:从硬编码改为品牌方在规则页面自行管理 - 驳回通知:AI 驳回时只通知达人,含具体原因 - 达人端:脚本/视频页面展示 AI 驳回原因 + 重新上传入口 - 规则页面:新增"功效词"分类 - 种子数据:新增 6 条默认功效词 - 其他:代理商管理下拉修复、AI 配置模型列表扩展、视觉模型标签修正、规则编辑放开限制 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0ef7650c09
commit
0b3dfa3c52
@@ -195,6 +195,42 @@ async def upload_video(
|
||||
return task
|
||||
|
||||
|
||||
AI_AUTO_REJECT_SCORE = 40
|
||||
|
||||
|
||||
def _check_ai_auto_reject(score: int, result: dict) -> tuple[bool, str]:
|
||||
"""
|
||||
判断 AI 审核结果是否应自动驳回
|
||||
|
||||
触发条件(任一):
|
||||
1. 法规合规维度存在 HIGH 级违规(违禁词/功效词)
|
||||
2. 品牌安全维度存在 HIGH 级违规(竞品提及)
|
||||
3. 总分 < 40
|
||||
"""
|
||||
reasons = []
|
||||
violations = result.get("violations", [])
|
||||
|
||||
# 条件1: 法规 HIGH
|
||||
high_legal = [v for v in violations if v.get("dimension") == "legal" and v.get("severity") == "high"]
|
||||
if high_legal:
|
||||
words = [v.get("content", "") for v in high_legal[:5]]
|
||||
reasons.append(f"法规违规:{', '.join(words)}")
|
||||
|
||||
# 条件2: 品牌安全 HIGH
|
||||
high_brand = [v for v in violations if v.get("dimension") == "brand_safety" and v.get("severity") == "high"]
|
||||
if high_brand:
|
||||
words = [v.get("content", "") for v in high_brand[:5]]
|
||||
reasons.append(f"品牌安全违规:{', '.join(words)}")
|
||||
|
||||
# 条件3: 总分过低
|
||||
if score < AI_AUTO_REJECT_SCORE:
|
||||
reasons.append(f"综合评分 {score} 分,低于合格线 {AI_AUTO_REJECT_SCORE} 分")
|
||||
|
||||
if reasons:
|
||||
return True, ";".join(reasons)
|
||||
return False, ""
|
||||
|
||||
|
||||
async def complete_ai_review(
|
||||
db: AsyncSession,
|
||||
task: Task,
|
||||
@@ -206,9 +242,16 @@ async def complete_ai_review(
|
||||
完成 AI 审核
|
||||
|
||||
- 更新 AI 审核结果
|
||||
- 状态流转到代理商审核
|
||||
- 自动驳回:法规/品牌安全 HIGH 违规或总分 < 40 → 回到上传阶段
|
||||
- 正常:流转到代理商审核
|
||||
"""
|
||||
now = datetime.now(timezone.utc)
|
||||
auto_rejected, reject_reason = _check_ai_auto_reject(score, result)
|
||||
|
||||
# 将自动驳回信息写入 result,前端可据此展示
|
||||
if auto_rejected:
|
||||
result["ai_auto_rejected"] = True
|
||||
result["ai_reject_reason"] = reject_reason
|
||||
|
||||
if review_type == "script":
|
||||
if task.stage != TaskStage.SCRIPT_AI_REVIEW:
|
||||
@@ -217,7 +260,11 @@ async def complete_ai_review(
|
||||
task.script_ai_score = score
|
||||
task.script_ai_result = result
|
||||
task.script_ai_reviewed_at = now
|
||||
task.stage = TaskStage.SCRIPT_AGENCY_REVIEW
|
||||
|
||||
if auto_rejected:
|
||||
task.stage = TaskStage.SCRIPT_UPLOAD
|
||||
else:
|
||||
task.stage = TaskStage.SCRIPT_AGENCY_REVIEW
|
||||
|
||||
elif review_type == "video":
|
||||
if task.stage != TaskStage.VIDEO_AI_REVIEW:
|
||||
@@ -226,7 +273,11 @@ async def complete_ai_review(
|
||||
task.video_ai_score = score
|
||||
task.video_ai_result = result
|
||||
task.video_ai_reviewed_at = now
|
||||
task.stage = TaskStage.VIDEO_AGENCY_REVIEW
|
||||
|
||||
if auto_rejected:
|
||||
task.stage = TaskStage.VIDEO_UPLOAD
|
||||
else:
|
||||
task.stage = TaskStage.VIDEO_AGENCY_REVIEW
|
||||
|
||||
else:
|
||||
raise ValueError(f"不支持的审核类型: {review_type}")
|
||||
|
||||
Reference in New Issue
Block a user