初始化

This commit is contained in:
2026-02-22 18:56:10 +08:00
commit 26677972a6
3112 changed files with 255972 additions and 0 deletions

View File

@@ -0,0 +1,350 @@
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue';
import {
CirclePlus,
Loading,
Minus,
RefreshRight,
} from '@element-plus/icons-vue';
import {
ElCollapse,
ElCollapseItem,
ElDialog,
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>
<ElDialog
v-model="dialogVisible"
draggable
:title="`${providerInfo?.providerName}${$t('llmProvider.model')}`"
:before-close="closeDialog"
:close-on-click-modal="false"
align-center
width="762"
>
<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>
</ElDialog>
</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>