Files
loom/backend/app/schemas/llm.py
T
2026-04-24 17:46:03 +08:00

167 lines
4.4 KiB
Python

from __future__ import annotations
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
# -------- Provider --------
class ProviderCreate(BaseModel):
code: str = Field(min_length=1, max_length=64)
name: str = Field(min_length=1, max_length=64)
vendor: str = Field(default="openai", pattern=r"^(openai|azure|anthropic|custom)$")
api_base: str = Field(min_length=1, max_length=255)
api_key: str | None = None
description: str | None = None
status: str = Field(default="ACTIVE", pattern=r"^(ACTIVE|DISABLED)$")
class ProviderUpdate(BaseModel):
name: str | None = None
vendor: str | None = Field(default=None, pattern=r"^(openai|azure|anthropic|custom)$")
api_base: str | None = None
# 留空 / undefined 不改;空串清空
api_key: str | None = None
description: str | None = None
status: str | None = Field(default=None, pattern=r"^(ACTIVE|DISABLED)$")
class ProviderRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
code: str
name: str
vendor: str
api_base: str
api_key_mask: str = ""
has_api_key: bool = False
description: str | None = None
status: str
# -------- Model --------
class ModelCreate(BaseModel):
provider_id: int
model: str = Field(min_length=1, max_length=128)
name: str = Field(min_length=1, max_length=128)
description: str | None = None
max_context: int = Field(default=8192, ge=1024, le=2_000_000)
price_input_per_1k: float = Field(default=0.0, ge=0)
price_output_per_1k: float = Field(default=0.0, ge=0)
status: str = Field(default="ACTIVE", pattern=r"^(ACTIVE|DISABLED)$")
class ModelUpdate(BaseModel):
name: str | None = None
description: str | None = None
max_context: int | None = Field(default=None, ge=1024, le=2_000_000)
price_input_per_1k: float | None = Field(default=None, ge=0)
price_output_per_1k: float | None = Field(default=None, ge=0)
status: str | None = Field(default=None, pattern=r"^(ACTIVE|DISABLED)$")
class ModelRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
provider_id: int
provider_code: str | None = None
provider_name: str | None = None
model: str
name: str
description: str | None = None
max_context: int
price_input_per_1k: float
price_output_per_1k: float
status: str
# -------- Routing --------
class RuleBase(BaseModel):
name: str = Field(min_length=1, max_length=128)
priority: int = Field(default=100, ge=0, le=10000)
conditions: dict | None = None
model_id: int
enabled: bool = True
description: str | None = None
class RuleCreate(RuleBase):
pass
class RuleUpdate(BaseModel):
name: str | None = None
priority: int | None = Field(default=None, ge=0, le=10000)
conditions: dict | None = None
model_id: int | None = None
enabled: bool | None = None
description: str | None = None
class RuleRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
name: str
priority: int
conditions: dict | None = None
model_id: int
model_label: str | None = None # "provider/model"
enabled: bool
description: str | None = None
# -------- Chat / Usage --------
class ChatRequest(BaseModel):
"""面向任务执行器 / playground 的统一请求。
- 若 `model` 指定(形如 "provider_code/model"),跳过路由
- 否则 `conditions` 走路由命中
"""
messages: list[dict]
model: str | None = None
conditions: dict | None = None
temperature: float | None = Field(default=None, ge=0, le=2)
max_tokens: int | None = Field(default=None, ge=1)
stream: bool = False # 目前仅 false
source: str = Field(default="playground", max_length=16)
class ChatResponse(BaseModel):
provider: str
model: str
content: str
prompt_tokens: int
completion_tokens: int
total_tokens: int
cost_usd: float
cost_ms: int
class UsageRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
provider_id: int | None = None
provider_code: str | None = None
model_id: int | None = None
model: str | None = None
operator_id: int | None = None
operator_name: str | None = None
source: str
prompt_tokens: int
completion_tokens: int
total_tokens: int
cost_usd: float
result: str
message: str | None = None
cost_ms: int
created_at: datetime | None = None