""" 管理员模型管理API路由 提供模型列表、详情、创建、更新、价格设置等API端点 Requirements: 7.1-7.4, 8.1-8.5, 9.1-9.4, 10.1-10.5, 11.1-11.7 """ import logging from typing import Optional from fastapi import APIRouter, Depends, HTTPException, status, Query, Request from sqlalchemy.orm import Session from app.database import get_db from app.schemas.admin_schema import ( ModelListItem, ModelDetailResponse, ModelCreateRequest, ModelUpdateRequest, ModelPriceRequest, ModelStatusRequest ) from app.schemas.model_schema import PaginatedResponse from app.services.admin_model_service import AdminModelService from app.services.operation_log_service import OperationLogService from app.dependencies.admin_auth import get_current_admin from app.models.admin import AdminUser logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/admin/models", tags=["模型管理"]) def _invalidate_model_caches(): """清除模型相关的所有 Redis 缓存""" try: from app.core.redis import redis_manager r = redis_manager.get_sync_client() except Exception: return if not r: return try: for pattern in ("model_list:*", "model_featured:*", "model_pricing:*", "model_keywords"): cursor = 0 while True: cursor, keys = r.scan(cursor, match=pattern, count=100) if keys: r.delete(*keys) if cursor == 0: break except Exception as e: logger.debug(f"模型缓存清除失败: {e}") ERROR_MESSAGES = { "MODEL_NOT_FOUND": "模型不存在", "MODEL_TITLE_EXISTS": "模型标识已存在", "INVALID_PRICE_TIERS": "价格阶梯配置无效", "INVALID_FIELD": "无效的字段" } @router.get("", response_model=PaginatedResponse) def list_models( keyword: Optional[str] = Query(None, description="搜索关键词"), category: Optional[int] = Query(None, description="模型分类"), supplier: Optional[str] = Query(None, description="供应商"), is_show_enabled: Optional[bool] = Query(None, description="是否展示"), is_api_enabled: Optional[bool] = Query(None, description="是否启用API"), page: int = Query(1, ge=1, description="页码"), size: int = Query(20, ge=1, le=100, description="每页数量"), current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """获取模型列表""" from app.schemas.admin_schema import ModelListParams params = ModelListParams( keyword=keyword, category=category, supplier=supplier, is_show_enabled=is_show_enabled, is_api_enabled=is_api_enabled, page=page, size=size ) service = AdminModelService(db) models, total = service.list_models(params) return PaginatedResponse( items=[m.model_dump() for m in models], total=total, page=page, page_size=size ) @router.get("/{model_id}", response_model=ModelDetailResponse) def get_model_detail( model_id: int, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """获取模型详情""" service = AdminModelService(db) model = service.get_model_detail(model_id) if not model: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail={"code": "MODEL_NOT_FOUND", "message": "模型不存在"} ) return model @router.post("") def create_model( data: ModelCreateRequest, request: Request, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """创建模型""" service = AdminModelService(db) try: model_id = service.create_model(data) _invalidate_model_caches() # 记录操作日志 log_service = OperationLogService(db) log_service.create_log( admin_id=current_admin.id, operation_type="create", module="model", target_id=str(model_id), detail={"title": data.title, "name": data.name}, ip_address=request.client.host if request.client else None ) return {"message": "模型创建成功", "model_id": model_id} except ValueError as e: error_code = str(e) raise HTTPException( status_code=status.HTTP_409_CONFLICT if error_code == "MODEL_TITLE_EXISTS" else status.HTTP_400_BAD_REQUEST, detail={"code": error_code, "message": ERROR_MESSAGES.get(error_code, "操作失败")} ) @router.put("/{model_id}") def update_model( model_id: int, data: ModelUpdateRequest, request: Request, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """更新模型信息""" service = AdminModelService(db) try: service.update_model(model_id, data) _invalidate_model_caches() # 记录操作日志 log_service = OperationLogService(db) log_service.create_log( admin_id=current_admin.id, operation_type="update", module="model", target_id=str(model_id), detail=data.model_dump(exclude_unset=True), ip_address=request.client.host if request.client else None ) return {"message": "模型更新成功", "model_id": model_id} except ValueError as e: error_code = str(e) status_code = status.HTTP_404_NOT_FOUND if error_code == "MODEL_NOT_FOUND" else status.HTTP_409_CONFLICT raise HTTPException( status_code=status_code, detail={"code": error_code, "message": ERROR_MESSAGES.get(error_code, "操作失败")} ) @router.put("/{model_id}/price") def update_model_price( model_id: int, data: ModelPriceRequest, request: Request, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """更新模型价格""" service = AdminModelService(db) try: service.update_model_price(model_id, data) _invalidate_model_caches() # 记录操作日志 log_service = OperationLogService(db) log_service.create_log( admin_id=current_admin.id, operation_type="update", module="model", target_id=str(model_id), detail={"action": "update_price", "pricing_mode": data.pricing_mode}, ip_address=request.client.host if request.client else None ) return {"message": "价格更新成功", "model_id": model_id} except ValueError as e: error_code = str(e) status_code = status.HTTP_404_NOT_FOUND if error_code == "MODEL_NOT_FOUND" else status.HTTP_400_BAD_REQUEST raise HTTPException( status_code=status_code, detail={"code": error_code, "message": ERROR_MESSAGES.get(error_code, "操作失败")} ) @router.put("/{model_id}/status") def update_model_status( model_id: int, data: ModelStatusRequest, request: Request, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """更新模型状态""" service = AdminModelService(db) try: service.update_model_status(model_id, data.field, data.value) _invalidate_model_caches() # 记录操作日志 log_service = OperationLogService(db) log_service.create_log( admin_id=current_admin.id, operation_type="update", module="model", target_id=str(model_id), detail={"action": "update_status", "field": data.field, "value": data.value}, ip_address=request.client.host if request.client else None ) return {"message": "状态更新成功", "model_id": model_id, data.field: data.value} except ValueError as e: error_code = str(e) raise HTTPException( status_code=status.HTTP_404_NOT_FOUND if error_code == "MODEL_NOT_FOUND" else status.HTTP_400_BAD_REQUEST, detail={"code": error_code, "message": ERROR_MESSAGES.get(error_code, "操作失败")} ) @router.put("/batch/api-enabled") def batch_update_api_enabled( model_ids: list[int] = Query(..., description="模型ID列表"), enabled: bool = Query(..., description="是否启用API"), request: Request = None, current_admin: AdminUser = Depends(get_current_admin), db: Session = Depends(get_db) ): """ 批量更新模型API权限 需求 13.2: 支持批量开启/关闭API权限 需求 13.3: 批量操作需要确认 """ from app.models.model import ModelNew updated_count = db.query(ModelNew).filter( ModelNew.id.in_(model_ids), ModelNew.is_local == False ).update( {ModelNew.is_api_enabled: enabled}, synchronize_session=False ) db.commit() _invalidate_model_caches() # 记录操作日志 log_service = OperationLogService(db) log_service.create_log( admin_id=current_admin.id, operation_type="batch_update", module="model", target_id=",".join(map(str, model_ids)), detail={"action": "batch_api_enabled", "enabled": enabled, "count": updated_count}, ip_address=request.client.host if request and request.client else None ) return {"message": f"已更新{updated_count}个模型的API权限", "updated_count": updated_count}