From dada4aafcd1b8305028112b41d4a56768dcc8974 Mon Sep 17 00:00:00 2001 From: Nelson <1475262689@qq.com> Date: Tue, 7 Jul 2026 13:12:27 +0800 Subject: [PATCH] Add quick LLM provider setup --- .../apps/admin-web/src/App.vue | 211 ++++++++++++------ .../apps/admin-web/src/styles.css | 32 +++ .../backend/app/services/model_service.py | 19 +- .../2026-07-06-decision-register.md | 3 +- .../2026-07-07-model-management-completion.md | 31 ++- 5 files changed, 208 insertions(+), 88 deletions(-) diff --git a/ai_knowledge_base_v2/apps/admin-web/src/App.vue b/ai_knowledge_base_v2/apps/admin-web/src/App.vue index ab66a6c..a3b8abe 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/App.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/App.vue @@ -43,7 +43,7 @@ const knowledgeForm = reactive({ }); const modelForm = reactive({ - provider: "openai", + provider: "openai-compatible", displayName: "", apiType: "openai_compatible", modelName: "", @@ -66,58 +66,65 @@ const modelForm = reactive({ timeoutSecond: 30, }); -const modelPresets = [ +const quickModelForm = reactive({ + provider: "deepseek", + modelName: "deepseek-v4-pro", + apiKey: "", +}); + +const quickModelProviders = [ { - label: "OpenAI", - provider: "openai", + label: "DeepSeek", + provider: "deepseek", + apiType: "openai_compatible", + baseUrl: "https://api.deepseek.com", + authType: "bearer", + apiVersion: "", + temperature: 0.2, + topP: null, + maxToken: 1024, + contextWindow: 128000, + models: [ + { label: "deepseek-v4-pro", value: "deepseek-v4-pro" }, + { label: "deepseek-v4-flash", value: "deepseek-v4-flash" }, + ], + }, + { + label: "MiniMax", + provider: "minimax", + apiType: "anthropic_messages", + baseUrl: "https://api.minimax.io/anthropic", + authType: "bearer", + apiVersion: "", + temperature: null, + topP: null, + maxToken: 1024, + contextWindow: 1000000, + models: [ + { label: "MiniMax-M3", value: "MiniMax-M3" }, + { label: "MiniMax-M2.7", value: "MiniMax-M2.7" }, + { label: "MiniMax-M2.7-highspeed", value: "MiniMax-M2.7-highspeed" }, + { label: "MiniMax-M2.5", value: "MiniMax-M2.5" }, + { label: "MiniMax-M2.5-highspeed", value: "MiniMax-M2.5-highspeed" }, + { label: "MiniMax-M2.1", value: "MiniMax-M2.1" }, + { label: "MiniMax-M2.1-highspeed", value: "MiniMax-M2.1-highspeed" }, + { label: "MiniMax-M2", value: "MiniMax-M2" }, + ], + }, +] as const; + +const protocolPresets = [ + { + label: "OpenAI 兼容协议", + provider: "openai-compatible", apiType: "openai_compatible", baseUrl: "https://api.openai.com/v1", apiUrl: "", authType: "bearer", }, { - label: "DeepSeek", - provider: "deepseek", - apiType: "openai_compatible", - baseUrl: "https://api.deepseek.com/v1", - apiUrl: "", - authType: "bearer", - }, - { - label: "通义千问 DashScope", - provider: "qwen", - apiType: "openai_compatible", - baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", - apiUrl: "", - authType: "bearer", - }, - { - label: "Kimi / Moonshot", - provider: "moonshot", - apiType: "openai_compatible", - baseUrl: "https://api.moonshot.cn/v1", - apiUrl: "", - authType: "bearer", - }, - { - label: "硅基流动 SiliconFlow", - provider: "siliconflow", - apiType: "openai_compatible", - baseUrl: "https://api.siliconflow.cn/v1", - apiUrl: "", - authType: "bearer", - }, - { - label: "火山方舟 Ark", - provider: "volcengine-ark", - apiType: "openai_compatible", - baseUrl: "https://ark.cn-beijing.volces.com/api/v3", - apiUrl: "", - authType: "bearer", - }, - { - label: "Anthropic Claude", - provider: "anthropic", + label: "Anthropic Messages 协议", + provider: "anthropic-compatible", apiType: "anthropic_messages", baseUrl: "https://api.anthropic.com", apiUrl: "", @@ -127,17 +134,6 @@ const modelPresets = [ topP: null, topK: null, }, - { - label: "Google Gemini", - provider: "gemini", - apiType: "gemini_generate_content", - baseUrl: "https://generativelanguage.googleapis.com/v1beta", - apiUrl: "", - authType: "api_key", - temperature: null, - topP: null, - topK: null, - }, ]; const nullableModelFields = [ @@ -267,6 +263,52 @@ function buildModelPayload() { return payload; } +async function quickAddModel() { + const provider = selectedQuickProvider(); + if (!provider) return; + if (!quickModelForm.apiKey) { + ElMessage.error("请填写 API Key"); + return; + } + + await api.createModel({ + provider: provider.provider, + displayName: `${provider.label} ${quickModelForm.modelName}`, + apiType: provider.apiType, + modelName: quickModelForm.modelName, + baseUrl: provider.baseUrl, + apiUrl: "", + apiKey: quickModelForm.apiKey, + authType: provider.authType, + apiVersion: provider.apiVersion, + temperature: provider.temperature, + topP: provider.topP, + topK: null, + presencePenalty: null, + frequencyPenalty: null, + maxToken: provider.maxToken, + contextWindow: provider.contextWindow, + streamEnabled: 1, + responseFormat: null, + extraParams: null, + remark: "快速添加", + timeoutSecond: 30, + }); + ElMessage.success(`${provider.label} 模型已新增`); + quickModelForm.apiKey = ""; + await loadCurrentMenu(); +} + +function selectedQuickProvider() { + return quickModelProviders.find((item) => item.provider === quickModelForm.provider) ?? quickModelProviders[0]; +} + +function applyQuickProvider(provider: string) { + const target = quickModelProviders.find((item) => item.provider === provider); + if (!target) return; + quickModelForm.modelName = target.models[0]?.value ?? ""; +} + async function enableModel(id: number) { await api.enableModel(id); ElMessage.success("模型已启用"); @@ -283,7 +325,7 @@ async function testModel(id: number) { } function applyModelPreset(label: string) { - const preset = modelPresets.find((item) => item.label === label); + const preset = protocolPresets.find((item) => item.label === label); if (!preset) return; Object.assign( modelForm, @@ -332,7 +374,7 @@ function editModel(row: ModelItem) { function resetModelForm() { editingModelId.value = null; Object.assign(modelForm, { - provider: "openai", + provider: "openai-compatible", displayName: "", apiType: "openai_compatible", modelName: "", @@ -516,27 +558,64 @@ function buildChatQuery() {