from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.dependencies import get_db, get_current_user from app.models.user import User from app.models.credit_ratio import CreditRatio from app.models.video_engine import VideoEngine from app.models.image_engine import ImageEngine from app.schemas.credit import CreditBalanceOut, CreditRecordOut from app.schemas.credit_ratio import CreditRatioOut from app.services.credit_ratio_service import list_all_credit_ratios from app.services.credits import get_records router = APIRouter(prefix="/credits", tags=["credits"]) @router.get("") async def get_credits( page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): records, total = await get_records(db, current_user.id, page, page_size) return { "credits": round(current_user.credits, 2), "records": [CreditRecordOut.model_validate(r) for r in records], "total": total, } @router.get( "/credit-ratios", response_model=list[CreditRatioOut], summary="获取积分比例列表", description="客户端获取当前系统配置的积分计费规则列表。普通登录用户可访问,只读返回 credit_ratios 表中的图片/视频积分比例配置。", ) async def list_client_credit_ratios( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): return await list_all_credit_ratios(db) @router.get("/ratios", response_model=dict) async def get_credit_ratios( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): import json async def get_engine_with_ratios(gen_type: str, engines: list): for engine in engines: result = await db.execute( select(CreditRatio) .where(CreditRatio.gen_type == gen_type) .where(CreditRatio.model_config_id == engine.id) ) ratios = result.scalars().all() if ratios: ratios_out = [CreditRatioOut.model_validate(r) for r in ratios] engine_info = { "id": engine.id, "name": engine.name, "provider": engine.provider, "ratios": ratios_out, } if gen_type == "video": try: supported_ratios = json.loads(engine.supported_ratios) if engine.supported_ratios else [] except Exception: supported_ratios = [] try: supported_resolutions = json.loads(engine.supported_resolutions) if engine.supported_resolutions else [] except Exception: supported_resolutions = [] try: supported_durations = json.loads(engine.supported_durations) if engine.supported_durations else [] except Exception: supported_durations = [] engine_info.update({ "supported_ratios": supported_ratios, "supported_resolutions": supported_resolutions, "supported_durations": supported_durations, "max_duration": engine.max_duration, "max_image_count": engine.max_image_count, "max_video_count": engine.max_video_count, }) return engine_info return None video_engines_result = await db.execute( select(VideoEngine) .where(VideoEngine.is_active == True) .order_by(VideoEngine.priority.desc()) ) video_engines = video_engines_result.scalars().all() image_engines_result = await db.execute( select(ImageEngine) .where(ImageEngine.is_active == True) .order_by(ImageEngine.priority.desc()) ) image_engines = image_engines_result.scalars().all() grouped = {} video_data = await get_engine_with_ratios("video", video_engines) if video_data: grouped["video"] = video_data image_data = await get_engine_with_ratios("image", image_engines) if image_data: grouped["image"] = image_data return grouped