feat: M1 — 立项→写章草稿(SSE)→自动保存;连一家 provider
- 薄自建 LLM 网关:OpenAI 兼容适配器(DeepSeek) + instructor 结构化输出 + usage_ledger 记账 + 档位路由 - 记忆服务 assemble:确定性选择(显式+主角+近况) + 渲染卡 + 缓存断点(中性文本) - LangGraph 写章节点 + Postgres checkpointer + SSE 归一(token/done/error) - API:立项 + 写章 draft(SSE) + PUT 自动保存 + 提供商凭据(Fernet 加密/测试连接) - 前端:AppShell + 作品库 + 5 步立项向导 + 写作工作台(流式打字机+自动保存) + 设置页 - M1 E2E:真实 DB + mock 网关零 token 走通闭环
This commit is contained in:
76
apps/api/ww_api/schemas/providers.py
Normal file
76
apps/api/ww_api/schemas/providers.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""提供商凭据/档位路由的请求/响应 schema(C3 / ARCH §4.7, §7.2)。
|
||||
|
||||
snake_case;响应一律 **掩码 Key**,绝不含明文。前端经 OpenAPI 生成 TS 类型消费。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ProviderView(BaseModel):
|
||||
"""已配置提供商(掩码视图)。"""
|
||||
|
||||
provider: str
|
||||
masked_key: str # 形如 sk-…1234;明文永不出现
|
||||
|
||||
|
||||
class TierRoutingView(BaseModel):
|
||||
"""档位 → provider:model 路由(含回退链)。"""
|
||||
|
||||
tier: str
|
||||
provider: str
|
||||
model: str
|
||||
fallback: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ProvidersResponse(BaseModel):
|
||||
"""GET/PUT 响应:已配置提供商(掩码)+ 当前档位路由。"""
|
||||
|
||||
providers: list[ProviderView] = Field(default_factory=list)
|
||||
tier_routing: list[TierRoutingView] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ProviderCredentialInput(BaseModel):
|
||||
"""单条提供商凭据写入。"""
|
||||
|
||||
provider: str = Field(min_length=1)
|
||||
api_key: str = Field(min_length=1) # 明文入站,加密入库,绝不回显
|
||||
|
||||
|
||||
class TierRoutingInput(BaseModel):
|
||||
"""单条档位路由写入。"""
|
||||
|
||||
tier: str = Field(min_length=1)
|
||||
provider: str = Field(min_length=1)
|
||||
model: str = Field(min_length=1)
|
||||
fallback: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ProvidersUpsertRequest(BaseModel):
|
||||
"""PUT 请求:可同时 upsert 若干凭据与档位路由(幂等)。"""
|
||||
|
||||
credentials: list[ProviderCredentialInput] = Field(default_factory=list)
|
||||
tier_routing: list[TierRoutingInput] = Field(default_factory=list)
|
||||
|
||||
|
||||
class TestConnectionRequest(BaseModel):
|
||||
"""POST /test:最小探测请求。"""
|
||||
|
||||
provider: str = Field(min_length=1)
|
||||
|
||||
|
||||
class CapabilitiesView(BaseModel):
|
||||
"""探测得到的能力矩阵(镜像网关 `Capabilities`)。"""
|
||||
|
||||
structured_output: bool = False
|
||||
prefix_cache: bool = False
|
||||
thinking: bool = False
|
||||
|
||||
|
||||
class TestConnectionResponse(BaseModel):
|
||||
"""POST /test 响应:连通性 + 能力矩阵。"""
|
||||
|
||||
provider: str
|
||||
ok: bool
|
||||
capabilities: CapabilitiesView
|
||||
Reference in New Issue
Block a user