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

432 lines
14 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 Task API Routes
审核任务API路由 - 提供过程中审核和生成后审核的管理接口
"""
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
from typing import List, Optional
import asyncio
from app.models.review_task import (
ReviewTask,
ReviewMode,
ReviewAction,
ProcessReviewRequest,
UserReviewActionRequest,
PostCreationReviewRequest,
PostCreationReviewResult,
ReviewTaskStatus
)
from app.core.review.review_task_manager import (
ReviewTaskManager,
get_review_task_manager,
StreamReviewHelper
)
from app.db.repositories import project_repo, episode_repo
from app.models.project import SeriesProject, Episode
from app.utils.logger import get_logger
logger = get_logger(__name__)
router = APIRouter(prefix="/review-task", tags=["审核任务"])
# ============================================
# 依赖注入
# ============================================
async def get_task_manager() -> ReviewTaskManager:
"""获取审核任务管理器"""
return get_review_task_manager()
async def get_stream_helper(project_id: str) -> StreamReviewHelper:
"""获取流式审核助手"""
task_manager = get_review_task_manager()
return StreamReviewHelper(project_id, task_manager)
# ============================================
# 过程中审核 API
# ============================================
@router.post("/process")
async def create_process_review_task(
request: ProcessReviewRequest,
task_manager: ReviewTaskManager = Depends(get_task_manager)
):
"""
创建过程中审核任务
由Agent在流式输出过程中调用推送审核任务到前端。
前端通过WebSocket接收通知并等待用户确认。
"""
try:
# 创建审核任务
task = await task_manager.create_process_review_task(request)
# 通过WebSocket推送到前端
from app.api.v1.websocket import manager
await manager.send_to_project(request.project_id, {
"type": "review_task_created",
"data": {
"task_id": task.id,
"mode": task.mode.value,
"issue_type": task.issue_type,
"issue_description": task.issue_description,
"severity": task.severity,
"location": task.location.dict(),
"available_actions": [action.value for action in task.available_actions],
"suggestion": task.suggestion,
"trigger_source": task.trigger_source.value,
"created_at": task.created_at.isoformat()
}
})
logger.info(f"过程中审核任务已创建并推送: {task.id}")
return {
"success": True,
"task_id": task.id,
"message": "审核任务已创建"
}
except Exception as e:
logger.error(f"创建过程中审核任务失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"创建审核任务失败: {str(e)}"
)
@router.post("/process/{task_id}/action")
async def handle_process_review_action(
task_id: str,
request: UserReviewActionRequest,
task_manager: ReviewTaskManager = Depends(get_task_manager)
):
"""
处理用户对过程中审核任务的响应
Args:
task_id: 任务ID
request: 用户操作请求
Returns:
处理结果
"""
try:
# 处理用户操作
task = await task_manager.handle_user_review_action(request)
# 通过WebSocket通知前端任务已完成
from app.api.v1.websocket import manager
await manager.send_to_project(task.project_id or "unknown", {
"type": "review_task_completed",
"data": {
"task_id": task_id,
"status": task.status.value,
"user_response": task.user_response,
"completed_at": task.completed_at.isoformat() if task.completed_at else None
}
})
logger.info(f"用户操作已处理: {task_id}, 操作: {request.action.value}")
return {
"success": True,
"task_id": task_id,
"status": task.status.value,
"message": "操作已处理"
}
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
except Exception as e:
logger.error(f"处理用户操作失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"处理失败: {str(e)}"
)
@router.get("/process/pending/{project_id}")
async def get_pending_process_tasks(
project_id: str,
task_manager: ReviewTaskManager = Depends(get_task_manager)
) -> List[ReviewTask]:
"""
获取项目所有待处理的过程审核任务
Args:
project_id: 项目ID
Returns:
List[ReviewTask]: 待处理任务列表
"""
return task_manager.get_pending_process_tasks(project_id)
# ============================================
# 生成后审核 API
# ============================================
@router.post("/post-creation")
async def execute_post_creation_review(
request: PostCreationReviewRequest,
task_manager: ReviewTaskManager = Depends(get_task_manager),
background_tasks: BackgroundTasks = None
):
"""
执行生成后审核
根据用户配置的规则/Skill进行自动检查根据阈值报告问题。
Args:
request: 生成后审核请求
background_tasks: FastAPI后台任务管理器
Returns:
PostCreationReviewResult: 审核结果
"""
# 获取项目
project = await project_repo.get(request.project_id)
if not project:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"项目不存在: {request.project_id}"
)
# 获取剧集
episodes = await episode_repo.list_by_project(request.project_id)
episode = next((ep for ep in episodes if ep.id == request.episode_id), None)
if not episode:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"剧集不存在: {request.episode_id}"
)
try:
# 获取审核配置
from app.models.review import ReviewConfig
raw_config = getattr(project, 'reviewConfig', None)
if isinstance(raw_config, dict):
config = ReviewConfig(**raw_config)
elif raw_config is None:
config = ReviewConfig()
else:
config = raw_config
# 确保dimension_settings是dict
if not hasattr(config, 'dimension_settings') or not isinstance(config.dimension_settings, dict):
config.dimension_settings = {}
# 执行审核
result = await task_manager.execute_post_creation_review(
request=request,
project_config=config
)
# 更新剧集审核结果
from app.models.review import ReviewResult
review_result = ReviewResult(
id=f"review_{episode.id}",
episode_id=episode.id,
episode_number=episode.number,
project_id=project.id,
overall_score=result.overall_score or 75.0,
passed=result.passed,
passed_dimensions=0,
total_dimensions=1,
dimension_scores=[],
issues=[],
issue_count=result.task_count,
high_severity_count=sum(1 for t in result.tasks if t.severity == "high"),
medium_severity_count=sum(1 for t in result.tasks if t.severity == "medium"),
low_severity_count=sum(1 for t in result.tasks if t.severity == "low")
)
# 保存审核结果到剧集
await episode_repo.update(episode.id, {
"reviewResult": review_result.dict()
})
# 通过WebSocket推送审核结果
from app.api.v1.websocket import manager
await manager.send_to_project(request.project_id, {
"type": "post_creation_review_completed",
"data": {
"episode_id": episode.id,
"episode_number": episode.number,
"overall_score": result.overall_score,
"passed": result.passed,
"task_count": result.task_count,
"tasks": [
{
"id": task.id,
"issue_type": task.issue_type,
"issue_description": task.issue_description,
"severity": task.severity,
"location": task.location.dict(),
"available_actions": [action.value for action in task.available_actions],
"status": task.status.value,
"suggestion": task.suggestion
}
for task in result.tasks
]
}
})
logger.info(f"生成后审核完成: {episode.id}, 分数: {result.overall_score}")
return result
except Exception as e:
logger.error(f"生成后审核失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"审核失败: {str(e)}"
)
@router.post("/post-creation/{task_id}/action")
async def handle_post_creation_task_action(
task_id: str,
request: UserReviewActionRequest,
task_manager: ReviewTaskManager = Depends(get_task_manager)
):
"""
处理用户对生成后审核任务的响应
Args:
task_id: 任务ID
request: 用户操作请求
Returns:
处理结果
"""
try:
# 处理用户操作
task = await task_manager.handle_user_review_action(request)
# 如果修改了内容,更新剧集内容
if request.action == ReviewAction.MODIFY and request.modified_content:
# 获取剧集
episodes = await episode_repo.list_by_project(task.project_id or "")
episode = next((ep for ep in episodes if ep.id == task.episode_id), None)
if episode:
# 更新内容
await episode_repo.update(episode.id, {
"content": request.modified_content
})
# 通过WebSocket通知内容已更新
from app.api.v1.websocket import manager
await manager.send_to_project(task.project_id or "", {
"type": "episode_content_updated",
"data": {
"episode_id": episode.id,
"episode_number": episode.number
}
})
# 通过WebSocket通知任务已完成
from app.api.v1.websocket import manager
await manager.send_to_project(task.project_id or "", {
"type": "review_task_completed",
"data": {
"task_id": task_id,
"status": task.status.value,
"user_response": task.user_response,
"completed_at": task.completed_at.isoformat() if task.completed_at else None
}
})
logger.info(f"生成后审核任务已处理: {task_id}, 操作: {request.action.value}")
return {
"success": True,
"task_id": task_id,
"status": task.status.value,
"message": "操作已处理"
}
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
except Exception as e:
logger.error(f"处理生成后审核任务操作失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"处理失败: {str(e)}"
)
# ============================================
# Agent流式审核辅助 API
# ============================================
@router.post("/agent/push")
async def agent_push_review_task(
project_id: str,
issue_type: str,
issue_description: str,
severity: str = "medium",
skill_id: Optional[str] = None,
suggestion: Optional[str] = None,
task_manager: ReviewTaskManager = Depends(get_task_manager)
):
"""
Agent推送审核任务简化版
由Agent在流式输出过程中调用推送审核任务。
Args:
project_id: 项目ID
issue_type: 问题类型
issue_description: 问题描述
severity: 严重程度
skill_id: 使用的Skill ID
suggestion: 修改建议
Returns:
创建的任务ID
"""
try:
from app.models.review_task import ReviewTaskLocation
task = await task_manager.create_process_review_task(
ProcessReviewRequest(
project_id=project_id,
issue_type=issue_type,
issue_description=issue_description,
severity=severity,
location=ReviewTaskLocation(),
trigger_source="agent_auto",
skill_id=skill_id,
suggestion=suggestion
)
)
return {
"success": True,
"task_id": task.id,
"message": "审核任务已推送"
}
except Exception as e:
logger.error(f"Agent推送审核任务失败: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"推送审核任务失败: {str(e)}"
)