creative_studio/backend/app/api/v1/review_cards.py
hjjjj 5487450f34 feat: 实现审核系统核心功能与UI优化
- 新增审核卡片和确认卡片模型,支持Agent推送审核任务和用户确认
- 实现审核卡片API服务,支持创建、更新、批准、驳回等操作
- 扩展审核维度配置,新增角色一致性、剧情连贯性等维度
- 优化前端审核配置页面,修复API路径错误和状态枚举问题
- 改进剧集创作平台布局,新增左侧边栏用于剧集管理和上下文查看
- 增强Skill管理,支持从审核系统跳转创建/编辑Skill
- 修复episodes.json数据问题,清理聊天历史记录
- 更新Agent提示词,明确Skill引用加载流程
- 统一前端主题配置,优化整体UI体验
2026-01-30 18:32:48 +08:00

275 lines
7.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Review Cards API Routes
审核卡片API路由 - 提供审核卡片的CRUD操作
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
from datetime import datetime
from app.models.review_card import (
ReviewCard, ReviewCardCreate, ReviewCardUpdate,
ReviewCardType, ReviewCardStatus
)
from app.db.review_card_repository import get_review_card_repo
from app.api.v1.websocket import manager
from app.utils.logger import get_logger
logger = get_logger(__name__)
router = APIRouter(prefix="/review-cards", tags=["审核卡片"])
# ============================================
# 依赖注入
# ============================================
async def get_repo():
"""获取审核卡片仓储"""
return get_review_card_repo()
# ============================================
# CRUD 端点
# ============================================
@router.post("")
async def create_review_card(
data: ReviewCardCreate,
repo=Depends(get_repo)
):
"""
创建审核卡片
触发场景:
1. Agent生成剧集内容后自动生成
2. 用户在对话框触发某一集/某几集/整个剧集的审核
"""
try:
card = await repo.create(data)
# 通过WebSocket推送通知
await manager.send_to_project(data.project_id, {
"type": "review_card_created",
"data": {
"card_id": card.id,
"card_type": card.card_type.value,
"episode_numbers": card.episode_numbers,
"severity": card.severity,
"review_reason": card.review_reason,
"created_at": card.created_at.isoformat()
}
})
logger.info(f"创建审核卡片成功: {card.id}")
return {"success": True, "card": card}
except Exception as e:
logger.error(f"创建审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"创建审核卡片失败: {str(e)}")
@router.get("")
async def list_review_cards(
project_id: str,
status: Optional[ReviewCardStatus] = None,
card_type: Optional[ReviewCardType] = None,
limit: int = Query(100, ge=1, le=500),
repo=Depends(get_repo)
) -> List[ReviewCard]:
"""
获取审核卡片列表
支持按状态和类型筛选
"""
try:
cards = await repo.list_by_project(project_id, status, limit)
if card_type:
cards = [c for c in cards if c.card_type == card_type]
return cards
except Exception as e:
logger.error(f"获取审核卡片列表失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"获取列表失败: {str(e)}")
@router.get("/stats/{project_id}")
async def get_review_card_stats(
project_id: str,
repo=Depends(get_repo)
):
"""
获取审核卡片统计信息
返回各类状态的数量统计
"""
try:
total = await repo.count_by_project(project_id)
pending = await repo.count_by_status(project_id, ReviewCardStatus.PENDING)
awaiting_user = await repo.count_by_status(project_id, ReviewCardStatus.AWAITING_USER)
approved = await repo.count_by_status(project_id, ReviewCardStatus.APPROVED)
rejected = await repo.count_by_status(project_id, ReviewCardStatus.REJECTED)
return {
"total": total,
"pending": pending,
"awaiting_user": awaiting_user,
"approved": approved,
"rejected": rejected
}
except Exception as e:
logger.error(f"获取审核卡片统计失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"获取统计失败: {str(e)}")
@router.get("/{card_id}")
async def get_review_card(
card_id: str,
repo=Depends(get_repo)
) -> ReviewCard:
"""获取审核卡片详情"""
card = await repo.get(card_id)
if not card:
raise HTTPException(status_code=404, detail="审核卡片不存在")
return card
@router.put("/{card_id}")
async def update_review_card(
card_id: str,
data: ReviewCardUpdate,
repo=Depends(get_repo)
):
"""
更新审核卡片
支持更新状态、用户评论、修改内容等
"""
try:
card = await repo.update(card_id, data)
if not card:
raise HTTPException(status_code=404, detail="审核卡片不存在")
# 通知WebSocket
await manager.send_to_project(card.project_id, {
"type": "review_card_updated",
"data": {
"card_id": card_id,
"status": card.status.value,
"updated_at": card.updated_at.isoformat()
}
})
logger.info(f"更新审核卡片成功: {card_id}")
return {"success": True, "card": card}
except HTTPException:
raise
except Exception as e:
logger.error(f"更新审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"更新失败: {str(e)}")
@router.delete("/{card_id}")
async def delete_review_card(
card_id: str,
repo=Depends(get_repo)
):
"""删除审核卡片"""
try:
success = await repo.delete(card_id)
if not success:
raise HTTPException(status_code=404, detail="审核卡片不存在")
logger.info(f"删除审核卡片成功: {card_id}")
return {"success": True}
except HTTPException:
raise
except Exception as e:
logger.error(f"删除审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"删除失败: {str(e)}")
# ============================================
# 操作端点
# ============================================
@router.post("/{card_id}/approve")
async def approve_review_card(
card_id: str,
user_comment: Optional[str] = None,
repo=Depends(get_repo)
):
"""
通过审核卡片
将卡片状态设置为APPROVED
"""
try:
update_data = ReviewCardUpdate(
status=ReviewCardStatus.APPROVED,
user_comment=user_comment
)
result = await update_review_card(card_id, update_data, repo)
return result
except Exception as e:
logger.error(f"通过审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}")
@router.post("/{card_id}/reject")
async def reject_review_card(
card_id: str,
user_comment: Optional[str] = None,
modified_content: Optional[str] = None,
repo=Depends(get_repo)
):
"""
驳回审核卡片
将卡片状态设置为REJECTED可选地包含修改内容
"""
try:
update_data = ReviewCardUpdate(
status=ReviewCardStatus.REJECTED,
user_comment=user_comment,
modified_content=modified_content
)
result = await update_review_card(card_id, update_data, repo)
return result
except Exception as e:
logger.error(f"驳回审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}")
@router.post("/{card_id}/modify")
async def modify_review_card(
card_id: str,
user_comment: Optional[str] = None,
modified_content: Optional[str] = None,
repo=Depends(get_repo)
):
"""
修改审核卡片内容
将卡片状态设置为MODIFIED包含修改后的内容
"""
try:
update_data = ReviewCardUpdate(
status=ReviewCardStatus.AWAITING_USER,
user_comment=user_comment,
modified_content=modified_content
)
result = await update_review_card(card_id, update_data, repo)
return result
except Exception as e:
logger.error(f"修改审核卡片失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}")