diff --git a/web/src/assets/providers/siliconflow.png b/web/src/assets/providers/siliconflow.png index f32fc6eb..d54921c6 100644 Binary files a/web/src/assets/providers/siliconflow.png and b/web/src/assets/providers/siliconflow.png differ diff --git a/web/src/views/SettingView.vue b/web/src/views/SettingView.vue index 522770ca..f3c493e4 100644 --- a/web/src/views/SettingView.vue +++ b/web/src/views/SettingView.vue @@ -5,11 +5,8 @@

配置文件也可以在 saves/config/base.yaml 中修改

@@ -121,12 +118,12 @@ > - +
{{ item.api_base }}
-
+
+ 添加模型
@@ -135,7 +132,7 @@ class="custom-model-modal" v-model:open="customModel.visible" :title="customModel.modelTitle" - @ok="handleAddCustomModel" + @ok="handleAddOrEditCustomModel" @cancel="handleCancelCustomModel" :okText="'确认'" :cancelText="'取消'" @@ -145,13 +142,13 @@

添加的模型是兼容 OpenAI 的模型,比如 vllm,Ollama。

- + - + - + @@ -164,25 +161,47 @@
模型图标
-

{{ modelNames[item].name }}

- -
-
-
+

{{ modelNames[item].name }}

+ + 更多模型 + +
+ -
{{ model }}
+ + + +
+
+
+
+
+
{{ model }}
+
-

{{ modelNames[item].name }}

- +
+ 模型图标 +
+
+

{{ modelNames[item].name }}

+ + 更多模型 + +
- 需配置 {{ key }} + 需配置{{ key }}
@@ -212,6 +231,8 @@ import { DeleteOutlined, EditOutlined, InfoCircleOutlined, + DownOutlined, + UpOutlined, } from '@ant-design/icons-vue'; import HeaderComponent from '@/components/HeaderComponent.vue'; import TableConfigComponent from '@/components/TableConfigComponent.vue'; @@ -228,7 +249,7 @@ const isNeedRestart = ref(false) const customModel = reactive({ modelTitle: '添加自定义模型', visible: false, - custom_id: '', // Add this line + custom_id: '', name: '', api_key: '', api_base: '', @@ -249,6 +270,9 @@ const notModelKeys = computed(() => { return Object.keys(modelStatus.value || {}).filter(key => !modelStatus.value?.[key]) }) +// 模型展开状态管理 +const expandedModels = reactive({}) + const generateRandomHash = (length) => { let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let hash = ''; @@ -298,49 +322,35 @@ const handleChange = (key, e) => { configStore.setConfigValue(key, e) } -const handleAddCustomModel = async () => { +const handleAddOrEditCustomModel = async () => { if (!customModel.name || !customModel.api_base) { - message.error('请填写完整模型信息') + message.error('请填写完整的模型名称和API Base信息。') return } - if (!configStore.config.custom_models) { - configStore.config.custom_models = [] - } - + let custom_models = configStore.config.custom_models || []; const model_info = { - custom_id: customModel.custom_id, + custom_id: customModel.custom_id || `${customModel.name}-${generateRandomHash(4)}`, name: customModel.name, api_key: customModel.api_key, api_base: customModel.api_base, } - if (customModel.edit_type == 'add') { - if (configStore.config.custom_models.find(item => item.custom_id == customModel.custom_id)) { - message.error('模型ID已存在') + if (customModel.edit_type === 'add') { + if (custom_models.find(item => item.custom_id === customModel.custom_id)) { + message.error('模型ID已存在') return } - const modelHash = generateRandomHash(4) - model_info.custom_id = `${customModel.name}-${modelHash}` - configStore.config.custom_models.push(model_info) + custom_models.push(model_info) } else { - configStore.config.custom_models = configStore.config.custom_models.map(item => { - if (item.custom_id == customModel.custom_id) { - if (item.name != customModel.name) { - const modelHash = generateRandomHash(4) - model_info.custom_id = `${customModel.name}-${modelHash}` - configStore.setConfigValue('model_name', model_info.custom_id) - } - return model_info - } - return item - }) + // 如果 custom_id 相同,则更新 + custom_models = custom_models.map(item => item.custom_id === customModel.custom_id ? model_info : item); } - customModel.visible = false - await configStore.setConfigValue('custom_models', configStore.config.custom_models) - message.success('添加自定义模型成功') + customModel.visible = false; + await configStore.setConfigValue('custom_models', custom_models); + message.success(customModel.edit_type === 'add' ? '模型添加成功' : '模型修改成功'); } const handleDeleteCustomModel = (custom_id) => { @@ -348,21 +358,32 @@ const handleDeleteCustomModel = (custom_id) => { configStore.setConfigValue('custom_models', updatedModels); } -const handleEditCustomModel = (item) => { +const prepareToEditCustomModel = (item) => { customModel.modelTitle = '编辑自定义模型' customModel.custom_id = item.custom_id + customModel.visible = true + customModel.edit_type = 'edit' customModel.name = item.name customModel.api_key = item.api_key customModel.api_base = item.api_base - customModel.visible = true - customModel.edit_type = 'edit' } -const handleCancelCustomModel = () => { +const prepareToAddCustomModel = () => { + customModel.modelTitle = '添加自定义模型' + customModel.edit_type = 'add' + customModel.visible = true + clearCustomModel() +} + +const clearCustomModel = () => { customModel.custom_id = '' customModel.name = '' customModel.api_key = '' customModel.api_base = '' +} + +const handleCancelCustomModel = () => { + clearCustomModel() customModel.visible = false } @@ -496,17 +517,31 @@ const sendRestart = () => { padding: 12px; .card-header { display: flex; - align-items: center; + align-items: flex-start; gap: 10px; + .model-title-container { + display: flex; + flex-direction: column; + flex: 1; + } + + .model-url { + font-size: 12px; + width: fit-content; + color: var(--gray-500); + } + .model-icon { - width: 24px; - height: 24px; + width: 40px; + height: 40px; // 灰度 filter: grayscale(100%); img { width: 100%; height: 100%; + border-radius: 4px; + border: 1px solid var(--gray-300); } &.available { @@ -514,10 +549,9 @@ const sendRestart = () => { } } - h3 { margin: 0; - font-size: 1rem; + font-size: 0.9rem; font-weight: bold; } @@ -546,12 +580,53 @@ const sendRestart = () => { } .missing-keys { + margin-top: 4px; color: var(--gray-600); + font-size: 12px; & > span { - margin-left: 10px; + margin-left: 6px; user-select: all; + background-color: var(--gray-100); + padding: 2px 6px; + border-radius: 4px; + color: var(--gray-800); } } + + .expand-button { + margin-left: auto; + height: 32px; + width: 32px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + cursor: pointer; + color: var(--gray-500); + + &:hover { + background-color: var(--gray-100); + } + + .icon-wrapper { + display: inline-flex; + transition: transform 0.5s ease; + + &.rotated { + transform: rotate(180deg); + } + } + } + } + + .card-body-wrapper { + max-height: 0; + overflow: hidden; + transition: max-height 0.5s ease-in-out; + + &.expanded { + max-height: 500px; /* 设置一个足够大的值 */ + } } .card-body { @@ -606,7 +681,7 @@ const sendRestart = () => { gap: 10px; .card-models__header { width: 100%; - height: 32px; + height: 24px; display: flex; justify-content: flex-start; align-items: center; @@ -631,6 +706,10 @@ const sendRestart = () => { .api_base { font-size: 12px; color: var(--gray-600); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; } &:hover {