""" Brief API 端点 """ from fastapi import APIRouter, HTTPException, status, Header, UploadFile, File, Form from pydantic import BaseModel, HttpUrl from typing import Optional, Any from datetime import datetime import uuid from app.api.v1.endpoints.auth import get_current_user from app.services.brief_parser import ( BriefParser, BriefFileValidator, OnlineDocumentValidator, OnlineDocumentImporter, ParsingStatus, ) from app.services.rule_engine import RuleConflictDetector router = APIRouter() # 模拟 Brief 存储 BRIEFS: dict[str, dict] = { "brief_001": { "brief_id": "brief_001", "task_id": "task_001", "platform": "douyin", "status": "completed", "selling_points": [ {"text": "24小时持妆", "priority": "high"}, {"text": "天然成分", "priority": "medium"}, ], "forbidden_words": [ {"word": "最", "severity": "hard"}, {"word": "第一", "severity": "hard"}, ], "brand_tone": {"style": "年轻活力"}, "timing_requirements": [ {"type": "product_visible", "min_duration_seconds": 5}, {"type": "brand_mention", "min_frequency": 3}, ], "created_at": datetime.now().isoformat(), }, } class BriefUploadResponse(BaseModel): parsing_id: str status: str message: str = "" class BriefImportRequest(BaseModel): url: str task_id: str class ConflictCheckRequest(BaseModel): platform: str class ConflictCheckResponse(BaseModel): has_conflicts: bool conflicts: list[dict[str, Any]] @router.post("/upload", response_model=BriefUploadResponse, status_code=status.HTTP_202_ACCEPTED) async def upload_brief( file: UploadFile = File(...), task_id: str = Form(...), platform: str = Form("douyin"), authorization: Optional[str] = Header(None), ): """上传 Brief 文件""" # 验证认证 if not authorization: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authorization header required", ) user = get_current_user(authorization) # 验证文件格式 file_ext = file.filename.split(".")[-1].lower() if file.filename else "" validator = BriefFileValidator() if not validator.is_supported(file_ext): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unsupported file format: {file_ext}", ) # 创建解析任务 parsing_id = f"parsing_{uuid.uuid4().hex[:8]}" # 模拟异步解析 brief_id = f"brief_{uuid.uuid4().hex[:8]}" BRIEFS[brief_id] = { "brief_id": brief_id, "task_id": task_id, "platform": platform, "status": "processing", "created_at": datetime.now().isoformat(), } return BriefUploadResponse( parsing_id=parsing_id, status="processing", message="Brief is being processed", ) @router.get("/{brief_id}") async def get_brief( brief_id: str, authorization: Optional[str] = Header(None), ): """获取 Brief 解析结果""" if not authorization: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authorization header required", ) user = get_current_user(authorization) brief = BRIEFS.get(brief_id) if not brief: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Brief not found: {brief_id}", ) return brief @router.post("/import", response_model=BriefUploadResponse, status_code=status.HTTP_202_ACCEPTED) async def import_online_document( request: BriefImportRequest, authorization: Optional[str] = Header(None), ): """导入在线文档""" if not authorization: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authorization header required", ) user = get_current_user(authorization) # 验证 URL validator = OnlineDocumentValidator() if not validator.is_valid(request.url): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Unsupported document URL", ) # 导入文档 importer = OnlineDocumentImporter() result = importer.import_document(request.url) if result.status == "failed": if result.error_code == "ACCESS_DENIED": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=result.error_message, ) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=result.error_message, ) parsing_id = f"parsing_{uuid.uuid4().hex[:8]}" return BriefUploadResponse( parsing_id=parsing_id, status="processing", ) @router.post("/{brief_id}/check_conflicts", response_model=ConflictCheckResponse) async def check_rule_conflicts( brief_id: str, request: ConflictCheckRequest, authorization: Optional[str] = Header(None), ): """检测规则冲突""" if not authorization: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Authorization header required", ) user = get_current_user(authorization) brief = BRIEFS.get(brief_id) if not brief: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Brief not found: {brief_id}", ) # 模拟平台规则 platform_rules = { "platform": request.platform, "forbidden_words": [ {"word": "最", "category": "ad_law"}, {"word": "第一", "category": "ad_law"}, ], } detector = RuleConflictDetector() result = detector.detect_conflicts(brief, platform_rules) return ConflictCheckResponse( has_conflicts=result.has_conflicts, conflicts=[ { "type": c.conflict_type, "description": c.description, } for c in result.conflicts ], )