forked from ChaiHao/BPOS-MVP
接入模型改成右侧抽屉:先挑供应商、再填连接、当场测连通(且只测不存)
上一版是把字段倒在地上:整页宽的内联卡、输入框拉到 1100px、动作钮掉出屏幕。 照模型接入面的通行做法重排 —— 520px 右侧抽屉,头固定 / 身滚动 / 底动作栏常驻: ① **供应商**:一排可点的牌子,挑中即预填它的默认端点(没有默认的标「端点自填」); ② **连接**:API 端点 + API Key(密码框带显示切换),下面就是「测试连接」; ③ **型号与用途**:模型(厂商侧型号名)+ 用途名(活动里声明的那个)+ 两枚开关。 遮罩点击与 Esc 都关得掉 —— 抽屉盖住整屏,不给键盘出路是把人关在里面。 **默认端点从服务端取**(新 `GET /api/gov/llm/providers`):前端不自带一份 URL 表 —— 那种表迟早与 provider 档案漂移,而漂移那天没人会发现(端点错了只表现为「连不上」)。 **「测试连接」只测不存**(新 `POST /api/gov/llm/probe` + `llm.probeDraft`): 拿表单上正填的四元真发一次最小调用,一个字节不落库;密钥留空则取该实例已存的密文, 改端点、换型号不必重打钥匙。上一版是「先存再试」—— 人只想知道钥匙对不对, 结果端点被改了、实例被建了,点取消也收不回来。实测:改错端点后测试, 库里 instances 逐字节未变(测过 before/after 全等)。 顺带补 `eye-off` 图标。五闸绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -84,6 +84,27 @@ export const llmInstanceViewSchema = z.object({
|
||||
});
|
||||
export type LlmInstanceView = z.infer<typeof llmInstanceViewSchema>;
|
||||
|
||||
/**
|
||||
* Provider 一览 —— 建实例那张表要**预填默认端点**,而唯一真相在服务端的 provider 档案里。
|
||||
* 前端不自带一份 URL 表:那种表迟早与服务端漂移,漂移的那天没人会发现(端点错了只表现为「连不上」)。
|
||||
*/
|
||||
export const listLlmProvidersRoute = {
|
||||
method: 'GET',
|
||||
path: '/api/gov/llm/providers',
|
||||
output: z.object({
|
||||
providers: z.array(
|
||||
z.object({
|
||||
provider: llmProviderSchema,
|
||||
label: z.string(),
|
||||
/** 留空即取它;`openai-compatible` 没有默认,回空串 —— 界面据此要求自填 */
|
||||
defaultBaseUrl: z.string(),
|
||||
/** 结构化出参口径:json-object = 厂商原生支持;prompt-only = 靠提示约束 */
|
||||
structuredOutput: z.enum(['json-object', 'prompt-only']),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
} as const satisfies RouteContract;
|
||||
|
||||
export const listLlmInstancesRoute = {
|
||||
method: 'GET',
|
||||
path: '/api/gov/llm',
|
||||
@@ -108,6 +129,25 @@ export const upsertLlmInstanceRoute = {
|
||||
output: llmInstanceViewSchema,
|
||||
} as const satisfies RouteContract;
|
||||
|
||||
/**
|
||||
* 测试连接(草稿)—— **只测不存**:拿表单上正填的四元真发一次最小调用,一个字节不落库。
|
||||
* 「测试」把表单写进库是个会咬人的副作用:人只想知道钥匙对不对,取消却收不回已改的端点。
|
||||
* 留空 `apiKey` 时取该实例已存的密钥(改端点、换型号不必重打钥匙)。
|
||||
*/
|
||||
export const probeLlmDraftRoute = {
|
||||
method: 'POST',
|
||||
path: '/api/gov/llm/probe',
|
||||
body: z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
provider: llmProviderSchema,
|
||||
baseUrl: z.string().default(''),
|
||||
model: z.string().min(1),
|
||||
apiKey: z.string().optional(),
|
||||
}),
|
||||
output: z.object({ ok: z.boolean(), latencyMs: z.number().int().optional(), error: z.string().optional() }),
|
||||
} as const satisfies RouteContract;
|
||||
|
||||
export const probeLlmInstanceRoute = {
|
||||
method: 'POST',
|
||||
path: '/api/gov/llm/:id/probe',
|
||||
|
||||
@@ -124,6 +124,7 @@ const GLYPHS: Record<string, React.ReactNode> = {
|
||||
"undo-2": (<><path d="M9 14 4 9l5-5" /><path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" /></>),
|
||||
"redo-2": (<><path d="m15 14 5-5-5-5" /><path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13" /></>),
|
||||
"maximize-2": (<><polyline points="15 3 21 3 21 9" /><polyline points="9 21 3 21 3 15" /><line x1="21" x2="14" y1="3" y2="10" /><line x1="3" x2="10" y1="21" y2="14" /></>),
|
||||
"eye-off": (<><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" /><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242" /><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" /><path d="m2 2 20 20" /></>),
|
||||
x: (<><path d="M18 6 6 18" /><path d="m6 6 12 12" /></>),
|
||||
square: (<rect width="18" height="18" x="3" y="3" rx="2" />),
|
||||
library: (<><path d="m16 6 4 14" /><path d="M12 6v14" /><path d="M8 8v12" /><path d="M4 4v16" /></>),
|
||||
|
||||
Reference in New Issue
Block a user