fetch: 页面移植

会话模型、向量模型、文生图模型、向量数据库
This commit is contained in:
杨谢雨 2025-02-18 11:32:36 +08:00
parent e77b7e7afd
commit f62e8d4cea
11 changed files with 856 additions and 179 deletions

View File

@ -0,0 +1,85 @@
import {ProviderEnum} from './provider';
export const baseColumns = [
{
label: '模型别名',
field: 'name',
},
{
label: '模型版本',
field: 'model',
width: '140',
},
{
label: '回复上限',
field: 'responseLimit',
width: '100',
},
{
label: '生成随机性',
field: 'temperature',
width: '100',
},
{
label: 'Top P',
field: 'topP',
width: '100',
},
];
export const openaiColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
];
export const ollamaColumns = [
...baseColumns,
{
label: 'Base Url',
field: 'baseUrl',
},
];
export const qfanColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
];
export const qwenColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
];
export const zhipuColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
];
export function getColumns(provider: string) {
switch (provider) {
case ProviderEnum.OLLAMA: {
return ollamaColumns;
}
case ProviderEnum.Q_FAN: {
return qfanColumns;
}
case ProviderEnum.Q_WEN: {
return qwenColumns;
}
case ProviderEnum.ZHIPU: {
return zhipuColumns;
}
}
return openaiColumns;
}

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
*
* Licensed under the GNU Affero General Public License, Version 3 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProviderEnum } from './provider';
export const LLMProviders: any[] = [
{
model: ProviderEnum.OPENAI,
name: 'OpenAI',
models: ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-32k', 'gpt-4-turbo', 'gpt-4o'],
},
{
model: ProviderEnum.Q_FAN,
name: '百度千帆',
models: [
'ERNIE-Bot',
'ERNIE-Bot 4.0',
'ERNIE-Bot-8K',
'ERNIE-Bot-turbo',
'ERNIE-Speed-128K',
'EB-turbo-AppBuilder',
'Yi-34B-Chat',
'BLOOMZ-7B',
'Qianfan-BLOOMZ-7B-compressed',
'Mixtral-8x7B-Instruct',
'Llama-2-7b-chat',
'Llama-2-13b-chat',
'Llama-2-70b-chat',
'Qianfan-Chinese-Llama-2-7B',
'ChatGLM2-6B-32K',
'AquilaChat-7B',
],
},
{
model: ProviderEnum.Q_WEN,
name: '阿里百炼',
models: [
'qwen-turbo',
'qwen-plus',
'qwen-max',
'qwen-max-longcontext',
'qwen-7b-chat',
'qwen-14b-chat',
'qwen-72b-chat',
],
},
{
model: ProviderEnum.ZHIPU,
name: '智谱清言',
models: [
'glm-4',
'glm-4v',
'glm-4-air',
'glm-4-airx',
'glm-4-flash',
'glm-3-turbo',
'chatglm_turbo',
],
},
{
model: ProviderEnum.GITEEAI,
name: 'Gitee AI',
models: [
'Qwen2-72B-Instruct',
'Qwen2-7B-Instruct',
'Qwen2.5-72B-Instruct',
'glm-4-9b-chat',
'deepseek-coder-33B-instruct',
'codegeex4-all-9b',
'Yi-34B-Chat',
'code-raccoon-v1',
'Qwen2.5-Coder-32B-Instruct',
],
},
{
model: ProviderEnum.DEEPSEEK,
name: 'DeepSeek',
models: ['deepseek-chat', 'deepseek-coder'],
},
{
model: ProviderEnum.DOUYIN,
name: '抖音豆包',
models: [],
},
{
model: ProviderEnum.SILICON,
name: '硅基流动',
models: [
'deepseek-ai/DeepSeek-V2-Chat',
'deepseek-ai/DeepSeek-Coder-V2-Instruct',
'deepseek-ai/DeepSeek-V2.5',
'Qwen/Qwen2.5-72B-Instruct-128K',
'Qwen/Qwen2.5-72B-Instruct',
'Qwen/Qwen2-VL-72B-Instruct',
'Qwen/Qwen2.5-32B-Instruct',
'Qwen/Qwen2.5-14B-Instruct',
'Qwen/Qwen2.5-7B-Instruct',
'Qwen/Qwen2.5-Math-72B-Instruct',
'Qwen/Qwen2.5-Coder-7B-Instruct',
'Qwen/Qwen2-72B-Instruct',
'Qwen/Qwen2-7B-Instruct',
'Qwen/Qwen2-1.5B-Instruct',
'Qwen/Qwen2-57B-A14B-Instruct',
'TeleAI/TeleChat2',
'01-ai/Yi-1.5-34B-Chat-16K',
'01-ai/Yi-1.5-9B-Chat-16K',
'01-ai/Yi-1.5-6B-Chat',
'THUDM/chatglm3-6b',
'THUDM/glm-4-9b-chat',
'Vendor-A/Qwen/Qwen2-72B-Instruct',
'Vendor-A/Qwen/Qwen2.5-72B-Instruct',
'internlm/internlm2_5-7b-chat',
'internlm/internlm2_5-20b-chat',
'OpenGVLab/InternVL2-Llama3-76B',
'OpenGVLab/InternVL2-26B',
'nvidia/Llama-3.1-Nemotron-70B-Instruct',
'meta-llama/Meta-Llama-3.1-405B-Instruct',
'meta-llama/Meta-Llama-3.1-70B-Instruct',
'meta-llama/Meta-Llama-3.1-8B-Instruct',
'meta-llama/Meta-Llama-3-8B-Instruct',
'meta-llama/Meta-Llama-3-70B-Instruct',
'google/gemma-2-27b-it',
'google/gemma-2-9b-it',
'Pro/Qwen/Qwen2.5-7B-Instruct',
'Pro/Qwen/Qwen2-7B-Instruct',
'Pro/Qwen/Qwen2-1.5B-Instruct',
'Pro/Qwen/Qwen2-VL-7B-Instruct',
'Pro/01-ai/Yi-1.5-9B-Chat-16K',
'Pro/01-ai/Yi-1.5-6B-Chat',
'Pro/THUDM/chatglm3-6b',
'Pro/THUDM/glm-4-9b-chat',
'Pro/internlm/internlm2_5-7b-chat',
'Pro/OpenGVLab/InternVL2-8B',
'Pro/meta-llama/Meta-Llama-3-8B-Instruct',
'Pro/meta-llama/Meta-Llama-3.1-8B-Instruct',
'Pro/google/gemma-2-9b-it',
],
},
{
model: ProviderEnum.YI,
name: '零一万物',
models: [
'yi-lightning',
'yi-large',
'yi-medium',
'yi-medium-200k',
'yi-spark',
'yi-large-rag',
'yi-large-turbo',
],
},
{
model: ProviderEnum.SPARK,
name: '讯飞星火',
// models: ['lite', 'generalv3', 'pro-128k', 'generalv3.5', 'max-32k', '4.0Ultra'],
models: [
{ label: 'Spark Lite', value: 'lite' },
{ label: 'Spark Pro', value: 'generalv3' },
{ label: 'Spark Pro-128K', value: 'pro-128k' },
{ label: 'Spark Max', value: 'generalv3.5' },
{ label: 'Spark Max-32K', value: 'max-32k' },
{ label: 'Spark4.0 Ultra', value: '4.0Ultra' },
],
},
{
model: ProviderEnum.OLLAMA,
name: 'Ollama',
models: [],
},
{
model: ProviderEnum.AZURE_OPENAI,
name: 'Azure OpenAI',
models: ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-32k', 'gpt-4-turbo', 'gpt-4o'],
},
{
model: ProviderEnum.GEMINI,
name: 'Gemini',
models: ['gemini-1.5-pro'],
},
{
model: ProviderEnum.CLAUDE,
name: 'Claude',
models: ['claude-3-opus', 'claude-3-opus-20240229', 'claude-3-sonnet', 'claude-3-haiku'],
},
];

