perf: 模型管理界面重做
@@ -92,13 +92,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
|
|||||||
return Result.ok();
|
return Result.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/updateByEntity")
|
|
||||||
@SaCheckPermission("/api/v1/model/save")
|
|
||||||
public Result<?> updateByEntity(@RequestBody Model entity) {
|
|
||||||
modelService.updateByEntity(entity);
|
|
||||||
return Result.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/selectLlmByProviderCategory")
|
@GetMapping("/selectLlmByProviderCategory")
|
||||||
@SaCheckPermission("/api/v1/model/query")
|
@SaCheckPermission("/api/v1/model/query")
|
||||||
public Result<Map<String, List<Model>>> selectLlmByProviderCategory(Model entity, String sortKey, String sortType) {
|
public Result<Map<String, List<Model>>> selectLlmByProviderCategory(Model entity, String sortKey, String sortType) {
|
||||||
@@ -129,19 +122,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加所有模型
|
|
||||||
*
|
|
||||||
* @param entity
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@PostMapping("addAllLlm")
|
|
||||||
public Result<?> addAllLlm(@JsonBody Model entity) {
|
|
||||||
QueryWrapper queryWrapper = QueryWrapper.create().eq(Model::getProviderId, entity.getProviderId());
|
|
||||||
service.update(entity, queryWrapper);
|
|
||||||
return Result.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/selectLlmList")
|
@GetMapping("/selectLlmList")
|
||||||
@SaCheckPermission("/api/v1/model/query")
|
@SaCheckPermission("/api/v1/model/query")
|
||||||
public Result<List<Model>> selectLlmList(Model entity, Boolean asTree, String sortKey, String sortType) {
|
public Result<List<Model>> selectLlmList(Model entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
@@ -154,15 +134,6 @@ public class ModelController extends BaseCurdController<ModelService, Model> {
|
|||||||
return Result.ok(totalList);
|
return Result.ok(totalList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Result<?> onSaveOrUpdateBefore(Model entity, boolean isSave) {
|
|
||||||
if (isSave) {
|
|
||||||
entity.setWithUsed(true);
|
|
||||||
}
|
|
||||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("removeLlmByIds")
|
@PostMapping("removeLlmByIds")
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) {
|
public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.mybatisflex.annotation.Column;
|
|||||||
import com.mybatisflex.annotation.Id;
|
import com.mybatisflex.annotation.Id;
|
||||||
import com.mybatisflex.annotation.KeyType;
|
import com.mybatisflex.annotation.KeyType;
|
||||||
import com.mybatisflex.core.handler.FastjsonTypeHandler;
|
import com.mybatisflex.core.handler.FastjsonTypeHandler;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -103,12 +104,6 @@ public class ModelBase implements Serializable {
|
|||||||
@Column(comment = "模型类型: chatModel/embeddingModel/rerankModel/orc..")
|
@Column(comment = "模型类型: chatModel/embeddingModel/rerankModel/orc..")
|
||||||
private String modelType;
|
private String modelType;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否使用
|
|
||||||
*/
|
|
||||||
@Column(comment = "是否使用")
|
|
||||||
private Boolean withUsed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持推理
|
* 是否支持推理
|
||||||
*/
|
*/
|
||||||
@@ -277,14 +272,6 @@ public class ModelBase implements Serializable {
|
|||||||
this.modelType = modelType;
|
this.modelType = modelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getWithUsed() {
|
|
||||||
return withUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWithUsed(Boolean withUsed) {
|
|
||||||
this.withUsed = withUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getSupportThinking() {
|
public Boolean getSupportThinking() {
|
||||||
return supportThinking;
|
return supportThinking;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package tech.easyflow.ai.service;
|
package tech.easyflow.ai.service;
|
||||||
|
|
||||||
import tech.easyflow.ai.entity.Model;
|
|
||||||
import com.mybatisflex.core.service.IService;
|
import com.mybatisflex.core.service.IService;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.ai.entity.Model;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,6 +24,4 @@ public interface ModelService extends IService<Model> {
|
|||||||
void removeByEntity(Model entity);
|
void removeByEntity(Model entity);
|
||||||
|
|
||||||
Model getModelInstance(BigInteger modelId);
|
Model getModelInstance(BigInteger modelId);
|
||||||
|
|
||||||
void updateByEntity(Model entity);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
package tech.easyflow.ai.service.impl;
|
package tech.easyflow.ai.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alicp.jetcache.Cache;
|
||||||
import com.easyagents.core.document.Document;
|
import com.easyagents.core.document.Document;
|
||||||
import com.easyagents.core.model.chat.ChatModel;
|
import com.easyagents.core.model.chat.ChatModel;
|
||||||
import com.easyagents.core.model.chat.ChatOptions;
|
import com.easyagents.core.model.chat.ChatOptions;
|
||||||
import com.easyagents.core.model.embedding.EmbeddingModel;
|
import com.easyagents.core.model.embedding.EmbeddingModel;
|
||||||
import com.easyagents.core.model.rerank.RerankModel;
|
import com.easyagents.core.model.rerank.RerankModel;
|
||||||
import com.easyagents.core.store.VectorData;
|
import com.easyagents.core.store.VectorData;
|
||||||
import com.alicp.jetcache.Cache;
|
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -21,7 +21,6 @@ import tech.easyflow.ai.entity.ModelProvider;
|
|||||||
import tech.easyflow.ai.mapper.ModelMapper;
|
import tech.easyflow.ai.mapper.ModelMapper;
|
||||||
import tech.easyflow.ai.service.ModelProviderService;
|
import tech.easyflow.ai.service.ModelProviderService;
|
||||||
import tech.easyflow.ai.service.ModelService;
|
import tech.easyflow.ai.service.ModelService;
|
||||||
import tech.easyflow.common.domain.Result;
|
|
||||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -92,7 +91,6 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
|
|||||||
|
|
||||||
QueryWrapper queryWrapper = new QueryWrapper()
|
QueryWrapper queryWrapper = new QueryWrapper()
|
||||||
.eq(Model::getProviderId, entity.getProviderId());
|
.eq(Model::getProviderId, entity.getProviderId());
|
||||||
queryWrapper.eq(Model::getWithUsed, entity.getWithUsed());
|
|
||||||
List<Model> totalList = modelMapper.selectListWithRelationsByQuery(queryWrapper);
|
List<Model> totalList = modelMapper.selectListWithRelationsByQuery(queryWrapper);
|
||||||
for (String modelType : Model.MODEL_TYPES) {
|
for (String modelType : Model.MODEL_TYPES) {
|
||||||
Map<String, List<Model>> groupMap = groupLlmByGroupName(totalList, modelType);
|
Map<String, List<Model>> groupMap = groupLlmByGroupName(totalList, modelType);
|
||||||
@@ -212,13 +210,4 @@ public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements
|
|||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateByEntity(Model entity) {
|
|
||||||
QueryWrapper queryWrapper = QueryWrapper.create().eq(Model::getProviderId, entity.getProviderId())
|
|
||||||
.eq(Model::getGroupName, entity.getGroupName());
|
|
||||||
Model model = new Model();
|
|
||||||
model.setWithUsed(entity.getWithUsed());
|
|
||||||
modelMapper.updateByQuery(model, queryWrapper);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ spring:
|
|||||||
activate:
|
activate:
|
||||||
on-profile: prod
|
on-profile: prod
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://127.0.0.1:3306/easyflow?useInformationSchema=true&characterEncoding=utf-8
|
url: jdbc:mysql://127.0.0.1:23306/easyflow?useInformationSchema=true&characterEncoding=utf-8
|
||||||
username: easyflow
|
username: easyflow
|
||||||
password: 123456
|
password: root
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
|
|||||||
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供应商
|
// 获取LLM供应商
|
||||||
export async function getLlmProviderList() {
|
export async function getLlmProviderList() {
|
||||||
return api.get('/api/v1/modelProvider/list');
|
return api.get('/api/v1/modelProvider/list');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ModelListQuery {
|
||||||
|
modelType?: string;
|
||||||
|
providerId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getModelList(params: ModelListQuery = {}) {
|
||||||
|
return api.get('/api/v1/model/list', { params });
|
||||||
|
}
|
||||||
|
|
||||||
// 保存LLM
|
// 保存LLM
|
||||||
export async function saveLlm(data: string) {
|
export async function saveLlm(data: string) {
|
||||||
return api.post('/api/v1/model/save', data);
|
return api.post('/api/v1/model/save', data);
|
||||||
@@ -20,6 +29,10 @@ export async function updateLlm(data: any) {
|
|||||||
return api.post(`/api/v1/model/update`, data);
|
return api.post(`/api/v1/model/update`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function verifyModelConfig(id: string) {
|
||||||
|
return api.get('/api/v1/model/verifyLlmConfig', { params: { id } });
|
||||||
|
}
|
||||||
|
|
||||||
// 一键添加LLM
|
// 一键添加LLM
|
||||||
export async function quickAddLlm(data: any) {
|
export async function quickAddLlm(data: any) {
|
||||||
return api.post(`/api/v1/model/quickAdd`, data);
|
return api.post(`/api/v1/model/quickAdd`, data);
|
||||||
@@ -33,7 +46,6 @@ export interface llmType {
|
|||||||
providerName: string;
|
providerName: string;
|
||||||
providerType: string;
|
providerType: string;
|
||||||
};
|
};
|
||||||
withUsed: boolean;
|
|
||||||
llmModel: string;
|
llmModel: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ interface Props {
|
|||||||
contentPadding?: number | string;
|
contentPadding?: number | string;
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
stickyToolbar?: boolean;
|
stickyToolbar?: boolean;
|
||||||
surface?: 'panel' | 'subtle';
|
surface?: 'panel' | 'plain' | 'subtle';
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -141,6 +141,18 @@ const contentStyle = computed((): CSSProperties => {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-page-shell.is-plain .list-page-shell__content {
|
||||||
|
background: hsl(var(--surface-panel) / 0.96);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 0.58);
|
||||||
|
border-radius: 20px;
|
||||||
|
box-shadow: none;
|
||||||
|
backdrop-filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-page-shell.is-plain .list-page-shell__content::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.list-page-shell__content::before {
|
.list-page-shell__content::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0 0 auto;
|
inset: 0 0 auto;
|
||||||
|
|||||||
@@ -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": {
|
"button": {
|
||||||
"management": "Management",
|
"management": "Management",
|
||||||
"test": "Test",
|
"test": "Test",
|
||||||
"addAllLlm": "Add models from the list",
|
|
||||||
"RetrieveAgain": "Retrieve the model list again"
|
"RetrieveAgain": "Retrieve the model list again"
|
||||||
},
|
},
|
||||||
"all": "All",
|
"all": "All",
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
"button": {
|
"button": {
|
||||||
"management": "管理",
|
"management": "管理",
|
||||||
"test": "检测",
|
"test": "检测",
|
||||||
"addAllLlm": "添加列表中的所有模型",
|
|
||||||
"RetrieveAgain": "重新获取模型列表"
|
"RetrieveAgain": "重新获取模型列表"
|
||||||
},
|
},
|
||||||
"all": "全部",
|
"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">
|
<script setup lang="ts">
|
||||||
import type { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability';
|
import type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
|
||||||
|
|
||||||
import { reactive, ref, watch } from 'vue';
|
|
||||||
|
|
||||||
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
|
||||||
|
|
||||||
import { ElForm, ElFormItem, ElInput, ElMessage, ElTag } from 'element-plus';
|
|
||||||
|
|
||||||
import { api } from '#/api/request';
|
|
||||||
import { $t } from '#/locales';
|
|
||||||
import {
|
import {
|
||||||
getDefaultModelAbility,
|
getDefaultModelAbility,
|
||||||
handleTagClick as handleTagClickUtil,
|
|
||||||
syncTagSelectedStatus as syncTagSelectedStatusUtil,
|
syncTagSelectedStatus as syncTagSelectedStatusUtil,
|
||||||
} from '#/views/ai/model/modelUtils/model-ability';
|
} from '#/views/ai/model/modelUtils/model-ability';
|
||||||
|
|
||||||
|
import {computed, reactive, ref, watch} from 'vue';
|
||||||
|
|
||||||
|
import {EasyFlowFormModal} from '@easyflow/common-ui';
|
||||||
|
|
||||||
|
import {ArrowDown, ArrowUp} from '@element-plus/icons-vue';
|
||||||
|
import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage} from 'element-plus';
|
||||||
|
|
||||||
|
import {api} from '#/api/request';
|
||||||
|
import {$t} from '#/locales';
|
||||||
import {
|
import {
|
||||||
generateFeaturesFromModelAbility,
|
generateFeaturesFromModelAbility,
|
||||||
resetModelAbility,
|
resetModelAbility,
|
||||||
} from '#/views/ai/model/modelUtils/model-ability-utils';
|
} from '#/views/ai/model/modelUtils/model-ability-utils';
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
|
id?: string;
|
||||||
modelType: string;
|
modelType: string;
|
||||||
title: string;
|
title: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
groupName: string;
|
groupName: string;
|
||||||
providerId: string;
|
providerId: string;
|
||||||
provider: string;
|
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
requestPath: string;
|
requestPath: string;
|
||||||
@@ -37,12 +37,6 @@ interface FormData {
|
|||||||
supportVideo: boolean;
|
supportVideo: boolean;
|
||||||
supportImageB64Only: boolean;
|
supportImageB64Only: boolean;
|
||||||
supportToolMessage: boolean;
|
supportToolMessage: boolean;
|
||||||
options: {
|
|
||||||
chatPath: string;
|
|
||||||
embedPath: string;
|
|
||||||
llmEndpoint: string;
|
|
||||||
rerankPath: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -55,7 +49,6 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
const selectedProviderId = ref<string>(props.providerId ?? '');
|
const selectedProviderId = ref<string>(props.providerId ?? '');
|
||||||
|
|
||||||
// 监听 providerId 的变化
|
|
||||||
watch(
|
watch(
|
||||||
() => props.providerId,
|
() => props.providerId,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
@@ -69,15 +62,15 @@ watch(
|
|||||||
const formDataRef = ref();
|
const formDataRef = ref();
|
||||||
const isAdd = ref(true);
|
const isAdd = ref(true);
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
|
const btnLoading = ref(false);
|
||||||
|
const showAdvanced = ref(false);
|
||||||
|
|
||||||
// 表单数据
|
|
||||||
const formData = reactive<FormData>({
|
const formData = reactive<FormData>({
|
||||||
modelType: '',
|
modelType: '',
|
||||||
title: '',
|
title: '',
|
||||||
modelName: '',
|
modelName: '',
|
||||||
groupName: '',
|
groupName: '',
|
||||||
providerId: '',
|
providerId: '',
|
||||||
provider: '',
|
|
||||||
apiKey: '',
|
apiKey: '',
|
||||||
endpoint: '',
|
endpoint: '',
|
||||||
requestPath: '',
|
requestPath: '',
|
||||||
@@ -88,87 +81,104 @@ const formData = reactive<FormData>({
|
|||||||
supportFree: false,
|
supportFree: false,
|
||||||
supportVideo: false,
|
supportVideo: false,
|
||||||
supportImageB64Only: false,
|
supportImageB64Only: false,
|
||||||
supportToolMessage: false,
|
supportToolMessage: true,
|
||||||
options: {
|
|
||||||
llmEndpoint: '',
|
|
||||||
chatPath: '',
|
|
||||||
embedPath: '',
|
|
||||||
rerankPath: '',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 使用抽取的函数获取模型能力配置
|
|
||||||
const modelAbility = ref<ModelAbilityItem[]>(getDefaultModelAbility());
|
const modelAbility = ref<ModelAbilityItem[]>(getDefaultModelAbility());
|
||||||
|
type SelectableModelType = '' | 'embeddingModel' | 'rerankModel';
|
||||||
|
|
||||||
|
const selectedModelType = ref<SelectableModelType>('');
|
||||||
|
const modelTypeAbilityOptions = [
|
||||||
|
{
|
||||||
|
label: $t('llmProvider.embeddingModel'),
|
||||||
|
value: 'embeddingModel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: $t('llmProvider.rerankModel'),
|
||||||
|
value: 'rerankModel',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
const hasSpecialModelType = computed(() => Boolean(selectedModelType.value));
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步标签选中状态与formData中的布尔字段
|
|
||||||
*/
|
|
||||||
const syncTagSelectedStatus = () => {
|
const syncTagSelectedStatus = () => {
|
||||||
syncTagSelectedStatusUtil(modelAbility.value, formData);
|
syncTagSelectedStatusUtil(modelAbility.value, formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const resetAbilitySelection = () => {
|
||||||
* 处理标签点击事件
|
resetModelAbility(modelAbility.value);
|
||||||
*/
|
syncTagSelectedStatus();
|
||||||
const handleTagClick = (item: ModelAbilityItem) => {
|
|
||||||
// handleTagClickUtil(modelAbility.value, item, formData);
|
|
||||||
handleTagClickUtil(item, formData);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 打开新增弹窗
|
const handleTagClick = (item: ModelAbilityItem) => {
|
||||||
defineExpose({
|
if (hasSpecialModelType.value) {
|
||||||
openAddDialog(modelType: string) {
|
return;
|
||||||
isAdd.value = true;
|
}
|
||||||
if (formDataRef.value) {
|
item.selected = !item.selected;
|
||||||
formDataRef.value.resetFields();
|
formData[item.field] = item.selected;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 重置表单数据
|
const handleModelTypeChipClick = (
|
||||||
Object.assign(formData, {
|
modelType: Exclude<SelectableModelType, ''>,
|
||||||
id: '',
|
) => {
|
||||||
modelType,
|
const nextType = selectedModelType.value === modelType ? '' : modelType;
|
||||||
title: '',
|
selectedModelType.value = nextType;
|
||||||
modelName: '',
|
if (nextType) {
|
||||||
groupName: '',
|
resetAbilitySelection();
|
||||||
provider: '',
|
}
|
||||||
endPoint: '',
|
};
|
||||||
providerId: '',
|
|
||||||
supportThinking: false,
|
const isAbilityChipDisabled = () => hasSpecialModelType.value;
|
||||||
supportTool: false,
|
|
||||||
supportAudio: false,
|
const resolveModelType = (): FormData['modelType'] => {
|
||||||
supportVideo: false,
|
return selectedModelType.value || 'chatModel';
|
||||||
supportImage: false,
|
};
|
||||||
supportImageB64Only: false,
|
|
||||||
supportFree: false,
|
const resetFormData = () => {
|
||||||
supportToolMessage: true,
|
Object.assign(formData, {
|
||||||
options: {
|
id: '',
|
||||||
llmEndpoint: '',
|
modelType: '',
|
||||||
chatPath: '',
|
title: '',
|
||||||
embedPath: '',
|
modelName: '',
|
||||||
rerankPath: '',
|
groupName: '',
|
||||||
},
|
providerId: '',
|
||||||
});
|
apiKey: '',
|
||||||
showMoreFields.value = false;
|
endpoint: '',
|
||||||
// 重置标签状态
|
requestPath: '',
|
||||||
resetModelAbility(modelAbility.value);
|
supportThinking: false,
|
||||||
syncTagSelectedStatus();
|
supportTool: false,
|
||||||
|
supportAudio: false,
|
||||||
|
supportVideo: false,
|
||||||
|
supportImage: false,
|
||||||
|
supportImageB64Only: false,
|
||||||
|
supportFree: false,
|
||||||
|
supportToolMessage: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openAddDialog() {
|
||||||
|
isAdd.value = true;
|
||||||
|
formDataRef.value?.resetFields();
|
||||||
|
resetFormData();
|
||||||
|
showAdvanced.value = false;
|
||||||
|
selectedModelType.value = '';
|
||||||
|
resetAbilitySelection();
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
openEditDialog(item: any) {
|
openEditDialog(item: any) {
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
isAdd.value = false;
|
isAdd.value = false;
|
||||||
|
resetFormData();
|
||||||
// 填充表单数据
|
|
||||||
Object.assign(formData, {
|
Object.assign(formData, {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
modelType: item.modelType || '',
|
modelType: item.modelType || '',
|
||||||
title: item.title || '',
|
title: item.title || '',
|
||||||
modelName: item.modelName || '',
|
modelName: item.modelName || '',
|
||||||
groupName: item.groupName || '',
|
groupName: item.groupName || '',
|
||||||
provider: item.provider || '',
|
|
||||||
endpoint: item.endpoint || '',
|
endpoint: item.endpoint || '',
|
||||||
requestPath: item.requestPath || '',
|
requestPath: item.requestPath || '',
|
||||||
|
apiKey: item.apiKey || '',
|
||||||
supportThinking: item.supportThinking || false,
|
supportThinking: item.supportThinking || false,
|
||||||
supportAudio: item.supportAudio || false,
|
supportAudio: item.supportAudio || false,
|
||||||
supportImage: item.supportImage || false,
|
supportImage: item.supportImage || false,
|
||||||
@@ -176,17 +186,21 @@ defineExpose({
|
|||||||
supportVideo: item.supportVideo || false,
|
supportVideo: item.supportVideo || false,
|
||||||
supportTool: item.supportTool || false,
|
supportTool: item.supportTool || false,
|
||||||
supportFree: item.supportFree || false,
|
supportFree: item.supportFree || false,
|
||||||
supportToolMessage: item.supportToolMessage || false,
|
supportToolMessage:
|
||||||
options: {
|
item.supportToolMessage === undefined ? true : item.supportToolMessage,
|
||||||
llmEndpoint: item.options?.llmEndpoint || '',
|
|
||||||
chatPath: item.options?.chatPath || '',
|
|
||||||
embedPath: item.options?.embedPath || '',
|
|
||||||
rerankPath: item.options?.rerankPath || '',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
showMoreFields.value = false;
|
selectedModelType.value =
|
||||||
// 同步标签状态
|
item.modelType === 'embeddingModel' || item.modelType === 'rerankModel'
|
||||||
syncTagSelectedStatus();
|
? item.modelType
|
||||||
|
: '';
|
||||||
|
showAdvanced.value = Boolean(
|
||||||
|
formData.apiKey || formData.endpoint || formData.requestPath,
|
||||||
|
);
|
||||||
|
if (selectedModelType.value) {
|
||||||
|
resetAbilitySelection();
|
||||||
|
} else {
|
||||||
|
syncTagSelectedStatus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -195,76 +209,53 @@ const closeDialog = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
title: [
|
title: [{ required: true, message: $t('message.required'), trigger: 'blur' }],
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: $t('message.required'),
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
modelName: [
|
modelName: [
|
||||||
{
|
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
||||||
required: true,
|
|
||||||
message: $t('message.required'),
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
groupName: [
|
groupName: [
|
||||||
{
|
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
||||||
required: true,
|
|
||||||
message: $t('message.required'),
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
provider: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: $t('message.required'),
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const btnLoading = ref(false);
|
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
|
const modelType = resolveModelType();
|
||||||
// 使用工具函数从模型能力生成features
|
|
||||||
const features = generateFeaturesFromModelAbility(modelAbility.value);
|
const features = generateFeaturesFromModelAbility(modelAbility.value);
|
||||||
|
|
||||||
|
if (modelType !== 'chatModel') {
|
||||||
|
for (const key of Object.keys(features) as Array<keyof typeof features>) {
|
||||||
|
features[key] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await formDataRef.value.validate();
|
await formDataRef.value.validate();
|
||||||
const submitData = { ...formData, ...features };
|
const submitData = {
|
||||||
|
...formData,
|
||||||
|
...features,
|
||||||
|
modelType,
|
||||||
|
providerId: isAdd.value ? selectedProviderId.value : formData.providerId,
|
||||||
|
};
|
||||||
|
|
||||||
if (isAdd.value) {
|
const url = isAdd.value ? '/api/v1/model/save' : '/api/v1/model/update';
|
||||||
submitData.providerId = selectedProviderId.value;
|
const res = await api.post(url, submitData);
|
||||||
const res = await api.post('/api/v1/model/save', submitData);
|
|
||||||
if (res.errorCode === 0) {
|
if (res.errorCode === 0) {
|
||||||
ElMessage.success(res.message);
|
ElMessage.success(res.message);
|
||||||
emit('reload');
|
emit('reload');
|
||||||
closeDialog();
|
closeDialog();
|
||||||
} else {
|
|
||||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const res = await api.post('/api/v1/model/update', submitData);
|
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||||
if (res.errorCode === 0) {
|
|
||||||
ElMessage.success(res.message);
|
|
||||||
emit('reload');
|
|
||||||
closeDialog();
|
|
||||||
} else {
|
|
||||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Save model error:', error);
|
if (!(error as any)?.fields) {
|
||||||
ElMessage.error($t('ui.actionMessage.operationFailed'));
|
ElMessage.error($t('ui.actionMessage.operationFailed'));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
btnLoading.value = false;
|
btnLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const showMoreFields = ref(false);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -272,91 +263,240 @@ const showMoreFields = ref(false);
|
|||||||
v-model:open="dialogVisible"
|
v-model:open="dialogVisible"
|
||||||
:centered="true"
|
:centered="true"
|
||||||
:closable="!btnLoading"
|
:closable="!btnLoading"
|
||||||
:title="isAdd ? $t('button.add') : $t('button.edit')"
|
:title="isAdd ? '添加模型' : '编辑模型'"
|
||||||
:before-close="closeDialog"
|
:before-close="closeDialog"
|
||||||
width="482"
|
width="640"
|
||||||
:confirm-loading="btnLoading"
|
:confirm-loading="btnLoading"
|
||||||
:confirm-text="$t('button.save')"
|
:confirm-text="$t('button.save')"
|
||||||
:submitting="btnLoading"
|
:submitting="btnLoading"
|
||||||
@confirm="save"
|
@confirm="save"
|
||||||
>
|
>
|
||||||
<ElForm
|
<div class="model-modal">
|
||||||
ref="formDataRef"
|
<ElForm
|
||||||
:model="formData"
|
ref="formDataRef"
|
||||||
status-icon
|
:model="formData"
|
||||||
:rules="rules"
|
status-icon
|
||||||
label-position="top"
|
:rules="rules"
|
||||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
label-position="top"
|
||||||
>
|
class="model-modal__form"
|
||||||
<ElFormItem prop="title" :label="$t('llm.title')">
|
>
|
||||||
<ElInput v-model.trim="formData.title" />
|
<div class="model-modal__section">
|
||||||
</ElFormItem>
|
<div class="model-modal__section-head">
|
||||||
<ElFormItem prop="modelName" :label="$t('llm.llmModel')">
|
<h4>基础信息</h4>
|
||||||
<ElInput v-model.trim="formData.modelName" />
|
<p>这些字段决定模型在列表里的展示与组织方式。</p>
|
||||||
</ElFormItem>
|
</div>
|
||||||
<ElFormItem prop="groupName" :label="$t('llm.groupName')">
|
|
||||||
<ElInput v-model.trim="formData.groupName" />
|
<ElFormItem prop="title" :label="$t('llm.title')">
|
||||||
</ElFormItem>
|
<ElInput
|
||||||
<ElFormItem prop="ability" :label="$t('llm.ability')">
|
v-model.trim="formData.title"
|
||||||
<div class="model-ability">
|
placeholder="例如:生产主模型"
|
||||||
<ElTag
|
/>
|
||||||
class="model-ability-tag"
|
</ElFormItem>
|
||||||
v-for="item in modelAbility"
|
<ElFormItem prop="modelName" :label="$t('llm.llmModel')">
|
||||||
:key="item.value"
|
<ElInput
|
||||||
:type="item.selected ? item.activeType : item.defaultType"
|
v-model.trim="formData.modelName"
|
||||||
@click="handleTagClick(item)"
|
placeholder="例如:gpt-4.1 / glm-4.5 / qwen3:8b"
|
||||||
:class="{ 'tag-selected': item.selected }"
|
/>
|
||||||
>
|
</ElFormItem>
|
||||||
{{ item.label }}
|
<ElFormItem prop="groupName" :label="$t('llm.groupName')">
|
||||||
</ElTag>
|
<ElInput
|
||||||
|
v-model.trim="formData.groupName"
|
||||||
|
placeholder="例如:默认组"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
</div>
|
</div>
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem label=" " v-if="!showMoreFields">
|
<div class="model-modal__section">
|
||||||
<ElButton @click="showMoreFields = !showMoreFields" type="primary">
|
<div class="model-modal__section-head">
|
||||||
{{ showMoreFields ? $t('button.hide') : $t('button.more') }}
|
<h4>{{ $t('llm.ability') }}</h4>
|
||||||
</ElButton>
|
<p>可选嵌入或重排模型类型;选择后其余能力会自动锁定。</p>
|
||||||
</ElFormItem>
|
</div>
|
||||||
<ElFormItem
|
<div class="model-modal__ability">
|
||||||
prop="apiKey"
|
<button
|
||||||
:label="$t('llmProvider.apiKey')"
|
v-for="item in modelTypeAbilityOptions"
|
||||||
v-show="showMoreFields"
|
:key="item.value"
|
||||||
>
|
type="button"
|
||||||
<ElInput v-model.trim="formData.apiKey" />
|
class="model-modal__ability-chip"
|
||||||
</ElFormItem>
|
:class="{ 'is-active': selectedModelType === item.value }"
|
||||||
<ElFormItem
|
@click="handleModelTypeChipClick(item.value)"
|
||||||
prop="endpoint"
|
>
|
||||||
:label="$t('llmProvider.endpoint')"
|
{{ item.label }}
|
||||||
v-show="showMoreFields"
|
</button>
|
||||||
>
|
</div>
|
||||||
<ElInput v-model.trim="formData.endpoint" />
|
<div class="model-modal__ability">
|
||||||
</ElFormItem>
|
<button
|
||||||
<ElFormItem
|
v-for="item in modelAbility"
|
||||||
prop="requestPath"
|
:key="item.value"
|
||||||
:label="$t('llm.requestPath')"
|
type="button"
|
||||||
v-show="showMoreFields"
|
class="model-modal__ability-chip"
|
||||||
>
|
:class="{
|
||||||
<ElInput v-model.trim="formData.requestPath" />
|
'is-active': item.selected,
|
||||||
</ElFormItem>
|
'is-disabled': isAbilityChipDisabled(),
|
||||||
</ElForm>
|
}"
|
||||||
|
:disabled="isAbilityChipDisabled()"
|
||||||
|
@click="handleTagClick(item)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="model-modal__section">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="model-modal__advanced-toggle"
|
||||||
|
@click="showAdvanced = !showAdvanced"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h4>高级设置</h4>
|
||||||
|
<p>仅在需要覆写服务商默认配置时填写。</p>
|
||||||
|
</div>
|
||||||
|
<ElIcon>
|
||||||
|
<ArrowUp v-if="showAdvanced" />
|
||||||
|
<ArrowDown v-else />
|
||||||
|
</ElIcon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div v-if="showAdvanced" class="model-modal__advanced-grid">
|
||||||
|
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.apiKey"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
placeholder="可选,单独覆写模型密钥"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.endpoint"
|
||||||
|
placeholder="可选,单独覆写 endpoint"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem prop="requestPath" :label="$t('llm.requestPath')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.requestPath"
|
||||||
|
placeholder="可选,单独覆写 requestPath"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ElForm>
|
||||||
|
</div>
|
||||||
</EasyFlowFormModal>
|
</EasyFlowFormModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.model-ability {
|
.model-modal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
hsl(var(--surface-panel) / 98%) 0%,
|
||||||
|
hsl(var(--surface-contrast-soft) / 94%) 100%
|
||||||
|
);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 50%);
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__section-head h4,
|
||||||
|
.model-modal__advanced-toggle h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__section-head p,
|
||||||
|
.model-modal__advanced-toggle p {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__ability {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__ability-chip {
|
||||||
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 4px;
|
justify-content: center;
|
||||||
}
|
padding: 8px 14px;
|
||||||
|
font-size: 13px;
|
||||||
.model-ability-tag {
|
color: hsl(var(--text-muted));
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
background: hsl(var(--surface-panel));
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 68%);
|
||||||
|
border-radius: 999px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s ease,
|
||||||
|
color 0.2s ease,
|
||||||
|
background 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-selected {
|
.model-modal__ability-chip:hover:not(:disabled),
|
||||||
font-weight: bold;
|
.model-modal__ability-chip:focus-visible:not(:disabled) {
|
||||||
transform: scale(1.05);
|
color: hsl(var(--text-strong));
|
||||||
|
border-color: hsl(var(--divider-faint));
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__ability-chip.is-active {
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
background: hsl(var(--primary) / 8%);
|
||||||
|
border-color: hsl(var(--primary) / 38%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__ability-chip.is-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.56;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__advanced-toggle {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__advanced-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__advanced-grid :deep(.el-form-item:last-child) {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.model-modal__advanced-grid {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-modal__advanced-grid :deep(.el-form-item:last-child) {
|
||||||
|
grid-column: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,41 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue';
|
import {computed, reactive, ref} from 'vue';
|
||||||
|
|
||||||
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
import {EasyFlowFormModal} from '@easyflow/common-ui';
|
||||||
|
|
||||||
import {
|
import {ArrowDown, ArrowUp} from '@element-plus/icons-vue';
|
||||||
ElForm,
|
import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage, ElOption, ElSelect,} from 'element-plus';
|
||||||
ElFormItem,
|
|
||||||
ElInput,
|
|
||||||
ElMessage,
|
|
||||||
ElOption,
|
|
||||||
ElSelect,
|
|
||||||
} from 'element-plus';
|
|
||||||
|
|
||||||
import { api } from '#/api/request';
|
import {api} from '#/api/request';
|
||||||
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
||||||
import { $t } from '#/locales';
|
import {$t} from '#/locales';
|
||||||
import providerList from '#/views/ai/model/modelUtils/providerList.json';
|
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
||||||
|
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon';
|
||||||
|
|
||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
|
|
||||||
const formDataRef = ref();
|
const formDataRef = ref();
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
openAddDialog() {
|
|
||||||
formDataRef.value?.resetFields();
|
|
||||||
dialogVisible.value = true;
|
|
||||||
},
|
|
||||||
openEditDialog(item: any) {
|
|
||||||
dialogVisible.value = true;
|
|
||||||
isAdd.value = false;
|
|
||||||
Object.assign(formData, item);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const providerOptions =
|
|
||||||
ref<Array<{ label: string; options: any; value: string }>>(providerList);
|
|
||||||
const isAdd = ref(true);
|
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
|
const btnLoading = ref(false);
|
||||||
|
const isAdd = ref(true);
|
||||||
|
const showAdvanced = ref(false);
|
||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
id: '',
|
id: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
@@ -47,9 +31,64 @@ const formData = reactive({
|
|||||||
embedPath: '',
|
embedPath: '',
|
||||||
rerankPath: '',
|
rerankPath: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedPreset = computed(() =>
|
||||||
|
getProviderPresetByValue(formData.providerType),
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasLegacyProvider = computed(
|
||||||
|
() => !selectedPreset.value && !!formData.providerType,
|
||||||
|
);
|
||||||
|
|
||||||
|
const getModeLabel = (mode?: 'hosted' | 'self-hosted') =>
|
||||||
|
mode === 'self-hosted' ? '自部署' : '云服务';
|
||||||
|
|
||||||
|
const resetFormData = () => {
|
||||||
|
Object.assign(formData, {
|
||||||
|
id: '',
|
||||||
|
icon: '',
|
||||||
|
providerName: '',
|
||||||
|
providerType: '',
|
||||||
|
apiKey: '',
|
||||||
|
endpoint: '',
|
||||||
|
chatPath: '',
|
||||||
|
embedPath: '',
|
||||||
|
rerankPath: '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openAddDialog() {
|
||||||
|
isAdd.value = true;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
showAdvanced.value = false;
|
||||||
|
formDataRef.value?.resetFields();
|
||||||
|
resetFormData();
|
||||||
|
},
|
||||||
|
openEditDialog(item: any) {
|
||||||
|
isAdd.value = false;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
showAdvanced.value = false;
|
||||||
|
formDataRef.value?.clearValidate();
|
||||||
|
resetFormData();
|
||||||
|
Object.assign(formData, {
|
||||||
|
...item,
|
||||||
|
icon: item.icon || '',
|
||||||
|
providerName: item.providerName || '',
|
||||||
|
providerType: item.providerType || '',
|
||||||
|
apiKey: item.apiKey || '',
|
||||||
|
endpoint: item.endpoint || '',
|
||||||
|
chatPath: item.chatPath || '',
|
||||||
|
embedPath: item.embedPath || '',
|
||||||
|
rerankPath: item.rerankPath || '',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
providerName: [
|
providerName: [
|
||||||
{
|
{
|
||||||
@@ -59,6 +98,20 @@ const rules = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
providerType: [
|
providerType: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: $t('message.required'),
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
endpoint: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: $t('message.required'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
chatPath: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: $t('message.required'),
|
message: $t('message.required'),
|
||||||
@@ -66,48 +119,47 @@ const rules = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const btnLoading = ref(false);
|
|
||||||
|
const applyPreset = (value: string) => {
|
||||||
|
const preset = getProviderPresetByValue(value);
|
||||||
|
if (!preset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.providerType = preset.value;
|
||||||
|
formData.providerName = preset.label;
|
||||||
|
formData.endpoint = preset.options.llmEndpoint || '';
|
||||||
|
formData.chatPath = preset.options.chatPath || '';
|
||||||
|
formData.embedPath = preset.options.embedPath || '';
|
||||||
|
formData.rerankPath = preset.options.rerankPath || '';
|
||||||
|
};
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isAdd.value) {
|
|
||||||
api.post('/api/v1/modelProvider/update', formData).then((res) => {
|
|
||||||
if (res.errorCode === 0) {
|
|
||||||
ElMessage.success(res.message);
|
|
||||||
emit('reload');
|
|
||||||
closeDialog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await formDataRef.value.validate();
|
await formDataRef.value.validate();
|
||||||
api.post('/api/v1/modelProvider/save', formData).then((res) => {
|
|
||||||
if (res.errorCode === 0) {
|
const url = isAdd.value
|
||||||
ElMessage.success(res.message);
|
? '/api/v1/modelProvider/save'
|
||||||
emit('reload');
|
: '/api/v1/modelProvider/update';
|
||||||
closeDialog();
|
const res = await api.post(url, formData);
|
||||||
}
|
|
||||||
});
|
if (res.errorCode === 0) {
|
||||||
|
ElMessage.success(res.message || '服务商已保存');
|
||||||
|
emit('reload');
|
||||||
|
closeDialog();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (!(error as any)?.fields) {
|
||||||
|
ElMessage.error($t('ui.actionMessage.operationFailed'));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
btnLoading.value = false;
|
btnLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleChangeProvider = (val: string) => {
|
|
||||||
const tempProvider = providerList.find((item) => item.value === val);
|
|
||||||
if (!tempProvider) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
formData.providerName = tempProvider.label;
|
|
||||||
formData.endpoint = providerOptions.value.find(
|
|
||||||
(item) => item.value === val,
|
|
||||||
)?.options.llmEndpoint;
|
|
||||||
formData.chatPath = providerOptions.value.find(
|
|
||||||
(item) => item.value === val,
|
|
||||||
)?.options.chatPath;
|
|
||||||
formData.embedPath = providerOptions.value.find(
|
|
||||||
(item) => item.value === val,
|
|
||||||
)?.options.embedPath;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -115,9 +167,9 @@ const handleChangeProvider = (val: string) => {
|
|||||||
v-model:open="dialogVisible"
|
v-model:open="dialogVisible"
|
||||||
:centered="true"
|
:centered="true"
|
||||||
:closable="!btnLoading"
|
:closable="!btnLoading"
|
||||||
:title="isAdd ? $t('button.add') : $t('button.edit')"
|
:title="isAdd ? '添加服务商' : '编辑服务商'"
|
||||||
:before-close="closeDialog"
|
:before-close="closeDialog"
|
||||||
width="482"
|
width="680"
|
||||||
:confirm-loading="btnLoading"
|
:confirm-loading="btnLoading"
|
||||||
:confirm-text="$t('button.save')"
|
:confirm-text="$t('button.save')"
|
||||||
:submitting="btnLoading"
|
:submitting="btnLoading"
|
||||||
@@ -129,63 +181,259 @@ const handleChangeProvider = (val: string) => {
|
|||||||
status-icon
|
status-icon
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
class="provider-modal"
|
||||||
>
|
>
|
||||||
<ElFormItem
|
<section class="provider-modal__section">
|
||||||
prop="icon"
|
<div class="provider-modal__section-head">
|
||||||
style="display: flex; align-items: center"
|
<h3>服务商预设</h3>
|
||||||
:label="$t('llmProvider.icon')"
|
<p>先选择预设,系统会自动回填推荐网关与默认路径。</p>
|
||||||
>
|
</div>
|
||||||
<UploadAvatar v-model="formData.icon" />
|
|
||||||
</ElFormItem>
|
<ElFormItem prop="providerType" :label="$t('llmProvider.apiType')">
|
||||||
<ElFormItem prop="providerName" :label="$t('llmProvider.providerName')">
|
<ElSelect
|
||||||
<ElInput v-model.trim="formData.providerName" />
|
v-model="formData.providerType"
|
||||||
</ElFormItem>
|
filterable
|
||||||
<ElFormItem prop="provider" :label="$t('llmProvider.apiType')">
|
placeholder="选择一个服务商预设"
|
||||||
<ElSelect
|
popper-class="provider-preset-select-dropdown"
|
||||||
v-model="formData.providerType"
|
@change="applyPreset"
|
||||||
@change="handleChangeProvider"
|
>
|
||||||
>
|
<template #prefix>
|
||||||
<ElOption
|
<ModelProviderBadge
|
||||||
v-for="item in providerOptions"
|
v-if="selectedPreset"
|
||||||
:key="item.value"
|
:provider-name="selectedPreset.label"
|
||||||
:label="item.label"
|
:provider-type="selectedPreset.value"
|
||||||
:value="item.value || ''"
|
:size="20"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<ElOption
|
||||||
|
v-for="item in providerPresets"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
<div class="provider-preset-option">
|
||||||
|
<div class="provider-preset-option__meta">
|
||||||
|
<ModelProviderBadge
|
||||||
|
:provider-name="item.label"
|
||||||
|
:provider-type="item.value"
|
||||||
|
:size="24"
|
||||||
|
/>
|
||||||
|
<strong>{{ item.label }}</strong>
|
||||||
|
</div>
|
||||||
|
<span>{{ getModeLabel(item.mode) }}</span>
|
||||||
|
</div>
|
||||||
|
</ElOption>
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
|
||||||
|
<div v-if="hasLegacyProvider" class="provider-modal__legacy">
|
||||||
|
当前类型为
|
||||||
|
{{
|
||||||
|
formData.providerType
|
||||||
|
}},该类型不在最新预设列表中,但仍可继续编辑。
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="provider-modal__section">
|
||||||
|
<div class="provider-modal__section-head">
|
||||||
|
<h3>基础接入</h3>
|
||||||
|
<p>先完成主流程字段:名称、密钥、Endpoint、对话路径。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="provider-modal__grid">
|
||||||
|
<ElFormItem
|
||||||
|
prop="providerName"
|
||||||
|
:label="$t('llmProvider.providerName')"
|
||||||
|
>
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.providerName"
|
||||||
|
placeholder="例如:OpenAI 生产环境"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.apiKey"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
placeholder="填写服务商密钥"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.endpoint"
|
||||||
|
placeholder="填写网关地址"
|
||||||
/>
|
/>
|
||||||
</ElSelect>
|
</ElFormItem>
|
||||||
</ElFormItem>
|
|
||||||
<ElFormItem prop="apiKey" :label="$t('llmProvider.apiKey')">
|
<ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')">
|
||||||
<ElInput v-model.trim="formData.apiKey" />
|
<ElInput
|
||||||
</ElFormItem>
|
v-model.trim="formData.chatPath"
|
||||||
<ElFormItem prop="endpoint" :label="$t('llmProvider.endpoint')">
|
placeholder="对话模型请求路径"
|
||||||
<ElInput v-model.trim="formData.endpoint" />
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem prop="chatPath" :label="$t('llmProvider.chatPath')">
|
</section>
|
||||||
<ElInput v-model.trim="formData.chatPath" />
|
|
||||||
</ElFormItem>
|
<section class="provider-modal__section">
|
||||||
<ElFormItem prop="rerankPath" :label="$t('llmProvider.rerankPath')">
|
<button
|
||||||
<ElInput v-model.trim="formData.rerankPath" />
|
type="button"
|
||||||
</ElFormItem>
|
class="provider-modal__advanced-toggle"
|
||||||
<ElFormItem prop="embedPath" :label="$t('llmProvider.embedPath')">
|
@click="showAdvanced = !showAdvanced"
|
||||||
<ElInput v-model.trim="formData.embedPath" />
|
>
|
||||||
</ElFormItem>
|
<div>
|
||||||
|
<h3>高级设置</h3>
|
||||||
|
<p>包含向量/重排路径、图标上传和预设说明,默认收起。</p>
|
||||||
|
</div>
|
||||||
|
<ElIcon>
|
||||||
|
<ArrowUp v-if="showAdvanced" />
|
||||||
|
<ArrowDown v-else />
|
||||||
|
</ElIcon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div v-if="showAdvanced" class="provider-modal__advanced">
|
||||||
|
<div class="provider-modal__grid">
|
||||||
|
<ElFormItem prop="embedPath" :label="$t('llmProvider.embedPath')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.embedPath"
|
||||||
|
placeholder="向量模型请求路径"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem prop="rerankPath" :label="$t('llmProvider.rerankPath')">
|
||||||
|
<ElInput
|
||||||
|
v-model.trim="formData.rerankPath"
|
||||||
|
placeholder="Rerank 请求路径"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="provider-modal__advanced-grid">
|
||||||
|
<div class="provider-modal__icon-panel">
|
||||||
|
<h4>图标上传</h4>
|
||||||
|
<p>用于区分同一厂商在测试、预发、生产等不同环境。</p>
|
||||||
|
<ElFormItem prop="icon" :label="$t('llmProvider.icon')">
|
||||||
|
<UploadAvatar v-model="formData.icon" />
|
||||||
|
</ElFormItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</ElForm>
|
</ElForm>
|
||||||
</EasyFlowFormModal>
|
</EasyFlowFormModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.headers-container-reduce {
|
.provider-modal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
background: hsl(var(--surface-panel) / 92%);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 54%);
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__section-head h3,
|
||||||
|
.provider-modal__advanced-toggle h3,
|
||||||
|
.provider-modal__preset-head h4,
|
||||||
|
.provider-modal__icon-panel h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__section-head p,
|
||||||
|
.provider-modal__advanced-toggle p,
|
||||||
|
.provider-modal__legacy,
|
||||||
|
.provider-modal__preset-head p,
|
||||||
|
.provider-modal__icon-panel p {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-preset-option {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-preset-option__meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.addHeadersBtn {
|
|
||||||
|
.provider-preset-option strong {
|
||||||
|
font-size: 14px;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-preset-option span {
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
background: hsl(var(--surface-contrast-soft));
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__legacy {
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: hsl(var(--warning) / 7%);
|
||||||
|
border: 1px solid hsl(var(--warning) / 26%);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__advanced-toggle {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-style: dashed;
|
padding: 0;
|
||||||
border-color: var(--el-color-primary);
|
text-align: left;
|
||||||
border-radius: 8px;
|
background: transparent;
|
||||||
margin-top: 8px;
|
border: none;
|
||||||
}
|
}
|
||||||
.head-con-content {
|
|
||||||
margin-bottom: 8px;
|
.provider-modal__advanced {
|
||||||
align-items: center;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__advanced-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.provider-modal__icon-panel {
|
||||||
|
padding: 12px;
|
||||||
|
background: hsl(var(--surface-contrast-soft) / 70%);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 54%);
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.provider-modal__grid,
|
||||||
|
.provider-modal__advanced-grid {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -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">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue';
|
import {computed, reactive, ref} from 'vue';
|
||||||
|
|
||||||
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
import {EasyFlowFormModal} from '@easyflow/common-ui';
|
||||||
|
|
||||||
import {
|
import {CircleCheckFilled, WarningFilled} from '@element-plus/icons-vue';
|
||||||
ElForm,
|
import {ElForm, ElFormItem, ElMessage, ElOption, ElSelect,} from 'element-plus';
|
||||||
ElFormItem,
|
|
||||||
ElMessage,
|
|
||||||
ElOption,
|
|
||||||
ElSelect,
|
|
||||||
} from 'element-plus';
|
|
||||||
|
|
||||||
import { api } from '#/api/request';
|
import {api} from '#/api/request';
|
||||||
import { $t } from '#/locales';
|
import {$t} from '#/locales';
|
||||||
|
|
||||||
|
type VerifyStatus = 'error' | 'idle' | 'success';
|
||||||
|
|
||||||
const options = ref<any[]>([]);
|
const options = ref<any[]>([]);
|
||||||
const getLlmList = (providerId: string) => {
|
|
||||||
api.get(`/api/v1/model/list?providerId=${providerId}`, {}).then((res) => {
|
|
||||||
if (res.errorCode === 0) {
|
|
||||||
options.value = res.data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const modelType = ref('');
|
const modelType = ref('');
|
||||||
const vectorDimension = ref('');
|
const vectorDimension = ref('');
|
||||||
|
const verifyStatus = ref<VerifyStatus>('idle');
|
||||||
|
const verifyMessage = ref('');
|
||||||
const formDataRef = ref();
|
const formDataRef = ref();
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
defineExpose({
|
const btnLoading = ref(false);
|
||||||
openDialog(providerId: string) {
|
|
||||||
formDataRef.value?.resetFields();
|
|
||||||
modelType.value = '';
|
|
||||||
vectorDimension.value = '';
|
|
||||||
getLlmList(providerId);
|
|
||||||
dialogVisible.value = true;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
llmId: '',
|
llmId: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const resultTitle = computed(() => {
|
||||||
|
if (verifyStatus.value === 'success') {
|
||||||
|
return '验证成功';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verifyStatus.value === 'error') {
|
||||||
|
return '验证失败';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '等待验证';
|
||||||
|
});
|
||||||
|
|
||||||
|
const getLlmList = async (providerId: string) => {
|
||||||
|
const res = await api.get(`/api/v1/model/list?providerId=${providerId}`, {});
|
||||||
|
if (res.errorCode === 0) {
|
||||||
|
options.value = res.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
async openDialog(providerId: string) {
|
||||||
|
formDataRef.value?.resetFields();
|
||||||
|
formData.llmId = '';
|
||||||
|
modelType.value = '';
|
||||||
|
vectorDimension.value = '';
|
||||||
|
verifyStatus.value = 'idle';
|
||||||
|
verifyMessage.value = '请选择一个模型并开始验证。';
|
||||||
|
await getLlmList(providerId);
|
||||||
|
dialogVisible.value = true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
llmId: [
|
llmId: [
|
||||||
{
|
{
|
||||||
@@ -49,28 +66,51 @@ const rules = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getModelInfo = (id: string) => {
|
||||||
|
const current = options.value.find((item: any) => item.id === id);
|
||||||
|
modelType.value = current?.modelType || '';
|
||||||
|
vectorDimension.value = '';
|
||||||
|
verifyStatus.value = 'idle';
|
||||||
|
verifyMessage.value = '已更新待验证模型,点击确认开始检测配置。';
|
||||||
|
};
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
await formDataRef.value.validate();
|
verifyStatus.value = 'idle';
|
||||||
api
|
verifyMessage.value = '正在连接模型服务,请稍候...';
|
||||||
.get(`/api/v1/model/verifyLlmConfig?id=${formData.llmId}`, {})
|
|
||||||
.then((res) => {
|
try {
|
||||||
if (res.errorCode === 0) {
|
await formDataRef.value.validate();
|
||||||
ElMessage.success($t('llm.testSuccess'));
|
const res = await api.get(
|
||||||
if (modelType.value === 'embeddingModel' && res?.data?.dimension) {
|
`/api/v1/model/verifyLlmConfig?id=${formData.llmId}`,
|
||||||
vectorDimension.value = res?.data?.dimension;
|
{},
|
||||||
}
|
);
|
||||||
|
|
||||||
|
if (res.errorCode === 0) {
|
||||||
|
verifyStatus.value = 'success';
|
||||||
|
verifyMessage.value = $t('llm.testSuccess');
|
||||||
|
ElMessage.success($t('llm.testSuccess'));
|
||||||
|
if (modelType.value === 'embeddingModel' && res?.data?.dimension) {
|
||||||
|
vectorDimension.value = res.data.dimension;
|
||||||
}
|
}
|
||||||
btnLoading.value = false;
|
} else {
|
||||||
});
|
verifyStatus.value = 'error';
|
||||||
};
|
verifyMessage.value =
|
||||||
const btnLoading = ref(false);
|
res.message || $t('ui.actionMessage.operationFailed');
|
||||||
const getModelInfo = (id: string) => {
|
ElMessage.error(verifyMessage.value);
|
||||||
options.value.forEach((item: any) => {
|
|
||||||
if (item.id === id) {
|
|
||||||
modelType.value = item.modelType;
|
|
||||||
}
|
}
|
||||||
});
|
} catch (error: any) {
|
||||||
|
if (error?.fields) {
|
||||||
|
verifyMessage.value = '请选择一个模型并开始验证。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyStatus.value = 'error';
|
||||||
|
verifyMessage.value =
|
||||||
|
error?.message || $t('ui.actionMessage.operationFailed');
|
||||||
|
} finally {
|
||||||
|
btnLoading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -80,54 +120,147 @@ const getModelInfo = (id: string) => {
|
|||||||
:centered="true"
|
:centered="true"
|
||||||
:closable="!btnLoading"
|
:closable="!btnLoading"
|
||||||
:title="$t('llm.verifyLlmTitle')"
|
:title="$t('llm.verifyLlmTitle')"
|
||||||
width="482"
|
width="560"
|
||||||
:confirm-loading="btnLoading"
|
:confirm-loading="btnLoading"
|
||||||
:confirm-text="$t('button.confirm')"
|
:confirm-text="$t('button.confirm')"
|
||||||
:submitting="btnLoading"
|
:submitting="btnLoading"
|
||||||
@confirm="save"
|
@confirm="save"
|
||||||
>
|
>
|
||||||
<ElForm
|
<div class="verify-modal">
|
||||||
ref="formDataRef"
|
<section class="verify-modal__section">
|
||||||
:model="formData"
|
<div class="verify-modal__section-head">
|
||||||
status-icon
|
<h3>1. 选择待验证模型</h3>
|
||||||
:rules="rules"
|
<p>
|
||||||
label-position="top"
|
会用当前保存的服务商配置发起一次真实请求,帮助你确认密钥和路径是否正确。
|
||||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
</p>
|
||||||
>
|
</div>
|
||||||
<ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
|
|
||||||
<ElSelect v-model="formData.llmId" @change="getModelInfo">
|
<ElForm
|
||||||
<ElOption
|
ref="formDataRef"
|
||||||
v-for="item in options"
|
:model="formData"
|
||||||
:key="item.id"
|
status-icon
|
||||||
:label="item.title"
|
:rules="rules"
|
||||||
:value="item.id || ''"
|
label-position="top"
|
||||||
/>
|
class="verify-modal__form"
|
||||||
</ElSelect>
|
>
|
||||||
</ElFormItem>
|
<ElFormItem prop="llmId" :label="$t('llm.modelToBeTested')">
|
||||||
<ElFormItem
|
<ElSelect
|
||||||
v-if="modelType === 'embeddingModel' && vectorDimension"
|
v-model="formData.llmId"
|
||||||
:label="$t('documentCollection.dimensionOfVectorModel')"
|
filterable
|
||||||
label-width="100px"
|
placeholder="选择一个模型"
|
||||||
>
|
@change="getModelInfo"
|
||||||
{{ vectorDimension }}
|
>
|
||||||
</ElFormItem>
|
<ElOption
|
||||||
</ElForm>
|
v-for="item in options"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.title"
|
||||||
|
:value="item.id || ''"
|
||||||
|
/>
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="verify-modal__section verify-modal__section--result">
|
||||||
|
<div class="verify-modal__section-head">
|
||||||
|
<h3>2. 查看验证结果</h3>
|
||||||
|
<p>成功后会返回可用状态;如果是向量模型,还会展示向量维度。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="verify-result-card"
|
||||||
|
:class="{
|
||||||
|
'is-success': verifyStatus === 'success',
|
||||||
|
'is-error': verifyStatus === 'error',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="verify-result-card__icon">
|
||||||
|
<CircleCheckFilled v-if="verifyStatus === 'success'" />
|
||||||
|
<WarningFilled v-else />
|
||||||
|
</div>
|
||||||
|
<div class="verify-result-card__content">
|
||||||
|
<h4>{{ resultTitle }}</h4>
|
||||||
|
<p>{{ verifyMessage }}</p>
|
||||||
|
<div
|
||||||
|
v-if="modelType === 'embeddingModel' && vectorDimension"
|
||||||
|
class="verify-result-card__meta"
|
||||||
|
>
|
||||||
|
向量维度:{{ vectorDimension }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</EasyFlowFormModal>
|
</EasyFlowFormModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.headers-container-reduce {
|
.verify-modal {
|
||||||
align-items: center;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
.addHeadersBtn {
|
|
||||||
width: 100%;
|
.verify-modal__section {
|
||||||
border-style: dashed;
|
display: flex;
|
||||||
border-color: var(--el-color-primary);
|
flex-direction: column;
|
||||||
border-radius: 8px;
|
gap: 14px;
|
||||||
margin-top: 8px;
|
padding: 20px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
hsl(var(--surface-panel) / 98%) 0%,
|
||||||
|
hsl(var(--surface-contrast-soft) / 94%) 100%
|
||||||
|
);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 50%);
|
||||||
|
border-radius: 24px;
|
||||||
}
|
}
|
||||||
.head-con-content {
|
|
||||||
margin-bottom: 8px;
|
.verify-modal__section-head h3,
|
||||||
|
.verify-result-card__content h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-modal__section-head p,
|
||||||
|
.verify-result-card__content p,
|
||||||
|
.verify-result-card__meta {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-result-card {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 18px;
|
||||||
|
background: hsl(var(--surface-panel) / 90%);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 56%);
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-result-card.is-success {
|
||||||
|
background: hsl(var(--success) / 6%);
|
||||||
|
border-color: hsl(var(--success) / 36%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-result-card.is-error {
|
||||||
|
background: hsl(var(--destructive) / 5%);
|
||||||
|
border-color: hsl(var(--destructive) / 36%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-result-card__icon {
|
||||||
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
font-size: 18px;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
|
background: hsl(var(--surface-contrast-soft));
|
||||||
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,201 +1,377 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PropType } from 'vue';
|
import type {PropType} from 'vue';
|
||||||
|
import {ref} from 'vue';
|
||||||
|
|
||||||
import type { llmType } from '#/api';
|
import type {llmType} from '#/api';
|
||||||
import type { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability';
|
import type {ModelAbilityItem} from '#/views/ai/model/modelUtils/model-ability';
|
||||||
|
import {getDefaultModelAbility} from '#/views/ai/model/modelUtils/model-ability';
|
||||||
|
|
||||||
import { Minus, Plus, Setting } from '@element-plus/icons-vue';
|
import {CircleCheck, CircleClose, Delete, Edit, Loading, Select,} from '@element-plus/icons-vue';
|
||||||
import { ElIcon, ElImage, ElTag } from 'element-plus';
|
import {ElButton, ElIcon, ElMessage, ElTag} from 'element-plus';
|
||||||
|
|
||||||
import { getIconByValue } from '#/views/ai/model/modelUtils/defaultIcon';
|
import {verifyModelConfig} from '#/api/ai/llm';
|
||||||
import { getDefaultModelAbility } from '#/views/ai/model/modelUtils/model-ability';
|
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
||||||
import { mapLlmToModelAbility } from '#/views/ai/model/modelUtils/model-ability-utils';
|
import {mapLlmToModelAbility} from '#/views/ai/model/modelUtils/model-ability-utils';
|
||||||
|
|
||||||
defineProps({
|
const props = defineProps({
|
||||||
llmList: {
|
llmList: {
|
||||||
type: Array as PropType<llmType[]>,
|
type: Array as PropType<llmType[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
icon: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
needHiddenSettingIcon: {
|
needHiddenSettingIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
isManagement: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['deleteLlm', 'editLlm', 'addLlm', 'updateWithUsed']);
|
const emit = defineEmits(['deleteLlm', 'editLlm']);
|
||||||
|
type VerifyButtonStatus = 'error' | 'idle' | 'loading' | 'success';
|
||||||
|
const verifyStatusMap = ref<Record<string, VerifyButtonStatus>>({});
|
||||||
|
const getModelId = (llm: llmType) =>
|
||||||
|
String((llm as any).id || (llm as any).llmId || (llm as any).modelId || '');
|
||||||
|
const getVerifyStatus = (llm: llmType): VerifyButtonStatus =>
|
||||||
|
verifyStatusMap.value[getModelId(llm)] || 'idle';
|
||||||
|
const isVerifying = (llm: llmType) => getVerifyStatus(llm) === 'loading';
|
||||||
|
const setVerifyStatus = (id: string, status: VerifyButtonStatus) => {
|
||||||
|
if (!id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifyStatusMap.value[id] = status;
|
||||||
|
};
|
||||||
|
const getVerifyButtonText = (llm: llmType) => {
|
||||||
|
const status = getVerifyStatus(llm);
|
||||||
|
if (status === 'loading') {
|
||||||
|
return '验证中';
|
||||||
|
}
|
||||||
|
if (status === 'success') {
|
||||||
|
return '验证成功';
|
||||||
|
}
|
||||||
|
if (status === 'error') {
|
||||||
|
return '验证失败';
|
||||||
|
}
|
||||||
|
return '验证配置';
|
||||||
|
};
|
||||||
|
const getVerifyButtonIcon = (llm: llmType) => {
|
||||||
|
const status = getVerifyStatus(llm);
|
||||||
|
if (status === 'loading') {
|
||||||
|
return Loading;
|
||||||
|
}
|
||||||
|
if (status === 'success') {
|
||||||
|
return CircleCheck;
|
||||||
|
}
|
||||||
|
if (status === 'error') {
|
||||||
|
return CircleClose;
|
||||||
|
}
|
||||||
|
return Select;
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteLlm = (id: string) => {
|
const handleDeleteLlm = (id: string) => {
|
||||||
emit('deleteLlm', id);
|
emit('deleteLlm', id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddLlm = (id: string) => {
|
|
||||||
emit('addLlm', id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditLlm = (id: string) => {
|
const handleEditLlm = (id: string) => {
|
||||||
emit('editLlm', id);
|
emit('editLlm', id);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改该模型为未使用状态,修改数据库的with_used字段为false
|
const canVerify = (llm: llmType) => llm.modelType !== 'rerankModel';
|
||||||
const handleUpdateWithUsedLlm = (id: string) => {
|
|
||||||
emit('updateWithUsed', id);
|
const handleVerifyLlm = async (llm: llmType) => {
|
||||||
|
const modelId = getModelId(llm);
|
||||||
|
if (!modelId || isVerifying(llm)) {
|
||||||
|
if (!modelId) {
|
||||||
|
ElMessage.warning('当前模型缺少ID,无法验证配置');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setVerifyStatus(modelId, 'loading');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await verifyModelConfig(modelId);
|
||||||
|
|
||||||
|
if (res.errorCode === 0) {
|
||||||
|
setVerifyStatus(modelId, 'success');
|
||||||
|
if (llm.modelType === 'embeddingModel' && res?.data?.dimension) {
|
||||||
|
ElMessage.success(`验证成功,向量维度:${res.data.dimension}`);
|
||||||
|
} else {
|
||||||
|
ElMessage.success('验证成功');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setVerifyStatus(modelId, 'error');
|
||||||
|
if (!res.message) {
|
||||||
|
ElMessage.error('验证失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setVerifyStatus(modelId, 'error');
|
||||||
|
// error toast is already handled by global response interceptors
|
||||||
|
} finally {
|
||||||
|
// keep final status for explicit visual feedback
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取LLM支持的选中的能力标签
|
|
||||||
* 只返回 selected 为 true 的标签
|
|
||||||
*/
|
|
||||||
const getSelectedAbilityTagsForLlm = (llm: llmType): ModelAbilityItem[] => {
|
const getSelectedAbilityTagsForLlm = (llm: llmType): ModelAbilityItem[] => {
|
||||||
const defaultAbility = getDefaultModelAbility();
|
const defaultAbility = getDefaultModelAbility();
|
||||||
const allTags = mapLlmToModelAbility(llm, defaultAbility);
|
const allTags = mapLlmToModelAbility(llm, defaultAbility);
|
||||||
return allTags.filter((tag) => tag.selected);
|
return allTags.filter((tag) => tag.selected);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getModelMeta = (llm: llmType) => {
|
||||||
|
const providerName =
|
||||||
|
llm?.modelProvider?.providerName || llm?.aiLlmProvider?.providerName || '';
|
||||||
|
const modelName = llm.llmModel || llm.title;
|
||||||
|
|
||||||
|
return `${providerName} · ${modelName}`;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-for="llm in llmList" :key="llm.id" class="container">
|
<div class="llm-list">
|
||||||
<div class="llm-item">
|
<article v-for="llm in props.llmList" :key="llm.id" class="llm-item">
|
||||||
<div class="start">
|
<div class="llm-item__main">
|
||||||
<ElImage
|
<ModelProviderBadge
|
||||||
v-if="llm.modelProvider.icon"
|
:icon="llm.modelProvider?.icon"
|
||||||
:src="llm.modelProvider.icon"
|
:provider-name="llm.modelProvider?.providerName"
|
||||||
style="width: 21px; height: 21px"
|
:provider-type="llm.modelProvider?.providerType"
|
||||||
|
:size="40"
|
||||||
/>
|
/>
|
||||||
|
<div class="llm-item__content">
|
||||||
<div
|
<div class="llm-item__headline">
|
||||||
v-else
|
<h4 class="llm-item__title">{{ llm.title }}</h4>
|
||||||
v-html="getIconByValue(llm.modelProvider.providerType)"
|
<div
|
||||||
:style="{
|
v-if="getSelectedAbilityTagsForLlm(llm).length > 0"
|
||||||
width: '21px',
|
class="llm-item__tags"
|
||||||
height: '21px',
|
>
|
||||||
display: 'flex',
|
<ElTag
|
||||||
alignItems: 'center',
|
v-for="tag in getSelectedAbilityTagsForLlm(llm)"
|
||||||
justifyContent: 'center',
|
:key="tag.value"
|
||||||
overflow: 'hidden',
|
effect="plain"
|
||||||
}"
|
size="small"
|
||||||
class="svg-container"
|
class="llm-item__tag"
|
||||||
></div>
|
>
|
||||||
|
{{ tag.label }}
|
||||||
<div>{{ llm?.modelProvider?.providerName }}/{{ llm.title }}</div>
|
</ElTag>
|
||||||
|
</div>
|
||||||
<!-- 模型能力 -->
|
</div>
|
||||||
<div
|
<p class="llm-item__meta">{{ getModelMeta(llm) }}</p>
|
||||||
v-if="getSelectedAbilityTagsForLlm(llm).length > 0"
|
<p v-if="llm.description" class="llm-item__description">
|
||||||
class="ability-tags"
|
{{ llm.description }}
|
||||||
>
|
</p>
|
||||||
<ElTag
|
|
||||||
v-for="tag in getSelectedAbilityTagsForLlm(llm)"
|
|
||||||
:key="tag.value"
|
|
||||||
class="ability-tag"
|
|
||||||
:type="tag.activeType"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
{{ tag.label }}
|
|
||||||
</ElTag>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="end">
|
|
||||||
<ElIcon
|
|
||||||
v-if="!needHiddenSettingIcon"
|
|
||||||
size="16"
|
|
||||||
@click="handleEditLlm(llm.id)"
|
|
||||||
style="cursor: pointer"
|
|
||||||
>
|
|
||||||
<Setting />
|
|
||||||
</ElIcon>
|
|
||||||
<template v-if="!isManagement">
|
|
||||||
<ElIcon
|
|
||||||
size="16"
|
|
||||||
@click="handleUpdateWithUsedLlm(llm.id)"
|
|
||||||
style="cursor: pointer"
|
|
||||||
>
|
|
||||||
<Minus />
|
|
||||||
</ElIcon>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="isManagement">
|
<div class="llm-item__actions">
|
||||||
<ElIcon
|
<ElButton
|
||||||
v-if="llm.withUsed"
|
v-if="canVerify(llm)"
|
||||||
size="16"
|
text
|
||||||
@click="handleDeleteLlm(llm.id)"
|
size="small"
|
||||||
style="cursor: pointer"
|
class="llm-item__verify-btn"
|
||||||
>
|
:class="`is-${getVerifyStatus(llm)}`"
|
||||||
<Minus />
|
:disabled="isVerifying(llm) || !getModelId(llm)"
|
||||||
</ElIcon>
|
@click="handleVerifyLlm(llm)"
|
||||||
<ElIcon
|
>
|
||||||
v-else
|
<template #icon>
|
||||||
size="16"
|
<ElIcon
|
||||||
@click="handleAddLlm(llm.id)"
|
class="llm-item__verify-icon"
|
||||||
style="cursor: pointer"
|
:class="`is-${getVerifyStatus(llm)}`"
|
||||||
>
|
>
|
||||||
<Plus />
|
<component :is="getVerifyButtonIcon(llm)" />
|
||||||
</ElIcon>
|
</ElIcon>
|
||||||
</template>
|
</template>
|
||||||
|
{{ getVerifyButtonText(llm) }}
|
||||||
|
</ElButton>
|
||||||
|
|
||||||
|
<ElButton
|
||||||
|
v-if="!needHiddenSettingIcon"
|
||||||
|
text
|
||||||
|
size="small"
|
||||||
|
:icon="Edit"
|
||||||
|
@click="handleEditLlm(llm.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</ElButton>
|
||||||
|
|
||||||
|
<ElButton
|
||||||
|
text
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
class="llm-item__danger"
|
||||||
|
@click="handleDeleteLlm(llm.id)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</ElButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.llm-item {
|
.llm-list {
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px 18px;
|
||||||
|
background: hsl(var(--surface-panel) / 90%);
|
||||||
|
border: 1px solid hsl(var(--divider-faint) / 54%);
|
||||||
|
border-radius: 18px;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s ease,
|
||||||
|
transform 0.2s ease,
|
||||||
|
box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item:hover {
|
||||||
|
border-color: hsl(var(--primary) / 28%);
|
||||||
|
box-shadow: 0 18px 30px -28px hsl(var(--foreground) / 34%);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__main {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: flex-start;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__headline {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 12px 18px;
|
|
||||||
border-bottom: 1px solid #e4e7ed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.start {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.end {
|
.llm-item__title {
|
||||||
display: flex;
|
margin: 0;
|
||||||
align-items: center;
|
font-size: 15px;
|
||||||
gap: 12px;
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: hsl(var(--text-strong));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ability-tags {
|
.llm-item__meta,
|
||||||
|
.llm-item__description {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__description {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ability-tag {
|
.llm-item__tag {
|
||||||
cursor: default;
|
color: hsl(var(--text-strong));
|
||||||
user-select: none;
|
background: hsl(var(--primary) / 8%);
|
||||||
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-container {
|
.llm-item__actions {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-container :deep(svg) {
|
.llm-item__actions :deep(.el-button) {
|
||||||
width: 21px;
|
border-radius: 10px;
|
||||||
height: 21px;
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-btn.is-idle {
|
||||||
|
color: hsl(var(--text-muted));
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-btn.is-loading {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-btn.is-success {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-btn.is-error {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-icon {
|
||||||
|
transition:
|
||||||
|
color 0.24s ease,
|
||||||
|
transform 0.24s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-icon.is-loading {
|
||||||
|
animation: llm-item-verify-spin 0.9s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__verify-icon.is-success,
|
||||||
|
.llm-item__verify-icon.is-error {
|
||||||
|
animation: llm-item-verify-pop 0.32s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__danger {
|
||||||
|
color: hsl(var(--danger) / 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__danger:hover,
|
||||||
|
.llm-item__danger:focus-visible {
|
||||||
|
color: hsl(var(--danger));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes llm-item-verify-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes llm-item-verify-pop {
|
||||||
|
0% {
|
||||||
|
opacity: 0.72;
|
||||||
|
transform: scale(0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.llm-item {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-item__actions {
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -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';
|
import providerList from './providerList.json';
|
||||||
|
|
||||||
const providerOptions =
|
export interface ProviderModelPreset {
|
||||||
ref<Array<{ icon: string; label: string; options: any; value: string }>>(
|
description: string;
|
||||||
providerList,
|
label: string;
|
||||||
);
|
llmModel: string;
|
||||||
|
supportChat?: boolean;
|
||||||
|
supportEmbed?: boolean;
|
||||||
|
supportFunctionCalling?: boolean;
|
||||||
|
supportRerank?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProviderPreset {
|
||||||
|
description: string;
|
||||||
|
icon: string;
|
||||||
|
label: string;
|
||||||
|
mode: 'hosted' | 'self-hosted';
|
||||||
|
options: {
|
||||||
|
chatPath?: string;
|
||||||
|
embedPath?: string;
|
||||||
|
llmEndpoint?: string;
|
||||||
|
modelList?: ProviderModelPreset[];
|
||||||
|
rerankPath?: string;
|
||||||
|
};
|
||||||
|
tags?: string[];
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerOptions = providerList as ProviderPreset[];
|
||||||
|
|
||||||
|
export const getProviderPresetByValue = (targetValue?: string) =>
|
||||||
|
providerOptions.find((item) => item.value === targetValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据传入的value,返回对应的icon属性
|
* 根据传入的value,返回对应的icon属性
|
||||||
* @param targetValue 要匹配的value值
|
* @param targetValue 要匹配的value值
|
||||||
* @returns 匹配到的icon字符串,未匹配到返回空字符串
|
* @returns 匹配到的icon字符串,未匹配到返回空字符串
|
||||||
*/
|
*/
|
||||||
export const getIconByValue = (targetValue: string): string => {
|
export const getIconByValue = (targetValue: string): string =>
|
||||||
const matchItem = providerOptions.value.find(
|
getProviderPresetByValue(targetValue)?.icon || '';
|
||||||
(item) => item.value === targetValue,
|
|
||||||
);
|
|
||||||
|
|
||||||
return matchItem?.icon || '';
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isSvgString = (icon: any) => {
|
export const isSvgString = (icon: any) => {
|
||||||
if (typeof icon !== 'string') return false;
|
if (typeof icon !== 'string') return false;
|
||||||
// 简单判断:是否包含 SVG 根标签
|
// 简单判断:是否包含 SVG 根标签
|
||||||
return icon.trim().startsWith('<svg') && icon.trim().endsWith('</svg>');
|
return icon.trim().startsWith('<svg') && icon.trim().endsWith('</svg>');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getProviderBadgeText = (
|
||||||
|
providerName?: string,
|
||||||
|
providerType?: string,
|
||||||
|
) => {
|
||||||
|
const preset = getProviderPresetByValue(providerType);
|
||||||
|
const source = providerName || preset?.label || providerType || 'AI';
|
||||||
|
const ascii = source
|
||||||
|
.replaceAll(/[^a-z]/gi, '')
|
||||||
|
.slice(0, 2)
|
||||||
|
.toUpperCase();
|
||||||
|
|
||||||
|
if (ascii) {
|
||||||
|
return ascii;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.replaceAll(/\s+/g, '').slice(0, 2).toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const providerPresets = providerOptions;
|
||||||
|
|||||||
@@ -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
|
-- Records of tb_model_provider
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (358906187162456064, 'Gitee', 'gitee', '', '', 'https://ai.gitee.com', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-17 22:26:03', 1, '2025-12-17 22:26:03', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359109019710914560, '百度千帆', 'baidu', '', '', 'https://qianfan.baidubce.com', '/v2/chat/completions', '/v2/embeddings', '', '2025-12-18 11:52:02', 1, '2025-12-18 11:52:02', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', 'http://127.0.0.1:11434', '/v1/chat/completions', '/api/embed', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110565693620224, '火山引擎', 'volcengine', '', '', 'https://ark.cn-beijing.volces.com', '/api/v3/chat/completions', '/api/v3/embeddings', '', '2025-12-18 11:58:11', 1, '2025-12-18 11:58:11', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110640402563072, '星火大模型', 'spark', '', '', 'https://spark-api-open.xf-yun.com', '/v1/chat/completions', NULL, '', '2025-12-18 11:58:29', 1, '2025-12-18 11:58:29', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'OpenAI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-18 11:58:35', 1, '2025-12-18 11:58:35', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '/api/v1/services/rerank/text-rerank/text-rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', NULL, NULL, NULL, '', '2025-12-18 11:58:40', 1, '2025-12-18 11:58:40', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000001, '智谱', 'zhipu', '', '', 'https://open.bigmodel.cn', '/api/paas/v4/chat/completions', '/api/paas/v4/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:00:23', 1, '2025-12-18 12:00:23', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000002, 'MiniMax', 'minimax', '', '', 'https://api.minimax.io', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'Open AI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2025-12-18 12:00:49', 1, '2025-12-18 12:00:49', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000003, 'Kimi', 'kimi', '', '', 'https://api.moonshot.cn', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:01:41', 1, '2025-12-18 12:01:41', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000004, '自部署', 'self-hosted', '', '', 'http://127.0.0.1:8000', '/v1/chat/completions', '/v1/embeddings', '/v1/score', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Records of tb_model
|
-- Records of tb_model
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359159030960295936, 1, 1000000, 358906187162456064, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010001, 1, 1000000, 359111120310632448, 'DeepSeek-V3', NULL, '通用对话与代码任务表现均衡。', NULL, NULL, 'deepseek-chat', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188398742933504, 1, 1000000, 358906187162456064, 'kimi-k2-instruct', NULL, NULL, NULL, NULL, 'kimi-k2-instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010002, 1, 1000000, 359111120310632448, 'DeepSeek-R1', NULL, '复杂推理与长链路分析场景。', NULL, NULL, 'deepseek-reasoner', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188487121113088, 1, 1000000, 358906187162456064, 'ERNIE-X1-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-X1-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010003, 1, 1000000, 359111228158771200, 'o4-mini', NULL, '轻量推理与通用生产任务模型。', NULL, NULL, 'o4-mini', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188591383121920, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010004, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, '复杂任务与多模态理解旗舰模型。', NULL, NULL, 'gpt-4.1', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188717564563456, 1, 1000000, 358906187162456064, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010005, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, '高质量文本向量模型。', NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188823290384384, 1, 1000000, 358906187162456064, 'Qwen3-235B-A22B', NULL, NULL, NULL, NULL, 'Qwen3-235B-A22B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010006, 1, 1000000, 359111448204541952, '通义千问 Plus', NULL, '适合通用问答与工具调用。', NULL, NULL, 'qwen-plus', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188894316728320, 1, 1000000, 358906187162456064, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010007, 1, 1000000, 359111448204541952, '通义千问 Max', NULL, '综合能力更强的主力模型。', NULL, NULL, 'qwen-max', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189040752463872, 1, 1000000, 358906187162456064, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010008, 1, 1000000, 359111448204541952, 'text-embedding-v4', NULL, '阿里百炼默认向量模型。', NULL, NULL, 'text-embedding-v4', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189205492142080, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo-VL', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo-VL', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010009, 1, 1000000, 359111448204541952, 'gte-rerank-v2', NULL, '阿里百炼默认重排模型。', NULL, NULL, 'gte-rerank-v2', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189277827108864, 1, 1000000, 358906187162456064, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010010, 1, 1000000, 366100000000000001, 'GLM-4.5', NULL, '中文与推理能力表现均衡。', NULL, NULL, 'glm-4.5', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189415073124352, 1, 1000000, 358906187162456064, 'InternVL3-78B', NULL, NULL, NULL, NULL, 'InternVL3-78B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010011, 1, 1000000, 366100000000000001, 'GLM-4.5-Air', NULL, '低延迟通用模型。', NULL, NULL, 'glm-4.5-air', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189479254364160, 1, 1000000, 358906187162456064, 'InternVL3-38B', NULL, NULL, NULL, NULL, 'InternVL3-38B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010012, 1, 1000000, 366100000000000001, 'Embedding-3', NULL, '知识库与检索常用向量模型。', NULL, NULL, 'embedding-3', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189562309971968, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010013, 1, 1000000, 366100000000000002, 'MiniMax-M2.5', NULL, '长上下文与复杂推理场景。', NULL, NULL, 'MiniMax-M2.5', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189617381183488, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010014, 1, 1000000, 366100000000000002, 'MiniMax-M2.5-highspeed', NULL, '更高吞吐的快速对话模型。', NULL, NULL, 'MiniMax-M2.5-highspeed', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359190580372410368, 1, 1000000, 359111120310632448, 'deepseek-chat', NULL, NULL, NULL, NULL, 'deepseek-chat', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010015, 1, 1000000, 366100000000000003, 'moonshot-v1-8k', NULL, '低延迟通用对话模型。', NULL, NULL, 'moonshot-v1-8k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250814495248384, 1, 1000000, 359111228158771200, 'o4-mini', NULL, NULL, NULL, NULL, 'o4-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010016, 1, 1000000, 366100000000000003, 'moonshot-v1-128k', NULL, '长文档理解与大上下文任务。', NULL, NULL, 'moonshot-v1-128k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250916064514048, 1, 1000000, 359111228158771200, 'o3', NULL, NULL, NULL, NULL, 'o3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010017, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, '统一平台接入的开源对话模型。', NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250975883677696, 1, 1000000, 359111228158771200, 'o3-pro', NULL, NULL, NULL, NULL, 'o3-pro', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010018, 1, 1000000, 359110667376132096, 'Kimi-K2-Instruct', NULL, '代码与 Agent 工作流场景常用模型。', NULL, NULL, 'moonshotai/Kimi-K2-Instruct', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251041788776448, 1, 1000000, 359111228158771200, 'o3-mini', NULL, NULL, NULL, NULL, 'o3-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010019, 1, 1000000, 359110667376132096, 'BAAI/bge-m3', NULL, '多语言检索与向量召回模型。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251651388919808, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, NULL, NULL, NULL, 'GPT-4.1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010020, 1, 1000000, 359110690079899648, 'qwen3:8b', NULL, '本地开发常用的通用对话模型。', NULL, NULL, 'qwen3:8b', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Ollama', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251703859662848, 1, 1000000, 359111228158771200, 'GPT-4o', NULL, NULL, NULL, NULL, 'GPT-4o', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010021, 1, 1000000, 359110690079899648, 'bge-m3', NULL, '本地向量化与检索验证。', NULL, NULL, 'bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251899029016576, 1, 1000000, 359111228158771200, 'text-embedding-3-small', NULL, NULL, NULL, NULL, 'text-embedding-3-small', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010022, 1, 1000000, 366100000000000004, 'Qwen/Qwen3-32B', NULL, '适合自部署对话与工具调用。', NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251948844765184, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, NULL, NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010023, 1, 1000000, 366100000000000004, 'BAAI/bge-m3', NULL, '自部署检索和知识库向量化。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252007019761664, 1, 1000000, 359111228158771200, 'text-embedding-ada-002', NULL, NULL, NULL, NULL, 'text-embedding-ada-002', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010024, 1, 1000000, 366100000000000004, 'jinaai/jina-reranker-m0', NULL, '自部署召回重排模型。', NULL, NULL, 'jinaai/jina-reranker-m0', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252333504385024, 1, 1000000, 359110667376132096, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252410297896960, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252901950017536, 1, 1000000, 359110667376132096, 'QwenLong-L1-32B', NULL, NULL, NULL, NULL, 'Tongyi-Zhiwen/QwenLong-L1-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253108129419264, 1, 1000000, 359110667376132096, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253178463703040, 1, 1000000, 359110667376132096, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253290258681856, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253356990058496, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-72B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-72B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253448664961024, 1, 1000000, 359110667376132096, 'deepseek-vl2', NULL, NULL, NULL, NULL, 'deepseek-ai/deepseek-vl2', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253538523729920, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253610657370112, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253918280208384, 1, 1000000, 359110667376132096, 'bge-m3', NULL, NULL, NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'BAAI', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254052095283200, 1, 1000000, 359110667376132096, 'bce-embedding-base_v1', NULL, NULL, NULL, NULL, 'netease-youdao/bce-embedding-base_v1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Netease-youdao', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254268492009472, 1, 1000000, 359110565693620224, 'doubao-seed-1.6', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254341498064896, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-flash', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-flash-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254465049677824, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-thinking', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-thinking-250715', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254550235992064, 1, 1000000, 359110565693620224, 'deepseek-r1', NULL, NULL, NULL, NULL, 'deepseek-r1-250528', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359255963729022976, 1, 1000000, 359110640402563072, 'Spark Max', NULL, NULL, NULL, NULL, 'generalv3.5', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256036009463808, 1, 1000000, 359110640402563072, 'Spark4.0 Ultra', NULL, NULL, NULL, NULL, '4.0Ultra', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256272148779008, 1, 1000000, 359110640402563072, 'Max-32K', NULL, NULL, NULL, NULL, 'max-32k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256472095444992, 1, 1000000, 359110640402563072, 'Spark Pro', NULL, NULL, NULL, NULL, 'generalv3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256641138479104, 1, 1000000, 359110640402563072, 'Spark Pro-128k', NULL, NULL, NULL, NULL, 'pro-128k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359498072033816576, 1, 1000000, 359111448204541952, 'text-embedding-v3', NULL, NULL, NULL, NULL, 'text-embedding-v3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359536003377258496, 1, 1000000, 358906187162456064, 'Qwen3-Reranker-8B', NULL, NULL, NULL, NULL, 'Qwen3-Reranker-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Records of tb_sys_option
|
-- Records of tb_sys_option
|
||||||
|
|||||||
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
|
-- Records of tb_model_provider
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (358906187162456064, 'Gitee', 'gitee', '', '', 'https://ai.gitee.com', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-17 22:26:03', 1, '2025-12-17 22:26:03', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359109019710914560, '百度千帆', 'baidu', '', '', 'https://qianfan.baidubce.com', '/v2/chat/completions', '/v2/embeddings', '', '2025-12-18 11:52:02', 1, '2025-12-18 11:52:02', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', 'http://127.0.0.1:11434', '/v1/chat/completions', '/api/embed', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110565693620224, '火山引擎', 'volcengine', '', '', 'https://ark.cn-beijing.volces.com', '/api/v3/chat/completions', '/api/v3/embeddings', '', '2025-12-18 11:58:11', 1, '2025-12-18 11:58:11', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110640402563072, '星火大模型', 'spark', '', '', 'https://spark-api-open.xf-yun.com', '/v1/chat/completions', NULL, '', '2025-12-18 11:58:29', 1, '2025-12-18 11:58:29', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'OpenAI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110667376132096, '硅基流动', 'siliconlow', '', '', 'https://api.siliconflow.cn', '/v1/chat/completions', '/v1/embeddings', '/v1/rerank', '2025-12-18 11:58:35', 1, '2025-12-18 11:58:35', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '/api/v1/services/rerank/text-rerank/text-rerank', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359110690079899648, 'Ollama', 'ollama', '', '', NULL, NULL, NULL, '', '2025-12-18 11:58:40', 1, '2025-12-18 11:58:40', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000001, '智谱', 'zhipu', '', '', 'https://open.bigmodel.cn', '/api/paas/v4/chat/completions', '/api/paas/v4/embeddings', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111120310632448, 'DeepSeek', 'deepseek', '', '', 'https://api.deepseek.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:00:23', 1, '2025-12-18 12:00:23', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000002, 'MiniMax', 'minimax', '', '', 'https://api.minimax.io', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111228158771200, 'Open AI', 'openai', '', '', 'https://api.openai.com', '/v1/chat/completions', '/v1/embeddings', '', '2025-12-18 12:00:49', 1, '2025-12-18 12:00:49', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000003, 'Kimi', 'kimi', '', '', 'https://api.moonshot.cn', '/v1/chat/completions', '', '', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (359111448204541952, '阿里百炼', 'aliyun', '', '', 'https://dashscope.aliyuncs.com', '/compatible-mode/v1/chat/completions', '/compatible-mode/v1/embeddings', '', '2025-12-18 12:01:41', 1, '2025-12-18 12:01:41', 1);
|
INSERT INTO `tb_model_provider` (`id`, `provider_name`, `provider_type`, `icon`, `api_key`, `endpoint`, `chat_path`, `embed_path`, `rerank_path`, `created`, `created_by`, `modified`, `modified_by`) VALUES (366100000000000004, '自部署', 'self-hosted', '', '', 'http://127.0.0.1:8000', '/v1/chat/completions', '/v1/embeddings', '/v1/score', '2026-03-10 10:00:00', 1, '2026-03-10 10:00:00', 1);
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Records of tb_model
|
-- Records of tb_model
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359159030960295936, 1, 1000000, 358906187162456064, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010001, 1, 1000000, 359111120310632448, 'DeepSeek-V3', NULL, '通用对话与代码任务表现均衡。', NULL, NULL, 'deepseek-chat', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188398742933504, 1, 1000000, 358906187162456064, 'kimi-k2-instruct', NULL, NULL, NULL, NULL, 'kimi-k2-instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010002, 1, 1000000, 359111120310632448, 'DeepSeek-R1', NULL, '复杂推理与长链路分析场景。', NULL, NULL, 'deepseek-reasoner', NULL, NULL, '{"llmEndpoint":"https://api.deepseek.com","chatPath":"/chat/completions","embedPath":"","rerankPath":""}', 'DeepSeek', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188487121113088, 1, 1000000, 358906187162456064, 'ERNIE-X1-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-X1-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010003, 1, 1000000, 359111228158771200, 'o4-mini', NULL, '轻量推理与通用生产任务模型。', NULL, NULL, 'o4-mini', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188591383121920, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010004, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, '复杂任务与多模态理解旗舰模型。', NULL, NULL, 'gpt-4.1', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'OpenAI', 'chatModel', 1, 1, 1, 1, 0, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188717564563456, 1, 1000000, 358906187162456064, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010005, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, '高质量文本向量模型。', NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{"llmEndpoint":"https://api.openai.com","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188823290384384, 1, 1000000, 358906187162456064, 'Qwen3-235B-A22B', NULL, NULL, NULL, NULL, 'Qwen3-235B-A22B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010006, 1, 1000000, 359111448204541952, '通义千问 Plus', NULL, '适合通用问答与工具调用。', NULL, NULL, 'qwen-plus', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359188894316728320, 1, 1000000, 358906187162456064, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010007, 1, 1000000, 359111448204541952, '通义千问 Max', NULL, '综合能力更强的主力模型。', NULL, NULL, 'qwen-max', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189040752463872, 1, 1000000, 358906187162456064, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010008, 1, 1000000, 359111448204541952, 'text-embedding-v4', NULL, '阿里百炼默认向量模型。', NULL, NULL, 'text-embedding-v4', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189205492142080, 1, 1000000, 358906187162456064, 'ERNIE-4.5-Turbo-VL', NULL, NULL, NULL, NULL, 'ERNIE-4.5-Turbo-VL', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', '文心ERNIE', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010009, 1, 1000000, 359111448204541952, 'gte-rerank-v2', NULL, '阿里百炼默认重排模型。', NULL, NULL, 'gte-rerank-v2', NULL, NULL, '{"llmEndpoint":"https://dashscope.aliyuncs.com","chatPath":"/compatible-mode/v1/chat/completions","embedPath":"/compatible-mode/v1/embeddings","rerankPath":"/api/v1/services/rerank/text-rerank/text-rerank"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189277827108864, 1, 1000000, 358906187162456064, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010010, 1, 1000000, 366100000000000001, 'GLM-4.5', NULL, '中文与推理能力表现均衡。', NULL, NULL, 'glm-4.5', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189415073124352, 1, 1000000, 358906187162456064, 'InternVL3-78B', NULL, NULL, NULL, NULL, 'InternVL3-78B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010011, 1, 1000000, 366100000000000001, 'GLM-4.5-Air', NULL, '低延迟通用模型。', NULL, NULL, 'glm-4.5-air', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'GLM', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189479254364160, 1, 1000000, 358906187162456064, 'InternVL3-38B', NULL, NULL, NULL, NULL, 'InternVL3-38B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'InternVL3', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010012, 1, 1000000, 366100000000000001, 'Embedding-3', NULL, '知识库与检索常用向量模型。', NULL, NULL, 'embedding-3', NULL, NULL, '{"llmEndpoint":"https://open.bigmodel.cn","chatPath":"/api/paas/v4/chat/completions","embedPath":"/api/paas/v4/embeddings","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189562309971968, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010013, 1, 1000000, 366100000000000002, 'MiniMax-M2.5', NULL, '长上下文与复杂推理场景。', NULL, NULL, 'MiniMax-M2.5', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 1, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359189617381183488, 1, 1000000, 358906187162456064, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010014, 1, 1000000, 366100000000000002, 'MiniMax-M2.5-highspeed', NULL, '更高吞吐的快速对话模型。', NULL, NULL, 'MiniMax-M2.5-highspeed', NULL, NULL, '{"llmEndpoint":"https://api.minimax.io","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'MiniMax', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359190580372410368, 1, 1000000, 359111120310632448, 'deepseek-chat', NULL, NULL, NULL, NULL, 'deepseek-chat', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010015, 1, 1000000, 366100000000000003, 'moonshot-v1-8k', NULL, '低延迟通用对话模型。', NULL, NULL, 'moonshot-v1-8k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250814495248384, 1, 1000000, 359111228158771200, 'o4-mini', NULL, NULL, NULL, NULL, 'o4-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010016, 1, 1000000, 366100000000000003, 'moonshot-v1-128k', NULL, '长文档理解与大上下文任务。', NULL, NULL, 'moonshot-v1-128k', NULL, NULL, '{"llmEndpoint":"https://api.moonshot.cn","chatPath":"/v1/chat/completions","embedPath":"","rerankPath":""}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250916064514048, 1, 1000000, 359111228158771200, 'o3', NULL, NULL, NULL, NULL, 'o3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010017, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, '统一平台接入的开源对话模型。', NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'DeepSeek', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359250975883677696, 1, 1000000, 359111228158771200, 'o3-pro', NULL, NULL, NULL, NULL, 'o3-pro', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010018, 1, 1000000, 359110667376132096, 'Kimi-K2-Instruct', NULL, '代码与 Agent 工作流场景常用模型。', NULL, NULL, 'moonshotai/Kimi-K2-Instruct', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Kimi', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251041788776448, 1, 1000000, 359111228158771200, 'o3-mini', NULL, NULL, NULL, NULL, 'o3-mini', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'O系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010019, 1, 1000000, 359110667376132096, 'BAAI/bge-m3', NULL, '多语言检索与向量召回模型。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"https://api.siliconflow.cn","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/rerank"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251651388919808, 1, 1000000, 359111228158771200, 'GPT-4.1', NULL, NULL, NULL, NULL, 'GPT-4.1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010020, 1, 1000000, 359110690079899648, 'qwen3:8b', NULL, '本地开发常用的通用对话模型。', NULL, NULL, 'qwen3:8b', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Ollama', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251703859662848, 1, 1000000, 359111228158771200, 'GPT-4o', NULL, NULL, NULL, NULL, 'GPT-4o', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'GPT系列', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010021, 1, 1000000, 359110690079899648, 'bge-m3', NULL, '本地向量化与检索验证。', NULL, NULL, 'bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:11434","chatPath":"/v1/chat/completions","embedPath":"/api/embed","rerankPath":""}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251899029016576, 1, 1000000, 359111228158771200, 'text-embedding-3-small', NULL, NULL, NULL, NULL, 'text-embedding-3-small', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010022, 1, 1000000, 366100000000000004, 'Qwen/Qwen3-32B', NULL, '适合自部署对话与工具调用。', NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Qwen', 'chatModel', 1, 0, 1, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359251948844765184, 1, 1000000, 359111228158771200, 'text-embedding-3-large', NULL, NULL, NULL, NULL, 'text-embedding-3-large', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010023, 1, 1000000, 366100000000000004, 'BAAI/bge-m3', NULL, '自部署检索和知识库向量化。', NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252007019761664, 1, 1000000, 359111228158771200, 'text-embedding-ada-002', NULL, NULL, NULL, NULL, 'text-embedding-ada-002', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (366100000000010024, 1, 1000000, 366100000000000004, 'jinaai/jina-reranker-m0', NULL, '自部署召回重排模型。', NULL, NULL, 'jinaai/jina-reranker-m0', NULL, NULL, '{"llmEndpoint":"http://127.0.0.1:8000","chatPath":"/v1/chat/completions","embedPath":"/v1/embeddings","rerankPath":"/v1/score"}', 'Rerank', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252333504385024, 1, 1000000, 359110667376132096, 'DeepSeek-R1', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-R1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252410297896960, 1, 1000000, 359110667376132096, 'DeepSeek-V3', NULL, NULL, NULL, NULL, 'deepseek-ai/DeepSeek-V3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359252901950017536, 1, 1000000, 359110667376132096, 'QwenLong-L1-32B', NULL, NULL, NULL, NULL, 'Tongyi-Zhiwen/QwenLong-L1-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253108129419264, 1, 1000000, 359110667376132096, 'Qwen3-30B-A3B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-30B-A3B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253178463703040, 1, 1000000, 359110667376132096, 'Qwen3-32B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-32B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253290258681856, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-32B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-32B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253356990058496, 1, 1000000, 359110667376132096, 'Qwen2.5-VL-72B-Instruct', NULL, NULL, NULL, NULL, 'Qwen/Qwen2.5-VL-72B-Instruct', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253448664961024, 1, 1000000, 359110667376132096, 'deepseek-vl2', NULL, NULL, NULL, NULL, 'deepseek-ai/deepseek-vl2', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253538523729920, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-8B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253610657370112, 1, 1000000, 359110667376132096, 'Qwen3-Embedding-4B', NULL, NULL, NULL, NULL, 'Qwen/Qwen3-Embedding-4B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359253918280208384, 1, 1000000, 359110667376132096, 'bge-m3', NULL, NULL, NULL, NULL, 'BAAI/bge-m3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'BAAI', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254052095283200, 1, 1000000, 359110667376132096, 'bce-embedding-base_v1', NULL, NULL, NULL, NULL, 'netease-youdao/bce-embedding-base_v1', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Netease-youdao', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254268492009472, 1, 1000000, 359110565693620224, 'doubao-seed-1.6', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254341498064896, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-flash', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-flash-250615', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254465049677824, 1, 1000000, 359110565693620224, 'doubao-seed-1.6-thinking', NULL, NULL, NULL, NULL, 'doubao-seed-1-6-thinking-250715', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Doubao', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359254550235992064, 1, 1000000, 359110565693620224, 'deepseek-r1', NULL, NULL, NULL, NULL, 'deepseek-r1-250528', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'DeepSeek', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359255963729022976, 1, 1000000, 359110640402563072, 'Spark Max', NULL, NULL, NULL, NULL, 'generalv3.5', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256036009463808, 1, 1000000, 359110640402563072, 'Spark4.0 Ultra', NULL, NULL, NULL, NULL, '4.0Ultra', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256272148779008, 1, 1000000, 359110640402563072, 'Max-32K', NULL, NULL, NULL, NULL, 'max-32k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256472095444992, 1, 1000000, 359110640402563072, 'Spark Pro', NULL, NULL, NULL, NULL, 'generalv3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359256641138479104, 1, 1000000, 359110640402563072, 'Spark Pro-128k', NULL, NULL, NULL, NULL, 'pro-128k', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Spark', 'chatModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359498072033816576, 1, 1000000, 359111448204541952, 'text-embedding-v3', NULL, NULL, NULL, NULL, 'text-embedding-v3', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Embedding', 'embeddingModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
INSERT INTO `tb_model` (`id`, `dept_id`, `tenant_id`, `provider_id`, `title`, `icon`, `description`, `endpoint`, `request_path`, `model_name`, `api_key`, `extra_config`, `options`, `group_name`, `model_type`, `with_used`, `support_thinking`, `support_tool`, `support_image`, `support_image_b64_only`, `support_video`, `support_audio`, `support_free`) VALUES (359536003377258496, 1, 1000000, 358906187162456064, 'Qwen3-Reranker-8B', NULL, NULL, NULL, NULL, 'Qwen3-Reranker-8B', NULL, NULL, '{\"rerankPath\":\"\",\"chatPath\":\"\",\"llmEndpoint\":\"\",\"embedPath\":\"\"}', 'Qwen', 'rerankModel', 1, 0, 0, NULL, NULL, NULL, NULL, 0);
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Records of tb_sys_option
|
-- Records of tb_sys_option
|
||||||
|
|||||||