perf: 模型管理界面重做
@@ -92,13 +92,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/updateByEntity")
|
||||
@SaCheckPermission("/api/v1/model/save")
|
||||
public Result<?> updateByEntity(@RequestBody Model entity) {
|
||||
modelService.updateByEntity(entity);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/selectLlmByProviderCategory")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
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")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Model entity, boolean isSave) {
|
||||
if (isSave) {
|
||||
entity.setWithUsed(true);
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("removeLlmByIds")
|
||||
@Transactional
|
||||
public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.core.handler.FastjsonTypeHandler;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
@@ -103,12 +104,6 @@ public class ModelBase implements Serializable {
|
||||
@Column(comment = "模型类型: chatModel/embeddingModel/rerankModel/orc..")
|
||||
private String modelType;
|
||||
|
||||
/**
|
||||
* 是否使用
|
||||
*/
|
||||
@Column(comment = "是否使用")
|
||||
private Boolean withUsed;
|
||||
|
||||
/**
|
||||
* 是否支持推理
|
||||
*/
|
||||
@@ -277,14 +272,6 @@ public class ModelBase implements Serializable {
|
||||
this.modelType = modelType;
|
||||
}
|
||||
|
||||
public Boolean getWithUsed() {
|
||||
return withUsed;
|
||||
}
|
||||
|
||||
public void setWithUsed(Boolean withUsed) {
|
||||
this.withUsed = withUsed;
|
||||
}
|
||||
|
||||
public Boolean getSupportThinking() {
|
||||
return supportThinking;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package tech.easyflow.ai.service;
|
||||
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
@@ -25,6 +24,4 @@ public interface ModelService extends IService<Model> {
|
||||
void removeByEntity(Model entity);
|
||||
|
||||
Model getModelInstance(BigInteger modelId);
|
||||
|
||||
void updateByEntity(Model entity);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
package tech.easyflow.ai.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.easyagents.core.model.chat.ChatModel;
|
||||
import com.easyagents.core.model.chat.ChatOptions;
|
||||
import com.easyagents.core.model.embedding.EmbeddingModel;
|
||||
import com.easyagents.core.model.rerank.RerankModel;
|
||||
import com.easyagents.core.store.VectorData;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import org.slf4j.Logger;
|
||||
@@ -21,7 +21,6 @@ import tech.easyflow.ai.entity.ModelProvider;
|
||||
import tech.easyflow.ai.mapper.ModelMapper;
|
||||
import tech.easyflow.ai.service.ModelProviderService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -92,7 +91,6 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
|
||||
|
||||
QueryWrapper queryWrapper = new QueryWrapper()
|
||||
.eq(Model::getProviderId, entity.getProviderId());
|
||||
queryWrapper.eq(Model::getWithUsed, entity.getWithUsed());
|
||||
List<Model> totalList = modelMapper.selectListWithRelationsByQuery(queryWrapper);
|
||||
for (String modelType : Model.MODEL_TYPES) {
|
||||
Map<String, List<Model>> groupMap = groupLlmByGroupName(totalList, modelType);
|
||||
@@ -212,13 +210,4 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ spring:
|
||||
activate:
|
||||
on-profile: prod
|
||||
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
|
||||
password: 123456
|
||||
password: root
|
||||
data:
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
|
||||
BIN
easyflow-ui-admin/app/public/model-providers/aliyun.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
easyflow-ui-admin/app/public/model-providers/deepseek.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
easyflow-ui-admin/app/public/model-providers/kimi.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
easyflow-ui-admin/app/public/model-providers/minimax.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
easyflow-ui-admin/app/public/model-providers/ollama.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
1
easyflow-ui-admin/app/public/model-providers/openai.ico
Normal file
10
easyflow-ui-admin/app/public/model-providers/openai.svg
Normal 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 |
@@ -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 |
BIN
easyflow-ui-admin/app/public/model-providers/siliconflow.png
Normal file
|
After Width: | Height: | Size: 583 B |
BIN
easyflow-ui-admin/app/public/model-providers/zhipu.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,10 +1,19 @@
|
||||
import { api } from '#/api/request.js';
|
||||
import {api} from '#/api/request.js';
|
||||
|
||||
// 获取LLM供应商
|
||||
export async function getLlmProviderList() {
|
||||
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
|
||||
export async function saveLlm(data: string) {
|
||||
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);
|
||||
}
|
||||
|
||||
export async function verifyModelConfig(id: string) {
|
||||
return api.get('/api/v1/model/verifyLlmConfig', { params: { id } });
|
||||
}
|
||||
|
||||
// 一键添加LLM
|
||||
export async function quickAddLlm(data: any) {
|
||||
return api.post(`/api/v1/model/quickAdd`, data);
|
||||
@@ -33,7 +46,6 @@ export interface llmType {
|
||||
providerName: string;
|
||||
providerType: string;
|
||||
};
|
||||
withUsed: boolean;
|
||||
llmModel: string;
|
||||
icon: string;
|
||||
description: string;
|
||||
|
||||
@@ -6,7 +6,7 @@ interface Props {
|
||||
contentPadding?: number | string;
|
||||
dense?: boolean;
|
||||
stickyToolbar?: boolean;
|
||||
surface?: 'panel' | 'subtle';
|
||||
surface?: 'panel' | 'plain' | 'subtle';
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -141,6 +141,18 @@ const contentStyle = computed((): CSSProperties => {
|
||||
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 {
|
||||
position: absolute;
|
||||
inset: 0 0 auto;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -58,7 +58,6 @@
|
||||
"button": {
|
||||
"management": "Management",
|
||||
"test": "Test",
|
||||
"addAllLlm": "Add models from the list",
|
||||
"RetrieveAgain": "Retrieve the model list again"
|
||||
},
|
||||
"all": "All",
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"button": {
|
||||
"management": "管理",
|
||||
"test": "检测",
|
||||
"addAllLlm": "添加列表中的所有模型",
|
||||
"RetrieveAgain": "重新获取模型列表"
|
||||
},
|
||||
"all": "全部",
|
||||
|
||||
@@ -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>
|
||||
@@ -1,31 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
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 type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
|
||||
import {
|
||||
getDefaultModelAbility,
|
||||
handleTagClick as handleTagClickUtil,
|
||||
syncTagSelectedStatus as syncTagSelectedStatusUtil,
|
||||
} 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 {
|
||||
generateFeaturesFromModelAbility,
|
||||
resetModelAbility,
|
||||
} from '#/views/ai/model/modelUtils/model-ability-utils';
|
||||
|
||||
interface FormData {
|
||||
id?: string;
|
||||
modelType: string;
|
||||
title: string;
|
||||
modelName: string;
|
||||
groupName: string;
|
||||
providerId: string;
|
||||
provider: string;
|
||||
apiKey: string;
|
||||
endpoint: string;
|
||||
requestPath: string;
|
||||
@@ -37,12 +37,6 @@ interface FormData {
|
||||
supportVideo: boolean;
|
||||
supportImageB64Only: boolean;
|
||||
supportToolMessage: boolean;
|
||||
options: {
|
||||
chatPath: string;
|
||||
embedPath: string;
|
||||
llmEndpoint: string;
|
||||
rerankPath: string;
|
||||
};
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
@@ -55,7 +49,6 @@ const props = defineProps({
|
||||
const emit = defineEmits(['reload']);
|
||||
const selectedProviderId = ref<string>(props.providerId ?? '');
|
||||
|
||||
// 监听 providerId 的变化
|
||||
watch(
|
||||
() => props.providerId,
|
||||
(newVal) => {
|
||||
@@ -69,15 +62,15 @@ watch(
|
||||
const formDataRef = ref();
|
||||
const isAdd = ref(true);
|
||||
const dialogVisible = ref(false);
|
||||
const btnLoading = ref(false);
|
||||
const showAdvanced = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive<FormData>({
|
||||
modelType: '',
|
||||
title: '',
|
||||
modelName: '',
|
||||
groupName: '',
|
||||
providerId: '',
|
||||
provider: '',
|
||||
apiKey: '',
|
||||
endpoint: '',
|
||||
requestPath: '',
|
||||
@@ -88,87 +81,104 @@ const formData = reactive<FormData>({
|
||||
supportFree: false,
|
||||
supportVideo: false,
|
||||
supportImageB64Only: false,
|
||||
supportToolMessage: false,
|
||||
options: {
|
||||
llmEndpoint: '',
|
||||
chatPath: '',
|
||||
embedPath: '',
|
||||
rerankPath: '',
|
||||
},
|
||||
supportToolMessage: true,
|
||||
});
|
||||
|
||||
// 使用抽取的函数获取模型能力配置
|
||||
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 = () => {
|
||||
syncTagSelectedStatusUtil(modelAbility.value, formData);
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理标签点击事件
|
||||
*/
|
||||
const handleTagClick = (item: ModelAbilityItem) => {
|
||||
// handleTagClickUtil(modelAbility.value, item, formData);
|
||||
handleTagClickUtil(item, formData);
|
||||
const resetAbilitySelection = () => {
|
||||
resetModelAbility(modelAbility.value);
|
||||
syncTagSelectedStatus();
|
||||
};
|
||||
|
||||
// 打开新增弹窗
|
||||
defineExpose({
|
||||
openAddDialog(modelType: string) {
|
||||
isAdd.value = true;
|
||||
if (formDataRef.value) {
|
||||
formDataRef.value.resetFields();
|
||||
}
|
||||
const handleTagClick = (item: ModelAbilityItem) => {
|
||||
if (hasSpecialModelType.value) {
|
||||
return;
|
||||
}
|
||||
item.selected = !item.selected;
|
||||
formData[item.field] = item.selected;
|
||||
};
|
||||
|
||||
// 重置表单数据
|
||||
Object.assign(formData, {
|
||||
id: '',
|
||||
modelType,
|
||||
title: '',
|
||||
modelName: '',
|
||||
groupName: '',
|
||||
provider: '',
|
||||
endPoint: '',
|
||||
providerId: '',
|
||||
supportThinking: false,
|
||||
supportTool: false,
|
||||
supportAudio: false,
|
||||
supportVideo: false,
|
||||
supportImage: false,
|
||||
supportImageB64Only: false,
|
||||
supportFree: false,
|
||||
supportToolMessage: true,
|
||||
options: {
|
||||
llmEndpoint: '',
|
||||
chatPath: '',
|
||||
embedPath: '',
|
||||
rerankPath: '',
|
||||
},
|
||||
});
|
||||
showMoreFields.value = false;
|
||||
// 重置标签状态
|
||||
resetModelAbility(modelAbility.value);
|
||||
syncTagSelectedStatus();
|
||||
const handleModelTypeChipClick = (
|
||||
modelType: Exclude<SelectableModelType, ''>,
|
||||
) => {
|
||||
const nextType = selectedModelType.value === modelType ? '' : modelType;
|
||||
selectedModelType.value = nextType;
|
||||
if (nextType) {
|
||||
resetAbilitySelection();
|
||||
}
|
||||
};
|
||||
|
||||
const isAbilityChipDisabled = () => hasSpecialModelType.value;
|
||||
|
||||
const resolveModelType = (): FormData['modelType'] => {
|
||||
return selectedModelType.value || 'chatModel';
|
||||
};
|
||||
|
||||
const resetFormData = () => {
|
||||
Object.assign(formData, {
|
||||
id: '',
|
||||
modelType: '',
|
||||
title: '',
|
||||
modelName: '',
|
||||
groupName: '',
|
||||
providerId: '',
|
||||
apiKey: '',
|
||||
endpoint: '',
|
||||
requestPath: '',
|
||||
supportThinking: false,
|
||||
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;
|
||||
},
|
||||
|
||||
openEditDialog(item: any) {
|
||||
dialogVisible.value = true;
|
||||
isAdd.value = false;
|
||||
|
||||
// 填充表单数据
|
||||
resetFormData();
|
||||
Object.assign(formData, {
|
||||
id: item.id,
|
||||
modelType: item.modelType || '',
|
||||
title: item.title || '',
|
||||
modelName: item.modelName || '',
|
||||
groupName: item.groupName || '',
|
||||
provider: item.provider || '',
|
||||
endpoint: item.endpoint || '',
|
||||
requestPath: item.requestPath || '',
|
||||
apiKey: item.apiKey || '',
|
||||
supportThinking: item.supportThinking || false,
|
||||
supportAudio: item.supportAudio || false,
|
||||
supportImage: item.supportImage || false,
|
||||
@@ -176,17 +186,21 @@ defineExpose({
|
||||
supportVideo: item.supportVideo || false,
|
||||
supportTool: item.supportTool || false,
|
||||
supportFree: item.supportFree || false,
|
||||
supportToolMessage: item.supportToolMessage || false,
|
||||
options: {
|
||||
llmEndpoint: item.options?.llmEndpoint || '',
|
||||
chatPath: item.options?.chatPath || '',
|
||||
embedPath: item.options?.embedPath || '',
|
||||
rerankPath: item.options?.rerankPath || '',
|
||||
},
|
||||
supportToolMessage:
|
||||
item.supportToolMessage === undefined ? true : item.supportToolMessage,
|
||||
});
|
||||
showMoreFields.value = false;
|
||||
// 同步标签状态
|
||||
syncTagSelectedStatus();
|
||||
selectedModelType.value =
|
||||
item.modelType === 'embeddingModel' || item.modelType === 'rerankModel'
|
||||
? 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 = {
|
||||
title: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
title: [{ required: true, message: $t('message.required'), trigger: 'blur' }],
|
||||
modelName: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
||||
],
|
||||
groupName: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
provider: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
||||
],
|
||||
};
|
||||
|
||||
const btnLoading = ref(false);
|
||||
|
||||
const save = async () => {
|
||||
btnLoading.value = true;
|
||||
|
||||
// 使用工具函数从模型能力生成features
|
||||
const modelType = resolveModelType();
|
||||
const features = generateFeaturesFromModelAbility(modelAbility.value);
|
||||
|
||||
if (modelType !== 'chatModel') {
|
||||
for (const key of Object.keys(features) as Array<keyof typeof features>) {
|
||||
features[key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await formDataRef.value.validate();
|
||||
const submitData = { ...formData, ...features };
|
||||
const submitData = {
|
||||
...formData,
|
||||
...features,
|
||||
modelType,
|
||||
providerId: isAdd.value ? selectedProviderId.value : formData.providerId,
|
||||
};
|
||||
|
||||
if (isAdd.value) {
|
||||
submitData.providerId = selectedProviderId.value;
|
||||
const res = await api.post('/api/v1/model/save', submitData);
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message);
|
||||
emit('reload');
|
||||
closeDialog();
|
||||
} else {
|
||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||
}
|
||||
const url = isAdd.value ? '/api/v1/model/save' : '/api/v1/model/update';
|
||||
const res = await api.post(url, submitData);
|
||||
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message);
|
||||
emit('reload');
|
||||
closeDialog();
|
||||
} else {
|
||||
const res = await api.post('/api/v1/model/update', submitData);
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message);
|
||||
emit('reload');
|
||||
closeDialog();
|
||||
} else {
|
||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||
}
|
||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Save model error:', error);
|
||||
ElMessage.error($t('ui.actionMessage.operationFailed'));
|
||||
if (!(error as any)?.fields) {
|
||||
ElMessage.error($t('ui.actionMessage.operationFailed'));
|
||||
}
|
||||
} finally {
|
||||
btnLoading.value = false;
|
||||
}
|
||||
};
|
||||
const showMoreFields = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -272,91 +263,240 @@ const showMoreFields = ref(false);
|
||||
v-model:open="dialogVisible"
|
||||
:centered="true"
|
||||
:closable="!btnLoading"
|
||||
:title="isAdd ? $t('button.add') : $t('button.edit')"
|
||||
:title="isAdd ? '添加模型' : '编辑模型'"
|
||||
:before-close="closeDialog"
|
||||
width="482"
|
||||
width="640"
|
||||
:confirm-loading="btnLoading"
|
||||
:confirm-text="$t('button.save')"
|
||||
:submitting="btnLoading"
|
||||
@confirm="save"
|
||||
>
|
||||
<ElForm
|
||||
ref="formDataRef"
|
||||
:model="formData"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
||||
>
|
||||
<ElFormItem prop="title" :label="$t('llm.title')">
|
||||
<ElInput v-model.trim="formData.title" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="modelName" :label="$t('llm.llmModel')">
|
||||
<ElInput v-model.trim="formData.modelName" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="groupName" :label="$t('llm.groupName')">
|
||||
<ElInput v-model.trim="formData.groupName" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="ability" :label="$t('llm.ability')">
|
||||
<div class="model-ability">
|
||||
<ElTag
|
||||
class="model-ability-tag"
|
||||
v-for="item in modelAbility"
|
||||
:key="item.value"
|
||||
:type="item.selected ? item.activeType : item.defaultType"
|
||||
@click="handleTagClick(item)"
|
||||
:class="{ 'tag-selected': item.selected }"
|
||||
>
|
||||
{{ item.label }}
|
||||
</ElTag>
|
||||
<div class="model-modal">
|
||||
<ElForm
|
||||
ref="formDataRef"
|
||||
:model="formData"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="model-modal__form"
|
||||
>
|
||||
<div class="model-modal__section">
|
||||
<div class="model-modal__section-head">
|
||||
<h4>基础信息</h4>
|
||||
<p>这些字段决定模型在列表里的展示与组织方式。</p>
|
||||
</div>
|
||||
|
||||
<ElFormItem prop="title" :label="$t('llm.title')">
|
||||
<ElInput
|
||||
v-model.trim="formData.title"
|
||||
placeholder="例如:生产主模型"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="modelName" :label="$t('llm.llmModel')">
|
||||
<ElInput
|
||||
v-model.trim="formData.modelName"
|
||||
placeholder="例如:gpt-4.1 / glm-4.5 / qwen3:8b"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="groupName" :label="$t('llm.groupName')">
|
||||
<ElInput
|
||||
v-model.trim="formData.groupName"
|
||||
placeholder="例如:默认组"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label=" " v-if="!showMoreFields">
|
||||
<ElButton @click="showMoreFields = !showMoreFields" type="primary">
|
||||
{{ showMoreFields ? $t('button.hide') : $t('button.more') }}
|
||||
</ElButton>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
prop="apiKey"
|
||||
:label="$t('llmProvider.apiKey')"
|
||||
v-show="showMoreFields"
|
||||
>
|
||||
<ElInput v-model.trim="formData.apiKey" />
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
prop="endpoint"
|
||||
:label="$t('llmProvider.endpoint')"
|
||||
v-show="showMoreFields"
|
||||
>
|
||||
<ElInput v-model.trim="formData.endpoint" />
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
prop="requestPath"
|
||||
:label="$t('llm.requestPath')"
|
||||
v-show="showMoreFields"
|
||||
>
|
||||
<ElInput v-model.trim="formData.requestPath" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<div class="model-modal__section">
|
||||
<div class="model-modal__section-head">
|
||||
<h4>{{ $t('llm.ability') }}</h4>
|
||||
<p>可选嵌入或重排模型类型;选择后其余能力会自动锁定。</p>
|
||||
</div>
|
||||
<div class="model-modal__ability">
|
||||
<button
|
||||
v-for="item in modelTypeAbilityOptions"
|
||||
:key="item.value"
|
||||
type="button"
|
||||
class="model-modal__ability-chip"
|
||||
:class="{ 'is-active': selectedModelType === item.value }"
|
||||
@click="handleModelTypeChipClick(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="model-modal__ability">
|
||||
<button
|
||||
v-for="item in modelAbility"
|
||||
:key="item.value"
|
||||
type="button"
|
||||
class="model-modal__ability-chip"
|
||||
:class="{
|
||||
'is-active': item.selected,
|
||||
'is-disabled': isAbilityChipDisabled(),
|
||||
}"
|
||||
: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>
|
||||
</template>
|
||||
|
||||
<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;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.model-modal__ability-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.model-ability-tag {
|
||||
justify-content: center;
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
color: hsl(var(--text-muted));
|
||||
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 {
|
||||
font-weight: bold;
|
||||
transform: scale(1.05);
|
||||
.model-modal__ability-chip:hover:not(:disabled),
|
||||
.model-modal__ability-chip:focus-visible:not(:disabled) {
|
||||
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>
|
||||
|
||||
@@ -1,41 +1,25 @@
|
||||
<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 {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElMessage,
|
||||
ElOption,
|
||||
ElSelect,
|
||||
} from 'element-plus';
|
||||
import {ArrowDown, ArrowUp} from '@element-plus/icons-vue';
|
||||
import {ElForm, ElFormItem, ElIcon, 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 { $t } from '#/locales';
|
||||
import providerList from '#/views/ai/model/modelUtils/providerList.json';
|
||||
import {$t} from '#/locales';
|
||||
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
||||
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon';
|
||||
|
||||
const emit = defineEmits(['reload']);
|
||||
|
||||
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 btnLoading = ref(false);
|
||||
const isAdd = ref(true);
|
||||
const showAdvanced = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
id: '',
|
||||
icon: '',
|
||||
@@ -47,9 +31,64 @@ const formData = reactive({
|
||||
embedPath: '',
|
||||
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 = () => {
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const rules = {
|
||||
providerName: [
|
||||
{
|
||||
@@ -59,6 +98,20 @@ const rules = {
|
||||
},
|
||||
],
|
||||
providerType: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
endpoint: [
|
||||
{
|
||||
required: true,
|
||||
message: $t('message.required'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
chatPath: [
|
||||
{
|
||||
required: true,
|
||||
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 () => {
|
||||
btnLoading.value = true;
|
||||
|
||||
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();
|
||||
api.post('/api/v1/modelProvider/save', formData).then((res) => {
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success(res.message);
|
||||
emit('reload');
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
const url = isAdd.value
|
||||
? '/api/v1/modelProvider/save'
|
||||
: '/api/v1/modelProvider/update';
|
||||
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 {
|
||||
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>
|
||||
|
||||
<template>
|
||||
@@ -115,9 +167,9 @@ const handleChangeProvider = (val: string) => {
|
||||
v-model:open="dialogVisible"
|
||||
:centered="true"
|
||||
:closable="!btnLoading"
|
||||
:title="isAdd ? $t('button.add') : $t('button.edit')"
|
||||
:title="isAdd ? '添加服务商' : '编辑服务商'"
|
||||
:before-close="closeDialog"
|
||||
width="482"
|
||||
width="680"
|
||||
:confirm-loading="btnLoading"
|
||||
:confirm-text="$t('button.save')"
|
||||
:submitting="btnLoading"
|
||||
@@ -129,63 +181,259 @@ const handleChangeProvider = (val: string) => {
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
||||
class="provider-modal"
|
||||
>
|
||||
<ElFormItem
|
||||
prop="icon"
|
||||
style="display: flex; align-items: center"
|
||||
:label="$t('llmProvider.icon')"
|
||||
>
|
||||
<UploadAvatar v-model="formData.icon" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="providerName" :label="$t('llmProvider.providerName')">
|
||||
<ElInput v-model.trim="formData.providerName" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="provider" :label="$t('llmProvider.apiType')">
|
||||
<ElSelect
|
||||
v-model="formData.providerType"
|
||||
@change="handleChangeProvider"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in providerOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value || ''"
|
||||
<section class="provider-modal__section">
|
||||
<div class="provider-modal__section-head">
|
||||
<h3>服务商预设</h3>
|
||||
<p>先选择预设,系统会自动回填推荐网关与默认路径。</p>
|
||||
</div>
|
||||
|
||||
<ElFormItem prop="providerType" :label="$t('llmProvider.apiType')">
|
||||
<ElSelect
|
||||
v-model="formData.providerType"
|
||||
filterable
|
||||
placeholder="选择一个服务商预设"
|
||||
popper-class="provider-preset-select-dropdown"
|
||||
@change="applyPreset"
|
||||
>
|
||||
<template #prefix>
|
||||
<ModelProviderBadge
|
||||
v-if="selectedPreset"
|
||||
:provider-name="selectedPreset.label"
|
||||
:provider-type="selectedPreset.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 prop="apiKey" :label="$t('llmProvider.apiKey')">
|
||||
<ElInput v-model.trim="formData.apiKey" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
|
||||
<ElInput v-model.trim="formData.endpoint" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')">
|
||||
<ElInput v-model.trim="formData.chatPath" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="rerankPath" :label="$t('llmProvider.rerankPath')">
|
||||
<ElInput v-model.trim="formData.rerankPath" />
|
||||
</ElFormItem>
|
||||
<ElFormItem prop="embedPath" :label="$t('llmProvider.embedPath')">
|
||||
<ElInput v-model.trim="formData.embedPath" />
|
||||
</ElFormItem>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')">
|
||||
<ElInput
|
||||
v-model.trim="formData.chatPath"
|
||||
placeholder="对话模型请求路径"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</section>
|
||||
|
||||
<section class="provider-modal__section">
|
||||
<button
|
||||
type="button"
|
||||
class="provider-modal__advanced-toggle"
|
||||
@click="showAdvanced = !showAdvanced"
|
||||
>
|
||||
<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>
|
||||
</EasyFlowFormModal>
|
||||
</template>
|
||||
|
||||
<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;
|
||||
}
|
||||
.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%;
|
||||
border-style: dashed;
|
||||
border-color: var(--el-color-primary);
|
||||
border-radius: 8px;
|
||||
margin-top: 8px;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
.head-con-content {
|
||||
margin-bottom: 8px;
|
||||
align-items: center;
|
||||
|
||||
.provider-modal__advanced {
|
||||
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>
|
||||
|
||||
@@ -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>
|
||||
155
easyflow-ui-admin/app/src/views/ai/model/ModelProviderBadge.vue
Normal 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>
|
||||
@@ -1,44 +1,61 @@
|
||||
<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 {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElMessage,
|
||||
ElOption,
|
||||
ElSelect,
|
||||
} from 'element-plus';
|
||||
import {CircleCheckFilled, WarningFilled} from '@element-plus/icons-vue';
|
||||
import {ElForm, ElFormItem, ElMessage, ElOption, ElSelect,} from 'element-plus';
|
||||
|
||||
import { api } from '#/api/request';
|
||||
import { $t } from '#/locales';
|
||||
import {api} from '#/api/request';
|
||||
import {$t} from '#/locales';
|
||||
|
||||
type VerifyStatus = 'error' | 'idle' | 'success';
|
||||
|
||||
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 vectorDimension = ref('');
|
||||
const verifyStatus = ref<VerifyStatus>('idle');
|
||||
const verifyMessage = ref('');
|
||||
const formDataRef = ref();
|
||||
const dialogVisible = ref(false);
|
||||
defineExpose({
|
||||
openDialog(providerId: string) {
|
||||
formDataRef.value?.resetFields();
|
||||
modelType.value = '';
|
||||
vectorDimension.value = '';
|
||||
getLlmList(providerId);
|
||||
dialogVisible.value = true;
|
||||
},
|
||||
});
|
||||
const btnLoading = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
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 = {
|
||||
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 () => {
|
||||
btnLoading.value = true;
|
||||
await formDataRef.value.validate();
|
||||
api
|
||||
.get(`/api/v1/model/verifyLlmConfig?id=${formData.llmId}`, {})
|
||||
.then((res) => {
|
||||
if (res.errorCode === 0) {
|
||||
ElMessage.success($t('llm.testSuccess'));
|
||||
if (modelType.value === 'embeddingModel' && res?.data?.dimension) {
|
||||
vectorDimension.value = res?.data?.dimension;
|
||||
}
|
||||
verifyStatus.value = 'idle';
|
||||
verifyMessage.value = '正在连接模型服务,请稍候...';
|
||||
|
||||
try {
|
||||
await formDataRef.value.validate();
|
||||
const res = await api.get(
|
||||
`/api/v1/model/verifyLlmConfig?id=${formData.llmId}`,
|
||||
{},
|
||||
);
|
||||
|
||||
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;
|
||||
});
|
||||
};
|
||||
const btnLoading = ref(false);
|
||||
const getModelInfo = (id: string) => {
|
||||
options.value.forEach((item: any) => {
|
||||
if (item.id === id) {
|
||||
modelType.value = item.modelType;
|
||||
} else {
|
||||
verifyStatus.value = 'error';
|
||||
verifyMessage.value =
|
||||
res.message || $t('ui.actionMessage.operationFailed');
|
||||
ElMessage.error(verifyMessage.value);
|
||||
}
|
||||
});
|
||||
} 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>
|
||||
|
||||
@@ -80,54 +120,147 @@ const getModelInfo = (id: string) => {
|
||||
:centered="true"
|
||||
:closable="!btnLoading"
|
||||
:title="$t('llm.verifyLlmTitle')"
|
||||
width="482"
|
||||
width="560"
|
||||
:confirm-loading="btnLoading"
|
||||
:confirm-text="$t('button.confirm')"
|
||||
:submitting="btnLoading"
|
||||
@confirm="save"
|
||||
>
|
||||
<ElForm
|
||||
ref="formDataRef"
|
||||
:model="formData"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
||||
>
|
||||
<ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
|
||||
<ElSelect v-model="formData.llmId" @change="getModelInfo">
|
||||
<ElOption
|
||||
v-for="item in options"
|
||||
:key="item.id"
|
||||
:label="item.title"
|
||||
:value="item.id || ''"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
v-if="modelType === 'embeddingModel' && vectorDimension"
|
||||
:label="$t('documentCollection.dimensionOfVectorModel')"
|
||||
label-width="100px"
|
||||
>
|
||||
{{ vectorDimension }}
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="verify-modal">
|
||||
<section class="verify-modal__section">
|
||||
<div class="verify-modal__section-head">
|
||||
<h3>1. 选择待验证模型</h3>
|
||||
<p>
|
||||
会用当前保存的服务商配置发起一次真实请求,帮助你确认密钥和路径是否正确。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ElForm
|
||||
ref="formDataRef"
|
||||
:model="formData"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
label-position="top"
|
||||
class="verify-modal__form"
|
||||
>
|
||||
<ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
|
||||
<ElSelect
|
||||
v-model="formData.llmId"
|
||||
filterable
|
||||
placeholder="选择一个模型"
|
||||
@change="getModelInfo"
|
||||
>
|
||||
<ElOption
|
||||
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>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.headers-container-reduce {
|
||||
align-items: center;
|
||||
.verify-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
.addHeadersBtn {
|
||||
width: 100%;
|
||||
border-style: dashed;
|
||||
border-color: var(--el-color-primary);
|
||||
border-radius: 8px;
|
||||
margin-top: 8px;
|
||||
|
||||
.verify-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;
|
||||
}
|
||||
.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;
|
||||
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>
|
||||
|
||||
@@ -1,201 +1,377 @@
|
||||
<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 { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability';
|
||||
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 { Minus, Plus, Setting } from '@element-plus/icons-vue';
|
||||
import { ElIcon, ElImage, ElTag } from 'element-plus';
|
||||
import {CircleCheck, CircleClose, Delete, Edit, Loading, Select,} from '@element-plus/icons-vue';
|
||||
import {ElButton, ElIcon, ElMessage, ElTag} from 'element-plus';
|
||||
|
||||
import { getIconByValue } from '#/views/ai/model/modelUtils/defaultIcon';
|
||||
import { getDefaultModelAbility } from '#/views/ai/model/modelUtils/model-ability';
|
||||
import { mapLlmToModelAbility } from '#/views/ai/model/modelUtils/model-ability-utils';
|
||||
import {verifyModelConfig} from '#/api/ai/llm';
|
||||
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
||||
import {mapLlmToModelAbility} from '#/views/ai/model/modelUtils/model-ability-utils';
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
llmList: {
|
||||
type: Array as PropType<llmType[]>,
|
||||
default: () => [],
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
needHiddenSettingIcon: {
|
||||
type: Boolean,
|
||||
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) => {
|
||||
emit('deleteLlm', id);
|
||||
};
|
||||
|
||||
const handleAddLlm = (id: string) => {
|
||||
emit('addLlm', id);
|
||||
};
|
||||
|
||||
const handleEditLlm = (id: string) => {
|
||||
emit('editLlm', id);
|
||||
};
|
||||
|
||||
// 修改该模型为未使用状态,修改数据库的with_used字段为false
|
||||
const handleUpdateWithUsedLlm = (id: string) => {
|
||||
emit('updateWithUsed', id);
|
||||
const canVerify = (llm: llmType) => llm.modelType !== 'rerankModel';
|
||||
|
||||
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 defaultAbility = getDefaultModelAbility();
|
||||
const allTags = mapLlmToModelAbility(llm, defaultAbility);
|
||||
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>
|
||||
|
||||
<template>
|
||||
<div v-for="llm in llmList" :key="llm.id" class="container">
|
||||
<div class="llm-item">
|
||||
<div class="start">
|
||||
<ElImage
|
||||
v-if="llm.modelProvider.icon"
|
||||
:src="llm.modelProvider.icon"
|
||||
style="width: 21px; height: 21px"
|
||||
<div class="llm-list">
|
||||
<article v-for="llm in props.llmList" :key="llm.id" class="llm-item">
|
||||
<div class="llm-item__main">
|
||||
<ModelProviderBadge
|
||||
:icon="llm.modelProvider?.icon"
|
||||
:provider-name="llm.modelProvider?.providerName"
|
||||
:provider-type="llm.modelProvider?.providerType"
|
||||
:size="40"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-else
|
||||
v-html="getIconByValue(llm.modelProvider.providerType)"
|
||||
:style="{
|
||||
width: '21px',
|
||||
height: '21px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
}"
|
||||
class="svg-container"
|
||||
></div>
|
||||
|
||||
<div>{{ llm?.modelProvider?.providerName }}/{{ llm.title }}</div>
|
||||
|
||||
<!-- 模型能力 -->
|
||||
<div
|
||||
v-if="getSelectedAbilityTagsForLlm(llm).length > 0"
|
||||
class="ability-tags"
|
||||
>
|
||||
<ElTag
|
||||
v-for="tag in getSelectedAbilityTagsForLlm(llm)"
|
||||
:key="tag.value"
|
||||
class="ability-tag"
|
||||
:type="tag.activeType"
|
||||
size="small"
|
||||
>
|
||||
{{ tag.label }}
|
||||
</ElTag>
|
||||
<div class="llm-item__content">
|
||||
<div class="llm-item__headline">
|
||||
<h4 class="llm-item__title">{{ llm.title }}</h4>
|
||||
<div
|
||||
v-if="getSelectedAbilityTagsForLlm(llm).length > 0"
|
||||
class="llm-item__tags"
|
||||
>
|
||||
<ElTag
|
||||
v-for="tag in getSelectedAbilityTagsForLlm(llm)"
|
||||
:key="tag.value"
|
||||
effect="plain"
|
||||
size="small"
|
||||
class="llm-item__tag"
|
||||
>
|
||||
{{ tag.label }}
|
||||
</ElTag>
|
||||
</div>
|
||||
</div>
|
||||
<p class="llm-item__meta">{{ getModelMeta(llm) }}</p>
|
||||
<p v-if="llm.description" class="llm-item__description">
|
||||
{{ llm.description }}
|
||||
</p>
|
||||
</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">
|
||||
<ElIcon
|
||||
v-if="llm.withUsed"
|
||||
size="16"
|
||||
@click="handleDeleteLlm(llm.id)"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<Minus />
|
||||
</ElIcon>
|
||||
<ElIcon
|
||||
v-else
|
||||
size="16"
|
||||
@click="handleAddLlm(llm.id)"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<Plus />
|
||||
</ElIcon>
|
||||
</template>
|
||||
<div class="llm-item__actions">
|
||||
<ElButton
|
||||
v-if="canVerify(llm)"
|
||||
text
|
||||
size="small"
|
||||
class="llm-item__verify-btn"
|
||||
:class="`is-${getVerifyStatus(llm)}`"
|
||||
:disabled="isVerifying(llm) || !getModelId(llm)"
|
||||
@click="handleVerifyLlm(llm)"
|
||||
>
|
||||
<template #icon>
|
||||
<ElIcon
|
||||
class="llm-item__verify-icon"
|
||||
:class="`is-${getVerifyStatus(llm)}`"
|
||||
>
|
||||
<component :is="getVerifyButtonIcon(llm)" />
|
||||
</ElIcon>
|
||||
</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>
|
||||
</article>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.llm-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.container {
|
||||
.llm-list {
|
||||
display: flex;
|
||||
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;
|
||||
padding: 12px 18px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.container:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
.llm-item__title {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
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;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.ability-tag {
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
.llm-item__tag {
|
||||
color: hsl(var(--text-strong));
|
||||
background: hsl(var(--primary) / 8%);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
display: flex;
|
||||
.llm-item__actions {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.svg-container :deep(svg) {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
.llm-item__actions :deep(.el-button) {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.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>
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -1,27 +1,66 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
import providerList from './providerList.json';
|
||||
|
||||
const providerOptions =
|
||||
ref<Array<{ icon: string; label: string; options: any; value: string }>>(
|
||||
providerList,
|
||||
);
|
||||
export interface ProviderModelPreset {
|
||||
description: string;
|
||||
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属性
|
||||
* @param targetValue 要匹配的value值
|
||||
* @returns 匹配到的icon字符串,未匹配到返回空字符串
|
||||
*/
|
||||
export const getIconByValue = (targetValue: string): string => {
|
||||
const matchItem = providerOptions.value.find(
|
||||
(item) => item.value === targetValue,
|
||||
);
|
||||
|
||||
return matchItem?.icon || '';
|
||||
};
|
||||
export const getIconByValue = (targetValue: string): string =>
|
||||
getProviderPresetByValue(targetValue)?.icon || '';
|
||||
|
||||
export const isSvgString = (icon: any) => {
|
||||
if (typeof icon !== 'string') return false;
|
||||
// 简单判断:是否包含 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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -176,66 +176,43 @@ INSERT INTO `tb_sys_role_menu` (`id`, `role_id`, `menu_id`) VALUES (365314364334
|
||||
-- ----------------------------
|
||||
-- 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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
|
||||
-- ----------------------------
|
||||
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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
|
||||
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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of tb_sys_option
|
||||
|
||||
81
sql/07-easyflow-v2.p4-model-provider-refresh.sql
Normal 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;
|
||||
@@ -176,66 +176,43 @@ INSERT INTO `tb_sys_role_menu` (`id`, `role_id`, `menu_id`) VALUES (365314364334
|
||||
-- ----------------------------
|
||||
-- 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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
|
||||
-- ----------------------------
|
||||
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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
|
||||
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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of tb_sys_option
|
||||
|
||||