View File

@ -0,0 +1,37 @@
export enum ProviderEnum {
OPENAI = 'OPENAI',
AZURE_OPENAI = 'AZURE_OPENAI',
GEMINI = 'GEMINI',
OLLAMA = 'OLLAMA',
CLAUDE = 'CLAUDE',
Q_FAN = 'Q_FAN',
Q_WEN = 'Q_WEN',
ZHIPU = 'ZHIPU',
GITEEAI = 'GITEEAI',
DEEPSEEK = 'DEEPSEEK',
DOUYIN = 'DOUYIN',
SILICON = 'SILICON',
YI = 'YI',
SPARK = 'SPARK',
}
export function getModels(provider: string, providers: Array<any>) {
const arr = providers.filter((i) => i.model === provider);
if (arr.length === 0) {
return [];
}
if (typeof arr[0].models[0] === 'string') {
return arr[0].models.map((i) => {
return {
label: i,
value: i,
};
});
} else {
return arr[0].models;
}
}
export function getTitle(provider: string, providers: Array<any>) {
return providers.filter((i) => i.model === provider)[0].name;
}

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div></div>
</template>
<style scoped lang="scss">
</style>

View File

@ -1,185 +1,125 @@
<script lang="ts" setup>
import { Table } from '@/components/Table';
import { Delete, Edit, Plus } from '@element-plus/icons-vue';
import editCom from './edit.vue';
import { computed, h, nextTick, reactive, ref } from 'vue';
import { getColumns } from './composables/columns.ts';
import { LLMProviders } from './composables/consts.ts';
// import { del, list as getModels } from '@/api/aigc/model';
import { ElMessage, ElMessageBox } from 'element-plus';
import {FormSchema} from "@/types/form";
// import { ModelTypeEnum } from '@/api/models';
import { ProviderEnum } from './composables/provider.ts';
const formData = ref({
provider: ProviderEnum.OPENAI
});
const message = ElMessage;
const dialog = ElMessageBox;
const actionRef = ref();
const editRef = ref();
const tableData = ref([
])
const shema = ref([
{
label: '模型名称',
field: 'provider',
component: 'Select',
colProps: {
span: 6
},
componentProps: {
style: {
width: '150px',
},
options: LLMProviders.map((item) => ({
label: item.name,
value: item.model,
})),
},
}
]) as FormSchema[]
const actionColumn = reactive({
width: 100,
title: '操作',
key: 'action',
fixed: 'right',
align: 'center',
render(record: any) {
return h(TableAction as any, {
style: 'text',
actions: [
{
type: 'info',
icon: Edit,
onClick: handleEdit.bind(null, record),
},
{
type: 'error',
icon: Delete,
onClick: handleDel.bind(null, record),
},
],
});
},
});
const columns = computed(() => {
console.log(formData.value.provider);
nextTick();
return getColumns(formData.value.provider);
});
const loadDataTable = async (params: any) => {
if (formData.value.provider === '') {
formData.value.provider = LLMProviders[0].model;
}
return await getModels({ ...params, provider: formData.value.provider, type: ModelTypeEnum.CHAT });
};
async function handleAdd() {
editRef.value.show({ provider: formData.value.provider });
}
function handleEdit(record: any) {
editRef.value.show(record);
}
function reloadTable() {
actionRef.value.reload();
}
function handleDel(record: any) {
dialog.warning({
title: '警告',
message: `你确定删除 [${record.name}] 模型吗?删除之后不可再用该模型对话`,
confirmButtonText: '确定',
cancelButtonText: '不确定',
type: 'warning',
}).then(async () => {
await del(record.id);
reloadTable();
message.success('模型删除成功');
}).catch(() => {
//
});
}
</script>
<template>
<content-wrap>
<Search :schema="shema" :model="formData" @search="({ provider}) => formData.provider = provider"/>
</content-wrap>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="模型名字" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入模型名字"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
<el-alert
class="w-full mb-10px min-alert"
title="对于完全适配OpenAI接口格式的模型都可在OpenAI中配置只需要定义BaseUrl"
type="info"
show-icon
/>
</el-form-item>
<el-form-item label="模型标识" prop="model">
<el-input
v-model="queryParams.model"
placeholder="请输入模型标识"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="模型平台" prop="platform">
<el-input
v-model="queryParams.platform"
placeholder="请输入模型平台"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['ai:chat-model:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
</el-form-item>
</el-form>
<el-button class="my-10px" type="primary" :icon="Plus">新增模型</el-button>
<Table height="cacl(100% - 400px)" border :columns="columns" :data="tableData.concat(tableData)" :pagination="false"/>
<editCom ref="editRef" :provider="provider" @reload="reloadTable" />
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="所属平台" align="center" prop="platform">
<template #default="scope">
<dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" />
</template>
</el-table-column>
<el-table-column label="模型名字" align="center" prop="name" />
<el-table-column label="模型标识" align="center" prop="model" />
<el-table-column label="API 秘钥" align="center" prop="keyId" min-width="140">
<template #default="scope">
<span>{{ apiKeyList.find((item) => item.id === scope.row.keyId)?.name }}</span>
</template>
</el-table-column>
<el-table-column label="排序" align="center" prop="sort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="温度参数" align="center" prop="temperature" />
<el-table-column label="回复数 Token 数" align="center" prop="maxTokens" min-width="140" />
<el-table-column label="上下文数量" align="center" prop="maxContexts" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['ai:chat-model:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['ai:chat-model:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<ChatModelForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel'
import ChatModelForm from './ChatModelForm.vue'
import { DICT_TYPE } from '@/utils/dict'
import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey'
/** API 聊天模型 列表 */
defineOptions({ name: 'AiChatModel' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<ChatModelVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
model: undefined,
platform: undefined
})
const queryFormRef = ref() //
const apiKeyList = ref([] as ApiKeyVO[]) // API
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await ChatModelApi.getChatModelPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await ChatModelApi.deleteChatModel(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 初始化 **/
onMounted(async () => {
getList()
//
apiKeyList.value = await ApiKeyApi.getApiKeySimpleList()
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,116 @@
import {ref} from "vue";
import {FormSchema} from "@/types/form";
import {ElTag} from "element-plus";
export enum ProviderEnum {
Redis = 'REDIS',
PgVector = 'PGVECTOR',
Milvus = 'MILVUS',
}
export default function () {
const ProviderConst = [
{ label: 'Redis', value: ProviderEnum.Redis },
{ label: 'PgVector', value: ProviderEnum.PgVector },
{ label: 'Milvus', value: ProviderEnum.Milvus },
];
function getProviderLabel(value: any) {
const arr = ProviderConst.filter((i) => i.value === value);
if (arr === undefined || arr.length === 0) {
return value;
}
return arr[0].label;
}
const shema = ref<FormSchema[]>([
{
label: '模型名称',
field: 'name',
component: 'Input',
colProps: {
span: 6
},
}
])
const columns = ref<object[]>([
{
label: '数据库别名',
field: 'name',
align: 'center',
},
{
label: '供应商',
field: 'provider',
align: 'center',
width: '120',
render(row) {
return h(
ElTag,
{
type: 'success',
},
{
default: () => getProviderLabel(row.provider),
}
);
},
},
{
label: '向量纬度',
field: 'dimension',
align: 'center',
width: '80',
render(row) {
return h(
ElTag,
{
size: 'small',
},
{
default: () => row.dimension,
}
);
},
},
{
label: '数据库地址',
field: 'host',
align: 'center',
width: '110',
},
{
label: '数据库端口',
field: 'port',
align: 'center',
width: '100',
},
{
label: '数据库用户名',
field: 'username',
align: 'center',
},
{
label: '数据库密码',
field: 'password',
align: 'center',
},
{
label: '数据库名',
field: 'databaseName',
align: 'center',
},
{
label: '表名称',
field: 'tableName',
align: 'center',
},
])
const tableData = ref([])
return {
ProviderConst,
getProviderLabel,
shema,
columns,
tableData
}
}

View File

@ -0,0 +1,26 @@
<script setup lang="ts">
import {Plus} from "@element-plus/icons-vue";
import {Table} from "@/components/Table";
import useEmbedStore from './composables'
const { shema, columns, tableData } = useEmbedStore()
</script>
<template>
<content-wrap>
<Search :schema="shema"/>
</content-wrap>
<ContentWrap>
<el-alert
class="w-full mb-10px min-alert"
title="注意请慎重修改模型的向量纬度参数Dimension此参数需要和向量库匹配错误修改可能将影响已有的向量数据"
type="info"
show-icon
/>
<el-button class="my-10px" type="primary" :icon="Plus">新增向量数据库</el-button>
<Table height="cacl(100% - 400px)" border :columns="columns" :data="tableData.concat(tableData)" :pagination="false"/>
</ContentWrap>
</template>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,102 @@
import {ElTag} from "element-plus";
import {ref} from "vue";
import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider";
import {FormSchema} from "@/types/form";
export default function () {
const LLMProviders: any[] = [
{
model: ProviderEnum.OPENAI,
name: 'OpenAI',
models: ['text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'],
},
{
model: ProviderEnum.Q_FAN,
name: '百度千帆',
models: ['bge-large-zh', 'bge-large-en', 'tao-8k'],
},
{
model: ProviderEnum.Q_WEN,
name: '阿里百炼',
models: ['text-embedding-v3'],
},
{
model: ProviderEnum.ZHIPU,
name: '智谱清言',
models: ['embedding-2', 'embedding-3'],
},
{
model: ProviderEnum.DOUYIN,
name: '抖音豆包',
models: ['text-240715', 'text-240515'],
},
{
model: ProviderEnum.OLLAMA,
name: 'Ollama',
models: ['text2vec-bge-large-chinese:latest'],
},
];
const baseColumns = [
{
label: '模型别名',
field: 'name',
},
{
label: '模型版本',
field: 'model',
width: '160',
},
{
label: '向量纬度',
field: 'dimension',
align: 'center',
width: '100',
render(row) {
return h(
ElTag,
{
size: 'small',
},
{
default: () => row.dimension,
}
);
},
},
{
label: 'Api Key',
field: 'apiKey',
},
{
label: 'Base Url',
field: 'baseUrl',
},
];
const tableData = ref([
])
const shema = ref<FormSchema[]>([
{
label: '模型名称',
field: 'name',
component: 'Select',
colProps: {
span: 6
},
componentProps: {
style: {
width: '150px',
},
options: LLMProviders.map((item) => ({
label: item.name,
value: item.model,
})),
},
}
])
return {
baseColumns,
shema,
tableData
}
}

View File

@ -0,0 +1,26 @@
<script setup lang="ts">
import {Plus} from "@element-plus/icons-vue";
import usePage from './composables/index'
const {shema, baseColumns: columns, tableData} = usePage()
</script>
<template>
<content-wrap>
<Search :schema="shema"/>
</content-wrap>
<ContentWrap>
<el-alert
class="w-full mb-10px min-alert"
title="注意为了实现向量数据库的动态切换这里Embedding供应商统一选择支持1024纬度的模型"
type="info"
show-icon
/>
<el-button class="my-10px" type="primary" :icon="Plus">新增向量模型</el-button>
<Table height="cacl(100% - 400px)" border :columns="columns" :data="tableData.concat(tableData)" :pagination="false"/>
</ContentWrap>
</template>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,110 @@
export default function () {
enum ProviderEnum {
OPENAI = 'OPENAI',
AZURE_OPENAI = 'AZURE_OPENAI',
ZHIPU = 'ZHIPU',
}
const LLMProviders: any[] = [
{
model: ProviderEnum.OPENAI,
name: 'OpenAI',
models: ['dall-e-2', 'dall-e-3'],
},
{
model: ProviderEnum.AZURE_OPENAI,
name: 'Azure OpenAI',
models: ['dall-e-2', 'dall-e-3'],
},
{
model: ProviderEnum.ZHIPU,
name: '智谱清言',
models: ['cogview-3'],
},
]
const formData = ref({
provider: ProviderEnum.OPENAI,
});
const tableData = ref([])
const shema = ref([
{
field: 'provider',
label: '模型别名',
component: 'Select',
required: true,
componentProps: {
placeholder: '请输入模型别名',
style: {
width: '180px',
},
options: LLMProviders.map((item) => ({
label: item.name,
value: item.model,
})),
},
},
])
const baseColumns = [
{
label: '模型别名',
field: 'name',
},
{
label: '模型版本',
field: 'model',
},
];
const openaiColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
];
const azureOpenaiColumns = [
...baseColumns,
{
label: 'Api Key',
field: 'apiKey',
},
{
label: 'Endpoint',
field: 'endpoint',
},
{
label: 'Deployment Name',
field: 'azureDeploymentName',
},
];
const zhipuColumns = [...baseColumns];
function getColumns(provider: string) {
console.log(provider);
switch (provider) {
case ProviderEnum.OPENAI: {
return openaiColumns;
}
case ProviderEnum.AZURE_OPENAI: {
return azureOpenaiColumns;
}
case ProviderEnum.ZHIPU: {
return zhipuColumns;
}
}
return [];
}
const columns = computed(() => {
nextTick();
return getColumns(formData.value.provider)
});
return {
LLMProviders,
columns,
tableData,
shema,
formData
}
}

View File

@ -0,0 +1,26 @@
<script setup lang="ts">
import {Plus} from "@element-plus/icons-vue";
import usePage from './composables/index'
const {shema, columns, tableData, formData} = usePage()
</script>
<template>
<content-wrap>
<Search :schema="shema" :model="formData" @search="(model) => formData.provider = model.provider"/>
</content-wrap>
<ContentWrap>
<el-alert
class="w-full mb-10px min-alert"
title="鉴于很多模型的文生图效果很差甚至没有这里只建议使用OpenAI的DALL-E模型"
type="info"
show-icon
/>
<el-button class="my-10px" type="primary" :icon="Plus">新增向量模型</el-button>
<Table height="cacl(100% - 400px)" border :columns="columns" :data="tableData.concat(tableData)" :pagination="false"/>
</ContentWrap>
</template>
<style scoped lang="scss">
</style>