Skip to content

Commit 9f641ed

Browse files
committed
feat(model-config): 添加模型手动管理功能及失效模型检测
- 在模型供应商组件中添加手动管理模式,当无法自动获取模型列表时可手动添加/移除模型 - 添加失效模型检测功能,可一键移除配置中不存在的模型 - 新增 ModelScope 供应商图标支持 - 调整用户头像和模型图标尺寸样式 - 更新文档说明图片显示的环境变量配置
1 parent 545723d commit 9f641ed

File tree

7 files changed

+153
-16
lines changed

7 files changed

+153
-16
lines changed

docs/latest/advanced/document-processing.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
- 优先处理名为 `full.md` 的文件,否则使用第一个 `.md` 文件
2828
- 支持图片目录的智能识别(`images/``../images/` 等)
2929

30+
::: tip 图片显示
31+
文档中的图片会自动上传到对象存储并替换为可访问的 URL。但是如果想要在外部正常显示图片,需要配置 `HOST_IP` 环境变量,将其设置为您的服务器 IP 地址。
32+
:::
33+
3034
## 快速配置
3135

3236
### 1. 基础 OCR (RapidOCR)
23.3 KB
Loading
-10.4 KB
Loading
99.2 KB
Loading

web/src/components/ModelProvidersComponent.vue

Lines changed: 144 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,27 @@
179179
</div>
180180

181181
<div class="modal-models-section">
182-
<div class="model-search">
182+
<!-- 警告:检测到失效模型 -->
183+
<div v-if="unsupportedModels.length > 0" class="simple-notice warning" style="margin-bottom: 20px;">
184+
<p>检测到配置中包含当前供应商列表中不存在的模型。以下模型可能已失效或被供应商移除:</p>
185+
<div class="unsupported-list">
186+
<a-tag
187+
closable
188+
v-for="model in unsupportedModels"
189+
:key="model"
190+
color="error"
191+
@close="removeModel(model)"
192+
style="margin-bottom: 4px;"
193+
>
194+
{{ model }}
195+
</a-tag>
196+
</div>
197+
<a-button size="small" type="primary" danger ghost @click="removeAllUnsupported" class="clear-btn">
198+
一键移除所有失效模型
199+
</a-button>
200+
</div>
201+
202+
<div class="model-search" v-if="providerConfig.allModels.length > 0">
183203
<a-input
184204
v-model:value="providerConfig.searchQuery"
185205
placeholder="搜索模型..."
@@ -192,14 +212,14 @@
192212
</div>
193213

194214
<!-- 显示选中统计信息 -->
195-
<div class="selection-summary">
215+
<div class="selection-summary" v-if="providerConfig.allModels.length > 0">
196216
<span>已选择 {{ providerConfig.selectedModels.length }} 个模型</span>
197217
<span v-if="providerConfig.searchQuery" class="filter-info">
198218
(当前筛选显示 {{ filteredModels.length }} 个)
199219
</span>
200220
</div>
201221

