- 删除后端 risk_exceptions 模块(API/Model/Schema/迁移/测试) - 删除后端 metrics 模块(API/测试) - 删除后端 ManualTask 模型和相关 Schema - 修复搜索接口响应缺少 total 字段的问题 - 统一 Platform 枚举(前端去掉后端不支持的 weibo/wechat) - 新增前端注册页面 /register,登录页添加注册链接 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
174 lines
6.5 KiB
Python
174 lines
6.5 KiB
Python
"""
|
||
审核相关的 Pydantic 模型(API 契约定义)
|
||
所有测试和实现必须遵循此契约
|
||
"""
|
||
from typing import Optional
|
||
from datetime import datetime
|
||
from pydantic import BaseModel, Field, HttpUrl
|
||
from enum import Enum
|
||
|
||
|
||
# ==================== 枚举定义 ====================
|
||
|
||
class Platform(str, Enum):
|
||
"""支持的投放平台"""
|
||
DOUYIN = "douyin"
|
||
XIAOHONGSHU = "xiaohongshu"
|
||
BILIBILI = "bilibili"
|
||
KUAISHOU = "kuaishou"
|
||
|
||
|
||
class TaskStatus(str, Enum):
|
||
"""任务状态"""
|
||
PENDING = "pending"
|
||
PROCESSING = "processing"
|
||
COMPLETED = "completed"
|
||
FAILED = "failed"
|
||
APPROVED = "approved"
|
||
REJECTED = "rejected"
|
||
|
||
|
||
class RiskLevel(str, Enum):
|
||
"""风险等级"""
|
||
HIGH = "high" # 法律违规(广告法极限词)
|
||
MEDIUM = "medium" # 平台规则违规
|
||
LOW = "low" # 品牌规范违规
|
||
|
||
|
||
class ViolationType(str, Enum):
|
||
"""违规类型"""
|
||
FORBIDDEN_WORD = "forbidden_word" # 违禁词
|
||
EFFICACY_CLAIM = "efficacy_claim" # 功效宣称
|
||
COMPETITOR_LOGO = "competitor_logo" # 竞品露出
|
||
DURATION_SHORT = "duration_short" # 时长不足
|
||
MENTION_MISSING = "mention_missing" # 品牌提及不足
|
||
BRAND_SAFETY = "brand_safety" # 品牌安全风险
|
||
|
||
|
||
class ViolationSource(str, Enum):
|
||
"""违规来源"""
|
||
TEXT = "text" # 文本/脚本
|
||
SPEECH = "speech" # 语音(ASR)
|
||
SUBTITLE = "subtitle" # 字幕(OCR)
|
||
VISUAL = "visual" # 画面(CV)
|
||
|
||
|
||
class SoftRiskAction(str, Enum):
|
||
"""软性风控动作"""
|
||
CONFIRM = "confirm" # 需要二次确认
|
||
NOTE = "note" # 需要填写备注
|
||
|
||
|
||
class SoftRiskWarning(BaseModel):
|
||
"""软性风控提示(Warn-only)"""
|
||
code: str = Field(..., description="提示类型代码")
|
||
message: str = Field(..., description="提示内容")
|
||
action_required: SoftRiskAction = Field(..., description="要求动作")
|
||
blocking: bool = Field(default=False, description="是否阻断(默认不阻断)")
|
||
context: Optional[dict] = Field(None, description="附加上下文")
|
||
|
||
|
||
class SoftRiskContext(BaseModel):
|
||
"""软性风控输入上下文"""
|
||
violation_rate: Optional[float] = Field(None, ge=0, le=1, description="违规率")
|
||
violation_threshold: Optional[float] = Field(None, ge=0, le=1, description="违规率阈值")
|
||
asr_confidence: Optional[float] = Field(None, ge=0, le=1, description="ASR 置信度")
|
||
ocr_confidence: Optional[float] = Field(None, ge=0, le=1, description="OCR 置信度")
|
||
has_history_violation: Optional[bool] = Field(None, description="是否有历史类似违规")
|
||
|
||
|
||
# ==================== 通用模型 ====================
|
||
|
||
class Position(BaseModel):
|
||
"""文本位置"""
|
||
start: int = Field(..., description="起始位置")
|
||
end: int = Field(..., description="结束位置")
|
||
|
||
|
||
class Violation(BaseModel):
|
||
"""违规项(统一结构)"""
|
||
type: ViolationType = Field(..., description="违规类型")
|
||
content: str = Field(..., description="违规内容")
|
||
severity: RiskLevel = Field(..., description="严重程度")
|
||
suggestion: str = Field(..., description="修改建议")
|
||
|
||
# 文本审核字段
|
||
position: Optional[Position] = Field(None, description="文本位置(脚本审核)")
|
||
|
||
# 视频审核字段
|
||
timestamp: Optional[float] = Field(None, description="开始时间戳(秒)")
|
||
timestamp_end: Optional[float] = Field(None, description="结束时间戳(秒)")
|
||
source: Optional[ViolationSource] = Field(None, description="违规来源(视频审核)")
|
||
|
||
|
||
# ==================== 脚本预审 ====================
|
||
|
||
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="必要卖点列表")
|
||
soft_risk_context: Optional[SoftRiskContext] = Field(None, description="软性风控上下文")
|
||
|
||
|
||
class ScriptReviewResponse(BaseModel):
|
||
"""
|
||
脚本预审响应
|
||
|
||
结构:
|
||
- score: 合规分数 0-100
|
||
- summary: 整体摘要
|
||
- violations: 违规项列表,每项包含 suggestion
|
||
- missing_points: 遗漏的卖点(可选)
|
||
"""
|
||
score: int = Field(..., ge=0, le=100, description="合规分数")
|
||
summary: str = Field(..., description="审核摘要")
|
||
violations: list[Violation] = Field(default_factory=list, description="违规项列表")
|
||
missing_points: Optional[list[str]] = Field(None, description="遗漏的卖点")
|
||
soft_warnings: list[SoftRiskWarning] = Field(default_factory=list, description="软性风控提示")
|
||
|
||
|
||
# ==================== 视频审核 ====================
|
||
|
||
class VideoReviewRequest(BaseModel):
|
||
"""视频审核请求"""
|
||
video_url: HttpUrl = Field(..., description="视频 URL")
|
||
platform: Platform = Field(..., description="投放平台")
|
||
brand_id: str = Field(..., description="品牌 ID")
|
||
creator_id: str = Field(..., description="达人 ID")
|
||
competitors: Optional[list[str]] = Field(None, description="竞品列表")
|
||
requirements: Optional[dict] = Field(None, description="审核要求(时长、频次等)")
|
||
|
||
|
||
class VideoReviewSubmitResponse(BaseModel):
|
||
"""视频审核提交响应(202 Accepted)"""
|
||
review_id: str = Field(..., description="审核任务 ID")
|
||
status: TaskStatus = Field(default=TaskStatus.PENDING, description="任务状态")
|
||
|
||
|
||
class VideoReviewProgressResponse(BaseModel):
|
||
"""视频审核进度响应"""
|
||
review_id: str = Field(..., description="审核任务 ID")
|
||
status: TaskStatus = Field(..., description="任务状态")
|
||
progress: int = Field(..., ge=0, le=100, description="进度百分比")
|
||
current_step: str = Field(..., description="当前处理步骤")
|
||
|
||
|
||
class VideoReviewResultResponse(BaseModel):
|
||
"""
|
||
视频审核结果响应(200 OK)
|
||
|
||
结构与脚本审核一致:
|
||
- score: 合规分数
|
||
- summary: 整体摘要
|
||
- violations: 违规项列表,每项包含 timestamp 和 suggestion
|
||
"""
|
||
review_id: str = Field(..., description="审核任务 ID")
|
||
status: TaskStatus = Field(default=TaskStatus.COMPLETED, description="任务状态")
|
||
score: int = Field(..., ge=0, le=100, description="合规分数")
|
||
summary: str = Field(..., description="审核摘要")
|
||
violations: list[Violation] = Field(default_factory=list, description="违规项列表")
|
||
soft_warnings: list[SoftRiskWarning] = Field(default_factory=list, description="软性风控提示")
|
||
|