perf: 模型管理界面重做

This commit is contained in:
2026-03-11 20:33:04 +08:00
parent 219fa566ef
commit 373d7f8201
37 changed files with 4120 additions and 2108 deletions

View File

@@ -92,13 +92,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
return Result.ok(); return Result.ok();
} }
@PostMapping("/updateByEntity")
@SaCheckPermission("/api/v1/model/save")
public Result<?> updateByEntity(@RequestBody Model entity) {
modelService.updateByEntity(entity);
return Result.ok();
}
@GetMapping("/selectLlmByProviderCategory") @GetMapping("/selectLlmByProviderCategory")
@SaCheckPermission("/api/v1/model/query") @SaCheckPermission("/api/v1/model/query")
public Result<Map<String, List<Model>>> selectLlmByProviderCategory(Model entity, String sortKey, String sortType) { public Result<Map<String, List<Model>>> selectLlmByProviderCategory(Model entity, String sortKey, String sortType) {
@@ -129,19 +122,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
} }
/**
* 添加所有模型
*
* @param entity
* @return
*/
@PostMapping("addAllLlm")
public Result<?> addAllLlm(@JsonBody Model entity) {
QueryWrapper queryWrapper = QueryWrapper.create().eq(Model::getProviderId, entity.getProviderId());
service.update(entity, queryWrapper);
return Result.ok();
}
@GetMapping("/selectLlmList") @GetMapping("/selectLlmList")
@SaCheckPermission("/api/v1/model/query") @SaCheckPermission("/api/v1/model/query")
public Result<List<Model>> selectLlmList(Model entity, Boolean asTree, String sortKey, String sortType) { public Result<List<Model>> selectLlmList(Model entity, Boolean asTree, String sortKey, String sortType) {
@@ -154,15 +134,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
return Result.ok(totalList); return Result.ok(totalList);
} }
@Override
protected Result<?> onSaveOrUpdateBefore(Model entity, boolean isSave) {
if (isSave) {
entity.setWithUsed(true);
}
return super.onSaveOrUpdateBefore(entity, isSave);
}
@PostMapping("removeLlmByIds") @PostMapping("removeLlmByIds")
@Transactional @Transactional
public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) { public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) {

View File

@@ -4,6 +4,7 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id; import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType; import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.core.handler.FastjsonTypeHandler; import com.mybatisflex.core.handler.FastjsonTypeHandler;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Map; import java.util.Map;
@@ -103,12 +104,6 @@ public class ModelBase implements Serializable {
@Column(comment = "模型类型: chatModel/embeddingModel/rerankModel/orc..") @Column(comment = "模型类型: chatModel/embeddingModel/rerankModel/orc..")
private String modelType; private String modelType;
/**
* 是否使用
*/
@Column(comment = "是否使用")
private Boolean withUsed;
/** /**
* 是否支持推理 * 是否支持推理
*/ */
@@ -277,14 +272,6 @@ public class ModelBase implements Serializable {
this.modelType = modelType; this.modelType = modelType;
} }
public Boolean getWithUsed() {
return withUsed;
}
public void setWithUsed(Boolean withUsed) {
this.withUsed = withUsed;
}
public Boolean getSupportThinking() { public Boolean getSupportThinking() {
return supportThinking; return supportThinking;
} }

View File

@@ -1,8 +1,7 @@
package tech.easyflow.ai.service; package tech.easyflow.ai.service;
import tech.easyflow.ai.entity.Model;
import com.mybatisflex.core.service.IService; import com.mybatisflex.core.service.IService;
import tech.easyflow.common.domain.Result; import tech.easyflow.ai.entity.Model;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
@@ -25,6 +24,4 @@ public interface ModelService extends IService<Model> {
void removeByEntity(Model entity); void removeByEntity(Model entity);
Model getModelInstance(BigInteger modelId); Model getModelInstance(BigInteger modelId);
void updateByEntity(Model entity);
} }

View File

@@ -2,13 +2,13 @@
package tech.easyflow.ai.service.impl; package tech.easyflow.ai.service.impl;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.Cache;
import com.easyagents.core.document.Document; import com.easyagents.core.document.Document;
import com.easyagents.core.model.chat.ChatModel; import com.easyagents.core.model.chat.ChatModel;
import com.easyagents.core.model.chat.ChatOptions; import com.easyagents.core.model.chat.ChatOptions;
import com.easyagents.core.model.embedding.EmbeddingModel; import com.easyagents.core.model.embedding.EmbeddingModel;
import com.easyagents.core.model.rerank.RerankModel; import com.easyagents.core.model.rerank.RerankModel;
import com.easyagents.core.store.VectorData; import com.easyagents.core.store.VectorData;
import com.alicp.jetcache.Cache;
import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl; import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -21,7 +21,6 @@ import tech.easyflow.ai.entity.ModelProvider;
import tech.easyflow.ai.mapper.ModelMapper; import tech.easyflow.ai.mapper.ModelMapper;
import tech.easyflow.ai.service.ModelProviderService; import tech.easyflow.ai.service.ModelProviderService;
import tech.easyflow.ai.service.ModelService; import tech.easyflow.ai.service.ModelService;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.web.exceptions.BusinessException; import tech.easyflow.common.web.exceptions.BusinessException;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -92,7 +91,6 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
QueryWrapper queryWrapper = new QueryWrapper() QueryWrapper queryWrapper = new QueryWrapper()
.eq(Model::getProviderId, entity.getProviderId()); .eq(Model::getProviderId, entity.getProviderId());
queryWrapper.eq(Model::getWithUsed, entity.getWithUsed());
List<Model> totalList = modelMapper.selectListWithRelationsByQuery(queryWrapper); List<Model> totalList = modelMapper.selectListWithRelationsByQuery(queryWrapper);
for (String modelType : Model.MODEL_TYPES) { for (String modelType : Model.MODEL_TYPES) {
Map<String, List<Model>> groupMap = groupLlmByGroupName(totalList, modelType); Map<String, List<Model>> groupMap = groupLlmByGroupName(totalList, modelType);
@@ -212,13 +210,4 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
return model; return model;
} }
@Override
public void updateByEntity(Model entity) {
QueryWrapper queryWrapper = QueryWrapper.create().eq(Model::getProviderId, entity.getProviderId())
.eq(Model::getGroupName, entity.getGroupName());
Model model = new Model();
model.setWithUsed(entity.getWithUsed());
modelMapper.updateByQuery(model, queryWrapper);
}
} }

View File