202-
<div class="modal-checkbox-list">
222+
<div class="modal-checkbox-list" v-if="providerConfig.allModels.length > 0">
203223
<div v-for="(model, index) in filteredModels" :key="index" class="modal-checkbox-item">
204224
<a-checkbox
205225
:checked="providerConfig.selectedModels.includes(model.id)"
@@ -209,14 +229,45 @@
209229
</a-checkbox>
210230
</div>
211231
</div>
212-
<div v-if="providerConfig.allModels.length === 0" class="modal-no-models">
213-
<a-alert v-if="!modelStatus[providerConfig.provider]" type="warning" message="请在 .env 中配置对应的 APIKEY,并重新启动服务" />
214-
<div v-else>
215-
<a-alert type="warning" message="该提供商暂未适配获取模型列表的方法,如需添加模型,请编辑 src/config/static/models.py 。">
216-
<template #description>
217-
<a href="https://xerrors.github.io/Yuxi-Know/latest/intro/model-config.html" target="_blank">模型配置</a>
218-
</template>
219-
</a-alert>
232+
233+
<!-- 手动管理模式 (当无法获取模型列表时) -->
234+
<div v-if="providerConfig.allModels.length === 0" class="modal-manual-manage">
235+
<div v-if="!modelStatus[providerConfig.provider]" class="simple-notice warning" style="margin-bottom: 16px;">
236+
请在 .env 中配置对应的 APIKEY,并重新启动服务
237+
</div>
238+
239+
<div class="manual-manage-container">
240+
<div class="manual-header">
241+
<div class="simple-notice info">
242+
无法获取模型列表,您可以手动管理模型配置。该提供商暂未适配自动获取模型列表,或者网络请求失败。您可以在下方手动添加或移除模型。
243+
</div>
244+
</div>
245+
246+
<div class="manual-add-box" style="margin: 16px 0;">
247+
<a-input-search
248+
v-model:value="manualModelInput"
249+
placeholder="请输入模型ID(如:gpt-4)"
250+
enter-button="添加模型"
251+
@search="addManualModel"
252+
/>
253+
</div>
254+
255+
<div class="current-models-list">
256+
<h4 style="margin-bottom: 10px; font-weight: 600;">当前配置的模型 ({{ providerConfig.selectedModels.length }})</h4>
257+
<div v-if="providerConfig.selectedModels.length === 0" class="empty-text" style="color: var(--gray-500); padding: 8px 0;">暂无配置模型</div>
258+
<div class="tags-container">
259+
<a-tag
260+
v-for="model in providerConfig.selectedModels"
261+
:key="model"
262+
closable
263+
color="blue"
264+
@close="removeModel(model)"
265+
style="margin-bottom: 8px; padding: 4px 8px;"
266+
>
267+
{{ model }}
268+
</a-tag>
269+
</div>
270+
</div>
220271
</div>
221272
</div>
222273
</div>
@@ -306,7 +357,7 @@
306357
import { computed, reactive, watch, h, ref } from 'vue'
307358
import { message } from 'ant-design-vue';
308359
import {
309-
InfoCircleOutlined,
360+
InfoCircleOutlined, // Keep if still used for other things, if not, remove. For now assume it might be used elsewhere.
310361
SettingOutlined,
311362
DownCircleOutlined,
312363
LoadingOutlined,
@@ -479,6 +530,46 @@ const filteredModels = computed(() => {
479530
return allModels.filter(model => model.id.toLowerCase().includes(searchQuery));
480531
});
481532
533+
// 计算不支持/已失效的模型
534+
const unsupportedModels = computed(() => {
535+
if (providerConfig.allModels.length === 0) return [];
536+
const availableIds = new Set(providerConfig.allModels.map(m => m.id));
537+
return providerConfig.selectedModels.filter(id => !availableIds.has(id));
538+
});
539+
540+
// 手动管理相关
541+
const manualModelInput = ref('');
542+
543+
// 添加手动输入的模型
544+
const addManualModel = () => {
545+
const val = manualModelInput.value.trim();
546+
if (!val) return;
547+
548+
if (providerConfig.selectedModels.includes(val)) {
549+
message.warning('该模型已存在');
550+
return;
551+
}
552+
553+
providerConfig.selectedModels.push(val);
554+
manualModelInput.value = '';
555+
message.success('添加成功');
556+
};
557+
558+
// 移除模型
559+
const removeModel = (modelId) => {
560+
const idx = providerConfig.selectedModels.indexOf(modelId);
561+
if (idx > -1) {
562+
providerConfig.selectedModels.splice(idx, 1);
563+
}
564+
};
565+
566+
// 移除所有不支持的模型
567+
const removeAllUnsupported = () => {
568+
const toRemove = unsupportedModels.value;
569+
providerConfig.selectedModels = providerConfig.selectedModels.filter(id => !toRemove.includes(id));
570+
message.success(`已移除 ${toRemove.length} 个失效模型`);
571+
};
572+
482573
// 自定义供应商管理
483574
const customProviderForm = ref();
484575
const customProviderModal = reactive({
@@ -998,8 +1089,8 @@ const testCustomProvider = async (providerId, modelName) => {
9981089
}
9991090
10001091
.model-icon {
1001-
width: 28px;
1002-
height: 28px;
1092+
width: 36px;
1093+
height: 36px;
10031094
border-radius: 6px;
10041095
overflow: hidden;
10051096
filter: grayscale(100%);
@@ -1438,4 +1529,43 @@ const testCustomProvider = async (providerId, modelName) => {
14381529
}
14391530
}
14401531
}
1532+
1533+
// Simple Notice Styles
1534+
.simple-notice {
1535+
padding: 8px 12px;
1536+
border-radius: 4px;
1537+
font-size: 12px;
1538+
line-height: 1.5;
1539+
margin-bottom: 12px;
1540+
border: 1px solid transparent; // Keep a subtle border
1541+
1542+
&.warning {
1543+
background-color: var(--color-warning-50);
1544+
color: var(--color-warning-700);
1545+
border-color: var(--color-warning-100);
1546+
}
1547+
1548+
&.info {
1549+
background-color: var(--color-info-50);
1550+
color: var(--color-info-700);
1551+
border-color: var(--color-info-100);
1552+
}
1553+
1554+
p { // For warning message, if it's multiline
1555+
margin: 0;
1556+
}
1557+
1558+
.unsupported-list {
1559+
margin-top: 8px;
1560+
display: flex;
1561+
flex-wrap: wrap;
1562+
gap: 4px;
1563+
}
1564+
.clear-btn {
1565+
margin-top: 8px;
1566+
font-size: 12px;
1567+
height: 24px;
1568+
padding: 0 8px;
1569+
}
1570+
}
14411571
</style>

web/src/components/UserInfoComponent.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ const handleAvatarChange = async (info) => {
395395
}
396396
397397
.user-avatar {
398-
width: 28px;
399-
height: 28px;
398+
width: 32px;
399+
height: 32px;
400400
border-radius: 50%;
401401
display: flex;
402402
align-items: center;
@@ -406,6 +406,7 @@ const handleAvatarChange = async (info) => {
406406
cursor: pointer;
407407
position: relative;
408408
overflow: hidden;
409+
box-shadow: 0 2px 8px var(--shadow-2);
409410
410411
&:hover {
411412
opacity: 0.9;

web/src/utils/modelIcon.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import siliconflowIcon from '@/assets/providers/siliconflow.png'
77
import arkIcon from '@/assets/providers/ark.png'
88
import openrouterIcon from '@/assets/providers/openrouterai.png'
99
import defaultIcon from '@/assets/providers/default.png'
10+
import modelscopeIcon from '@/assets/providers/modelscope.png'
1011

1112
export const modelIcons = {
1213
openai: openaiIcon,
@@ -18,5 +19,6 @@ export const modelIcons = {
1819
ark: arkIcon,
1920
'together.ai': togetherIcon,
2021
openrouter: openrouterIcon,
22+
modelscope: modelscopeIcon,
2123
default: defaultIcon // 添加默认图标
2224
}

0 commit comments

Comments
 (0)