feat: 增加对新模型提供商的支持,包括智谱、MiniMax 和 Moonshot,更新相关配置和 UI

This commit is contained in:
锦麟 王
2026-02-06 10:59:27 +08:00
parent 427ea6ae8d
commit f919487506
4 changed files with 326 additions and 51 deletions

View File

@@ -428,17 +428,30 @@ async def test_llm_with_config(request: LLMTestRequest) -> dict[str, Any]:
# 根据提供商进行测试 # 根据提供商进行测试
start = time.time() start = time.time()
if provider in ["openai-compatible", "openai", "deepseek"]: if provider in ["openai-compatible", "openai", "deepseek", "zhipu", "minimax", "moonshot"]:
# OpenAI 兼容接口 # OpenAI 兼容接口
import httpx import httpx
url = base_url or "https://api.openai.com/v1" url = base_url or "https://api.openai.com/v1"
model_name = model or "gpt-3.5-turbo" model_name = model or "gpt-3.5-turbo"
# 获取代理设置 # 设置各提供商默认 URL
if provider == "deepseek" and not base_url:
url = "https://api.deepseek.com/v1"
elif provider == "zhipu" and not base_url:
url = "https://open.bigmodel.cn/api/paas/v4"
model_name = model or "glm-4-flash"
elif provider == "minimax" and not base_url:
url = "https://api.minimax.chat/v1"
model_name = model or "abab6.5s-chat"
elif provider == "moonshot" and not base_url:
url = "https://api.moonshot.cn/v1"
model_name = model or "moonshot-v1-8k"
# 国内 API 不需要代理
settings = get_settings() settings = get_settings()
proxy_url = None proxy_url = None
if settings.proxy.enabled and provider not in ["deepseek"]: if settings.proxy.enabled and provider not in ["deepseek", "zhipu", "minimax", "moonshot"]:
proxy_url = settings.proxy.http or settings.proxy.https proxy_url = settings.proxy.http or settings.proxy.https
async with httpx.AsyncClient( async with httpx.AsyncClient(

View File

@@ -458,99 +458,277 @@ body {
} }
} }
/* 亮色主题额外样式覆盖 */ /* ========== 亮色主题全面覆盖 ========== */
/* 全局背景 & 文字 */
.theme-light,
.theme-light body {
background-color: #f0f2f5 !important;
color: #303133 !important;
}
.theme-light .app-container {
background-color: #f0f2f5;
}
/* 侧边栏 */
.theme-light .sidebar {
background-color: #fff !important;
border-right-color: #e4e7ed !important;
}
.theme-light .logo {
border-bottom-color: #e4e7ed !important;
}
.theme-light .el-menu { .theme-light .el-menu {
background-color: var(--bg-primary) !important; background-color: #fff !important;
} }
.theme-light .el-menu-item, .theme-light .el-menu-item,
.theme-light .el-sub-menu__title { .theme-light .el-sub-menu__title {
color: var(--text-primary) !important; color: #303133 !important;
} }
.theme-light .el-menu-item.is-active { .theme-light .el-menu-item.is-active {
background-color: var(--bg-secondary) !important; background-color: #ecf5ff !important;
color: var(--accent-primary) !important; color: #409eff !important;
} }
.theme-light .el-menu-item:hover, .theme-light .el-menu-item:hover,
.theme-light .el-sub-menu__title:hover { .theme-light .el-sub-menu__title:hover {
background-color: var(--bg-tertiary) !important; background-color: #f5f7fa !important;
} }
/* 头部 */
.theme-light .header {
background-color: #fff !important;
border-bottom-color: #e4e7ed !important;
color: #303133 !important;
}
.theme-light .header h3,
.theme-light .header span {
color: #303133 !important;
}
/* 主内容区 */
.theme-light .main-content {
background-color: #f0f2f5 !important;
}
/* 卡片 */
.theme-light .el-card { .theme-light .el-card {
background-color: var(--bg-secondary); background-color: #fff !important;
border-color: var(--border-color); border-color: #e4e7ed !important;
color: #303133 !important;
--el-card-bg-color: #fff;
}
.theme-light .el-card__header {
background-color: #fafbfc !important;
border-bottom-color: #e4e7ed !important;
color: #303133 !important;
}
.theme-light .el-card__body {
color: #303133 !important;
}
.theme-light .config-card {
background-color: #fff !important;
}
.theme-light .config-card .el-card__header {
background-color: #fafbfc !important;
border-bottom-color: #e4e7ed !important;
}
.theme-light .provider-card {
background-color: #fafbfc !important;
border-color: #e4e7ed !important;
}
.theme-light .stat-card {
background-color: #fff !important;
border-color: #e4e7ed !important;
}
/* 表单 */
.theme-light .el-form-item__label {
color: #606266 !important;
} }
.theme-light .el-input__inner, .theme-light .el-input__inner,
.theme-light .el-textarea__inner { .theme-light .el-textarea__inner {
background-color: var(--bg-primary) !important; background-color: #fff !important;
border-color: var(--border-color) !important; border-color: #dcdfe6 !important;
color: var(--text-primary) !important; color: #303133 !important;
}
.theme-light .el-input__wrapper {
background-color: #fff !important;
box-shadow: 0 0 0 1px #dcdfe6 inset !important;
}
.theme-light .el-input__wrapper:hover {
box-shadow: 0 0 0 1px #c0c4cc inset !important;
}
.theme-light .el-input__wrapper.is-focus {
box-shadow: 0 0 0 1px #409eff inset !important;
} }
.theme-light .el-select-dropdown { .theme-light .el-select-dropdown {
background-color: var(--bg-primary) !important; background-color: #fff !important;
} }
.theme-light .el-select-dropdown__item { .theme-light .el-select-dropdown__item {
color: var(--text-primary) !important; color: #303133 !important;
} }
.theme-light .config-card { /* 按钮 */
background-color: var(--bg-secondary); .theme-light .el-button--default {
--el-button-bg-color: #fff;
--el-button-border-color: #dcdfe6;
--el-button-text-color: #606266;
--el-button-hover-bg-color: #ecf5ff;
--el-button-hover-border-color: #c6e2ff;
--el-button-hover-text-color: #409eff;
} }
.theme-light .provider-card { .theme-light .el-button--primary {
background-color: var(--bg-primary); --el-button-bg-color: #409eff;
--el-button-border-color: #409eff;
--el-button-hover-bg-color: #66b1ff;
--el-button-hover-border-color: #66b1ff;
} }
.theme-light .stat-card { /* 分割线 */
background-color: var(--bg-secondary); .theme-light .el-divider {
border-color: #e4e7ed !important;
} }
/* 标签 */
.theme-light .el-tag {
--el-tag-bg-color: #ecf5ff;
--el-tag-border-color: #d9ecff;
--el-tag-text-color: #409eff;
}
/* Alert */
.theme-light .el-alert--info {
background-color: #f4f4f5 !important;
color: #909399 !important;
}
.theme-light .el-alert--info .el-alert__title {
color: #606266 !important;
}
/* 表格 */
.theme-light .el-table {
--el-table-bg-color: #fff;
--el-table-header-bg-color: #fafbfc;
--el-table-tr-bg-color: #fff;
--el-table-row-hover-bg-color: #f5f7fa;
--el-table-text-color: #303133;
--el-table-header-text-color: #909399;
--el-table-border-color: #ebeef5;
}
/* Tabs */
.theme-light .el-tabs__item {
color: #909399 !important;
}
.theme-light .el-tabs__item.is-active {
color: #409eff !important;
}
.theme-light .el-tabs--border-card {
background-color: #fff !important;
border-color: #dcdfe6 !important;
}
.theme-light .el-tabs__header {
background-color: #f5f7fa !important;
border-bottom-color: #e4e7ed !important;
}
/* Switch */
.theme-light .el-switch__label {
color: #606266 !important;
}
/* 对话框 */
.theme-light .el-dialog {
--el-dialog-bg-color: #fff;
}
.theme-light .el-dialog__title {
color: #303133 !important;
}
.theme-light .el-breadcrumb__inner {
color: #303133 !important;
}
/* 终端 & 日志 */
.theme-light .terminal-container, .theme-light .terminal-container,
.theme-light .logs-container { .theme-light .logs-container {
background-color: var(--bg-primary); background-color: #fff !important;
border-color: #e4e7ed !important;
} }
.theme-light .terminal-header, .theme-light .terminal-header,
.theme-light .logs-header { .theme-light .logs-header {
background-color: var(--bg-secondary); background-color: #fafbfc !important;
border-bottom-color: #e4e7ed !important;
} }
.theme-light .el-breadcrumb__inner { .theme-light .log-entry {
color: var(--text-primary) !important; border-bottom-color: #ebeef5 !important;
}
.theme-light .el-dialog {
--el-dialog-bg-color: var(--bg-primary);
}
.theme-light .el-table {
--el-table-bg-color: var(--bg-secondary);
--el-table-header-bg-color: var(--bg-tertiary);
--el-table-tr-bg-color: var(--bg-secondary);
--el-table-row-hover-bg-color: var(--bg-tertiary);
--el-table-text-color: var(--text-primary);
--el-table-header-text-color: var(--text-secondary);
--el-table-border-color: var(--border-color);
} }
/* LLM 配置状态卡片 */
.theme-light .status-chip { .theme-light .status-chip {
background-color: var(--bg-primary); background-color: #fff !important;
border-color: #e4e7ed !important;
} }
.theme-light .status-chip:hover, .theme-light .status-chip:hover,
.theme-light .status-chip.selected { .theme-light .status-chip.selected {
background-color: rgba(64, 158, 255, 0.1); background-color: #ecf5ff !important;
border-color: #409eff !important;
} }
.theme-light .test-result.success { .theme-light .test-result.success {
background-color: rgba(103, 194, 58, 0.15); color: #67c23a;
background-color: rgba(103, 194, 58, 0.1);
} }
.theme-light .test-result.error { .theme-light .test-result.error {
background-color: rgba(245, 108, 108, 0.15); color: #f56c6c;
background-color: rgba(245, 108, 108, 0.1);
}
/* 文字颜色确保 */
.theme-light span,
.theme-light p,
.theme-light div,
.theme-light label {
color: inherit;
}
.theme-light .provider-name,
.theme-light .status-name,
.theme-light .stat-card-title,
.theme-light .log-message {
color: #303133;
}
.theme-light .stat-card-sub,
.theme-light .log-time {
color: #909399;
} }

