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

181 lines
6.0 KiB
Python

"""
Review Card Repository
审核卡片持久化仓储 - JSON文件存储
"""
from pathlib import Path
from typing import List, Optional
import json
import uuid
from datetime import datetime
from app.models.review_card import (
ReviewCard, ReviewCardCreate, ReviewCardUpdate, ReviewCardStatus
)
from app.utils.logger import get_logger
logger = get_logger(__name__)
# 数据文件路径
DATA_DIR = Path(__file__).parent.parent.parent / "data"
REVIEW_CARDS_FILE = DATA_DIR / "review_cards.json"
class ReviewCardRepository:
"""审核卡片仓储 - JSON文件持久化"""
def __init__(self):
self.file_path = REVIEW_CARDS_FILE
self._cards: Dict[str, ReviewCard] = {}
self._ensure_data_dir()
self._load()
def _ensure_data_dir(self):
"""确保数据目录存在"""
self.file_path.parent.mkdir(parents=True, exist_ok=True)
def _load(self):
"""从文件加载"""
if self.file_path.exists():
try:
content = self.file_path.read_text(encoding="utf-8")
if content.strip():
data = json.loads(content)
for card_id, card_data in data.items():
# 确保created_at和updated_at是datetime对象
if isinstance(card_data.get("created_at"), str):
card_data["created_at"] = datetime.fromisoformat(
card_data["created_at"].replace('Z', '+00:00')
)
if isinstance(card_data.get("updated_at"), str):
card_data["updated_at"] = datetime.fromisoformat(
card_data["updated_at"].replace('Z', '+00:00')
)
if isinstance(card_data.get("completed_at"), str):
card_data["completed_at"] = datetime.fromisoformat(
card_data["completed_at"].replace('Z', '+00:00')
)
self._cards[card_id] = ReviewCard(**card_data)
except Exception as e:
logger.error(f"加载审核卡片失败: {e}")
self._cards = {}
def _save(self):
"""保存到文件"""
try:
data = {}
for card_id, card in self._cards.items():
card_dict = card.dict()
# 确保datetime正确序列化
if isinstance(card_dict.get("created_at"), datetime):
card_dict["created_at"] = card_dict["created_at"].isoformat()
if isinstance(card_dict.get("updated_at"), datetime):
card_dict["updated_at"] = card_dict["updated_at"].isoformat()
if isinstance(card_dict.get("completed_at"), datetime):
card_dict["completed_at"] = card_dict["completed_at"].isoformat()
data[card_id] = card_dict
self.file_path.write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding="utf-8"
)
except Exception as e:
logger.error(f"保存审核卡片失败: {e}")
raise
async def create(self, data: ReviewCardCreate) -> ReviewCard:
"""创建审核卡片"""
card_id = str(uuid.uuid4())
card = ReviewCard(
id=card_id,
**data.dict(),
created_at=datetime.now(),
updated_at=datetime.now()
)
self._cards[card_id] = card
self._save()
logger.info(f"创建审核卡片: {card_id}")
return card
async def get(self, card_id: str) -> Optional[ReviewCard]:
"""获取单个卡片"""
return self._cards.get(card_id)
async def list_by_project(
self,
project_id: str,
status: Optional[ReviewCardStatus] = None,
limit: int = 100
) -> List[ReviewCard]:
"""列出项目的审核卡片"""
cards = [
card for card in self._cards.values()
if card.project_id == project_id
]
if status:
cards = [c for c in cards if c.status == status]
# 按创建时间倒序
cards = sorted(cards, key=lambda c: c.created_at, reverse=True)
return cards[:limit]
async def update(self, card_id: str, data: ReviewCardUpdate) -> Optional[ReviewCard]:
"""更新审核卡片"""
card = self._cards.get(card_id)
if not card:
return None
# 更新字段
update_data = data.dict(exclude_unset=True, exclude_none=True)
for field, value in update_data.items():
setattr(card, field, value)
card.updated_at = datetime.now()
if data.status == ReviewCardStatus.COMPLETED:
card.completed_at = datetime.now()
self._cards[card_id] = card
self._save()
logger.info(f"更新审核卡片: {card_id}")
return card
async def delete(self, card_id: str) -> bool:
"""删除审核卡片"""
if card_id in self._cards:
del self._cards[card_id]
self._save()
return True
return False
async def count_by_project(self, project_id: str) -> int:
"""统计项目的审核卡片数量"""
return sum(1 for card in self._cards.values() if card.project_id == project_id)
async def count_by_status(self, project_id: str, status: ReviewCardStatus) -> int:
"""统计项目特定状态的审核卡片数量"""
return sum(
1 for card in self._cards.values()
if card.project_id == project_id and card.status == status
)
# 全局单例
_review_card_repo = None
def get_review_card_repo() -> ReviewCardRepository:
"""获取审核卡片仓储单例"""
global _review_card_repo
if _review_card_repo is None:
_review_card_repo = ReviewCardRepository()
return _review_card_repo
# 导入Dict类型
from typing import Dict