- 新增审核卡片和确认卡片模型,支持Agent推送审核任务和用户确认 - 实现审核卡片API服务,支持创建、更新、批准、驳回等操作 - 扩展审核维度配置,新增角色一致性、剧情连贯性等维度 - 优化前端审核配置页面,修复API路径错误和状态枚举问题 - 改进剧集创作平台布局,新增左侧边栏用于剧集管理和上下文查看 - 增强Skill管理,支持从审核系统跳转创建/编辑Skill - 修复episodes.json数据问题,清理聊天历史记录 - 更新Agent提示词,明确Skill引用加载流程 - 统一前端主题配置,优化整体UI体验
275 lines
7.7 KiB
Python
275 lines
7.7 KiB
Python
"""
|
||
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)}")
|