优化 API 配置:一个弹窗完成接口、Key 与模型选择
- 去掉预设供应商,直接选择接口类型并填写 Base URL、API Key - 可在保存前从接口拉取模型,搜索并勾选多个;也可手动输入模型名 - 适配中转站:漏写 /v1(Gemini 为 /v1beta)时自动补全,同时发送 Bearer 与官方鉴权头 - 保存时服务端同步连接下的模型列表;编辑时不填 Key 也可拉取 - 单模型测试与参数设置;手机端布局优化 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+18
-8
@@ -30,18 +30,28 @@ async function waitIdle(pid, timeout = 30000) {
|
||||
}
|
||||
const step = msg => console.log(`✔ ${msg}`)
|
||||
|
||||
// 1. 提供方与模型
|
||||
const provider = await api('/api/providers', 'POST', { name: 'Mock', type: 'openai-compatible', baseUrl: mock, apiKey: 'test-key' })
|
||||
// 1. API 连接与模型
|
||||
const mockRoot = mock.replace(/\/v1$/, '')
|
||||
const pulled = await api('/api/providers/remote-models', 'POST', { type: 'openai-compatible', baseUrl: mockRoot, apiKey: 'test-key' })
|
||||
assert.deepEqual(pulled.models, ['mock-editor', 'mock-writer-trunc'])
|
||||
assert.equal(pulled.baseUrl, mockRoot + '/v1', '漏写 /v1 时应自动补全')
|
||||
const provider = await api('/api/providers', 'POST', { type: 'openai-compatible', baseUrl: pulled.baseUrl, apiKey: 'test-key', models: [...pulled.models, 'extra-model'] })
|
||||
const providers = await api('/api/providers')
|
||||
assert.ok(providers.find(p => p.id === provider.id).apiKeyMasked.length > 0)
|
||||
const savedProvider = providers.find(p => p.id === provider.id)
|
||||
assert.equal(savedProvider.name, new URL(mock).host, '未填名称时使用域名')
|
||||
assert.ok(!JSON.stringify(providers).includes('test-key'), '接口不应返回明文 Key')
|
||||
const remote = await api(`/api/providers/${provider.id}/remote-models`)
|
||||
assert.deepEqual(remote, ['mock-editor', 'mock-writer-trunc'])
|
||||
const editorModel = await api('/api/models', 'POST', { providerId: provider.id, modelId: 'mock-editor', label: '模拟主编' })
|
||||
const writerModel = await api('/api/models', 'POST', { providerId: provider.id, modelId: 'mock-writer-trunc', label: '模拟作家', maxOutputTokens: 4096 })
|
||||
const pulledAgain = await api('/api/providers/remote-models', 'POST', { type: 'openai-compatible', baseUrl: pulled.baseUrl, providerId: provider.id })
|
||||
assert.equal(pulledAgain.models.length, 2, '编辑时不填 Key 应使用已保存的 Key')
|
||||
const synced = await api(`/api/providers/${provider.id}`, 'PUT', { models: pulled.models })
|
||||
assert.equal(synced.removed, 1)
|
||||
let allModels = (await api('/api/models')).filter(m => m.providerId === provider.id)
|
||||
assert.deepEqual(allModels.map(m => m.modelId).sort(), ['mock-editor', 'mock-writer-trunc'])
|
||||
const editorModel = allModels.find(m => m.modelId === 'mock-editor')
|
||||
const writerModel = allModels.find(m => m.modelId === 'mock-writer-trunc')
|
||||
await api(`/api/models/${writerModel.id}`, 'PUT', { label: '模拟作家', maxOutputTokens: 4096 })
|
||||
const test = await api(`/api/models/${editorModel.id}/test`, 'POST', {})
|
||||
assert.equal(test.ok, true, JSON.stringify(test))
|
||||
step('提供方/模型/连接测试')
|
||||
step('API 连接:拉取模型(自动补全 /v1)、批量保存、同步、连接测试')
|
||||
|
||||
// 2. 项目与设定
|
||||
const { id: pid } = await api('/api/projects', 'POST', { title: 'E2E 测试作品' })
|
||||
|
||||
Reference in New Issue
Block a user