feat: 添加格式转换追踪、模型过滤规则和 Provider 超时配置

1. Usage 格式转换追踪
   - 新增 endpoint_api_format 和 has_format_conversion 字段
   - 在用量记录中显示格式转换信息(请求格式 → 端点格式)
   - 兼容历史数据的回填逻辑

2. Provider API Key 模型过滤规则
   - 新增 model_include_patterns 和 model_exclude_patterns 字段
   - 支持 * 和 ? 通配符,不区分大小写
   - 自动获取模型时应用过滤规则

3. Provider 超时配置
   - 新增 stream_first_byte_timeout 和 request_timeout 字段
   - 支持每个 Provider 单独配置超时时间
   - 优先使用 Provider 配置,否则回退到全局配置

Close #122, Close #123

Co-Authored-By: AAEE86 <33052466+AAEE86@users.noreply.github.com>
This commit is contained in:
fawney19
2026-01-28 00:04:47 +08:00
parent 3c0bf5fdae
commit c732a03263
23 changed files with 652 additions and 97 deletions

View File

@@ -91,6 +91,9 @@ class CreateProviderRequest(BaseModel):
# 请求配置(从 Endpoint 迁移)
max_retries: Optional[int] = Field(2, ge=0, le=10, description="最大重试次数")
proxy: Optional[ProxyConfig] = Field(None, description="代理配置")
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(None, ge=1, le=300, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(None, ge=1, le=600, description="非流式请求整体超时(秒)")
config: Optional[Dict[str, Any]] = Field(None, description="其他配置")
@field_validator("name", "description")
@@ -161,6 +164,9 @@ class UpdateProviderRequest(BaseModel):
# 请求配置(从 Endpoint 迁移)
max_retries: Optional[int] = Field(None, ge=0, le=10, description="最大重试次数")
proxy: Optional[ProxyConfig] = Field(None, description="代理配置")
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(None, ge=1, le=300, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(None, ge=1, le=600, description="非流式请求整体超时(秒)")
config: Optional[Dict[str, Any]] = None
# 复用相同的验证器

View File

@@ -405,6 +405,10 @@ class ProviderCreate(BaseModel):
config: Optional[dict] = Field(None, description="额外配置")
is_active: bool = Field(False, description="是否启用默认false需要配置API密钥后才能启用")
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(None, ge=1, le=300, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(None, ge=1, le=600, description="非流式请求整体超时(秒)")
class ProviderUpdate(BaseModel):
"""更新提供商请求"""
@@ -423,6 +427,10 @@ class ProviderUpdate(BaseModel):
config: Optional[dict] = None
is_active: Optional[bool] = None
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(None, ge=1, le=300, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(None, ge=1, le=600, description="非流式请求整体超时(秒)")
class ProviderResponse(BaseModel):
"""提供商响应"""
@@ -447,6 +455,10 @@ class ProviderResponse(BaseModel):
active_models_count: int = 0
api_keys_count: int = 0
# 超时配置
stream_first_byte_timeout: Optional[float] = None
request_timeout: Optional[float] = None
model_config = ConfigDict(from_attributes=True)

View File

@@ -327,7 +327,9 @@ class Usage(Base):
# 请求详情
request_type = Column(String(50)) # chat, completion, embedding等
api_format = Column(String(50), nullable=True) # API 格式: CLAUDE, OPENAI 等
api_format = Column(String(50), nullable=True) # API 格式: CLAUDE, OPENAI 等(用户请求格式)
endpoint_api_format = Column(String(50), nullable=True) # 端点原生 API 格式
has_format_conversion = Column(Boolean, nullable=True, default=False) # 是否发生了格式转换
is_stream = Column(Boolean, default=False) # 是否为流式请求
status_code = Column(Integer)
error_message = Column(Text, nullable=True)
@@ -653,6 +655,10 @@ class Provider(Base):
max_retries = Column(Integer, default=2, nullable=True) # 最大重试次数
proxy = Column(JSONB, nullable=True) # 代理配置: {url, username, password, enabled}
# 超时配置(秒),为 None 时使用全局配置
stream_first_byte_timeout = Column(Float, nullable=True) # 流式请求首字节超时
request_timeout = Column(Float, nullable=True) # 非流式请求整体超时
# 配置
config = Column(JSON, nullable=True) # 额外配置如Azure deployment name等
@@ -1178,6 +1184,9 @@ class ProviderAPIKey(Base):
last_models_fetch_at = Column(DateTime(timezone=True), nullable=True) # 最后获取时间
last_models_fetch_error = Column(Text, nullable=True) # 最后获取错误信息
locked_models = Column(JSON, nullable=True) # 被锁定的模型列表(刷新时不会被删除)
# 模型过滤规则(支持 * 和 ? 通配符,如 "gpt-*", "claude-?-sonnet"
model_include_patterns = Column(JSON, nullable=True) # 包含规则列表,空表示不过滤(包含所有)
model_exclude_patterns = Column(JSON, nullable=True) # 排除规则列表,空表示不排除
# 时间戳
created_at = Column(

View File

@@ -211,6 +211,14 @@ class EndpointAPIKeyCreate(BaseModel):
default=None, description="被锁定的模型列表(刷新时不会被删除)"
)
# 模型过滤规则(仅当 auto_fetch_models=True 时生效)
model_include_patterns: Optional[List[str]] = Field(
default=None, description="模型包含规则(支持 * 和 ? 通配符),空表示包含所有"
)
model_exclude_patterns: Optional[List[str]] = Field(
default=None, description="模型排除规则(支持 * 和 ? 通配符),空表示不排除"
)
@field_validator("api_formats")
@classmethod
def validate_api_formats(cls, v: Optional[List[str]]) -> Optional[List[str]]:
@@ -345,6 +353,13 @@ class EndpointAPIKeyUpdate(BaseModel):
locked_models: Optional[List[str]] = Field(
default=None, description="被锁定的模型列表(刷新时不会被删除)"
)
# 模型过滤规则(仅当 auto_fetch_models=True 时生效)
model_include_patterns: Optional[List[str]] = Field(
default=None, description="模型包含规则(支持 * 和 ? 通配符),空表示包含所有"
)
model_exclude_patterns: Optional[List[str]] = Field(
default=None, description="模型排除规则(支持 * 和 ? 通配符),空表示不排除"
)
@field_validator("api_formats")
@classmethod
@@ -502,6 +517,9 @@ class EndpointAPIKeyResponse(BaseModel):
last_models_fetch_at: Optional[datetime] = Field(None, description="最后获取模型时间")
last_models_fetch_error: Optional[str] = Field(None, description="最后获取模型错误信息")
locked_models: Optional[List[str]] = Field(None, description="被锁定的模型列表")
# 模型过滤规则
model_include_patterns: Optional[List[str]] = Field(None, description="模型包含规则")
model_exclude_patterns: Optional[List[str]] = Field(None, description="模型排除规则")
# 时间戳
last_used_at: Optional[datetime] = None
@@ -605,6 +623,9 @@ class ProviderUpdateRequest(BaseModel):
# 请求配置(从 Endpoint 迁移)
max_retries: Optional[int] = Field(None, ge=0, le=10, description="最大重试次数")
proxy: Optional[Dict[str, Any]] = Field(None, description="代理配置")
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(None, ge=1, le=300, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(None, ge=1, le=600, description="非流式请求整体超时(秒)")
class ProviderWithEndpointsSummary(BaseModel):
@@ -629,6 +650,9 @@ class ProviderWithEndpointsSummary(BaseModel):
# 请求配置(从 Endpoint 迁移)
max_retries: Optional[int] = Field(default=2, description="最大重试次数")
proxy: Optional[Dict[str, Any]] = Field(default=None, description="代理配置")
# 超时配置(秒),为空时使用全局配置
stream_first_byte_timeout: Optional[float] = Field(default=None, description="流式请求首字节超时(秒)")
request_timeout: Optional[float] = Field(default=None, description="非流式请求整体超时(秒)")
# Endpoint 统计
total_endpoints: int = Field(default=0, description="总 Endpoint 数量")