import json import logging from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.models.image_engine import ImageEngine from app.models.video_engine import VideoEngine logger = logging.getLogger("videogen") async def resolve_video_engine( db: AsyncSession, engine_id: str, callable_models: list[dict], ) -> VideoEngine: """根据 engine_id 解析视频引擎,并验证是否在 api-key 的可调用列表中。""" # 验证授权 allowed = {m["engine_id"] for m in callable_models if m.get("engine_type") == "video"} if engine_id not in allowed: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"该 API Key 无权使用引擎 {engine_id}", ) result = await db.execute( select(VideoEngine).where( VideoEngine.id == engine_id, VideoEngine.is_active == True, VideoEngine.deleted_at.is_(None), ).limit(1) ) engine = result.scalar_one_or_none() if not engine: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"视频引擎 {engine_id} 不存在或未启用", ) return engine async def resolve_image_engine( db: AsyncSession, engine_id: str, callable_models: list[dict], ) -> ImageEngine: """根据 engine_id 解析图片引擎,并验证是否在 api-key 的可调用列表中。""" allowed = {m["engine_id"] for m in callable_models if m.get("engine_type") == "image"} if engine_id not in allowed: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"该 API Key 无权使用引擎 {engine_id}", ) result = await db.execute( select(ImageEngine).where( ImageEngine.id == engine_id, ImageEngine.is_active == True, ImageEngine.deleted_at.is_(None), ).limit(1) ) engine = result.scalar_one_or_none() if not engine: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"图片引擎 {engine_id} 不存在或未启用", ) return engine def build_engine_snapshot(engine: VideoEngine | ImageEngine) -> dict: """构建引擎配置快照。""" snapshot = { "id": str(engine.id), "name": str(engine.name), "provider": str(getattr(engine, "provider", "")), "api_base": str(engine.api_base), "model_name": str(engine.model_name), } # 可选字段 for field in [ "supported_ratios", "supported_resolutions", "supported_durations", "default_size", "multi_generation_enabled", "max_generation_count", ]: val = getattr(engine, field, None) if val is not None: if isinstance(val, str): try: val = json.loads(val) except (json.JSONDecodeError, TypeError): pass snapshot[field] = val return snapshot async def resolve_engine_by_model_name( db: AsyncSession, model_name: str, callable_models: list[dict], engine_type: str, ) -> tuple[str, VideoEngine | ImageEngine]: """根据模型名称查找对应的引擎。 Returns: (engine_id, engine 对象) """ # 在 callable_models 中查找 target = None for m in callable_models: if m.get("model_name") == model_name and m.get("engine_type") == engine_type: target = m break if not target: from fastapi import HTTPException, status raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"该 API Key 无权使用模型 {model_name}", ) engine_id = target["engine_id"] if engine_type == "video": engine = await resolve_video_engine(db, engine_id, callable_models) else: engine = await resolve_image_engine(db, engine_id, callable_models) return engine_id, engine