283f40892a
- 去掉预设供应商,直接选择接口类型并填写 Base URL、API Key - 可在保存前从接口拉取模型,搜索并勾选多个;也可手动输入模型名 - 适配中转站:漏写 /v1(Gemini 为 /v1beta)时自动补全,同时发送 Bearer 与官方鉴权头 - 保存时服务端同步连接下的模型列表;编辑时不填 Key 也可拉取 - 单模型测试与参数设置;手机端布局优化 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.5 KiB
TypeScript
41 lines
1.5 KiB
TypeScript
import { and, eq, inArray } from 'drizzle-orm'
|
|
import type { ProviderType } from '#shared/types'
|
|
|
|
const TYPE_NAME: Record<ProviderType, string> = {
|
|
'openai-compatible': 'OpenAI 兼容',
|
|
'anthropic': 'Anthropic',
|
|
'google': 'Gemini'
|
|
}
|
|
|
|
/** 未填写名称时,用 Base URL 的域名作为连接名称 */
|
|
export function defaultProviderName(type: ProviderType, baseUrl: string) {
|
|
try {
|
|
if (baseUrl.trim()) return new URL(baseUrl.trim()).host
|
|
}
|
|
catch {}
|
|
return TYPE_NAME[type]
|
|
}
|
|
|
|
export function normalizeModelIds(ids: string[]) {
|
|
return [...new Set(ids.map(s => s.trim()).filter(Boolean))]
|
|
}
|
|
|
|
/**
|
|
* 把连接下的模型同步为给定列表:新增缺少的,删除不在列表中的。
|
|
* 被删除模型的 AI 成员会因外键 ON DELETE SET NULL 变为“未指定模型”。
|
|
*/
|
|
export function syncProviderModels(providerId: string, modelIds: string[]) {
|
|
const db = useDb()
|
|
const wanted = normalizeModelIds(modelIds)
|
|
const existing = db.select().from(tables.models).where(eq(tables.models.providerId, providerId)).all()
|
|
const toDelete = existing.filter(m => !wanted.includes(m.modelId)).map(m => m.id)
|
|
const toAdd = wanted.filter(id => !existing.some(m => m.modelId === id))
|
|
if (toDelete.length) {
|
|
db.delete(tables.models).where(and(eq(tables.models.providerId, providerId), inArray(tables.models.id, toDelete))).run()
|
|
}
|
|
if (toAdd.length) {
|
|
db.insert(tables.models).values(toAdd.map(modelId => ({ id: newId(), providerId, label: modelId, modelId }))).run()
|
|
}
|
|
return { added: toAdd.length, removed: toDelete.length }
|
|
}
|