Files
Aether/_deprecated_py_src/api/admin/pool/schemas.py
fawney19 1d9c77522a refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
2026-04-03 16:26:16 +08:00

246 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Pydantic schemas for Pool management API."""
from __future__ import annotations
from typing import Any
from pydantic import BaseModel, ConfigDict, Field
from src.models.status_snapshot import ProviderKeyStatusSnapshotResponse
# ---------------------------------------------------------------------------
# Overview
# ---------------------------------------------------------------------------
class PoolOverviewItem(BaseModel):
"""One Provider in the overview list."""
provider_id: str
provider_name: str
provider_type: str = "custom"
total_keys: int = 0
active_keys: int = 0
cooldown_count: int = 0
pool_enabled: bool = False
model_config = ConfigDict(from_attributes=True)
class PoolOverviewResponse(BaseModel):
items: list[PoolOverviewItem] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Scheduling presets metadata
# ---------------------------------------------------------------------------
class PresetModeMetaResponse(BaseModel):
value: str
label: str
class PresetDimensionMetaResponse(BaseModel):
name: str
label: str
description: str
providers: list[str] = Field(default_factory=list)
modes: list[PresetModeMetaResponse] | None = None
default_mode: str | None = None
mutex_group: str | None = None
evidence_hint: str | None = None
# ---------------------------------------------------------------------------
# Paginated key list
# ---------------------------------------------------------------------------
class PoolSchedulingReason(BaseModel):
"""Structured scheduling reason for a key."""
code: str
label: str
blocking: bool = False
source: str = "pool" # manual / pool / health / policy
ttl_seconds: int | None = None
detail: str | None = None
class OAuthOrganizationSummary(BaseModel):
id: str | None = None
title: str | None = None
is_default: bool = False
role: str | None = None
class PoolKeyDetail(BaseModel):
"""Detailed status of a single pool key."""
key_id: str
key_name: str
is_active: bool
auth_type: str = "api_key"
oauth_expires_at: int | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.oauth"
)
oauth_invalid_at: int | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.oauth"
)
oauth_invalid_reason: str | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.oauth"
)
oauth_plan_type: str | None = None
oauth_account_id: str | None = None
oauth_account_name: str | None = None
oauth_account_user_id: str | None = None
oauth_organizations: list[OAuthOrganizationSummary] = Field(default_factory=list)
account_status_code: str | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.account"
)
account_status_label: str | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.account"
)
account_status_reason: str | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.account"
)
account_status_blocked: bool = Field(
default=False, description="兼容字段;优先使用 status_snapshot.account"
)
account_status_recoverable: bool = Field(
default=False, description="兼容字段;优先使用 status_snapshot.account"
)
account_status_source: str | None = Field(
default=None, description="兼容字段;优先使用 status_snapshot.account"
)
status_snapshot: ProviderKeyStatusSnapshotResponse = Field(
default_factory=ProviderKeyStatusSnapshotResponse,
description="统一的账号/OAuth/额度状态快照",
)
quota_updated_at: int | None = None
# 健康度聚合字段(与 Provider Key 列表口径一致)
health_score: float = 1.0
circuit_breaker_open: bool = False
# 编辑/权限/代理所需字段
api_formats: list[str] = Field(default_factory=list)
rate_multipliers: dict[str, float] | None = None
internal_priority: int = 50
rpm_limit: int | None = None
cache_ttl_minutes: int = 5
max_probe_interval_minutes: int = 32
note: str | None = None
allowed_models: list[str] | None = None
capabilities: dict[str, bool] | None = None
auto_fetch_models: bool = False
locked_models: list[str] | None = None
model_include_patterns: list[str] | None = None
model_exclude_patterns: list[str] | None = None
proxy: dict[str, Any] | None = None
fingerprint: dict[str, Any] | None = None
account_quota: str | None = None
cooldown_reason: str | None = None
cooldown_ttl_seconds: int | None = None
cost_window_usage: int = 0
cost_limit: int | None = None
request_count: int = 0
total_tokens: int = 0
total_cost_usd: str = "0.00000000"
sticky_sessions: int = 0
lru_score: float | None = None
created_at: str | None = None
last_used_at: str | None = None
scheduling_status: str = "available" # available / degraded / blocked
scheduling_reason: str = "available"
scheduling_label: str = "可用"
scheduling_reasons: list[PoolSchedulingReason] = Field(default_factory=list)
model_config = ConfigDict(from_attributes=True)
class PoolKeysPageResponse(BaseModel):
"""Server-side paginated key list."""
total: int
page: int
page_size: int
keys: list[PoolKeyDetail] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Batch import
# ---------------------------------------------------------------------------
class PoolKeyImportItem(BaseModel):
"""Single key to import."""
name: str
api_key: str
auth_type: str = "api_key"
class BatchImportRequest(BaseModel):
keys: list[PoolKeyImportItem] = Field(..., max_length=500)
proxy_node_id: str | None = Field(
default=None,
description="导入时绑定到账号的代理节点 ID可选",
)
class BatchImportError(BaseModel):
index: int
reason: str
class BatchImportResponse(BaseModel):
imported: int = 0
skipped: int = 0
errors: list[BatchImportError] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Batch selection
# ---------------------------------------------------------------------------
class PoolKeySelectionRequest(BaseModel):
search: str = ""
quick_selectors: list[str] = Field(default_factory=list, max_length=10)
class PoolKeySelectionItem(BaseModel):
key_id: str
key_name: str = ""
auth_type: str = "api_key"
class PoolKeySelectionResponse(BaseModel):
total: int = 0
items: list[PoolKeySelectionItem] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Batch action
# ---------------------------------------------------------------------------
class BatchActionRequest(BaseModel):
key_ids: list[str] = Field(..., max_length=2000)
action: str # enable / disable / delete / clear_cooldown / reset_cost / regenerate_fingerprint / clear_proxy / set_proxy
payload: dict[str, Any] | None = None
class BatchActionResponse(BaseModel):
affected: int = 0
message: str = ""
task_id: str | None = None
class BatchDeleteTaskResponse(BaseModel):
task_id: str
status: str # pending / running / completed / failed
total: int = 0
deleted: int = 0
message: str = ""