from typing import Optional, List, Tuple from sqlalchemy.orm import Session from fastapi import HTTPException, status from app.models.project import ClassificationProject, ClassificationTask, ClassificationResult from app.models.classification import Category, DataLevel from app.models.metadata import DataColumn, DataTable, Database as MetaDatabase def get_project(db: Session, project_id: int) -> Optional[ClassificationProject]: return db.query(ClassificationProject).filter(ClassificationProject.id == project_id).first() def list_projects( db: Session, keyword: Optional[str] = None, page: int = 1, page_size: int = 20, created_by: Optional[int] = None ) -> Tuple[List[ClassificationProject], int]: query = db.query(ClassificationProject) if keyword: query = query.filter(ClassificationProject.name.contains(keyword)) if created_by: query = query.filter(ClassificationProject.created_by == created_by) total = query.count() items = query.order_by(ClassificationProject.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all() return items, total def create_project(db: Session, name: str, template_id: int, created_by: int, **kwargs) -> ClassificationProject: db_obj = ClassificationProject( name=name, template_id=template_id, created_by=created_by, **kwargs, ) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj def update_project(db: Session, db_obj: ClassificationProject, **kwargs) -> ClassificationProject: for k, v in kwargs.items(): if v is not None: setattr(db_obj, k, v) db.commit() db.refresh(db_obj) return db_obj def delete_project(db: Session, project_id: int) -> None: db_obj = get_project(db, project_id) if not db_obj: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="项目不存在") db.delete(db_obj) db.commit() def get_project_stats(db: Session, project_id: int) -> dict: total = db.query(ClassificationResult).filter(ClassificationResult.project_id == project_id).count() auto_count = db.query(ClassificationResult).filter( ClassificationResult.project_id == project_id, ClassificationResult.source == "auto", ).count() manual_count = db.query(ClassificationResult).filter( ClassificationResult.project_id == project_id, ClassificationResult.source == "manual", ).count() reviewed_count = db.query(ClassificationResult).filter( ClassificationResult.project_id == project_id, ClassificationResult.status == "reviewed", ).count() return { "total": total, "auto": auto_count, "manual": manual_count, "reviewed": reviewed_count, } def list_results( db: Session, project_id: Optional[int] = None, table_id: Optional[int] = None, status: Optional[str] = None, keyword: Optional[str] = None, page: int = 1, page_size: int = 50, project_ids: Optional[List[int]] = None, ) -> Tuple[List[ClassificationResult], int]: query = db.query(ClassificationResult) if project_id: query = query.filter(ClassificationResult.project_id == project_id) if project_ids: query = query.filter(ClassificationResult.project_id.in_(project_ids)) if table_id: query = query.join(DataColumn).filter(DataColumn.table_id == table_id) if status: query = query.filter(ClassificationResult.status == status) if keyword: query = query.join(DataColumn).filter( (DataColumn.name.contains(keyword)) | (DataColumn.comment.contains(keyword)) ) total = query.count() items = query.offset((page - 1) * page_size).limit(page_size).all() return items, total def update_result_label( db: Session, result_id: int, category_id: int, level_id: int, labeler_id: int, ) -> ClassificationResult: result = db.query(ClassificationResult).filter(ClassificationResult.id == result_id).first() if not result: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="结果不存在") result.category_id = category_id result.level_id = level_id result.labeler_id = labeler_id result.source = "manual" result.status = "manual" result.label_time = __import__('datetime').datetime.utcnow() db.commit() db.refresh(result) return result