@@ -3,9 +3,9 @@ spring:
activate: activate:
on-profile: prod on-profile: prod
datasource: datasource:
url: jdbc:mysql://127.0.0.1:3306/easyflow?useInformationSchema=true&characterEncoding=utf-8 url: jdbc:mysql://127.0.0.1:23306/easyflow?useInformationSchema=true&characterEncoding=utf-8
username: easyflow username: easyflow
password: 123456 password: root
data: data:
redis: redis:
host: 127.0.0.1 host: 127.0.0.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="146 227 268 266"
fill="none"
>
<path
d="M249.176 323.434V298.276C249.176 296.158 249.971 294.569 251.825 293.509L302.406 264.381C309.29 260.409 317.5 258.555 325.973 258.555C357.75 258.555 377.877 283.185 377.877 309.399C377.877 311.253 377.877 313.371 377.611 315.49L325.178 284.771C322.001 282.919 318.822 282.919 315.645 284.771L249.176 323.434ZM367.283 421.415V361.301C367.283 357.592 365.694 354.945 362.516 353.092L296.048 314.43L317.763 301.982C319.617 300.925 321.206 300.925 323.058 301.982L373.639 331.112C388.205 339.586 398.003 357.592 398.003 375.069C398.003 395.195 386.087 413.733 367.283 421.412V421.415ZM233.553 368.452L211.838 355.742C209.986 354.684 209.19 353.095 209.19 350.975V292.718C209.19 264.383 230.905 242.932 260.301 242.932C271.423 242.932 281.748 246.641 290.49 253.26L238.321 283.449C235.146 285.303 233.555 287.951 233.555 291.659V368.455L233.553 368.452ZM280.292 395.462L249.176 377.985V340.913L280.292 323.436L311.407 340.913V377.985L280.292 395.462ZM300.286 475.968C289.163 475.968 278.837 472.259 270.097 465.64L322.264 435.449C325.441 433.597 327.03 430.949 327.03 427.239V350.445L349.011 363.155C350.865 364.213 351.66 365.802 351.66 367.922V426.179C351.66 454.514 329.679 475.965 300.286 475.965V475.968ZM237.525 416.915L186.944 387.785C172.378 379.31 162.582 361.305 162.582 343.827C162.582 323.436 174.763 305.164 193.563 297.485V357.861C193.563 361.571 195.154 364.217 198.33 366.071L264.535 404.467L242.82 416.915C240.967 417.972 239.377 417.972 237.525 416.915ZM234.614 460.343C204.689 460.343 182.71 437.833 182.71 410.028C182.71 407.91 182.976 405.792 183.238 403.672L235.405 433.863C238.582 435.715 241.763 435.715 244.938 433.863L311.407 395.466V420.622C311.407 422.742 310.612 424.331 308.758 425.389L258.179 454.519C251.293 458.491 243.083 460.343 234.611 460.343H234.614ZM300.286 491.854C332.329 491.854 359.073 469.082 365.167 438.892C394.825 431.211 413.892 403.406 413.892 375.073C413.892 356.535 405.948 338.529 391.648 325.552C392.972 319.991 393.766 314.43 393.766 308.87C393.766 271.003 363.048 242.666 327.562 242.666C320.413 242.666 313.528 243.723 306.644 246.109C294.725 234.457 278.307 227.042 260.301 227.042C228.258 227.042 201.513 249.815 195.42 280.004C165.761 287.685 146.694 315.49 146.694 343.824C146.694 362.362 154.638 380.368 168.938 393.344C167.613 398.906 166.819 404.467 166.819 410.027C166.819 447.894 197.538 476.231 233.024 476.231C240.172 476.231 247.058 475.173 253.943 472.788C265.859 484.441 282.278 491.854 300.286 491.854Z"
fill="#111827"
/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,8 @@
<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="96" height="96" rx="28" fill="#475569"/>
<path d="M26 35C26 31.6863 28.6863 29 32 29H64C67.3137 29 70 31.6863 70 35V42C70 45.3137 67.3137 48 64 48H32C28.6863 48 26 45.3137 26 42V35Z" fill="white" fill-opacity="0.95"/>
<path d="M30 40H66" stroke="#475569" stroke-width="4" stroke-linecap="round"/>
<path d="M37 58C37 55.7909 38.7909 54 41 54H55C57.2091 54 59 55.7909 59 58V63C59 65.2091 57.2091 67 55 67H41C38.7909 67 37 65.2091 37 63V58Z" fill="white" fill-opacity="0.9"/>
<path d="M48 48V54" stroke="white" stroke-width="4" stroke-linecap="round"/>
<circle cx="48" cy="60.5" r="2.5" fill="#475569"/>
</svg>

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,10 +1,19 @@
import { api } from '#/api/request.js'; import {api} from '#/api/request.js';
// 获取LLM供应商 // 获取LLM供应商
export async function getLlmProviderList() { export async function getLlmProviderList() {
return api.get('/api/v1/modelProvider/list'); return api.get('/api/v1/modelProvider/list');
} }
export interface ModelListQuery {
modelType?: string;
providerId?: string;
}
export async function getModelList(params: ModelListQuery = {}) {
return api.get('/api/v1/model/list', { params });
}
// 保存LLM // 保存LLM
export async function saveLlm(data: string) { export async function saveLlm(data: string) {
return api.post('/api/v1/model/save', data); return api.post('/api/v1/model/save', data);
@@ -20,6 +29,10 @@ export async function updateLlm(data: any) {
return api.post(`/api/v1/model/update`, data); return api.post(`/api/v1/model/update`, data);
} }
export async function verifyModelConfig(id: string) {
return api.get('/api/v1/model/verifyLlmConfig', { params: { id } });
}
// 一键添加LLM // 一键添加LLM
export async function quickAddLlm(data: any) { export async function quickAddLlm(data: any) {
return api.post(`/api/v1/model/quickAdd`, data); return api.post(`/api/v1/model/quickAdd`, data);
@@ -33,7 +46,6 @@ export interface llmType {
providerName: string; providerName: string;
providerType: string; providerType: string;
}; };
withUsed: boolean;
llmModel: string; llmModel: string;
icon: string; icon: string;
description: string; description: string;

View File

@@ -6,7 +6,7 @@ interface Props {
contentPadding?: number | string; contentPadding?: number | string;
dense?: boolean; dense?: boolean;
stickyToolbar?: boolean; stickyToolbar?: boolean;
surface?: 'panel' | 'subtle'; surface?: 'panel' | 'plain' | 'subtle';
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -141,6 +141,18 @@ const contentStyle = computed((): CSSProperties => {
box-shadow: none; box-shadow: none;
} }
.list-page-shell.is-plain .list-page-shell__content {
background: hsl(var(--surface-panel) / 0.96);
border: 1px solid hsl(var(--divider-faint) / 0.58);
border-radius: 20px;
box-shadow: none;
backdrop-filter: none;
}
.list-page-shell.is-plain .list-page-shell__content::before {
display: none;
}
.list-page-shell__content::before { .list-page-shell__content::before {
position: absolute; position: absolute;
inset: 0 0 auto; inset: 0 0 auto;

View File

@@ -0,0 +1,112 @@
import {mount} from '@vue/test-utils';
import {describe, expect, it, vi} from 'vitest';
import CardList from '../CardList.vue';
const { hasAccessByCodes } = vi.hoisted(() => ({
hasAccessByCodes: vi.fn((codes: string[]) => codes[0] !== 'blocked'),
}));
vi.mock('@easyflow/access', () => ({
useAccess: () => ({
hasAccessByCodes,
}),
}));
describe('CardList', () => {
function mountCardList(props: Record<string, unknown>) {
return mount(CardList, {
props: {
data: [
{
id: 'bot-1',
title: '演示卡片',
description: '用于验证主次交互是否正常工作',
},
],
defaultIcon: '/favicon.svg',
...props,
},
global: {
stubs: {
IconifyIcon: {
props: ['icon'],
template: '<span class="iconify-icon">{{ icon }}</span>',
},
},
},
});
}
it('点击卡片空白区域时触发主动作', async () => {
const primaryAction = vi.fn();
const wrapper = mountCardList({
primaryAction: {
text: '进入设置',
onClick: primaryAction,
},
});
await wrapper.get('.card-item').trigger('click');
expect(primaryAction).toHaveBeenCalledTimes(1);
expect(primaryAction).toHaveBeenCalledWith(
expect.objectContaining({ id: 'bot-1' }),
);
});
it('点击次级按钮时不会冒泡触发主动作', async () => {
const primaryAction = vi.fn();
const inlineAction = vi.fn();
const wrapper = mountCardList({
primaryAction: {
text: '进入设置',
onClick: primaryAction,
},
actions: [
{
text: '编辑',
placement: 'inline',
onClick: inlineAction,
},
],
});
await wrapper.get('.card-action-btn').trigger('click');
expect(inlineAction).toHaveBeenCalledTimes(1);
expect(primaryAction).not.toHaveBeenCalled();
});
it('键盘 Enter 可以触发主动作', async () => {
const primaryAction = vi.fn();
const wrapper = mountCardList({
primaryAction: {
text: '进入设计',
onClick: primaryAction,
},
});
await wrapper.get('.card-item').trigger('keydown.enter');
expect(primaryAction).toHaveBeenCalledTimes(1);
});
it('未提供主动作时保持旧卡片模式,不会把卡片变成可点击入口', async () => {
const legacyAction = vi.fn();
const wrapper = mountCardList({
actions: [
{
text: '编辑',
onClick: legacyAction,
},
],
});
await wrapper.get('.card-item').trigger('click');
await wrapper.get('.card-action-btn').trigger('click');
expect(wrapper.get('.card-item').attributes('role')).toBeUndefined();
expect(legacyAction).toHaveBeenCalledTimes(1);
});
});

View File

@@ -58,7 +58,6 @@
"button": { "button": {
"management": "Management", "management": "Management",
"test": "Test", "test": "Test",
"addAllLlm": "Add models from the list",
"RetrieveAgain": "Retrieve the model list again" "RetrieveAgain": "Retrieve the model list again"
}, },
"all": "All", "all": "All",

View File

@@ -55,7 +55,6 @@
"button": { "button": {
"management": "管理", "management": "管理",
"test": "检测", "test": "检测",
"addAllLlm": "添加列表中的所有模型",
"RetrieveAgain": "重新获取模型列表" "RetrieveAgain": "重新获取模型列表"
}, },
"all": "全部", "all": "全部",

View File

@@ -0,0 +1,774 @@
<script setup lang="ts">
import type {llmType} from '#/api';
import type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
import {getDefaultModelAbility} from '#/views/ai/model/modelUtils/model-ability';
import {computed, onMounted, reactive, ref} from 'vue';
import {CircleCheck, CircleClose, Delete, Edit, Loading, Select,} from '@element-plus/icons-vue';
import {
ElButton,
ElEmpty,
ElIcon,
ElInput,
ElMessage,
ElMessageBox,
ElOption,
ElSelect,
ElTable,
ElTableColumn,
ElTag,
} from 'element-plus';
import {deleteLlm, getModelList, verifyModelConfig,} from '#/api/ai/llm';
import {$t} from '#/locales';
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
import {mapLlmToModelAbility} from '#/views/ai/model/modelUtils/model-ability-utils';
interface ProviderOption {
id: string;
providerName: string;
}
interface FilterState {
keyword: string;
modelType: string;
providerId: string;
}
interface BatchDeleteResult {
failed: Array<{ id: string; message: string }>;
successIds: string[];
}
const props = defineProps<{
providers: ProviderOption[];
}>();
const emit = defineEmits<{
(e: 'createModel', modelType?: string): void;
(e: 'editModel', id: string): void;
(e: 'refreshProviderStats'): void;
}>();
const isLoading = ref(false);
const isActionLoading = ref(false);
const modelRows = ref<llmType[]>([]);
const selectedRows = ref<llmType[]>([]);
const lastErrorMessage = ref('');
type VerifyButtonStatus = 'error' | 'idle' | 'loading' | 'success';
const verifyStatusMap = ref<Record<string, VerifyButtonStatus>>({});
const filterState = reactive<FilterState>({
keyword: '',
modelType: '',
providerId: '',
});
const modelTypeOptions = [
{
label: $t('llmProvider.chatModel'),
value: 'chatModel',
},
{
label: $t('llmProvider.embeddingModel'),
value: 'embeddingModel',
},
{
label: $t('llmProvider.rerankModel'),
value: 'rerankModel',
},
];
const modelTypeLabelMap: Record<string, string> = {
chatModel: $t('llmProvider.chatModel'),
embeddingModel: $t('llmProvider.embeddingModel'),
rerankModel: $t('llmProvider.rerankModel'),
};
const getProviderName = (row: llmType) =>
row.modelProvider?.providerName || row.aiLlmProvider?.providerName || '-';
const getProviderType = (row: llmType) =>
row.modelProvider?.providerType || row.aiLlmProvider?.providerType || '';
const getProviderIcon = (row: llmType) =>
row.modelProvider?.icon || row.aiLlmProvider?.icon || '';
const getModelName = (row: llmType) =>
row.llmModel || (row as any).modelName || '-';
const getModelTypeLabel = (row: llmType) =>
modelTypeLabelMap[row.modelType] || row.modelType || '-';
const canVerify = (row: llmType) => row.modelType !== 'rerankModel';
const getModelId = (row: llmType) =>
String((row as any).id || (row as any).llmId || (row as any).modelId || '');
const getVerifyStatus = (row: llmType): VerifyButtonStatus =>
verifyStatusMap.value[getModelId(row)] || 'idle';
const setVerifyStatus = (id: string, status: VerifyButtonStatus) => {
if (!id) {
return;
}
verifyStatusMap.value[id] = status;
};
const isVerifying = (row: llmType) => getVerifyStatus(row) === 'loading';
const getVerifyButtonText = (row: llmType) => {
const status = getVerifyStatus(row);
if (status === 'loading') {
return '验证中';
}
if (status === 'success') {
return '验证成功';
}
if (status === 'error') {
return '验证失败';
}
return '验证配置';
};
const getVerifyButtonIcon = (row: llmType) => {
const status = getVerifyStatus(row);
if (status === 'loading') {
return Loading;
}
if (status === 'success') {
return CircleCheck;
}
if (status === 'error') {
return CircleClose;
}
return Select;
};
const getAbilityTags = (row: llmType): ModelAbilityItem[] =>
mapLlmToModelAbility(row, getDefaultModelAbility()).filter(
(tag) => tag.selected,
);
const totalCount = computed(() => modelRows.value.length);
const filteredRows = computed(() => {
const keyword = filterState.keyword.trim().toLowerCase();
return modelRows.value.filter((item) => {
if (
filterState.providerId &&
String((item as any).providerId) !== filterState.providerId
) {
return false;
}
if (filterState.modelType && item.modelType !== filterState.modelType) {
return false;
}
if (!keyword) {
return true;
}
const searchTargets = [
item.title,
getModelName(item),
item.groupName,
getProviderName(item),
]
.filter(Boolean)
.map((text) => String(text).toLowerCase());
return searchTargets.some((text) => text.includes(keyword));
});
});
const selectableRowCount = computed(() => selectedRows.value.length);
const loadModels = async () => {
isLoading.value = true;
lastErrorMessage.value = '';
try {
const res = await getModelList();
if (res.errorCode === 0) {
modelRows.value = res.data || [];
verifyStatusMap.value = {};
} else {
modelRows.value = [];
verifyStatusMap.value = {};
lastErrorMessage.value =
res.message || $t('ui.actionMessage.operationFailed');
}
} catch (error) {
modelRows.value = [];
verifyStatusMap.value = {};
lastErrorMessage.value =
(error as Error)?.message || $t('ui.actionMessage.operationFailed');
} finally {
isLoading.value = false;
}
};
const reloadAndNotify = async () => {
await loadModels();
emit('refreshProviderStats');
selectedRows.value = [];
};
const handleSelectionChange = (rows: llmType[]) => {
selectedRows.value = rows;
};
const handleEdit = (row: llmType) => {
const modelId = getModelId(row);
if (!modelId) {
ElMessage.warning('当前模型缺少ID无法编辑');
return;
}
emit('editModel', modelId);
};
const handleDelete = async (row: llmType) => {
const modelId = getModelId(row);
if (!modelId) {
ElMessage.warning('当前模型缺少ID无法删除');
return;
}
try {
await ElMessageBox.confirm(
`确认删除模型「${row.title}」吗?该操作不可恢复。`,
$t('message.noticeTitle'),
{
cancelButtonText: $t('message.cancel'),
confirmButtonText: $t('message.ok'),
type: 'warning',
},
);
} catch {
return;
}
isActionLoading.value = true;
try {
const res = await deleteLlm({ id: modelId });
if (res.errorCode === 0) {
ElMessage.success(res.message || '模型已删除');
await reloadAndNotify();
} else {
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
}
} finally {
isActionLoading.value = false;
}
};
const handleVerify = async (row: llmType) => {
const modelId = getModelId(row);
if (!canVerify(row) || !modelId || isVerifying(row)) {
if (!modelId) {
ElMessage.warning('当前模型缺少ID无法验证配置');
}
return;
}
setVerifyStatus(modelId, 'loading');
try {
const res = await verifyModelConfig(modelId);
if (res.errorCode === 0) {
setVerifyStatus(modelId, 'success');
if (row.modelType === 'embeddingModel' && res?.data?.dimension) {
ElMessage.success(`验证成功,向量维度:${res.data.dimension}`);
} else {
ElMessage.success('验证成功');
}
} else {
setVerifyStatus(modelId, 'error');
if (!res.message) {
ElMessage.error($t('ui.actionMessage.operationFailed'));
}
}
} catch {
setVerifyStatus(modelId, 'error');
// error toast is already handled by global response interceptors
} finally {
// keep final status to show explicit success/failure state
}
};
const runBatchDelete = async (
ids: string[],
concurrency = 5,
): Promise<BatchDeleteResult> => {
const queue = [...ids];
const successIds: string[] = [];
const failed: Array<{ id: string; message: string }> = [];
const worker = async () => {
while (queue.length > 0) {
const id = queue.shift();
if (!id) {
return;
}
try {
const res = await deleteLlm({ id });
if (res.errorCode === 0) {
successIds.push(id);
} else {
failed.push({ id, message: res.message || '删除失败' });
}
} catch (error) {
failed.push({ id, message: (error as Error)?.message || '网络错误' });
}
}
};
const workerCount = Math.max(1, Math.min(concurrency, ids.length || 1));
await Promise.all(Array.from({ length: workerCount }, () => worker()));
return {
failed,
successIds,
};
};
const handleBatchDelete = async () => {
const ids = selectedRows.value
.map((item) => getModelId(item))
.filter(Boolean);
if (ids.length === 0) {
ElMessage.warning('请先选择要删除的模型');
return;
}
try {
await ElMessageBox.confirm(
`确认批量删除 ${ids.length} 个模型吗?该操作不可恢复。`,
$t('message.noticeTitle'),
{
cancelButtonText: $t('message.cancel'),
confirmButtonText: $t('message.ok'),
type: 'warning',
},
);
} catch {
return;
}
isActionLoading.value = true;
try {
const result = await runBatchDelete(ids, 5);
const successCount = result.successIds.length;
const failCount = result.failed.length;
if (failCount === 0) {
ElMessage.success(`批量删除完成,共 ${successCount} 个模型`);
} else {
ElMessage.warning(
`批量删除完成,成功 ${successCount} 个,失败 ${failCount}`,
);
}
await reloadAndNotify();
} finally {
isActionLoading.value = false;
}
};
const resetFilters = () => {
filterState.keyword = '';
filterState.providerId = '';
filterState.modelType = '';
};
onMounted(loadModels);
defineExpose({
async reloadData() {
await loadModels();
},
});
</script>
<template>
<section class="active-workspace">
<header class="active-workspace__header">
<div class="active-workspace__summary">
<h3>已配置模型</h3>
<p> {{ totalCount }} 个模型</p>
</div>
</header>
<div class="active-workspace__filters">
<ElInput
v-model.trim="filterState.keyword"
clearable
placeholder="搜索模型名、模型ID、服务商、分组"
/>
<ElSelect
v-model="filterState.providerId"
clearable
placeholder="全部服务商"
>
<ElOption
v-for="provider in props.providers"
:key="provider.id"
:label="provider.providerName"
:value="provider.id"
/>
</ElSelect>
<ElSelect
v-model="filterState.modelType"
clearable
placeholder="全部模型类型"
>
<ElOption
v-for="type in modelTypeOptions"
:key="type.value"
:label="type.label"
:value="type.value"
/>
</ElSelect>
<ElButton @click="resetFilters">重置</ElButton>
</div>
<div v-if="selectableRowCount > 0" class="active-workspace__batch-bar">
<span>已选 {{ selectableRowCount }} </span>
<div class="active-workspace__batch-actions">
<ElButton
class="is-danger"
:disabled="isActionLoading"
@click="handleBatchDelete"
>
批量删除
</ElButton>
</div>
</div>
<div v-if="isLoading" class="active-workspace__state">
正在加载模型数据...
</div>
<div v-else-if="lastErrorMessage" class="active-workspace__state is-error">
{{ lastErrorMessage }}
</div>
<div v-else-if="modelRows.length === 0" class="active-workspace__empty">
<ElEmpty description="还没有模型,先添加一个模型开始使用。">
<ElButton type="primary" @click="emit('createModel', 'chatModel')">
添加模型
</ElButton>
</ElEmpty>
</div>
<div v-else-if="filteredRows.length === 0" class="active-workspace__empty">
<ElEmpty description="没有符合筛选条件的模型,试试调整筛选项。" />
</div>
<ElTable
v-else
row-key="id"
:data="filteredRows"
class="active-workspace__table"
@selection-change="handleSelectionChange"
>
<ElTableColumn type="selection" width="48" />
<ElTableColumn label="模型名称" min-width="220">
<template #default="{ row }">
<div class="active-workspace__name-with-logo">
<ModelProviderBadge
:icon="getProviderIcon(row)"
:provider-name="getProviderName(row)"
:provider-type="getProviderType(row)"
:size="30"
/>
<div class="active-workspace__name-cell">
<strong>{{ row.title }}</strong>
<span>{{ getModelName(row) }}</span>
</div>
</div>
</template>
</ElTableColumn>
<ElTableColumn label="服务商" min-width="140">
<template #default="{ row }">
{{ getProviderName(row) }}
</template>
</ElTableColumn>
<ElTableColumn label="类型" width="110">
<template #default="{ row }">
{{ getModelTypeLabel(row) }}
</template>
</ElTableColumn>
<ElTableColumn label="分组" min-width="120">
<template #default="{ row }">
{{ row.groupName || '-' }}
</template>
</ElTableColumn>
<ElTableColumn label="能力" min-width="220">
<template #default="{ row }">
<div class="active-workspace__ability">
<ElTag
v-for="tag in getAbilityTags(row)"
:key="tag.value"
effect="plain"
size="small"
>
{{ tag.label }}
</ElTag>
<span v-if="getAbilityTags(row).length === 0">-</span>
</div>
</template>
</ElTableColumn>
<ElTableColumn label="操作" min-width="290" fixed="right">
<template #default="{ row }">
<div class="active-workspace__actions">
<ElButton
v-if="canVerify(row)"
text
size="small"
class="active-workspace__verify-btn"
:class="`is-${getVerifyStatus(row)}`"
:disabled="
isVerifying(row) || isActionLoading || !getModelId(row)
"
@click="handleVerify(row)"
>
<template #icon>
<ElIcon
class="active-workspace__verify-icon"
:class="`is-${getVerifyStatus(row)}`"
>
<component :is="getVerifyButtonIcon(row)" />
</ElIcon>
</template>
{{ getVerifyButtonText(row) }}
</ElButton>
<ElButton text size="small" :icon="Edit" @click="handleEdit(row)">
编辑
</ElButton>
<ElButton
text
size="small"
class="is-danger"
:icon="Delete"
@click="handleDelete(row)"
>
删除
</ElButton>
</div>
</template>
</ElTableColumn>
</ElTable>
</section>
</template>
<style scoped>
.active-workspace {
display: flex;
flex-direction: column;
gap: 16px;
height: 100%;
min-height: 0;
}
.active-workspace__header {
display: flex;
gap: 16px;
align-items: flex-start;
justify-content: space-between;
padding-bottom: 12px;
border-bottom: 1px solid hsl(var(--divider-faint) / 58%);
}
.active-workspace__summary h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: hsl(var(--text-strong));
}
.active-workspace__summary p,
.active-workspace__state {
margin: 6px 0 0;
font-size: 13px;
line-height: 1.6;
color: hsl(var(--text-muted));
}
.active-workspace__filters {
display: grid;
grid-template-columns: minmax(220px, 1.6fr) repeat(2, minmax(0, 1fr)) auto;
gap: 12px;
}
.active-workspace__batch-bar {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
background: hsl(var(--surface-contrast-soft) / 68%);
border: 1px solid hsl(var(--divider-faint) / 58%);
border-radius: 12px;
}
.active-workspace__batch-bar span {
font-size: 13px;
color: hsl(var(--text-muted));
}
.active-workspace__batch-actions {
display: inline-flex;
flex-wrap: wrap;
gap: 8px;
}
.active-workspace__batch-actions .is-danger,
.active-workspace__actions .is-danger {
color: hsl(var(--destructive));
}
.active-workspace__state {
padding: 14px 0;
}
.active-workspace__state.is-error {
color: hsl(var(--destructive));
}
.active-workspace__empty {
display: flex;
flex: 1;
}
.active-workspace__empty :deep(.el-empty) {
margin: auto;
}
.active-workspace__table {
flex: 1;
}
.active-workspace__name-cell {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.active-workspace__name-with-logo {
display: flex;
gap: 10px;
align-items: center;
}
.active-workspace__name-cell strong {
font-size: 14px;
font-weight: 600;
color: hsl(var(--text-strong));
}
.active-workspace__name-cell span {
font-size: 12px;
color: hsl(var(--text-muted));
}
.active-workspace__ability {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.active-workspace__actions {
display: inline-flex;
gap: 4px;
align-items: center;
}
.active-workspace__verify-btn.is-idle {
color: hsl(var(--text-muted));
}
.active-workspace__verify-btn.is-loading {
color: hsl(var(--primary));
}
.active-workspace__verify-btn.is-success {
color: hsl(var(--success));
}
.active-workspace__verify-btn.is-error {
color: hsl(var(--destructive));
}
.active-workspace__verify-icon {
transition:
color 0.24s ease,
transform 0.24s ease;
}
.active-workspace__verify-icon.is-loading {
animation: active-workspace-verify-spin 0.9s linear infinite;
}
.active-workspace__verify-icon.is-success,
.active-workspace__verify-icon.is-error {
animation: active-workspace-verify-pop 0.32s ease;
}
@keyframes active-workspace-verify-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes active-workspace-verify-pop {
0% {
opacity: 0.72;
transform: scale(0.82);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@media (max-width: 1024px) {
.active-workspace__filters {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 768px) {
.active-workspace__header {
flex-direction: column;
}
.active-workspace__filters {
grid-template-columns: minmax(0, 1fr);
}
.active-workspace__batch-bar {
flex-direction: column;
align-items: flex-start;
}
}
</style>

View File

@@ -1,31 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability'; import type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
import { reactive, ref, watch } from 'vue';
import { EasyFlowFormModal } from '@easyflow/common-ui';
import { ElForm, ElFormItem, ElInput, ElMessage, ElTag } from 'element-plus';
import { api } from '#/api/request';
import { $t } from '#/locales';
import { import {
getDefaultModelAbility, getDefaultModelAbility,
handleTagClick as handleTagClickUtil,
syncTagSelectedStatus as syncTagSelectedStatusUtil, syncTagSelectedStatus as syncTagSelectedStatusUtil,
} from '#/views/ai/model/modelUtils/model-ability'; } from '#/views/ai/model/modelUtils/model-ability';
import {computed, reactive, ref, watch} from 'vue';
import {EasyFlowFormModal} from '@easyflow/common-ui';
import {ArrowDown, ArrowUp} from '@element-plus/icons-vue';
import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage} from 'element-plus';
import {api} from '#/api/request';
import {$t} from '#/locales';
import { import {
generateFeaturesFromModelAbility, generateFeaturesFromModelAbility,
resetModelAbility, resetModelAbility,
} from '#/views/ai/model/modelUtils/model-ability-utils'; } from '#/views/ai/model/modelUtils/model-ability-utils';
interface FormData { interface FormData {
id?: string;
modelType: string; modelType: string;
title: string; title: string;
modelName: string; modelName: string;
groupName: string; groupName: string;
providerId: string; providerId: string;
provider: string;
apiKey: string; apiKey: string;
endpoint: string; endpoint: string;
requestPath: string; requestPath: string;
@@ -37,12 +37,6 @@ interface FormData {
supportVideo: boolean; supportVideo: boolean;
supportImageB64Only: boolean; supportImageB64Only: boolean;
supportToolMessage: boolean; supportToolMessage: boolean;
options: {
chatPath: string;
embedPath: string;
llmEndpoint: string;
rerankPath: string;
};
} }
const props = defineProps({ const props = defineProps({
@@ -55,7 +49,6 @@ const props = defineProps({
const emit = defineEmits(['reload']); const emit = defineEmits(['reload']);
const selectedProviderId = ref<string>(props.providerId ?? ''); const selectedProviderId = ref<string>(props.providerId ?? '');
// 监听 providerId 的变化
watch( watch(
() => props.providerId, () => props.providerId,
(newVal) => { (newVal) => {
@@ -69,15 +62,15 @@ watch(
const formDataRef = ref(); const formDataRef = ref();
const isAdd = ref(true); const isAdd = ref(true);
const dialogVisible = ref(false); const dialogVisible = ref(false);
const btnLoading = ref(false);
const showAdvanced = ref(false);
// 表单数据
const formData = reactive<FormData>({ const formData = reactive<FormData>({
modelType: '', modelType: '',
title: '', title: '',
modelName: '', modelName: '',
groupName: '', groupName: '',
providerId: '', providerId: '',
provider: '',
apiKey: '', apiKey: '',
endpoint: '', endpoint: '',
requestPath: '', requestPath: '',
@@ -88,87 +81,104 @@ const formData = reactive<FormData>({
supportFree: false, supportFree: false,
supportVideo: false, supportVideo: false,
supportImageB64Only: false, supportImageB64Only: false,
supportToolMessage: false, supportToolMessage: true,
options: {
llmEndpoint: '',
chatPath: '',
embedPath: '',
rerankPath: '',
},
}); });
// 使用抽取的函数获取模型能力配置
const modelAbility = ref<ModelAbilityItem[]>(getDefaultModelAbility()); const modelAbility = ref<ModelAbilityItem[]>(getDefaultModelAbility());
type SelectableModelType = '' | 'embeddingModel' | 'rerankModel';
const selectedModelType = ref<SelectableModelType>('');
const modelTypeAbilityOptions = [
{
label: $t('llmProvider.embeddingModel'),
value: 'embeddingModel',
},
{
label: $t('llmProvider.rerankModel'),
value: 'rerankModel',
},
] as const;
const hasSpecialModelType = computed(() => Boolean(selectedModelType.value));
/**
* 同步标签选中状态与formData中的布尔字段
*/
const syncTagSelectedStatus = () => { const syncTagSelectedStatus = () => {
syncTagSelectedStatusUtil(modelAbility.value, formData); syncTagSelectedStatusUtil(modelAbility.value, formData);
}; };
/** const resetAbilitySelection = () => {
* 处理标签点击事件 resetModelAbility(modelAbility.value);
*/ syncTagSelectedStatus();
const handleTagClick = (item: ModelAbilityItem) => {
// handleTagClickUtil(modelAbility.value, item, formData);
handleTagClickUtil(item, formData);
}; };
// 打开新增弹窗 const handleTagClick = (item: ModelAbilityItem) => {
defineExpose({ if (hasSpecialModelType.value) {
openAddDialog(modelType: string) { return;
isAdd.value = true; }
if (formDataRef.value) { item.selected = !item.selected;
formDataRef.value.resetFields(); formData[item.field] = item.selected;
} };
// 重置表单数据 const handleModelTypeChipClick = (
Object.assign(formData, { modelType: Exclude<SelectableModelType, ''>,
id: '', ) => {
modelType, const nextType = selectedModelType.value === modelType ? '' : modelType;
title: '', selectedModelType.value = nextType;
modelName: '', if (nextType) {
groupName: '', resetAbilitySelection();
provider: '', }
endPoint: '', };
providerId: '',
supportThinking: false, const isAbilityChipDisabled = () => hasSpecialModelType.value;
supportTool: false,
supportAudio: false, const resolveModelType = (): FormData['modelType'] => {
supportVideo: false, return selectedModelType.value || 'chatModel';
supportImage: false, };
supportImageB64Only: false,
supportFree: false, const resetFormData = () => {
supportToolMessage: true, Object.assign(formData, {
options: { id: '',
llmEndpoint: '', modelType: '',
chatPath: '', title: '',
embedPath: '', modelName: '',
rerankPath: '', groupName: '',
}, providerId: '',
}); apiKey: '',
showMoreFields.value = false; endpoint: '',
// 重置标签状态 requestPath: '',
resetModelAbility(modelAbility.value); supportThinking: false,
syncTagSelectedStatus(); supportTool: false,
supportAudio: false,
supportVideo: false,
supportImage: false,
supportImageB64Only: false,
supportFree: false,
supportToolMessage: true,
});
};
defineExpose({
openAddDialog() {
isAdd.value = true;
formDataRef.value?.resetFields();
resetFormData();
showAdvanced.value = false;
selectedModelType.value = '';
resetAbilitySelection();
dialogVisible.value = true; dialogVisible.value = true;
}, },
openEditDialog(item: any) { openEditDialog(item: any) {
dialogVisible.value = true; dialogVisible.value = true;
isAdd.value = false; isAdd.value = false;
resetFormData();
// 填充表单数据
Object.assign(formData, { Object.assign(formData, {
id: item.id, id: item.id,
modelType: item.modelType || '', modelType: item.modelType || '',
title: item.title || '', title: item.title || '',
modelName: item.modelName || '', modelName: item.modelName || '',
groupName: item.groupName || '', groupName: item.groupName || '',
provider: item.provider || '',
endpoint: item.endpoint || '', endpoint: item.endpoint || '',
requestPath: item.requestPath || '', requestPath: item.requestPath || '',
apiKey: item.apiKey || '',
supportThinking: item.supportThinking || false, supportThinking: item.supportThinking || false,
supportAudio: item.supportAudio || false, supportAudio: item.supportAudio || false,
supportImage: item.supportImage || false, supportImage: item.supportImage || false,
@@ -176,17 +186,21 @@ defineExpose({
supportVideo: item.supportVideo || false, supportVideo: item.supportVideo || false,
supportTool: item.supportTool || false, supportTool: item.supportTool || false,
supportFree: item.supportFree || false, supportFree: item.supportFree || false,
supportToolMessage: item.supportToolMessage || false, supportToolMessage:
options: { item.supportToolMessage === undefined ? true : item.supportToolMessage,
llmEndpoint: item.options?.llmEndpoint || '',
chatPath: item.options?.chatPath || '',
embedPath: item.options?.embedPath || '',
rerankPath: item.options?.rerankPath || '',
},
}); });
showMoreFields.value = false; selectedModelType.value =
// 同步标签状态 item.modelType === 'embeddingModel' || item.modelType === 'rerankModel'
syncTagSelectedStatus(); ? item.modelType
: '';
showAdvanced.value = Boolean(
formData.apiKey || formData.endpoint || formData.requestPath,
);
if (selectedModelType.value) {
resetAbilitySelection();
} else {
syncTagSelectedStatus();
}
}, },
}); });
@@ -195,76 +209,53 @@ const closeDialog = () => {
}; };
const rules = { const rules = {
title: [ title: [{ required: true, message: $t('message.required'), trigger: 'blur' }],
{
required: true,
message: $t('message.required'),
trigger: 'blur',
},
],
modelName: [ modelName: [
{ { required: true, message: $t('message.required'), trigger: 'blur' },
required: true,
message: $t('message.required'),
trigger: 'blur',
},
], ],
groupName: [ groupName: [
{ { required: true, message: $t('message.required'), trigger: 'blur' },
required: true,
message: $t('message.required'),
trigger: 'blur',
},
],
provider: [
{
required: true,
message: $t('message.required'),
trigger: 'blur',
},
], ],
}; };
const btnLoading = ref(false);
const save = async () => { const save = async () => {
btnLoading.value = true; btnLoading.value = true;
const modelType = resolveModelType();
// 使用工具函数从模型能力生成features
const features = generateFeaturesFromModelAbility(modelAbility.value); const features = generateFeaturesFromModelAbility(modelAbility.value);
if (modelType !== 'chatModel') {
for (const key of Object.keys(features) as Array<keyof typeof features>) {
features[key] = false;
}
}
try { try {
await formDataRef.value.validate(); await formDataRef.value.validate();
const submitData = { ...formData, ...features }; const submitData = {
...formData,
...features,
modelType,
providerId: isAdd.value ? selectedProviderId.value : formData.providerId,
};
if (isAdd.value) { const url = isAdd.value ? '/api/v1/model/save' : '/api/v1/model/update';
submitData.providerId = selectedProviderId.value; const res = await api.post(url, submitData);
const res = await api.post('/api/v1/model/save', submitData);
if (res.errorCode === 0) { if (res.errorCode === 0) {
ElMessage.success(res.message); ElMessage.success(res.message);
emit('reload'); emit('reload');
closeDialog(); closeDialog();
} else {
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
}
} else { } else {
const res = await api.post('/api/v1/model/update', submitData); ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
if (res.errorCode === 0) {
ElMessage.success(res.message);
emit('reload');
closeDialog();
} else {
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
}
} }
} catch (error) { } catch (error) {
console.error('Save model error:', error); if (!(error as any)?.fields) {
ElMessage.error($t('ui.actionMessage.operationFailed')); ElMessage.error($t('ui.actionMessage.operationFailed'));
}
} finally { } finally {
btnLoading.value = false; btnLoading.value = false;
} }
}; };
const showMoreFields = ref(false);
</script> </script>
<template> <template>
@@ -272,91 +263,240 @@ const showMoreFields = ref(false);
v-model:open="dialogVisible" v-model:open="dialogVisible"
:centered="true" :centered="true"
:closable="!btnLoading" :closable="!btnLoading"
:title="isAdd ? $t('button.add') : $t('button.edit')" :title="isAdd ? '添加模型' : '编辑模型'"
:before-close="closeDialog" :before-close="closeDialog"
width="482" width="640"
:confirm-loading="btnLoading" :confirm-loading="btnLoading"
:confirm-text="$t('button.save')" :confirm-text="$t('button.save')"
:submitting="btnLoading" :submitting="btnLoading"
@confirm="save" @confirm="save"
> >
<ElForm <div class="model-modal">
ref="formDataRef" <ElForm
:model="formData" ref="formDataRef"
status-icon :model="formData"
:rules="rules" status-icon
label-position="top" :rules="rules"
class="easyflow-modal-form easyflow-modal-form--compact" label-position="top"
> class="model-modal__form"
<ElFormItem prop="title" :label="$t('llm.title')"> >
<ElInput v-model.trim="formData.title" /> <div class="model-modal__section">
</ElFormItem> <div class="model-modal__section-head">
<ElFormItem prop="modelName" :label="$t('llm.llmModel')"> <h4>基础信息</h4>
<ElInput v-model.trim="formData.modelName" /> <p>这些字段决定模型在列表里的展示与组织方式</p>
</ElFormItem> </div>
<ElFormItem prop="groupName" :label="$t('llm.groupName')">
<ElInput v-model.trim="formData.groupName" /> <ElFormItem prop="title" :label="$t('llm.title')">
</ElFormItem> <ElInput
<ElFormItem prop="ability" :label="$t('llm.ability')"> v-model.trim="formData.title"
<div class="model-ability"> placeholder="例如:生产主模型"
<ElTag />
class="model-ability-tag" </ElFormItem>
v-for="item in modelAbility" <ElFormItem prop="modelName" :label="$t('llm.llmModel')">
:key="item.value" <ElInput
:type="item.selected ? item.activeType : item.defaultType" v-model.trim="formData.modelName"
@click="handleTagClick(item)" placeholder="例如gpt-4.1 / glm-4.5 / qwen3:8b"
:class="{ 'tag-selected': item.selected }" />
> </ElFormItem>
{{ item.label }} <ElFormItem prop="groupName" :label="$t('llm.groupName')">
</ElTag> <ElInput
v-model.trim="formData.groupName"
placeholder="例如:默认组"
/>
</ElFormItem>
</div> </div>
</ElFormItem>
<ElFormItem label=" " v-if="!showMoreFields"> <div class="model-modal__section">
<ElButton @click="showMoreFields = !showMoreFields" type="primary"> <div class="model-modal__section-head">
{{ showMoreFields ? $t('button.hide') : $t('button.more') }} <h4>{{ $t('llm.ability') }}</h4>
</ElButton> <p>可选嵌入或重排模型类型选择后其余能力会自动锁定</p>
</ElFormItem> </div>
<ElFormItem <div class="model-modal__ability">
prop="apiKey" <button
:label="$t('llmProvider.apiKey')" v-for="item in modelTypeAbilityOptions"
v-show="showMoreFields" :key="item.value"
> type="button"
<ElInput v-model.trim="formData.apiKey" /> class="model-modal__ability-chip"
</ElFormItem> :class="{ 'is-active': selectedModelType === item.value }"
<ElFormItem @click="handleModelTypeChipClick(item.value)"
prop="endpoint" >
:label="$t('llmProvider.endpoint')" {{ item.label }}
v-show="showMoreFields" </button>
> </div>
<ElInput v-model.trim="formData.endpoint" /> <div class="model-modal__ability">
</ElFormItem> <button
<ElFormItem v-for="item in modelAbility"
prop="requestPath" :key="item.value"
:label="$t('llm.requestPath')" type="button"
v-show="showMoreFields" class="model-modal__ability-chip"
> :class="{
<ElInput v-model.trim="formData.requestPath" /> 'is-active': item.selected,
</ElFormItem> 'is-disabled': isAbilityChipDisabled(),
</ElForm> }"
:disabled="isAbilityChipDisabled()"
@click="handleTagClick(item)"
>
{{ item.label }}
</button>
</div>
</div>
<div class="model-modal__section">
<button
type="button"
class="model-modal__advanced-toggle"
@click="showAdvanced = !showAdvanced"
>
<div>
<h4>高级设置</h4>
<p>仅在需要覆写服务商默认配置时填写</p>
</div>
<ElIcon>
<ArrowUp v-if="showAdvanced" />
<ArrowDown v-else />
</ElIcon>
</button>
<div v-if="showAdvanced" class="model-modal__advanced-grid">
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')">
<ElInput
v-model.trim="formData.apiKey"
type="password"
show-password
placeholder="可选,单独覆写模型密钥"
/>
</ElFormItem>
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
<ElInput
v-model.trim="formData.endpoint"
placeholder="可选,单独覆写 endpoint"
/>
</ElFormItem>
<ElFormItem prop="requestPath" :label="$t('llm.requestPath')">
<ElInput
v-model.trim="formData.requestPath"
placeholder="可选,单独覆写 requestPath"
/>
</ElFormItem>
</div>
</div>
</ElForm>
</div>
</EasyFlowFormModal> </EasyFlowFormModal>
</template> </template>
<style scoped> <style scoped>
.model-ability { .model-modal {
display: flex;
flex-direction: column;
gap: 20px;
}
.model-modal__section {
display: flex;
flex-direction: column;
gap: 14px;
padding: 20px;
background: linear-gradient(
180deg,
hsl(var(--surface-panel) / 98%) 0%,
hsl(var(--surface-contrast-soft) / 94%) 100%
);
border: 1px solid hsl(var(--divider-faint) / 50%);
border-radius: 24px;
}
.model-modal__section-head h4,
.model-modal__advanced-toggle h4 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: hsl(var(--text-strong));
}
.model-modal__section-head p,
.model-modal__advanced-toggle p {
margin: 6px 0 0;
font-size: 13px;
line-height: 1.6;
color: hsl(var(--text-muted));
}
.model-modal__form {
display: flex;
flex-direction: column;
gap: 18px;
}
.model-modal__ability {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 10px;
}
.model-modal__ability-chip {
display: inline-flex;
align-items: center; align-items: center;
margin-top: 4px; justify-content: center;
} padding: 8px 14px;
font-size: 13px;
.model-ability-tag { color: hsl(var(--text-muted));
cursor: pointer; cursor: pointer;
transition: all 0.2s; background: hsl(var(--surface-panel));
border: 1px solid hsl(var(--divider-faint) / 68%);
border-radius: 999px;
transition:
border-color 0.2s ease,
color 0.2s ease,
background 0.2s ease;
} }
.tag-selected { .model-modal__ability-chip:hover:not(:disabled),
font-weight: bold; .model-modal__ability-chip:focus-visible:not(:disabled) {
transform: scale(1.05); color: hsl(var(--text-strong));
border-color: hsl(var(--divider-faint));
}
.model-modal__ability-chip.is-active {
color: hsl(var(--text-strong));
background: hsl(var(--primary) / 8%);
border-color: hsl(var(--primary) / 38%);
}
.model-modal__ability-chip.is-disabled {
cursor: not-allowed;
opacity: 0.56;
}
.model-modal__advanced-toggle {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0;
text-align: left;
background: transparent;
border: none;
}
.model-modal__advanced-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.model-modal__advanced-grid :deep(.el-form-item:last-child) {
grid-column: 1 / -1;
}
@media (max-width: 640px) {
.model-modal__advanced-grid {
grid-template-columns: minmax(0, 1fr);
}
.model-modal__advanced-grid :deep(.el-form-item:last-child) {
grid-column: auto;
}
} }
</style> </style>

View File

@@ -1,41 +1,25 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import {computed, reactive, ref} from 'vue';
import { EasyFlowFormModal } from '@easyflow/common-ui'; import {EasyFlowFormModal} from '@easyflow/common-ui';
import { import {ArrowDown, ArrowUp} from '@element-plus/icons-vue';
ElForm, import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage, ElOption, ElSelect,} from 'element-plus';
ElFormItem,
ElInput,
ElMessage,
ElOption,
ElSelect,
} from 'element-plus';
import { api } from '#/api/request'; import {api} from '#/api/request';
import UploadAvatar from '#/components/upload/UploadAvatar.vue'; import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import { $t } from '#/locales'; import {$t} from '#/locales';
import providerList from '#/views/ai/model/modelUtils/providerList.json'; import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon';
const emit = defineEmits(['reload']); const emit = defineEmits(['reload']);
const formDataRef = ref(); const formDataRef = ref();
defineExpose({
openAddDialog() {
formDataRef.value?.resetFields();
dialogVisible.value = true;
},
openEditDialog(item: any) {
dialogVisible.value = true;
isAdd.value = false;
Object.assign(formData, item);
},
});
const providerOptions =
ref<Array<{ label: string; options: any; value: string }>>(providerList);
const isAdd = ref(true);
const dialogVisible = ref(false); const dialogVisible = ref(false);
const btnLoading = ref(false);
const isAdd = ref(true);
const showAdvanced = ref(false);
const formData = reactive({ const formData = reactive({
id: '', id: '',
icon: '', icon: '',
@@ -47,9 +31,64 @@ const formData = reactive({
embedPath: '', embedPath: '',
rerankPath: '', rerankPath: '',
}); });
const selectedPreset = computed(() =>
getProviderPresetByValue(formData.providerType),
);
const hasLegacyProvider = computed(
() => !selectedPreset.value && !!formData.providerType,
);
const getModeLabel = (mode?: 'hosted' | 'self-hosted') =>
mode === 'self-hosted' ? '自部署' : '云服务';
const resetFormData = () => {
Object.assign(formData, {
id: '',
icon: '',
providerName: '',
providerType: '',
apiKey: '',
endpoint: '',
chatPath: '',
embedPath: '',
rerankPath: '',
});
};
defineExpose({
openAddDialog() {
isAdd.value = true;
dialogVisible.value = true;
showAdvanced.value = false;
formDataRef.value?.resetFields();
resetFormData();
},
openEditDialog(item: any) {
isAdd.value = false;
dialogVisible.value = true;
showAdvanced.value = false;
formDataRef.value?.clearValidate();
resetFormData();
Object.assign(formData, {
...item,
icon: item.icon || '',
providerName: item.providerName || '',
providerType: item.providerType || '',
apiKey: item.apiKey || '',
endpoint: item.endpoint || '',
chatPath: item.chatPath || '',
embedPath: item.embedPath || '',
rerankPath: item.rerankPath || '',
});
},
});
const closeDialog = () => { const closeDialog = () => {
dialogVisible.value = false; dialogVisible.value = false;
}; };
const rules = { const rules = {
providerName: [ providerName: [
{ {
@@ -59,6 +98,20 @@ const rules = {
}, },
], ],
providerType: [ providerType: [
{
required: true,
message: $t('message.required'),
trigger: 'change',
},
],
endpoint: [
{
required: true,
message: $t('message.required'),
trigger: 'blur',
},
],
chatPath: [
{ {
required: true, required: true,
message: $t('message.required'), message: $t('message.required'),
@@ -66,48 +119,47 @@ const rules = {
}, },
], ],
}; };
const btnLoading = ref(false);
const applyPreset = (value: string) => {
const preset = getProviderPresetByValue(value);
if (!preset) {
return;
}
formData.providerType = preset.value;
formData.providerName = preset.label;
formData.endpoint = preset.options.llmEndpoint || '';
formData.chatPath = preset.options.chatPath || '';
formData.embedPath = preset.options.embedPath || '';
formData.rerankPath = preset.options.rerankPath || '';
};
const save = async () => { const save = async () => {
btnLoading.value = true; btnLoading.value = true;
try { try {
if (!isAdd.value) {
api.post('/api/v1/modelProvider/update', formData).then((res) => {
if (res.errorCode === 0) {
ElMessage.success(res.message);
emit('reload');
closeDialog();
}
});
return;
}
await formDataRef.value.validate(); await formDataRef.value.validate();
api.post('/api/v1/modelProvider/save', formData).then((res) => {
if (res.errorCode === 0) { const url = isAdd.value
ElMessage.success(res.message); ? '/api/v1/modelProvider/save'
emit('reload'); : '/api/v1/modelProvider/update';
closeDialog(); const res = await api.post(url, formData);
}
}); if (res.errorCode === 0) {
ElMessage.success(res.message || '服务商已保存');
emit('reload');
closeDialog();
} else {
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
}
} catch (error) {
if (!(error as any)?.fields) {
ElMessage.error($t('ui.actionMessage.operationFailed'));
}
} finally { } finally {
btnLoading.value = false; btnLoading.value = false;
} }
}; };
const handleChangeProvider = (val: string) => {
const tempProvider = providerList.find((item) => item.value === val);
if (!tempProvider) {
return;
}
formData.providerName = tempProvider.label;
formData.endpoint = providerOptions.value.find(
(item) => item.value === val,
)?.options.llmEndpoint;
formData.chatPath = providerOptions.value.find(
(item) => item.value === val,
)?.options.chatPath;
formData.embedPath = providerOptions.value.find(
(item) => item.value === val,
)?.options.embedPath;
};
</script> </script>
<template> <template>
@@ -115,9 +167,9 @@ const handleChangeProvider = (val: string) => {
v-model:open="dialogVisible" v-model:open="dialogVisible"
:centered="true" :centered="true"
:closable="!btnLoading" :closable="!btnLoading"
:title="isAdd ? $t('button.add') : $t('button.edit')" :title="isAdd ? '添加服务商' : '编辑服务商'"
:before-close="closeDialog" :before-close="closeDialog"
width="482" width="680"
:confirm-loading="btnLoading" :confirm-loading="btnLoading"
:confirm-text="$t('button.save')" :confirm-text="$t('button.save')"
:submitting="btnLoading" :submitting="btnLoading"
@@ -129,63 +181,259 @@ const handleChangeProvider = (val: string) => {
status-icon status-icon
:rules="rules" :rules="rules"
label-position="top" label-position="top"
class="easyflow-modal-form easyflow-modal-form--compact" class="provider-modal"
> >
<ElFormItem <section class="provider-modal__section">
prop="icon" <div class="provider-modal__section-head">
style="display: flex; align-items: center" <h3>服务商预设</h3>
:label="$t('llmProvider.icon')" <p>先选择预设系统会自动回填推荐网关与默认路径</p>
> </div>
<UploadAvatar v-model="formData.icon" />
</ElFormItem> <ElFormItem prop="providerType" :label="$t('llmProvider.apiType')">
<ElFormItem prop="providerName" :label="$t('llmProvider.providerName')"> <ElSelect
<ElInput v-model.trim="formData.providerName" /> v-model="formData.providerType"
</ElFormItem> filterable
<ElFormItem prop="provider" :label="$t('llmProvider.apiType')"> placeholder="选择一个服务商预设"
<ElSelect popper-class="provider-preset-select-dropdown"
v-model="formData.providerType" @change="applyPreset"
@change="handleChangeProvider" >
> <template #prefix>
<ElOption <ModelProviderBadge
v-for="item in providerOptions" v-if="selectedPreset"
:key="item.value" :provider-name="selectedPreset.label"
:label="item.label" :provider-type="selectedPreset.value"
:value="item.value || ''" :size="20"
/>
</template>
<ElOption
v-for="item in providerPresets"
:key="item.value"
:label="item.label"
:value="item.value"
>
<div class="provider-preset-option">
<div class="provider-preset-option__meta">
<ModelProviderBadge
:provider-name="item.label"
:provider-type="item.value"
:size="24"
/>
<strong>{{ item.label }}</strong>
</div>
<span>{{ getModeLabel(item.mode) }}</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
<div v-if="hasLegacyProvider" class="provider-modal__legacy">
当前类型为
{{
formData.providerType
}}该类型不在最新预设列表中但仍可继续编辑
</div>
</section>
<section class="provider-modal__section">
<div class="provider-modal__section-head">
<h3>基础接入</h3>
<p>先完成主流程字段名称密钥Endpoint对话路径</p>
</div>
<div class="provider-modal__grid">
<ElFormItem
prop="providerName"
:label="$t('llmProvider.providerName')"
>
<ElInput
v-model.trim="formData.providerName"
placeholder="例如OpenAI 生产环境"
/>
</ElFormItem>
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')">
<ElInput
v-model.trim="formData.apiKey"
type="password"
show-password
placeholder="填写服务商密钥"
/>
</ElFormItem>
</div>
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
<ElInput
v-model.trim="formData.endpoint"
placeholder="填写网关地址"
/> />
</ElSelect> </ElFormItem>
</ElFormItem>
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')"> <ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')">
<ElInput v-model.trim="formData.apiKey" /> <ElInput
</ElFormItem> v-model.trim="formData.chatPath"
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')"> placeholder="对话模型请求路径"
<ElInput v-model.trim="formData.endpoint" /> />
</ElFormItem> </ElFormItem>
<ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')"> </section>
<ElInput v-model.trim="formData.chatPath" />
</ElFormItem> <section class="provider-modal__section">
<ElFormItem prop="rerankPath" :label="$t('llmProvider.rerankPath')"> <button
<ElInput v-model.trim="formData.rerankPath" /> type="button"
</ElFormItem> class="provider-modal__advanced-toggle"
<ElFormItem prop="embedPath" :label="$t('llmProvider.embedPath')"> @click="showAdvanced = !showAdvanced"
<ElInput v-model.trim="formData.embedPath" /> >
</ElFormItem> <div>
<h3>高级设置</h3>
<p>包含向量/重排路径图标上传和预设说明默认收起</p>
</div>
<ElIcon>
<ArrowUp v-if="showAdvanced" />
<ArrowDown v-else />
</ElIcon>
</button>
<div v-if="showAdvanced" class="provider-modal__advanced">
<div class="provider-modal__grid">
<ElFormItem prop="embedPath" :label="$t('llmProvider.embedPath')">
<ElInput
v-model.trim="formData.embedPath"
placeholder="向量模型请求路径"
/>
</ElFormItem>
<ElFormItem prop="rerankPath" :label="$t('llmProvider.rerankPath')">
<ElInput
v-model.trim="formData.rerankPath"
placeholder="Rerank 请求路径"
/>
</ElFormItem>
</div>
<div class="provider-modal__advanced-grid">
<div class="provider-modal__icon-panel">
<h4>图标上传</h4>
<p>用于区分同一厂商在测试预发生产等不同环境</p>
<ElFormItem prop="icon" :label="$t('llmProvider.icon')">
<UploadAvatar v-model="formData.icon" />
</ElFormItem>
</div>
</div>
</div>
</section>
</ElForm> </ElForm>
</EasyFlowFormModal> </EasyFlowFormModal>
</template> </template>
<style scoped> <style scoped>
.headers-container-reduce { .provider-modal {
display: flex;
flex-direction: column;
gap: 14px;
}
.provider-modal__section {
display: flex;
flex-direction: column;
gap: 12px;
padding: 16px;
background: hsl(var(--surface-panel) / 92%);
border: 1px solid hsl(var(--divider-faint) / 54%);
border-radius: 14px;
}
.provider-modal__section-head h3,
.provider-modal__advanced-toggle h3,
.provider-modal__preset-head h4,
.provider-modal__icon-panel h4 {
margin: 0;
font-size: 15px;
font-weight: 600;
color: hsl(var(--text-strong));
}
.provider-modal__section-head p,
.provider-modal__advanced-toggle p,
.provider-modal__legacy,
.provider-modal__preset-head p,
.provider-modal__icon-panel p {
margin: 6px 0 0;
font-size: 13px;
line-height: 1.6;
color: hsl(var(--text-muted));
}
.provider-preset-option {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
}
.provider-preset-option__meta {
display: flex;
gap: 10px;
align-items: center; align-items: center;
} }
.addHeadersBtn {
.provider-preset-option strong {
font-size: 14px;
color: hsl(var(--text-strong));
}
.provider-preset-option span {
padding: 4px 8px;
font-size: 12px;
color: hsl(var(--text-muted));
background: hsl(var(--surface-contrast-soft));
border-radius: 999px;
}
.provider-modal__legacy {
padding: 10px 12px;
background: hsl(var(--warning) / 7%);
border: 1px solid hsl(var(--warning) / 26%);
border-radius: 10px;
}
.provider-modal__grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.provider-modal__advanced-toggle {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
width: 100%; width: 100%;
border-style: dashed; padding: 0;
border-color: var(--el-color-primary); text-align: left;
border-radius: 8px; background: transparent;
margin-top: 8px; border: none;
} }
.head-con-content {
margin-bottom: 8px; .provider-modal__advanced {
align-items: center; display: flex;
flex-direction: column;
gap: 14px;
}
.provider-modal__advanced-grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 12px;
}
.provider-modal__icon-panel {
padding: 12px;
background: hsl(var(--surface-contrast-soft) / 70%);
border: 1px solid hsl(var(--divider-faint) / 54%);
border-radius: 12px;
}
@media (max-width: 760px) {
.provider-modal__grid,
.provider-modal__advanced-grid {
grid-template-columns: minmax(0, 1fr);
}
} }
</style> </style>

View File

@@ -1,350 +0,0 @@
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue';
import { EasyFlowPanelModal } from '@easyflow/common-ui';
import {
CirclePlus,
Loading,
Minus,
RefreshRight,
} from '@element-plus/icons-vue';
import {
ElCollapse,
ElCollapseItem,
ElForm,
ElFormItem,
ElIcon,
ElInput,
ElMessageBox,
ElTabPane,
ElTabs,
ElTooltip,
} from 'element-plus';
import { api } from '#/api/request';
import { $t } from '#/locales';
import ModelViewItemOperation from '#/views/ai/model/ModelViewItemOperation.vue';
const emit = defineEmits(['reload']);
const tabList = ref<any>([]);
const isLoading = ref(false);
const chatModelTabList = [
// {
// label: $t('llm.all'),
// name: 'all',
// },
{
label: $t('llmProvider.chatModel'),
name: 'chatModel',
},
// {
// label: $t('llm.modelAbility.free'),
// name: 'supportFree',
// },
];
const embeddingModelTabList = [
{
label: $t('llmProvider.embeddingModel'),
name: 'embeddingModel',
},
];
const rerankModelTabList = [
{
label: $t('llmProvider.rerankModel'),
name: 'rerankModel',
},
];
const formDataRef = ref();
const providerInfo = ref<any>();
const getProviderInfo = (id: string) => {
api.get(`/api/v1/modelProvider/detail?id=${id}`).then((res) => {
if (res.errorCode === 0) {
providerInfo.value = res.data;
}
});
};
const modelList = ref<any>([]);
const getLlmList = (providerId: string, modelType: string) => {
isLoading.value = true;
const url =
modelType === ''
? `/api/v1/model/selectLlmByProviderAndModelType?providerId=${providerId}&modelType=${modelType}&supportFree=true`
: `/api/v1/model/selectLlmByProviderAndModelType?providerId=${providerId}&modelType=${modelType}&selectText=${searchFormDada.searchText}`;
api.get(url).then((res) => {
if (res.errorCode === 0) {
const chatModelMap = res.data || {};
modelList.value = Object.entries(chatModelMap).map(
([groupName, llmList]) => ({
groupName,
llmList,
}),
);
}
isLoading.value = false;
});
};
const selectedProviderId = ref('');
defineExpose({
// providerId: 供应商id clickModelType 父组件点击的是什么类型的模型 可以是chatModel or embeddingModel
openDialog(providerId: string, clickModelType: string) {
switch (clickModelType) {
case 'chatModel': {
tabList.value = [...chatModelTabList];
break;
}
case 'embeddingModel': {
tabList.value = [...embeddingModelTabList];
break;
}
case 'rerankModel': {
tabList.value = [...rerankModelTabList];
break;
}
// No default
}
selectedProviderId.value = providerId;
formDataRef.value?.resetFields();
modelList.value = [];
activeName.value = tabList.value[0]?.name;
getProviderInfo(providerId);
getLlmList(providerId, clickModelType);
dialogVisible.value = true;
},
openEditDialog(item: any) {
dialogVisible.value = true;
isAdd.value = false;
formData.icon = item.icon;
formData.providerName = item.providerName;
formData.provider = item.provider;
},
});
const isAdd = ref(true);
const dialogVisible = ref(false);
const formData = reactive({
icon: '',
providerName: '',
provider: '',
apiKey: '',
endPoint: '',
chatPath: '',
embedPath: '',
});
const closeDialog = () => {
dialogVisible.value = false;
};
const handleTabClick = async () => {
await nextTick();
getLlmList(providerInfo.value.id, activeName.value);
};
const activeName = ref('all');
const handleGroupNameDelete = (groupName: string) => {
ElMessageBox.confirm(
$t('message.deleteModelGroupAlert'),
$t('message.noticeTitle'),
{
confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'),
type: 'warning',
},
).then(() => {
api
.post(`/api/v1/model/removeByEntity`, {
groupName,
providerId: selectedProviderId.value,
})
.then((res) => {
if (res.errorCode === 0) {
getLlmList(providerInfo.value.id, activeName.value);
emit('reload');
}
});
});
};
const handleDeleteLlm = (id: any) => {
ElMessageBox.confirm(
$t('message.deleteModelAlert'),
$t('message.noticeTitle'),
{
confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'),
type: 'warning',
},
).then(() => {
api.post(`/api/v1/model/removeLlmByIds`, { id }).then((res) => {
if (res.errorCode === 0) {
getLlmList(providerInfo.value.id, activeName.value);
emit('reload');
}
});
});
};
const handleAddLlm = (id: string) => {
api
.post(`/api/v1/model/update`, {
id,
withUsed: true,
})
.then((res) => {
if (res.errorCode === 0) {
getLlmList(providerInfo.value.id, activeName.value);
emit('reload');
}
});
};
const searchFormDada = reactive({
searchText: '',
});
const handleAddAllLlm = () => {
api
.post(`/api/v1/model/addAllLlm`, {
providerId: selectedProviderId.value,
withUsed: true,
})
.then((res) => {
if (res.errorCode === 0) {
getLlmList(providerInfo.value.id, activeName.value);
emit('reload');
}
});
};
const handleRefresh = () => {
if (isLoading.value) return;
getLlmList(providerInfo.value.id, activeName.value);
};
</script>
<template>
<EasyFlowPanelModal
v-model:open="dialogVisible"
:centered="true"
:title="`${providerInfo?.providerName}${$t('llmProvider.model')}`"
:before-close="closeDialog"
width="762"
:show-footer="false"
>
<div class="manage-llm-container">
<div class="form-container">
<ElForm ref="formDataRef" :model="searchFormDada" status-icon>
<ElFormItem prop="searchText">
<div class="search-container">
<ElInput
v-model.trim="searchFormDada.searchText"
@input="handleRefresh"
:placeholder="$t('llm.searchTextPlaceholder')"
/>
<ElTooltip
:content="$t('llm.button.addAllLlm')"
placement="top"
effect="dark"
>
<ElIcon
size="20"
@click="handleAddAllLlm"
class="cursor-pointer"
>
<CirclePlus />
</ElIcon>
</ElTooltip>
<ElTooltip
:content="$t('llm.button.RetrieveAgain')"
placement="top"
effect="dark"
>
<ElIcon size="20" @click="handleRefresh" class="cursor-pointer">
<RefreshRight />
</ElIcon>
</ElTooltip>
</div>
</ElFormItem>
</ElForm>
</div>
<div class="llm-table-container">
<ElTabs v-model="activeName" @tab-click="handleTabClick">
<ElTabPane
:label="item.label"
:name="item.name"
v-for="item in tabList"
default-active="all"
:key="item.name"
>
<div v-if="isLoading" class="collapse-loading">
<ElIcon class="is-loading" size="24">
<Loading />
</ElIcon>
</div>
<div v-else>
<ElCollapse
expand-icon-position="left"
v-if="modelList.length > 0"
>
<ElCollapseItem
v-for="group in modelList"
:key="group.groupName"
:title="group.groupName"
:name="group.groupName"
>
<template #title>
<div class="flex items-center justify-between pr-2">
<span>{{ group.groupName }}</span>
<span>
<ElIcon
@click.stop="handleGroupNameDelete(group.groupName)"
>
<Minus />
</ElIcon>
</span>
</div>
</template>
<ModelViewItemOperation
:need-hidden-setting-icon="true"
:llm-list="group.llmList"
@delete-llm="handleDeleteLlm"
@add-llm="handleAddLlm"
:is-management="true"
/>
</ElCollapseItem>
</ElCollapse>
</div>
</ElTabPane>
</ElTabs>
</div>
</div>
</EasyFlowPanelModal>
</template>
<style scoped>
.manage-llm-container {
height: 540px;
display: flex;
flex-direction: column;
gap: 12px;
}
.form-container {
height: 30px;
}
.search-container {
width: 100%;
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
}
.llm-table-container {
flex: 1;
}
.collapse-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
gap: 12px;
color: var(--el-text-color-secondary);
}
:deep(.el-tabs__nav-wrap::after) {
height: 1px !important;
background-color: #e4e7ed !important;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
<script setup lang="ts">
import {computed} from 'vue';
import {ElImage} from 'element-plus';
import {
getIconByValue,
getProviderBadgeText,
isSvgString,
} from '#/views/ai/model/modelUtils/defaultIcon';
const props = withDefaults(
defineProps<{
icon?: string;
providerName?: string;
providerType?: string;
size?: number;
}>(),
{
icon: '',
providerName: '',
providerType: '',
size: 40,
},
);
const presetIcon = computed(() => getIconByValue(props.providerType));
const resolvedSvg = computed(() => {
if (presetIcon.value && isSvgString(presetIcon.value)) {
return presetIcon.value;
}
return isSvgString(props.icon) ? props.icon : '';
});
const resolvedImage = computed(() => {
if (props.icon && !isSvgString(props.icon)) {
return props.icon;
}
return presetIcon.value && !isSvgString(presetIcon.value)
? presetIcon.value
: '';
});
const badgeText = computed(() =>
getProviderBadgeText(props.providerName, props.providerType),
);
const badgeStyle = computed(() => ({
width: `${props.size}px`,
height: `${props.size}px`,
}));
</script>
<template>
<div class="provider-badge" :style="badgeStyle" :aria-hidden="true">
<ElImage
v-if="resolvedImage"
:src="resolvedImage"
fit="contain"
class="provider-badge__image"
/>
<!-- eslint-disable vue/no-v-html -->
<div
v-else-if="resolvedSvg"
class="provider-badge__svg"
v-html="resolvedSvg"
></div>
<!-- eslint-enable vue/no-v-html -->
<div v-else class="provider-badge__fallback" :title="badgeText">
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="7" cy="7" r="2.5" />
<circle cx="17" cy="7" r="2.5" />
<circle cx="12" cy="17" r="2.5" />
<path d="M8.9 8.4L10.6 12" />
<path d="M15.1 8.4L13.4 12" />
<path d="M9.2 16h5.6" />
</svg>
</div>
</div>
</template>
<style scoped>
.provider-badge {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
overflow: hidden;
background: linear-gradient(
145deg,
hsl(var(--surface-contrast-soft) / 96%) 0%,
hsl(var(--surface-panel) / 98%) 100%
);
border: 1px solid hsl(var(--glass-border) / 58%);
border-radius: 14px;
box-shadow: 0 12px 26px -22px hsl(var(--foreground) / 30%);
}
.provider-badge__image,
.provider-badge__svg {
width: 100%;
height: 100%;
}
.provider-badge__image {
padding: 10%;
}
.provider-badge__image :deep(img) {
object-fit: contain;
}
.provider-badge__svg {
padding: 16%;
}
.provider-badge__svg :deep(svg) {
display: block;
width: 100%;
height: 100%;
}
.provider-badge__fallback {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: hsl(var(--text-strong));
}
.provider-badge__fallback svg {
width: 58%;
height: 58%;
}
.provider-badge__fallback circle,
.provider-badge__fallback path {
stroke: currentcolor;
stroke-width: 1.8;
stroke-linecap: round;
stroke-linejoin: round;
}
.provider-badge__fallback circle {
fill: hsl(var(--surface-panel));
}
.provider-badge__fallback path {
fill: none;
}
</style>

View File

@@ -1,44 +1,61 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue'; import {computed, reactive, ref} from 'vue';
import { EasyFlowFormModal } from '@easyflow/common-ui'; import {EasyFlowFormModal} from '@easyflow/common-ui';
import { import {CircleCheckFilled, WarningFilled} from '@element-plus/icons-vue';
ElForm, import {ElForm, ElFormItem, ElMessage, ElOption, ElSelect,} from 'element-plus';
ElFormItem,
ElMessage,
ElOption,
ElSelect,
} from 'element-plus';
import { api } from '#/api/request'; import {api} from '#/api/request';
import { $t } from '#/locales'; import {$t} from '#/locales';
type VerifyStatus = 'error' | 'idle' | 'success';
const options = ref<any[]>([]); const options = ref<any[]>([]);
const getLlmList = (providerId: string) => {
api.get(`/api/v1/model/list?providerId=${providerId}`, {}).then((res) => {
if (res.errorCode === 0) {
options.value = res.data;
}
});
};
const modelType = ref(''); const modelType = ref('');
const vectorDimension = ref(''); const vectorDimension = ref('');
const verifyStatus = ref<VerifyStatus>('idle');
const verifyMessage = ref('');
const formDataRef = ref(); const formDataRef = ref();
const dialogVisible = ref(false); const dialogVisible = ref(false);
defineExpose({ const btnLoading = ref(false);
openDialog(providerId: string) {
formDataRef.value?.resetFields();
modelType.value = '';
vectorDimension.value = '';
getLlmList(providerId);
dialogVisible.value = true;
},
});
const formData = reactive({ const formData = reactive({
llmId: '', llmId: '',
}); });
const resultTitle = computed(() => {
if (verifyStatus.value === 'success') {
return '验证成功';
}
if (verifyStatus.value === 'error') {
return '验证失败';
}
return '等待验证';
});
const getLlmList = async (providerId: string) => {
const res = await api.get(`/api/v1/model/list?providerId=${providerId}`, {});
if (res.errorCode === 0) {
options.value = res.data;
}
};
defineExpose({
async openDialog(providerId: string) {
formDataRef.value?.resetFields();
formData.llmId = '';
modelType.value = '';
vectorDimension.value = '';
verifyStatus.value = 'idle';
verifyMessage.value = '请选择一个模型并开始验证。';
await getLlmList(providerId);
dialogVisible.value = true;
},
});
const rules = { const rules = {
llmId: [ llmId: [
{ {
@@ -49,28 +66,51 @@ const rules = {
], ],
}; };
const getModelInfo = (id: string) => {
const current = options.value.find((item: any) => item.id === id);
modelType.value = current?.modelType || '';
vectorDimension.value = '';
verifyStatus.value = 'idle';
verifyMessage.value = '已更新待验证模型,点击确认开始检测配置。';
};
const save = async () => { const save = async () => {
btnLoading.value = true; btnLoading.value = true;
await formDataRef.value.validate(); verifyStatus.value = 'idle';
api verifyMessage.value = '正在连接模型服务,请稍候...';
.get(`/api/v1/model/verifyLlmConfig?id=${formData.llmId}`, {})
.then((res) => { try {
if (res.errorCode === 0) { await formDataRef.value.validate();
ElMessage.success($t('llm.testSuccess')); const res = await api.get(
if (modelType.value === 'embeddingModel' && res?.data?.dimension) { `/api/v1/model/verifyLlmConfig?id=${formData.llmId}`,
vectorDimension.value = res?.data?.dimension; {},
} );
if (res.errorCode === 0) {
verifyStatus.value = 'success';
verifyMessage.value = $t('llm.testSuccess');
ElMessage.success($t('llm.testSuccess'));
if (modelType.value === 'embeddingModel' && res?.data?.dimension) {
vectorDimension.value = res.data.dimension;
} }
btnLoading.value = false; } else {
}); verifyStatus.value = 'error';
}; verifyMessage.value =
const btnLoading = ref(false); res.message || $t('ui.actionMessage.operationFailed');
const getModelInfo = (id: string) => { ElMessage.error(verifyMessage.value);
options.value.forEach((item: any) => {
if (item.id === id) {
modelType.value = item.modelType;
} }
}); } catch (error: any) {
if (error?.fields) {
verifyMessage.value = '请选择一个模型并开始验证。';
return;
}
verifyStatus.value = 'error';
verifyMessage.value =
error?.message || $t('ui.actionMessage.operationFailed');
} finally {
btnLoading.value = false;
}
}; };
</script> </script>
@@ -80,54 +120,147 @@ const getModelInfo = (id: string) => {
:centered="true" :centered="true"
:closable="!btnLoading" :closable="!btnLoading"
:title="$t('llm.verifyLlmTitle')" :title="$t('llm.verifyLlmTitle')"
width="482" width="560"
:confirm-loading="btnLoading" :confirm-loading="btnLoading"
:confirm-text="$t('button.confirm')" :confirm-text="$t('button.confirm')"
:submitting="btnLoading" :submitting="btnLoading"
@confirm="save" @confirm="save"
> >
<ElForm <div class="verify-modal">
ref="formDataRef" <section class="verify-modal__section">
:model="formData" <div class="verify-modal__section-head">
status-icon <h3>1. 选择待验证模型</h3>
:rules="rules" <p>
label-position="top" 会用当前保存的服务商配置发起一次真实请求帮助你确认密钥和路径是否正确
class="easyflow-modal-form easyflow-modal-form--compact" </p>
> </div>
<ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
<ElSelect v-model="formData.llmId" @change="getModelInfo"> <ElForm
<ElOption ref="formDataRef"
v-for="item in options" :model="formData"
:key="item.id" status-icon
:label="item.title" :rules="rules"
:value="item.id || ''" label-position="top"
/> class="verify-modal__form"
</ElSelect> >
</ElFormItem> <ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
<ElFormItem <ElSelect
v-if="modelType === 'embeddingModel' && vectorDimension" v-model="formData.llmId"
:label="$t('documentCollection.dimensionOfVectorModel')" filterable
label-width="100px" placeholder="选择一个模型"
> @change="getModelInfo"
{{ vectorDimension }} >
</ElFormItem> <ElOption
</ElForm> v-for="item in options"
:key="item.id"
:label="item.title"
:value="item.id || ''"
/>
</ElSelect>
</ElFormItem>
</ElForm>
</section>
<section class="verify-modal__section verify-modal__section--result">
<div class="verify-modal__section-head">
<h3>2. 查看验证结果</h3>
<p>成功后会返回可用状态如果是向量模型还会展示向量维度</p>
</div>
<div
class="verify-result-card"
:class="{
'is-success': verifyStatus === 'success',
'is-error': verifyStatus === 'error',
}"
>
<div class="verify-result-card__icon">
<CircleCheckFilled v-if="verifyStatus === 'success'" />
<WarningFilled v-else />
</div>
<div class="verify-result-card__content">
<h4>{{ resultTitle }}</h4>
<p>{{ verifyMessage }}</p>
<div
v-if="modelType === 'embeddingModel' && vectorDimension"
class="verify-result-card__meta"
>
向量维度{{ vectorDimension }}
</div>
</div>
</div>
</section>
</div>
</EasyFlowFormModal> </EasyFlowFormModal>
</template> </template>
<style scoped> <style scoped>
.headers-container-reduce { .verify-modal {
align-items: center; display: flex;
flex-direction: column;
gap: 20px;
} }
.addHeadersBtn {
width: 100%; .verify-modal__section {
border-style: dashed; display: flex;
border-color: var(--el-color-primary); flex-direction: column;
border-radius: 8px; gap: 14px;
margin-top: 8px; padding: 20px;
background: linear-gradient(
180deg,
hsl(var(--surface-panel) / 98%) 0%,
hsl(var(--surface-contrast-soft) / 94%) 100%
);
border: 1px solid hsl(var(--divider-faint) / 50%);
border-radius: 24px;
} }
.head-con-content {
margin-bottom: 8px; .verify-modal__section-head h3,
.verify-result-card__content h4 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: hsl(var(--text-strong));
}
.verify-modal__section-head p,
.verify-result-card__content p,
.verify-result-card__meta {
margin: 6px 0 0;
font-size: 13px;
line-height: 1.6;
color: hsl(var(--text-muted));
}
.verify-result-card {
display: flex;
gap: 14px;
align-items: flex-start;
padding: 18px;
background: hsl(var(--surface-panel) / 90%);
border: 1px solid hsl(var(--divider-faint) / 56%);
border-radius: 20px;
}
.verify-result-card.is-success {
background: hsl(var(--success) / 6%);
border-color: hsl(var(--success) / 36%);
}
.verify-result-card.is-error {
background: hsl(var(--destructive) / 5%);
border-color: hsl(var(--destructive) / 36%);
}
.verify-result-card__icon {
display: inline-flex;
align-items: center; align-items: center;
justify-content: center;
width: 36px;
height: 36px;
font-size: 18px;
color: hsl(var(--text-strong));
background: hsl(var(--surface-contrast-soft));
border-radius: 999px;
} }
</style> </style>

View File

@@ -1,201 +1,377 @@
<script setup lang="ts"> <script setup lang="ts">
import type { PropType } from 'vue'; import type {PropType} from 'vue';
import {ref} from 'vue';
import type { llmType } from '#/api'; import type {llmType} from '#/api';
import type { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability'; import type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
import {getDefaultModelAbility} from '#/views/ai/model/modelUtils/model-ability';
import { Minus, Plus, Setting } from '@element-plus/icons-vue'; import {CircleCheck, CircleClose, Delete, Edit, Loading, Select,} from '@element-plus/icons-vue';
import { ElIcon, ElImage, ElTag } from 'element-plus'; import {ElButton, ElIcon, ElMessage, ElTag} from 'element-plus';
import { getIconByValue } from '#/views/ai/model/modelUtils/defaultIcon'; import {verifyModelConfig} from '#/api/ai/llm';
import { getDefaultModelAbility } from '#/views/ai/model/modelUtils/model-ability'; import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
import { mapLlmToModelAbility } from '#/views/ai/model/modelUtils/model-ability-utils'; import {mapLlmToModelAbility} from '#/views/ai/model/modelUtils/model-ability-utils';
defineProps({ const props = defineProps({
llmList: { llmList: {
type: Array as PropType<llmType[]>, type: Array as PropType<llmType[]>,
default: () => [], default: () => [],
}, },
icon: {
type: String,
default: '',
},
needHiddenSettingIcon: { needHiddenSettingIcon: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
isManagement: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(['deleteLlm', 'editLlm', 'addLlm', 'updateWithUsed']); const emit = defineEmits(['deleteLlm', 'editLlm']);
type VerifyButtonStatus = 'error' | 'idle' | 'loading' | 'success';
const verifyStatusMap = ref<Record<string, VerifyButtonStatus>>({});
const getModelId = (llm: llmType) =>
String((llm as any).id || (llm as any).llmId || (llm as any).modelId || '');
const getVerifyStatus = (llm: llmType): VerifyButtonStatus =>
verifyStatusMap.value[getModelId(llm)] || 'idle';
const isVerifying = (llm: llmType) => getVerifyStatus(llm) === 'loading';
const setVerifyStatus = (id: string, status: VerifyButtonStatus) => {
if (!id) {
return;
}
verifyStatusMap.value[id] = status;
};
const getVerifyButtonText = (llm: llmType) => {
const status = getVerifyStatus(llm);
if (status === 'loading') {
return '验证中';
}
if (status === 'success') {
return '验证成功';
}
if (status === 'error') {
return '验证失败';
}
return '验证配置';
};
const getVerifyButtonIcon = (llm: llmType) => {
const status = getVerifyStatus(llm);
if (status === 'loading') {
return Loading;
}
if (status === 'success') {
return CircleCheck;
}
if (status === 'error') {
return CircleClose;
}
return Select;
};
const handleDeleteLlm = (id: string) => { const handleDeleteLlm = (id: string) => {
emit('deleteLlm', id); emit('deleteLlm', id);
}; };
const handleAddLlm = (id: string) => {
emit('addLlm', id);
};
const handleEditLlm = (id: string) => { const handleEditLlm = (id: string) => {
emit('editLlm', id); emit('editLlm', id);
}; };
// 修改该模型为未使用状态修改数据库的with_used字段为false const canVerify = (llm: llmType) => llm.modelType !== 'rerankModel';
const handleUpdateWithUsedLlm = (id: string) => {
emit('updateWithUsed', id); const handleVerifyLlm = async (llm: llmType) => {
const modelId = getModelId(llm);
if (!modelId || isVerifying(llm)) {
if (!modelId) {
ElMessage.warning('当前模型缺少ID无法验证配置');
}
return;
}
setVerifyStatus(modelId, 'loading');
try {
const res = await verifyModelConfig(modelId);
if (res.errorCode === 0) {
setVerifyStatus(modelId, 'success');
if (llm.modelType === 'embeddingModel' && res?.data?.dimension) {
ElMessage.success(`验证成功,向量维度:${res.data.dimension}`);
} else {
ElMessage.success('验证成功');
}
} else {
setVerifyStatus(modelId, 'error');
if (!res.message) {
ElMessage.error('验证失败');
}
}
} catch {
setVerifyStatus(modelId, 'error');
// error toast is already handled by global response interceptors
} finally {
// keep final status for explicit visual feedback
}
}; };
/**
* 获取LLM支持的选中的能力标签
* 只返回 selected 为 true 的标签
*/
const getSelectedAbilityTagsForLlm = (llm: llmType): ModelAbilityItem[] => { const getSelectedAbilityTagsForLlm = (llm: llmType): ModelAbilityItem[] => {
const defaultAbility = getDefaultModelAbility(); const defaultAbility = getDefaultModelAbility();
const allTags = mapLlmToModelAbility(llm, defaultAbility); const allTags = mapLlmToModelAbility(llm, defaultAbility);
return allTags.filter((tag) => tag.selected); return allTags.filter((tag) => tag.selected);
}; };
const getModelMeta = (llm: llmType) => {
const providerName =
llm?.modelProvider?.providerName || llm?.aiLlmProvider?.providerName || '';
const modelName = llm.llmModel || llm.title;
return `${providerName} · ${modelName}`;
};
</script> </script>
<template> <template>
<div v-for="llm in llmList" :key="llm.id" class="container"> <div class="llm-list">
<div class="llm-item"> <article v-for="llm in props.llmList" :key="llm.id" class="llm-item">
<div class="start"> <div class="llm-item__main">
<ElImage <ModelProviderBadge
v-if="llm.modelProvider.icon" :icon="llm.modelProvider?.icon"
:src="llm.modelProvider.icon" :provider-name="llm.modelProvider?.providerName"
style="width: 21px; height: 21px" :provider-type="llm.modelProvider?.providerType"
:size="40"
/> />
<div class="llm-item__content">
<div <div class="llm-item__headline">
v-else <h4 class="llm-item__title">{{ llm.title }}</h4>
v-html="getIconByValue(llm.modelProvider.providerType)" <div
:style="{ v-if="getSelectedAbilityTagsForLlm(llm).length > 0"
width: '21px', class="llm-item__tags"
height: '21px', >
display: 'flex', <ElTag
alignItems: 'center', v-for="tag in getSelectedAbilityTagsForLlm(llm)"
justifyContent: 'center', :key="tag.value"
overflow: 'hidden', effect="plain"
}" size="small"
class="svg-container" class="llm-item__tag"
></div> >
{{ tag.label }}
<div>{{ llm?.modelProvider?.providerName }}/{{ llm.title }}</div> </ElTag>
</div>
<!-- 模型能力 --> </div>
<div <p class="llm-item__meta">{{ getModelMeta(llm) }}</p>
v-if="getSelectedAbilityTagsForLlm(llm).length > 0" <p v-if="llm.description" class="llm-item__description">
class="ability-tags" {{ llm.description }}
> </p>
<ElTag
v-for="tag in getSelectedAbilityTagsForLlm(llm)"
:key="tag.value"
class="ability-tag"
:type="tag.activeType"
size="small"
>
{{ tag.label }}
</ElTag>
</div> </div>
</div> </div>
<div class="end">
<ElIcon
v-if="!needHiddenSettingIcon"
size="16"
@click="handleEditLlm(llm.id)"
style="cursor: pointer"
>
<Setting />
</ElIcon>
<template v-if="!isManagement">
<ElIcon
size="16"
@click="handleUpdateWithUsedLlm(llm.id)"
style="cursor: pointer"
>
<Minus />
</ElIcon>
</template>
<template v-if="isManagement"> <div class="llm-item__actions">
<ElIcon <ElButton
v-if="llm.withUsed" v-if="canVerify(llm)"
size="16" text
@click="handleDeleteLlm(llm.id)" size="small"
style="cursor: pointer" class="llm-item__verify-btn"
> :class="`is-${getVerifyStatus(llm)}`"
<Minus /> :disabled="isVerifying(llm) || !getModelId(llm)"
</ElIcon> @click="handleVerifyLlm(llm)"
<ElIcon >
v-else <template #icon>
size="16" <ElIcon
@click="handleAddLlm(llm.id)" class="llm-item__verify-icon"
style="cursor: pointer" :class="`is-${getVerifyStatus(llm)}`"
> >
<Plus /> <component :is="getVerifyButtonIcon(llm)" />
</ElIcon> </ElIcon>
</template> </template>
{{ getVerifyButtonText(llm) }}
</ElButton>
<ElButton
v-if="!needHiddenSettingIcon"
text
size="small"
:icon="Edit"
@click="handleEditLlm(llm.id)"
>
编辑
</ElButton>
<ElButton
text
size="small"
:icon="Delete"
class="llm-item__danger"
@click="handleDeleteLlm(llm.id)"
>
删除
</ElButton>
</div> </div>
</div> </article>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.llm-item { .llm-list {
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
}
.container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px;
}
.llm-item {
display: flex;
gap: 16px;
align-items: flex-start;
justify-content: space-between;
padding: 16px 18px;
background: hsl(var(--surface-panel) / 90%);
border: 1px solid hsl(var(--divider-faint) / 54%);
border-radius: 18px;
transition:
border-color 0.2s ease,
transform 0.2s ease,
box-shadow 0.2s ease;
}
.llm-item:hover {
border-color: hsl(var(--primary) / 28%);
box-shadow: 0 18px 30px -28px hsl(var(--foreground) / 34%);
transform: translateY(-1px);
}
.llm-item__main {
display: flex;
flex: 1;
gap: 14px;
align-items: flex-start;
min-width: 0;
}
.llm-item__content {
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.llm-item__headline {
display: flex;
flex-wrap: wrap;
gap: 8px; gap: 8px;
padding: 12px 18px;
border-bottom: 1px solid #e4e7ed;
}
.container:last-child {
border-bottom: none;
}
.start {
display: flex;
align-items: center; align-items: center;
gap: 12px;
font-weight: 500;
} }
.end { .llm-item__title {
display: flex; margin: 0;
align-items: center; font-size: 15px;
gap: 12px; font-weight: 600;
line-height: 1.4;
color: hsl(var(--text-strong));
} }
.ability-tags { .llm-item__meta,
.llm-item__description {
margin: 0;
font-size: 13px;
line-height: 1.5;
color: hsl(var(--text-muted));
}
.llm-item__description {
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.llm-item__tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 6px; gap: 6px;
} }
.ability-tag { .llm-item__tag {
cursor: default; color: hsl(var(--text-strong));
user-select: none; background: hsl(var(--primary) / 8%);
border-color: transparent;
} }
.svg-container { .llm-item__actions {
display: flex; display: inline-flex;
flex-wrap: wrap;
gap: 4px;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-end;
} }
.svg-container :deep(svg) { .llm-item__actions :deep(.el-button) {
width: 21px; border-radius: 10px;
height: 21px; }
.llm-item__verify-btn.is-idle {
color: hsl(var(--text-muted));
}
.llm-item__verify-btn.is-loading {
color: hsl(var(--primary));
}
.llm-item__verify-btn.is-success {
color: hsl(var(--success));
}
.llm-item__verify-btn.is-error {
color: hsl(var(--destructive));
}
.llm-item__verify-icon {
transition:
color 0.24s ease,
transform 0.24s ease;
}
.llm-item__verify-icon.is-loading {
animation: llm-item-verify-spin 0.9s linear infinite;
}
.llm-item__verify-icon.is-success,
.llm-item__verify-icon.is-error {
animation: llm-item-verify-pop 0.32s ease;
}
.llm-item__danger {
color: hsl(var(--danger) / 90%);
}
.llm-item__danger:hover,
.llm-item__danger:focus-visible {
color: hsl(var(--danger));
}
@keyframes llm-item-verify-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes llm-item-verify-pop {
0% {
opacity: 0.72;
transform: scale(0.82);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@media (max-width: 768px) {
.llm-item {
flex-direction: column;
}
.llm-item__actions {
justify-content: flex-start;
width: 100%;
}
} }
</style> </style>

View File

@@ -0,0 +1,17 @@
import {describe, expect, it} from 'vitest';
import {getProviderBadgeText, getProviderPresetByValue} from '../defaultIcon';
describe('defaultIcon helpers', () => {
it('可以读取新的服务商预设', () => {
const preset = getProviderPresetByValue('self-hosted');
expect(preset?.label).toBe('自部署');
expect(preset?.mode).toBe('self-hosted');
});
it('未知服务商类型会回退到 providerName 文本', () => {
expect(getProviderBadgeText('历史服务商', 'legacy')).toBe('历史');
expect(getProviderBadgeText('', 'legacy-provider')).toBe('LE');
});
});

View File

@@ -0,0 +1,67 @@
import {describe, expect, it} from 'vitest';
import {
createProviderDraft,
getProviderConfigMetrics,
isProviderDraftDirty,
} from '../providerDraft';
describe('providerDraft helpers', () => {
it('相同配置不会被识别为脏数据', () => {
const provider = {
apiKey: 'key',
endpoint: 'https://api.example.com',
chatPath: '/v1/chat/completions',
embedPath: '/v1/embeddings',
rerankPath: '',
};
expect(isProviderDraftDirty(provider, createProviderDraft(provider))).toBe(
false,
);
});
it('修改任一关键字段后会被识别为脏数据', () => {
const provider = {
apiKey: 'key',
endpoint: 'https://api.example.com',
chatPath: '/v1/chat/completions',
embedPath: '',
rerankPath: '',
};
expect(
isProviderDraftDirty(provider, {
...createProviderDraft(provider),
apiKey: 'next-key',
}),
).toBe(true);
});
it('会根据预设路径计算配置完成度', () => {
const metrics = getProviderConfigMetrics(
{
apiKey: 'key',
endpoint: 'https://api.example.com',
chatPath: '/v1/chat/completions',
embedPath: '/v1/embeddings',
rerankPath: '',
},
{
label: '示例',
value: 'demo',
description: '',
icon: '',
mode: 'hosted',
options: {
chatPath: '/v1/chat/completions',
embedPath: '/v1/embeddings',
},
},
);
expect(metrics.completed).toBe(4);
expect(metrics.total).toBe(4);
expect(metrics.complete).toBe(true);
});
});

View File

@@ -1,27 +1,66 @@
import { ref } from 'vue';
import providerList from './providerList.json'; import providerList from './providerList.json';
const providerOptions = export interface ProviderModelPreset {
ref<Array<{ icon: string; label: string; options: any; value: string }>>( description: string;
providerList, label: string;
); llmModel: string;
supportChat?: boolean;
supportEmbed?: boolean;
supportFunctionCalling?: boolean;
supportRerank?: boolean;
}
export interface ProviderPreset {
description: string;
icon: string;
label: string;
mode: 'hosted' | 'self-hosted';
options: {
chatPath?: string;
embedPath?: string;
llmEndpoint?: string;
modelList?: ProviderModelPreset[];
rerankPath?: string;
};
tags?: string[];
value: string;
}
const providerOptions = providerList as ProviderPreset[];
export const getProviderPresetByValue = (targetValue?: string) =>
providerOptions.find((item) => item.value === targetValue);
/** /**
* 根据传入的value返回对应的icon属性 * 根据传入的value返回对应的icon属性
* @param targetValue 要匹配的value值 * @param targetValue 要匹配的value值
* @returns 匹配到的icon字符串未匹配到返回空字符串 * @returns 匹配到的icon字符串未匹配到返回空字符串
*/ */
export const getIconByValue = (targetValue: string): string => { export const getIconByValue = (targetValue: string): string =>
const matchItem = providerOptions.value.find( getProviderPresetByValue(targetValue)?.icon || '';
(item) => item.value === targetValue,
);
return matchItem?.icon || '';
};
export const isSvgString = (icon: any) => { export const isSvgString = (icon: any) => {
if (typeof icon !== 'string') return false; if (typeof icon !== 'string') return false;
// 简单判断:是否包含 SVG 根标签 // 简单判断:是否包含 SVG 根标签
return icon.trim().startsWith('<svg') && icon.trim().endsWith('</svg>'); return icon.trim().startsWith('<svg') && icon.trim().endsWith('</svg>');
}; };
export const getProviderBadgeText = (
providerName?: string,
providerType?: string,
) => {
const preset = getProviderPresetByValue(providerType);
const source = providerName || preset?.label || providerType || 'AI';
const ascii = source
.replaceAll(/[^a-z]/gi, '')
.slice(0, 2)
.toUpperCase();
if (ascii) {
return ascii;
}
return source.replaceAll(/\s+/g, '').slice(0, 2).toUpperCase();
};
export const providerPresets = providerOptions;

View File

@@ -0,0 +1,72 @@
import type {ProviderPreset} from './defaultIcon';
export const PROVIDER_EDITABLE_FIELDS = [
'apiKey',
'endpoint',
'chatPath',
'embedPath',
'rerankPath',
] as const;
export type ProviderEditableField = (typeof PROVIDER_EDITABLE_FIELDS)[number];
export interface ProviderDraft {
apiKey: string;
endpoint: string;
chatPath: string;
embedPath: string;
rerankPath: string;
}
type ProviderLike = Partial<Record<ProviderEditableField, string>> & {
providerType?: string;
};
export const createProviderDraft = (
provider?: null | ProviderLike,
): ProviderDraft => ({
apiKey: provider?.apiKey || '',
endpoint: provider?.endpoint || '',
chatPath: provider?.chatPath || '',
embedPath: provider?.embedPath || '',
rerankPath: provider?.rerankPath || '',
});
export const isProviderDraftDirty = (
provider?: null | ProviderLike,
draft?: null | ProviderLike,
) =>
PROVIDER_EDITABLE_FIELDS.some(
(field) => (provider?.[field] || '') !== (draft?.[field] || ''),
);
export const getProviderConfigMetrics = (
provider?: null | ProviderLike,
preset?: ProviderPreset,
) => {
const requiredFields: ProviderEditableField[] = [
'apiKey',
'endpoint',
'chatPath',
];
if (preset?.options?.embedPath || provider?.embedPath) {
requiredFields.push('embedPath');
}
if (preset?.options?.rerankPath || provider?.rerankPath) {
requiredFields.push('rerankPath');
}
const completed = requiredFields.filter((field) =>
Boolean((provider?.[field] || '').trim()),
).length;
const total = requiredFields.length;
return {
completed,
total,
ratio: total === 0 ? 0 : Math.round((completed / total) * 100),
complete: total > 0 && completed === total,
};
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,152 @@
import {mount} from '@vue/test-utils';
import {nextTick} from 'vue';
import {beforeEach, describe, expect, it, vi} from 'vitest';
import AuthenticationLogin from '../login.vue';
const { formApi, routerPush } = vi.hoisted(() => ({
formApi: {
getValues: vi.fn(),
setFieldValue: vi.fn(),
validate: vi.fn(),
},
routerPush: vi.fn(),
}));
vi.mock('vue-router', () => ({
useRouter: () => ({
push: routerPush,
}),
}));
vi.mock('@easyflow/locales', () => ({
$t: (key: string) => key,
}));
vi.mock('@easyflow-core/form-ui', async () => {
const vue = await import('vue');
return {
useEasyFlowForm: () => [
vue.defineComponent({
name: 'MockEasyFlowForm',
setup() {
return () => vue.h('div', { class: 'mock-form' });
},
}),
formApi,
],
};
});
vi.mock('@easyflow-core/shadcn-ui', async (importOriginal) => {
const vue = await import('vue');
const actual = await importOriginal<typeof import('@easyflow-core/shadcn-ui')>();
return {
...actual,
EasyFlowButton: vue.defineComponent({
name: 'EasyFlowButton',
props: {
loading: {
default: false,
type: Boolean,
},
},
emits: ['click'],
setup(props, { attrs, emit, slots }) {
return () =>
vue.h(
'button',
{
...attrs,
'data-loading': String(props.loading),
type: 'button',
onClick: () => emit('click'),
},
slots.default?.(),
);
},
}),
EasyFlowCheckbox: vue.defineComponent({
name: 'EasyFlowCheckbox',
props: {
modelValue: {
default: false,
type: Boolean,
},
name: {
default: '',
type: String,
},
},
emits: ['update:modelValue'],
setup(props, { emit, slots }) {
return () =>
vue.h('label', [
vue.h('input', {
checked: props.modelValue,
name: props.name,
type: 'checkbox',
onChange: (event: Event) => {
emit(
'update:modelValue',
(event.target as HTMLInputElement).checked,
);
},
}),
slots.default?.(),
]);
},
}),
};
});
describe('AuthenticationLogin', () => {
const rememberKey = `REMEMBER_ME_ACCOUNT_${location.hostname}`;
beforeEach(() => {
localStorage.clear();
vi.clearAllMocks();
formApi.validate.mockResolvedValue({ valid: true });
formApi.getValues.mockResolvedValue({ account: 'admin' });
});
it('restores remembered account into the account field', async () => {
localStorage.setItem(rememberKey, 'remembered-user');
mount(AuthenticationLogin, {
props: {
formSchema: [],
},
});
await nextTick();
expect(formApi.setFieldValue).toHaveBeenCalledWith(
'account',
'remembered-user',
);
});
it('persists remembered account using the account field and renders overlay slot', async () => {
localStorage.setItem(rememberKey, 'remembered-user');
const wrapper = mount(AuthenticationLogin, {
props: {
formSchema: [],
showRememberMe: true,
},
slots: {
overlay: '<div id="captcha-box"></div>',
},
});
await nextTick();
await wrapper.get('button').trigger('click');
expect(localStorage.getItem(rememberKey)).toBe('admin');
expect(wrapper.emitted('submit')?.[0]).toEqual([{ account: 'admin' }]);
expect(wrapper.find('#captcha-box').exists()).toBe(true);
});
});

View File

@@ -176,66 +176,43 @@ INSERT INTO `tb_sys_role_menu` (`id`, `role_id`, `menu_id`) VALUES (365314364334
-- ---------------------------- -- ----------------------------
-- Records of tb_model_provider -- Records of tb_model_provider
-- ---------------------------- -- ----------------------------
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (358906187162456064, 'Gitee', 'gitee', '', '', 'https://ai.gitee.com', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-17 22:26:03', 1, '2025-12-17 22:26:03', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359109019710914560, '百度千帆', 'baidu', '', '', 'https://qianfan.baidubce.com', '/v2/chat/completions', '/v2/embeddings', '', '2025-12-18 11:52:02', 1, '2025-12-18 11:52:02', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', 'http://127.0.0.1:11434', '/v1/chat/completions', '/api/embed', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110565693620224, '火山引擎', 'volcengine', '', '', 'https://ark.cn-beijing.volces.com', '/api/v3/chat/completions', '/api/v3/embeddings', '', '2025-12-18 11:58:11', 1, '2025-12-18 11:58:11', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110640402563072, '星火大模型', 'spark', '', '', 'https://spark-api-open.xf-yun.com', '/v1/chat/completions', NULL, '', '2025-12-18 11:58:29', 1, '2025-12-18 11:58:29', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'OpenAI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-18 11:58:35', 1, '2025-12-18 11:58:35', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '/api/v1/services/rerank/text-rerank/text-rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', NULL, NULL, NULL, '', '2025-12-18 11:58:40', 1, '2025-12-18 11:58:40', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000001, '智谱', 'zhipu', '', '', 'https://open.bigmodel.cn', '/api/paas/v4/chat/completions', '/api/paas/v4/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:00:23', 1, '2025-12-18 12:00:23', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000002, 'MiniMax', 'minimax', '', '', 'https://api.minimax.io', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'Open AI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2025-12-18 12:00:49', 1, '2025-12-18 12:00:49', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000003, 'Kimi', 'kimi', '', '', 'https://api.moonshot.cn', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:01:41', 1, '2025-12-18 12:01:41', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000004, '自部署', 'self-hosted', '', '', 'http://127.0.0.1:8000', '/v1/chat/completions', '/v1/embeddings', '/v1/score', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
-- ---------------------------- -- ----------------------------
-- Records of tb_model -- Records of tb_model
-- ---------------------------- -- ----------------------------
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359159030960295936, 1, 1000000, 358906187162456064, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010001, 1, 1000000, 359111120310632448, 'DeepSeek-V3', NULL, '通用对话与代码任务表现均衡。', NULL, NULL, 'deepseek-chat', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188398742933504, 1, 1000000, 358906187162456064, 'kimi-k2-instruct', NULL, NULL, NULL, NULL, 'kimi-k2-instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010002, 1, 1000000, 359111120310632448, 'DeepSeek-R1', NULL, '复杂推理与长链路分析场景。', NULL, NULL, 'deepseek-reasoner', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188487121113088, 1, 1000000, 358906187162456064, 'ERNIE-X1-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-X1-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010003, 1, 1000000, 359111228158771200, 'o4-mini', NULL, '轻量推理与通用生产任务模型。', NULL, NULL, 'o4-mini', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188591383121920, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010004, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, '复杂任务与多模态理解旗舰模型。', NULL, NULL, 'gpt-4.1', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188717564563456, 1, 1000000, 358906187162456064, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010005, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, '高质量文本向量模型。', NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188823290384384, 1, 1000000, 358906187162456064, 'Qwen3-235B-A22B', NULL, NULL, NULL, NULL, 'Qwen3-235B-A22B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010006, 1, 1000000, 359111448204541952, '通义千问 Plus', NULL, '适合通用问答与工具调用。', NULL, NULL, 'qwen-plus', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188894316728320, 1, 1000000, 358906187162456064, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010007, 1, 1000000, 359111448204541952, '通义千问 Max', NULL, '综合能力更强的主力模型。', NULL, NULL, 'qwen-max', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189040752463872, 1, 1000000, 358906187162456064, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010008, 1, 1000000, 359111448204541952, 'text-embedding-v4', NULL, '阿里百炼默认向量模型。', NULL, NULL, 'text-embedding-v4', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189205492142080, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo-VL', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo-VL', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010009, 1, 1000000, 359111448204541952, 'gte-rerank-v2', NULL, '阿里百炼默认重排模型。', NULL, NULL, 'gte-rerank-v2', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189277827108864, 1, 1000000, 358906187162456064, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010010, 1, 1000000, 366100000000000001, 'GLM-4.5', NULL, '中文与推理能力表现均衡。', NULL, NULL, 'glm-4.5', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189415073124352, 1, 1000000, 358906187162456064, 'InternVL3-78B', NULL, NULL, NULL, NULL, 'InternVL3-78B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010011, 1, 1000000, 366100000000000001, 'GLM-4.5-Air', NULL, '低延迟通用模型。', NULL, NULL, 'glm-4.5-air', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189479254364160, 1, 1000000, 358906187162456064, 'InternVL3-38B', NULL, NULL, NULL, NULL, 'InternVL3-38B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010012, 1, 1000000, 366100000000000001, 'Embedding-3', NULL, '知识库与检索常用向量模型。', NULL, NULL, 'embedding-3', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189562309971968, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010013, 1, 1000000, 366100000000000002, 'MiniMax-M2.5', NULL, '长上下文与复杂推理场景。', NULL, NULL, 'MiniMax-M2.5', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189617381183488, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010014, 1, 1000000, 366100000000000002, 'MiniMax-M2.5-highspeed', NULL, '更高吞吐的快速对话模型。', NULL, NULL, 'MiniMax-M2.5-highspeed', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359190580372410368, 1, 1000000, 359111120310632448, 'deepseek-chat', NULL, NULL, NULL, NULL, 'deepseek-chat', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010015, 1, 1000000, 366100000000000003, 'moonshot-v1-8k', NULL, '低延迟通用对话模型。', NULL, NULL, 'moonshot-v1-8k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250814495248384, 1, 1000000, 359111228158771200, 'o4-mini', NULL, NULL, NULL, NULL, 'o4-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010016, 1, 1000000, 366100000000000003, 'moonshot-v1-128k', NULL, '长文档理解与大上下文任务。', NULL, NULL, 'moonshot-v1-128k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250916064514048, 1, 1000000, 359111228158771200, 'o3', NULL, NULL, NULL, NULL, 'o3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010017, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, '统一平台接入的开源对话模型。', NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250975883677696, 1, 1000000, 359111228158771200, 'o3-pro', NULL, NULL, NULL, NULL, 'o3-pro', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010018, 1, 1000000, 359110667376132096, 'Kimi-K2-Instruct', NULL, '代码与 Agent 工作流场景常用模型。', NULL, NULL, 'moonshotai/Kimi-K2-Instruct', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251041788776448, 1, 1000000, 359111228158771200, 'o3-mini', NULL, NULL, NULL, NULL, 'o3-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010019, 1, 1000000, 359110667376132096, 'BAAI/bge-m3', NULL, '多语言检索与向量召回模型。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251651388919808, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, NULL, NULL, NULL, 'GPT-4.1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010020, 1, 1000000, 359110690079899648, 'qwen3:8b', NULL, '本地开发常用的通用对话模型。', NULL, NULL, 'qwen3:8b', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Ollama', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251703859662848, 1, 1000000, 359111228158771200, 'GPT-4o', NULL, NULL, NULL, NULL, 'GPT-4o', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010021, 1, 1000000, 359110690079899648, 'bge-m3', NULL, '本地向量化与检索验证。', NULL, NULL, 'bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251899029016576, 1, 1000000, 359111228158771200, 'text-embedding-3-small', NULL, NULL, NULL, NULL, 'text-embedding-3-small', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010022, 1, 1000000, 366100000000000004, 'Qwen/Qwen3-32B', NULL, '适合自部署对话与工具调用。', NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251948844765184, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, NULL, NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010023, 1, 1000000, 366100000000000004, 'BAAI/bge-m3', NULL, '自部署检索和知识库向量化。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252007019761664, 1, 1000000, 359111228158771200, 'text-embedding-ada-002', NULL, NULL, NULL, NULL, 'text-embedding-ada-002', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010024, 1, 1000000, 366100000000000004, 'jinaai/jina-reranker-m0', NULL, '自部署召回重排模型。', NULL, NULL, 'jinaai/jina-reranker-m0', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252333504385024, 1, 1000000, 359110667376132096, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252410297896960, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252901950017536, 1, 1000000, 359110667376132096, 'QwenLong-L1-32B', NULL, NULL, NULL, NULL, 'Tongyi-Zhiwen/QwenLong-L1-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253108129419264, 1, 1000000, 359110667376132096, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253178463703040, 1, 1000000, 359110667376132096, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253290258681856, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253356990058496, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-72B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-72B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253448664961024, 1, 1000000, 359110667376132096, 'deepseek-vl2', NULL, NULL, NULL, NULL, 'deepseek-ai/deepseek-vl2', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253538523729920, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253610657370112, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253918280208384, 1, 1000000, 359110667376132096, 'bge-m3', NULL, NULL, NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'BAAI', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254052095283200, 1, 1000000, 359110667376132096, 'bce-embedding-base_v1', NULL, NULL, NULL, NULL, 'netease-youdao/bce-embedding-base_v1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Netease-youdao', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254268492009472, 1, 1000000, 359110565693620224, 'doubao-seed-1.6', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254341498064896, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-flash', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-flash-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254465049677824, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-thinking', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-thinking-250715', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254550235992064, 1, 1000000, 359110565693620224, 'deepseek-r1', NULL, NULL, NULL, NULL, 'deepseek-r1-250528', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359255963729022976, 1, 1000000, 359110640402563072, 'Spark Max', NULL, NULL, NULL, NULL, 'generalv3.5', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256036009463808, 1, 1000000, 359110640402563072, 'Spark4.0 Ultra', NULL, NULL, NULL, NULL, '4.0Ultra', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256272148779008, 1, 1000000, 359110640402563072, 'Max-32K', NULL, NULL, NULL, NULL, 'max-32k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256472095444992, 1, 1000000, 359110640402563072, 'Spark Pro', NULL, NULL, NULL, NULL, 'generalv3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256641138479104, 1, 1000000, 359110640402563072, 'Spark Pro-128k', NULL, NULL, NULL, NULL, 'pro-128k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359498072033816576, 1, 1000000, 359111448204541952, 'text-embedding-v3', NULL, NULL, NULL, NULL, 'text-embedding-v3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359536003377258496, 1, 1000000, 358906187162456064, 'Qwen3-Reranker-8B', NULL, NULL, NULL, NULL, 'Qwen3-Reranker-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
-- ---------------------------- -- ----------------------------
-- Records of tb_sys_option -- Records of tb_sys_option

View File

@@ -0,0 +1,81 @@
-- 模型服务商集合刷新脚本
-- 用途:
-- 1. 清理已下线的旧服务商及其关联模型星火、火山、千帆、Gitee
-- 2. 对保留服务商做默认路径对齐
-- 3. 补齐新的服务商预设智谱、MiniMax、Kimi、自部署
START TRANSACTION;
DELETE m
FROM tb_model AS m
INNER JOIN tb_model_provider AS p ON p.id = m.provider_id
WHERE p.provider_type IN ('gitee', 'baidu', 'volcengine', 'spark');
DELETE FROM tb_model_provider
WHERE provider_type IN ('gitee', 'baidu', 'volcengine', 'spark');
UPDATE tb_model_provider
SET provider_name = 'DeepSeek',
endpoint = 'https://api.deepseek.com',
chat_path = '/chat/completions',
embed_path = '',
rerank_path = ''
WHERE provider_type = 'deepseek';
UPDATE tb_model_provider
SET provider_name = 'OpenAI',
endpoint = 'https://api.openai.com',
chat_path = '/v1/chat/completions',
embed_path = '/v1/embeddings',
rerank_path = ''
WHERE provider_type = 'openai';
UPDATE tb_model_provider
SET provider_name = '阿里百炼',
endpoint = 'https://dashscope.aliyuncs.com',
chat_path = '/compatible-mode/v1/chat/completions',
embed_path = '/compatible-mode/v1/embeddings',
rerank_path = '/api/v1/services/rerank/text-rerank/text-rerank'
WHERE provider_type = 'aliyun';
UPDATE tb_model_provider
SET provider_name = '硅基流动',
endpoint = 'https://api.siliconflow.cn',
chat_path = '/v1/chat/completions',
embed_path = '/v1/embeddings',
rerank_path = '/v1/rerank'
WHERE provider_type = 'siliconlow';
UPDATE tb_model_provider
SET provider_name = 'Ollama',
endpoint = 'http://127.0.0.1:11434',
chat_path = '/v1/chat/completions',
embed_path = '/api/embed',
rerank_path = ''
WHERE provider_type = 'ollama';
INSERT INTO tb_model_provider (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`)
SELECT 366100000000000001, '智谱', 'zhipu', '', '', 'https://open.bigmodel.cn', '/api/paas/v4/chat/completions', '/api/paas/v4/embeddings', '', NOW(), 1, NOW(), 1
WHERE NOT EXISTS (
SELECT 1 FROM tb_model_provider WHERE provider_type = 'zhipu'
);
INSERT INTO tb_model_provider (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`)
SELECT 366100000000000002, 'MiniMax', 'minimax', '', '', 'https://api.minimax.io', '/v1/chat/completions', '', '', NOW(), 1, NOW(), 1
WHERE NOT EXISTS (
SELECT 1 FROM tb_model_provider WHERE provider_type = 'minimax'
);
INSERT INTO tb_model_provider (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`)
SELECT 366100000000000003, 'Kimi', 'kimi', '', '', 'https://api.moonshot.cn', '/v1/chat/completions', '', '', NOW(), 1, NOW(), 1
WHERE NOT EXISTS (
SELECT 1 FROM tb_model_provider WHERE provider_type = 'kimi'
);
INSERT INTO tb_model_provider (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`)
SELECT 366100000000000004, '自部署', 'self-hosted', '', '', 'http://127.0.0.1:8000', '/v1/chat/completions', '/v1/embeddings', '/v1/score', NOW(), 1, NOW(), 1
WHERE NOT EXISTS (
SELECT 1 FROM tb_model_provider WHERE provider_type = 'self-hosted'
);
COMMIT;

View File

@@ -176,66 +176,43 @@ INSERT INTO `tb_sys_role_menu` (`id`, `role_id`, `menu_id`) VALUES (365314364334
-- ---------------------------- -- ----------------------------
-- Records of tb_model_provider -- Records of tb_model_provider
-- ---------------------------- -- ----------------------------
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (358906187162456064, 'Gitee', 'gitee', '', '', 'https://ai.gitee.com', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-17 22:26:03', 1, '2025-12-17 22:26:03', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359109019710914560, '百度千帆', 'baidu', '', '', 'https://qianfan.baidubce.com', '/v2/chat/completions', '/v2/embeddings', '', '2025-12-18 11:52:02', 1, '2025-12-18 11:52:02', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', 'http://127.0.0.1:11434', '/v1/chat/completions', '/api/embed', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110565693620224, '火山引擎', 'volcengine', '', '', 'https://ark.cn-beijing.volces.com', '/api/v3/chat/completions', '/api/v3/embeddings', '', '2025-12-18 11:58:11', 1, '2025-12-18 11:58:11', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110640402563072, '星火大模型', 'spark', '', '', 'https://spark-api-open.xf-yun.com', '/v1/chat/completions', NULL, '', '2025-12-18 11:58:29', 1, '2025-12-18 11:58:29', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'OpenAI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-18 11:58:35', 1, '2025-12-18 11:58:35', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '/api/v1/services/rerank/text-rerank/text-rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', NULL, NULL, NULL, '', '2025-12-18 11:58:40', 1, '2025-12-18 11:58:40', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000001, '智谱', 'zhipu', '', '', 'https://open.bigmodel.cn', '/api/paas/v4/chat/completions', '/api/paas/v4/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:00:23', 1, '2025-12-18 12:00:23', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000002, 'MiniMax', 'minimax', '', '', 'https://api.minimax.io', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'Open AI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2025-12-18 12:00:49', 1, '2025-12-18 12:00:49', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000003, 'Kimi', 'kimi', '', '', 'https://api.moonshot.cn', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:01:41', 1, '2025-12-18 12:01:41', 1); INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000004, '自部署', 'self-hosted', '', '', 'http://127.0.0.1:8000', '/v1/chat/completions', '/v1/embeddings', '/v1/score', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
-- ---------------------------- -- ----------------------------
-- Records of tb_model -- Records of tb_model
-- ---------------------------- -- ----------------------------
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359159030960295936, 1, 1000000, 358906187162456064, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010001, 1, 1000000, 359111120310632448, 'DeepSeek-V3', NULL, '通用对话与代码任务表现均衡。', NULL, NULL, 'deepseek-chat', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188398742933504, 1, 1000000, 358906187162456064, 'kimi-k2-instruct', NULL, NULL, NULL, NULL, 'kimi-k2-instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010002, 1, 1000000, 359111120310632448, 'DeepSeek-R1', NULL, '复杂推理与长链路分析场景。', NULL, NULL, 'deepseek-reasoner', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188487121113088, 1, 1000000, 358906187162456064, 'ERNIE-X1-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-X1-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010003, 1, 1000000, 359111228158771200, 'o4-mini', NULL, '轻量推理与通用生产任务模型。', NULL, NULL, 'o4-mini', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188591383121920, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010004, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, '复杂任务与多模态理解旗舰模型。', NULL, NULL, 'gpt-4.1', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188717564563456, 1, 1000000, 358906187162456064, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010005, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, '高质量文本向量模型。', NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188823290384384, 1, 1000000, 358906187162456064, 'Qwen3-235B-A22B', NULL, NULL, NULL, NULL, 'Qwen3-235B-A22B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010006, 1, 1000000, 359111448204541952, '通义千问 Plus', NULL, '适合通用问答与工具调用。', NULL, NULL, 'qwen-plus', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188894316728320, 1, 1000000, 358906187162456064, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010007, 1, 1000000, 359111448204541952, '通义千问 Max', NULL, '综合能力更强的主力模型。', NULL, NULL, 'qwen-max', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189040752463872, 1, 1000000, 358906187162456064, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010008, 1, 1000000, 359111448204541952, 'text-embedding-v4', NULL, '阿里百炼默认向量模型。', NULL, NULL, 'text-embedding-v4', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189205492142080, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo-VL', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo-VL', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010009, 1, 1000000, 359111448204541952, 'gte-rerank-v2', NULL, '阿里百炼默认重排模型。', NULL, NULL, 'gte-rerank-v2', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189277827108864, 1, 1000000, 358906187162456064, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010010, 1, 1000000, 366100000000000001, 'GLM-4.5', NULL, '中文与推理能力表现均衡。', NULL, NULL, 'glm-4.5', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189415073124352, 1, 1000000, 358906187162456064, 'InternVL3-78B', NULL, NULL, NULL, NULL, 'InternVL3-78B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010011, 1, 1000000, 366100000000000001, 'GLM-4.5-Air', NULL, '低延迟通用模型。', NULL, NULL, 'glm-4.5-air', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189479254364160, 1, 1000000, 358906187162456064, 'InternVL3-38B', NULL, NULL, NULL, NULL, 'InternVL3-38B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010012, 1, 1000000, 366100000000000001, 'Embedding-3', NULL, '知识库与检索常用向量模型。', NULL, NULL, 'embedding-3', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189562309971968, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010013, 1, 1000000, 366100000000000002, 'MiniMax-M2.5', NULL, '长上下文与复杂推理场景。', NULL, NULL, 'MiniMax-M2.5', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189617381183488, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010014, 1, 1000000, 366100000000000002, 'MiniMax-M2.5-highspeed', NULL, '更高吞吐的快速对话模型。', NULL, NULL, 'MiniMax-M2.5-highspeed', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359190580372410368, 1, 1000000, 359111120310632448, 'deepseek-chat', NULL, NULL, NULL, NULL, 'deepseek-chat', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010015, 1, 1000000, 366100000000000003, 'moonshot-v1-8k', NULL, '低延迟通用对话模型。', NULL, NULL, 'moonshot-v1-8k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250814495248384, 1, 1000000, 359111228158771200, 'o4-mini', NULL, NULL, NULL, NULL, 'o4-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010016, 1, 1000000, 366100000000000003, 'moonshot-v1-128k', NULL, '长文档理解与大上下文任务。', NULL, NULL, 'moonshot-v1-128k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250916064514048, 1, 1000000, 359111228158771200, 'o3', NULL, NULL, NULL, NULL, 'o3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010017, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, '统一平台接入的开源对话模型。', NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250975883677696, 1, 1000000, 359111228158771200, 'o3-pro', NULL, NULL, NULL, NULL, 'o3-pro', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010018, 1, 1000000, 359110667376132096, 'Kimi-K2-Instruct', NULL, '代码与 Agent 工作流场景常用模型。', NULL, NULL, 'moonshotai/Kimi-K2-Instruct', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251041788776448, 1, 1000000, 359111228158771200, 'o3-mini', NULL, NULL, NULL, NULL, 'o3-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010019, 1, 1000000, 359110667376132096, 'BAAI/bge-m3', NULL, '多语言检索与向量召回模型。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251651388919808, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, NULL, NULL, NULL, 'GPT-4.1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010020, 1, 1000000, 359110690079899648, 'qwen3:8b', NULL, '本地开发常用的通用对话模型。', NULL, NULL, 'qwen3:8b', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Ollama', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251703859662848, 1, 1000000, 359111228158771200, 'GPT-4o', NULL, NULL, NULL, NULL, 'GPT-4o', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010021, 1, 1000000, 359110690079899648, 'bge-m3', NULL, '本地向量化与检索验证。', NULL, NULL, 'bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251899029016576, 1, 1000000, 359111228158771200, 'text-embedding-3-small', NULL, NULL, NULL, NULL, 'text-embedding-3-small', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010022, 1, 1000000, 366100000000000004, 'Qwen/Qwen3-32B', NULL, '适合自部署对话与工具调用。', NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251948844765184, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, NULL, NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010023, 1, 1000000, 366100000000000004, 'BAAI/bge-m3', NULL, '自部署检索和知识库向量化。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252007019761664, 1, 1000000, 359111228158771200, 'text-embedding-ada-002', NULL, NULL, NULL, NULL, 'text-embedding-ada-002', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0); INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010024, 1, 1000000, 366100000000000004, 'jinaai/jina-reranker-m0', NULL, '自部署召回重排模型。', NULL, NULL, 'jinaai/jina-reranker-m0', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252333504385024, 1, 1000000, 359110667376132096, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252410297896960, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252901950017536, 1, 1000000, 359110667376132096, 'QwenLong-L1-32B', NULL, NULL, NULL, NULL, 'Tongyi-Zhiwen/QwenLong-L1-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253108129419264, 1, 1000000, 359110667376132096, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253178463703040, 1, 1000000, 359110667376132096, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253290258681856, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253356990058496, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-72B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-72B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253448664961024, 1, 1000000, 359110667376132096, 'deepseek-vl2', NULL, NULL, NULL, NULL, 'deepseek-ai/deepseek-vl2', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253538523729920, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253610657370112, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253918280208384, 1, 1000000, 359110667376132096, 'bge-m3', NULL, NULL, NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'BAAI', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254052095283200, 1, 1000000, 359110667376132096, 'bce-embedding-base_v1', NULL, NULL, NULL, NULL, 'netease-youdao/bce-embedding-base_v1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Netease-youdao', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254268492009472, 1, 1000000, 359110565693620224, 'doubao-seed-1.6', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254341498064896, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-flash', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-flash-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254465049677824, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-thinking', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-thinking-250715', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254550235992064, 1, 1000000, 359110565693620224, 'deepseek-r1', NULL, NULL, NULL, NULL, 'deepseek-r1-250528', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359255963729022976, 1, 1000000, 359110640402563072, 'Spark Max', NULL, NULL, NULL, NULL, 'generalv3.5', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256036009463808, 1, 1000000, 359110640402563072, 'Spark4.0 Ultra', NULL, NULL, NULL, NULL, '4.0Ultra', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256272148779008, 1, 1000000, 359110640402563072, 'Max-32K', NULL, NULL, NULL, NULL, 'max-32k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256472095444992, 1, 1000000, 359110640402563072, 'Spark Pro', NULL, NULL, NULL, NULL, 'generalv3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256641138479104, 1, 1000000, 359110640402563072, 'Spark Pro-128k', NULL, NULL, NULL, NULL, 'pro-128k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359498072033816576, 1, 1000000, 359111448204541952, 'text-embedding-v3', NULL, NULL, NULL, NULL, 'text-embedding-v3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359536003377258496, 1, 1000000, 358906187162456064, 'Qwen3-Reranker-8B', NULL, NULL, NULL, NULL, 'Qwen3-Reranker-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
-- ---------------------------- -- ----------------------------
-- Records of tb_sys_option -- Records of tb_sys_option