View File

@@ -72,7 +72,8 @@ app.component('channels-config-page', {
<li>登录企业微信管理后台 → 应用管理 → 创建应用</li> <li>登录企业微信管理后台 → 应用管理 → 创建应用</li>
<li>获取 CorpID、AgentID、Secret</li> <li>获取 CorpID、AgentID、Secret</li>
<li>在「接收消息」中配置 URL、Token、EncodingAESKey</li> <li>在「接收消息」中配置 URL、Token、EncodingAESKey</li>
<li>Webhook URL: <code>https://your-domain.com/webhook/wework</code></li> <li>回调地址指向 <b>Gateway 服务</b>(默认端口 8000</li>
<li>Webhook URL: <code>http://你的服务器IP:8000/webhook/wework</code></li>
</ol> </ol>
</template> </template>
</el-alert> </el-alert>
@@ -125,7 +126,8 @@ app.component('channels-config-page', {
<li>登录飞书开放平台 → 创建企业自建应用</li> <li>登录飞书开放平台 → 创建企业自建应用</li>
<li>获取 App ID 和 App Secret</li> <li>获取 App ID 和 App Secret</li>
<li>在「事件订阅」中配置请求地址和 Token</li> <li>在「事件订阅」中配置请求地址和 Token</li>
<li>Webhook URL: <code>https://your-domain.com/webhook/feishu</code></li> <li>事件请求地址指向 <b>Gateway 服务</b>(默认端口 8000</li>
<li>Webhook URL: <code>http://你的服务器IP:8000/webhook/feishu</code></li>
</ol> </ol>
</template> </template>
</el-alert> </el-alert>

View File

@@ -26,7 +26,7 @@ app.component('llm-config-page', {
// 保存状态 // 保存状态
const saving = ref(false); const saving = ref(false);
// 表单数据 - 简化为通用的 OpenAI 兼容格式 // 表单数据
const form = reactive({ const form = reactive({
// 当前使用的配置 // 当前使用的配置
provider: 'openai-compatible', provider: 'openai-compatible',
@@ -62,6 +62,28 @@ app.component('llm-config-page', {
base_url: '', base_url: '',
model: 'gemini-2.5-flash-preview-05-20', model: 'gemini-2.5-flash-preview-05-20',
configured: false configured: false
},
'zhipu': {
name: '智谱 GLM',
api_key: '',
base_url: 'https://open.bigmodel.cn/api/paas/v4',
model: 'glm-4-flash',
configured: false
},
'minimax': {
name: 'MiniMax',
api_key: '',
base_url: 'https://api.minimax.chat/v1',
model: 'abab6.5s-chat',
group_id: '',
configured: false
},
'moonshot': {
name: 'Moonshot (Kimi)',
api_key: '',
base_url: 'https://api.moonshot.cn/v1',
model: 'moonshot-v1-8k',
configured: false
} }
} }
}); });
@@ -107,6 +129,37 @@ app.component('llm-config-page', {
defaultModel: 'gemini-2.5-flash-preview-05-20', defaultModel: 'gemini-2.5-flash-preview-05-20',
keyPlaceholder: 'AIzaSy-xxx', keyPlaceholder: 'AIzaSy-xxx',
domestic: false domestic: false
},
{
id: 'zhipu',
name: '智谱 GLM',
icon: '🧠',
description: '智谱 AI 大模型,国内直连',
defaultUrl: 'https://open.bigmodel.cn/api/paas/v4',
defaultModel: 'glm-4-flash',
keyPlaceholder: 'xxx.xxx',
domestic: true
},
{
id: 'minimax',
name: 'MiniMax',
icon: '🎯',
description: 'MiniMax 大模型,国内直连(需 Group ID',
defaultUrl: 'https://api.minimax.chat/v1',
defaultModel: 'abab6.5s-chat',
keyPlaceholder: 'eyJhbGci-xxx',
domestic: true,
extraFields: ['group_id']
},
{
id: 'moonshot',
name: 'Moonshot (Kimi)',
icon: '🌙',
description: 'Moonshot/Kimi 大模型,国内直连',
defaultUrl: 'https://api.moonshot.cn/v1',
defaultModel: 'moonshot-v1-8k',
keyPlaceholder: 'sk-xxx',
domestic: true
} }
]; ];
@@ -137,6 +190,13 @@ app.component('llm-config-page', {
migrateConfig('anthropic', newVal.anthropic_api_key, newVal.anthropic_base_url); migrateConfig('anthropic', newVal.anthropic_api_key, newVal.anthropic_base_url);
migrateConfig('deepseek', newVal.deepseek_api_key, newVal.deepseek_base_url); migrateConfig('deepseek', newVal.deepseek_api_key, newVal.deepseek_base_url);
migrateConfig('gemini', newVal.gemini_api_key, newVal.gemini_base_url); migrateConfig('gemini', newVal.gemini_api_key, newVal.gemini_base_url);
migrateConfig('zhipu', newVal.zhipu_api_key, newVal.zhipu_base_url);
migrateConfig('minimax', newVal.minimax_api_key, newVal.minimax_base_url);
migrateConfig('moonshot', newVal.moonshot_api_key, newVal.moonshot_base_url);
// MiniMax group_id
if (newVal.minimax_group_id) {
form.configs['minimax'].group_id = newVal.minimax_group_id;
}
} }
}, { immediate: true, deep: true }); }, { immediate: true, deep: true });
@@ -147,9 +207,9 @@ app.component('llm-config-page', {
'anthropic': 'anthropic', 'anthropic': 'anthropic',
'deepseek': 'deepseek', 'deepseek': 'deepseek',
'gemini': 'gemini', 'gemini': 'gemini',
'zhipu': 'openai-compatible', 'zhipu': 'zhipu',
'minimax': 'openai-compatible', 'minimax': 'minimax',
'moonshot': 'openai-compatible' 'moonshot': 'moonshot'
}; };
return map[name] || 'openai-compatible'; return map[name] || 'openai-compatible';
} }
@@ -263,7 +323,17 @@ app.component('llm-config-page', {
deepseek_base_url: form.configs['deepseek'].base_url, deepseek_base_url: form.configs['deepseek'].base_url,
// Gemini // Gemini
gemini_api_key: form.configs['gemini'].api_key, gemini_api_key: form.configs['gemini'].api_key,
gemini_base_url: form.configs['gemini'].base_url gemini_base_url: form.configs['gemini'].base_url,
// 智谱
zhipu_api_key: form.configs['zhipu'].api_key,
zhipu_base_url: form.configs['zhipu'].base_url,
// MiniMax
minimax_api_key: form.configs['minimax'].api_key,
minimax_base_url: form.configs['minimax'].base_url,
minimax_group_id: form.configs['minimax'].group_id || '',
// Moonshot
moonshot_api_key: form.configs['moonshot'].api_key,
moonshot_base_url: form.configs['moonshot'].base_url
}; };
emit('save', saveData); emit('save', saveData);
@@ -406,6 +476,18 @@ app.component('llm-config-page', {
留空将使用默认模型:{{ currentProvider.defaultModel }} 留空将使用默认模型:{{ currentProvider.defaultModel }}
</div> </div>
</el-form-item> </el-form-item>
<!-- MiniMax 额外的 Group ID 字段 -->
<el-form-item v-if="activeProvider === 'minimax'" label="Group ID" required>
<el-input
v-model="form.configs['minimax'].group_id"
placeholder="MiniMax Group ID"
size="large"
/>
<div style="margin-top: 4px; font-size: 12px; color: var(--text-secondary);">
在 MiniMax 控制台获取,用于 API 调用
</div>
</el-form-item>
</el-form> </el-form>
<!-- 测试区域 --> <!-- 测试区域 -->