Preserve local user table for superDream-specific features while syncing user lifecycle, API key CRUD and usage queries through sub2api. Admin token handles reads and user lifecycle; per-user tokens (Fernet-encrypted in DB) handle key writes that admin endpoints do not expose. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
from typing import Any, Dict, Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.database import get_db
|
|
from app.core.dependencies import get_current_user
|
|
from app.datamodels.schemas import DashboardAPIKeysUsageRequest
|
|
from app.models import User
|
|
from app.services.usage_service import UsageService
|
|
|
|
router = APIRouter(prefix="/usage", tags=["usage"])
|
|
|
|
|
|
@router.get("")
|
|
async def list_logs(
|
|
page: int = Query(1, ge=1),
|
|
page_size: int = Query(20, ge=1, le=100),
|
|
sort_by: str = Query("created_at"),
|
|
sort_order: str = Query("desc"),
|
|
api_key_id: Optional[int] = Query(None),
|
|
model: Optional[str] = Query(None),
|
|
request_type: Optional[str] = Query(None),
|
|
stream: Optional[bool] = Query(None),
|
|
billing_type: Optional[int] = Query(None),
|
|
start_date: Optional[str] = Query(None),
|
|
end_date: Optional[str] = Query(None),
|
|
timezone: Optional[str] = Query(None),
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.list_logs(
|
|
db,
|
|
user,
|
|
page=page,
|
|
page_size=page_size,
|
|
sort_by=sort_by,
|
|
sort_order=sort_order,
|
|
api_key_id=api_key_id,
|
|
model=model,
|
|
request_type=request_type,
|
|
stream=stream,
|
|
billing_type=billing_type,
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
timezone=timezone,
|
|
)
|
|
|
|
|
|
@router.get("/stats")
|
|
async def stats(
|
|
period: Optional[str] = Query(None, regex="^(today|week|month)$"),
|
|
start_date: Optional[str] = Query(None),
|
|
end_date: Optional[str] = Query(None),
|
|
api_key_id: Optional[int] = Query(None),
|
|
timezone: Optional[str] = Query(None),
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.stats(
|
|
db,
|
|
user,
|
|
period=period,
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
api_key_id=api_key_id,
|
|
timezone=timezone,
|
|
)
|
|
|
|
|
|
@router.get("/dashboard/stats")
|
|
async def dashboard_stats(
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.dashboard_stats(db, user)
|
|
|
|
|
|
@router.get("/dashboard/trend")
|
|
async def dashboard_trend(
|
|
granularity: str = Query("day"),
|
|
start_date: Optional[str] = Query(None),
|
|
end_date: Optional[str] = Query(None),
|
|
timezone: Optional[str] = Query(None),
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.dashboard_trend(
|
|
db, user, granularity=granularity, start_date=start_date, end_date=end_date, timezone=timezone
|
|
)
|
|
|
|
|
|
@router.get("/dashboard/models")
|
|
async def dashboard_models(
|
|
start_date: Optional[str] = Query(None),
|
|
end_date: Optional[str] = Query(None),
|
|
timezone: Optional[str] = Query(None),
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.dashboard_models(
|
|
db, user, start_date=start_date, end_date=end_date, timezone=timezone
|
|
)
|
|
|
|
|
|
@router.post("/dashboard/api-keys-usage")
|
|
async def dashboard_api_keys_usage(
|
|
body: DashboardAPIKeysUsageRequest,
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> Dict[str, Any]:
|
|
return await UsageService.dashboard_api_keys_usage(db, user, body.api_key_ids) |