mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
feat: 缓存计费细分、能力匹配优化、用户模型调用计数
1. 缓存创建 tokens 区分 5min/1h TTL,支持按缓存时长差异化计费 - Usage 表新增 cache_creation_input_tokens_5m/1h 字段 - Claude handler 解析新格式 (ephemeral_5m/1h, claude_cache_creation_5/1h) - 计费规则支持 cache_ttl_pricing 覆盖 cache_creation 价格 2. 能力匹配机制优化 - COMPATIBLE 能力不再硬过滤,改为排序阶段通过 capability_miss_count 优先级处理 - cache_1h 改为 COMPATIBLE + REQUEST_PARAM(自动检测请求体中的 ttl=1h) - gemini_files 改为 EXCLUSIVE + REQUEST_PARAM(自动检测 fileData.fileUri) - 移除前端模型偏好/能力配置 UI(不再需要用户手动配置) 3. 新增用户-模型维度调用次数计数器 (UserModelUsageCount) - 原子递增,避免从 Usage 表聚合查询 - 前端模型目录和用户可用模型列表展示调用次数 4. 其他改进 - global_model_id 改为必填(NOT NULL),清理孤立模型 - 模型映射对话框支持从上游获取模型列表并分组折叠 - 端点测试不再依赖端点启用状态 - 异步任务页面对普通用户隐藏用户信息列 - Dashboard 响应式布局断点调整 (sm -> lg) - 号池管理仅展示已启用号池的提供商
This commit is contained in:
@@ -577,7 +577,7 @@ class ModelResponse(BaseModel):
|
||||
|
||||
id: str
|
||||
provider_id: str
|
||||
global_model_id: str | None
|
||||
global_model_id: str
|
||||
provider_model_name: str
|
||||
provider_model_mappings: list[dict] | None = None
|
||||
|
||||
@@ -612,7 +612,7 @@ class ModelResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
# 关联的 GlobalModel 信息(如果有)
|
||||
# 关联的 GlobalModel 信息
|
||||
global_model_name: str | None = None
|
||||
global_model_display_name: str | None = None
|
||||
|
||||
@@ -744,6 +744,8 @@ class PublicGlobalModelResponse(BaseModel):
|
||||
supported_capabilities: list[str] | None = None
|
||||
# 模型配置(JSON)
|
||||
config: dict | None = None
|
||||
# 调用次数
|
||||
usage_count: int = 0
|
||||
|
||||
|
||||
class PublicGlobalModelListResponse(BaseModel):
|
||||
|
||||
@@ -1001,8 +1001,8 @@ class GlobalModel(ExportMixin, Base):
|
||||
# "cache_creation_price_per_1m": 3.75, # 可选
|
||||
# "cache_read_price_per_1m": 0.30, # 可选
|
||||
# "cache_ttl_pricing": [ # 可选:按缓存时长分价格
|
||||
# {"ttl_minutes": 5, "cache_read_price_per_1m": 0.30},
|
||||
# {"ttl_minutes": 60, "cache_read_price_per_1m": 0.50}
|
||||
# {"ttl_minutes": 5, "cache_creation_price_per_1m": 3.75, "cache_read_price_per_1m": 0.30},
|
||||
# {"ttl_minutes": 60, "cache_creation_price_per_1m": 6.00, "cache_read_price_per_1m": 0.50}
|
||||
# ]
|
||||
# },
|
||||
# {"up_to": null, "input_price_per_1m": 1.25, ...}
|
||||
@@ -2700,5 +2700,36 @@ class GeminiFileMapping(Base):
|
||||
)
|
||||
|
||||
|
||||
class UserModelUsageCount(Base):
|
||||
"""用户-模型维度调用次数计数器
|
||||
|
||||
每个用户对每个模型维护一个原子递增的计数器,
|
||||
避免从 Usage 表聚合查询,查询性能 O(N) 其中 N 是用户使用过的模型数。
|
||||
"""
|
||||
|
||||
__tablename__ = "user_model_usage_counts"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
user_id = Column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
||||
model = Column(String(100), nullable=False)
|
||||
usage_count = Column(Integer, default=0, nullable=False)
|
||||
|
||||
created_at = Column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False
|
||||
)
|
||||
updated_at = Column(
|
||||
DateTime(timezone=True),
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("user_id", "model", name="uq_user_model_usage_count"),
|
||||
Index("idx_user_model_usage_user", "user_id"),
|
||||
Index("idx_user_model_usage_model", "model"),
|
||||
)
|
||||
|
||||
|
||||
# 导入扩展的数据库模型
|
||||
from .database_extensions import ApiKeyProviderMapping, ProviderUsageTracking
|
||||
|
||||
@@ -69,8 +69,8 @@ class GlobalModel(ExportMixin, Base):
|
||||
# "cache_creation_price_per_1m": 3.75, # 可选
|
||||
# "cache_read_price_per_1m": 0.30, # 可选
|
||||
# "cache_ttl_pricing": [ # 可选:按缓存时长分价格
|
||||
# {"ttl_minutes": 5, "cache_read_price_per_1m": 0.30},
|
||||
# {"ttl_minutes": 60, "cache_read_price_per_1m": 0.50}
|
||||
# {"ttl_minutes": 5, "cache_creation_price_per_1m": 3.75, "cache_read_price_per_1m": 0.30},
|
||||
# {"ttl_minutes": 60, "cache_creation_price_per_1m": 6.00, "cache_read_price_per_1m": 0.50}
|
||||
# ]
|
||||
# },
|
||||
# {"up_to": null, "input_price_per_1m": 1.25, ...}
|
||||
@@ -132,9 +132,7 @@ class Model(ExportMixin, Base):
|
||||
|
||||
设计原则:
|
||||
- Model 表示 Provider 对某个模型的具体实现
|
||||
- global_model_id 可为空:
|
||||
- 为空时:模型尚未关联到 GlobalModel,不参与路由
|
||||
- 不为空时:模型已关联 GlobalModel,参与路由
|
||||
- global_model_id 必填,必须关联到一个 GlobalModel
|
||||
- provider_model_name 是 Provider 侧的实际模型名称 (可能与 GlobalModel.name 不同)
|
||||
- 价格和能力配置可为空,为空时使用 GlobalModel 的默认值
|
||||
"""
|
||||
@@ -154,8 +152,8 @@ class Model(ExportMixin, Base):
|
||||
|
||||
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()), index=True)
|
||||
provider_id = Column(String(36), ForeignKey("providers.id"), nullable=False)
|
||||
# 可为空:NULL 表示未关联,不参与路由;非 NULL 表示已关联,参与路由
|
||||
global_model_id = Column(String(36), ForeignKey("global_models.id"), nullable=True, index=True)
|
||||
# 必须关联一个 GlobalModel
|
||||
global_model_id = Column(String(36), ForeignKey("global_models.id"), nullable=False, index=True)
|
||||
|
||||
# Provider 映射配置
|
||||
provider_model_name = Column(String(200), nullable=False) # Provider 侧的主模型名称
|
||||
|
||||
@@ -19,6 +19,9 @@ class CacheTTLPricing(BaseModel):
|
||||
cache_creation_price_per_1m: float = Field(
|
||||
..., ge=0, description="该时长的缓存创建价格/M tokens"
|
||||
)
|
||||
cache_read_price_per_1m: float | None = Field(
|
||||
None, ge=0, description="该时长的缓存读取价格/M tokens"
|
||||
)
|
||||
|
||||
|
||||
class PricingTier(BaseModel):
|
||||
@@ -313,8 +316,8 @@ class ImportFromUpstreamSuccessItem(BaseModel):
|
||||
|
||||
model_id: str = Field(..., description="上游模型 ID")
|
||||
provider_model_id: str = Field(..., description="Provider Model ID")
|
||||
global_model_id: str | None = Field("", description="GlobalModel ID(如果已关联)")
|
||||
global_model_name: str | None = Field("", description="GlobalModel 名称(如果已关联)")
|
||||
global_model_id: str = Field(..., description="GlobalModel ID")
|
||||
global_model_name: str = Field(..., description="GlobalModel 名称")
|
||||
created_global_model: bool = Field(
|
||||
False, description="是否新创建了 GlobalModel(始终为 false)"
|
||||
)
|
||||
|
||||
@@ -71,6 +71,8 @@ class Usage(Base):
|
||||
# 缓存相关 tokens (for Claude models)
|
||||
cache_creation_input_tokens = Column(Integer, default=0)
|
||||
cache_read_input_tokens = Column(Integer, default=0)
|
||||
cache_creation_input_tokens_5m = Column(Integer, default=0) # 5min TTL 缓存创建
|
||||
cache_creation_input_tokens_1h = Column(Integer, default=0) # 1h TTL 缓存创建
|
||||
|
||||
# 成本计算
|
||||
input_cost_usd = Column(Float, default=0.0)
|
||||
|
||||
Reference in New Issue
Block a user