知识库功能增强,支持Milvus,并优化相关逻辑

This commit is contained in:
2026-02-24 11:19:53 +08:00
parent 148a08a3f1
commit 094b185c49
10 changed files with 196 additions and 59 deletions

View File

@@ -1,9 +1,5 @@
<script setup lang="ts">
import type { FormInstance } from 'element-plus';
import { onMounted, ref, watch } from 'vue';
import { InfoFilled } from '@element-plus/icons-vue';
import type {FormInstance} from 'element-plus';
import {
ElButton,
ElForm,
@@ -17,9 +13,13 @@ import {
ElTooltip,
} from 'element-plus';
import { api } from '#/api/request';
import {computed, onMounted, ref, watch} from 'vue';
import {InfoFilled} from '@element-plus/icons-vue';
import {api} from '#/api/request';
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import { $t } from '#/locales';
import {$t} from '#/locales';
const props = defineProps({
detailData: {
@@ -39,6 +39,7 @@ const props = defineProps({
vectorEmbedModelId: '',
options: {
canUpdateEmbeddingModel: true,
rerankEnable: false,
},
rerankModelId: '',
searchEngineEnable: false,
@@ -50,12 +51,26 @@ const props = defineProps({
const emit = defineEmits(['reload']);
const entity = ref<any>({ ...props.detailData });
const normalizeEntity = (raw: any) => {
const options = {
canUpdateEmbeddingModel: true,
...(raw?.options || {}),
};
if (options.rerankEnable === undefined || options.rerankEnable === null) {
options.rerankEnable = !!raw?.rerankModelId;
}
return {
...raw,
options,
};
};
const entity = ref<any>(normalizeEntity(props.detailData));
watch(
() => props.detailData,
(newVal) => {
entity.value = { ...newVal };
entity.value = normalizeEntity(newVal);
},
{ immediate: true, deep: true },
);
@@ -63,7 +78,7 @@ watch(
const embeddingLlmList = ref<any>([]);
const rerankerLlmList = ref<any>([]);
const vecotrDatabaseList = ref<any>([
// { value: 'milvus', label: 'Milvus' },
{ value: 'milvus', label: 'Milvus' },
{ value: 'redis', label: 'Redis' },
{ value: 'opensearch', label: 'OpenSearch' },
{ value: 'elasticsearch', label: 'ElasticSearch' },
@@ -71,6 +86,20 @@ const vecotrDatabaseList = ref<any>([
{ value: 'qcloud', label: $t('documentCollection.tencentCloud') },
]);
const milvusVectorStoreConfigPlaceholder =
'uri=http://127.0.0.1:19530\n' +
'databaseName=default\n' +
'token=\n' +
'username=\n' +
'password=\n' +
'autoCreateCollection=true';
const vectorStoreConfigPlaceholder = computed(() => {
return entity.value?.vectorStoreType === 'milvus'
? milvusVectorStoreConfigPlaceholder
: '';
});
const getEmbeddingLlmListData = async () => {
try {
const url = `/api/v1/model/list?modelType=embeddingModel`;
@@ -131,6 +160,11 @@ async function save() {
const valid = await saveForm.value?.validate();
if (!valid) return;
if (!entity.value.options) {
entity.value.options = {};
}
entity.value.options.rerankEnable = !!entity.value.options.rerankEnable;
btnLoading.value = true;
const res = await api.post(
'/api/v1/documentCollection/update',
@@ -233,6 +267,7 @@ async function save() {
v-model.trim="entity.vectorStoreConfig"
:rows="4"
type="textarea"
:placeholder="vectorStoreConfigPlaceholder"
/>
</ElFormItem>
<ElFormItem prop="vectorEmbedModelId">
@@ -302,12 +337,19 @@ async function save() {
type="number"
/>
</ElFormItem>
<ElFormItem
prop="options.rerankEnable"
:label="$t('documentCollection.rerankEnable')"
>
<ElSwitch v-model="entity.options.rerankEnable" />
</ElFormItem>
<ElFormItem
prop="rerankModelId"
:label="$t('documentCollection.rerankLlmId')"
>
<ElSelect
v-model="entity.rerankModelId"
clearable
:placeholder="$t('documentCollection.placeholder.rerankLlm')"
>
<ElOption

View File

@@ -1,9 +1,5 @@
<script setup lang="ts">
import type { FormInstance } from 'element-plus';
import { onMounted, ref } from 'vue';
import { InfoFilled } from '@element-plus/icons-vue';
import type {FormInstance} from 'element-plus';
import {
ElButton,
ElDialog,
@@ -18,10 +14,14 @@ import {
ElTooltip,
} from 'element-plus';
import { api } from '#/api/request';
import {onMounted, ref} from 'vue';
import {InfoFilled} from '@element-plus/icons-vue';
import {api} from '#/api/request';
import DictSelect from '#/components/dict/DictSelect.vue';
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import { $t } from '#/locales';
import {$t} from '#/locales';
const emit = defineEmits(['reload']);
const embeddingLlmList = ref<any>([]);
@@ -83,12 +83,28 @@ const defaultEntity = {
dimensionOfVectorModel: undefined,
options: {
canUpdateEmbeddingModel: true,
rerankEnable: false,
},
rerankModelId: '',
searchEngineEnable: '',
englishName: '',
};
const entity = ref<any>({ ...defaultEntity });
const normalizeEntity = (raw: any = {}) => {
const options = {
canUpdateEmbeddingModel: true,
...(raw.options || {}),
};
if (options.rerankEnable === undefined || options.rerankEnable === null) {
options.rerankEnable = !!raw.rerankModelId;
}
return {
...defaultEntity,
...raw,
options,
};
};
const entity = ref<any>(normalizeEntity(defaultEntity));
const btnLoading = ref(false);
const rules = ref({
@@ -119,14 +135,10 @@ const rules = ref({
function openDialog(row: any = {}) {
if (row.id) {
isAdd.value = false;
entity.value = {
...defaultEntity,
...row,
options: { ...defaultEntity.options, ...row.options },
};
entity.value = normalizeEntity(row);
} else {
isAdd.value = true;
entity.value = { ...defaultEntity };
entity.value = normalizeEntity(defaultEntity);
}
dialogVisible.value = true;
}
@@ -136,6 +148,11 @@ async function save() {
const valid = await saveForm.value?.validate();
if (!valid) return;
if (!entity.value.options) {
entity.value.options = {};
}
entity.value.options.rerankEnable = !!entity.value.options.rerankEnable;
btnLoading.value = true;
const res = await api.post(
isAdd.value
@@ -162,7 +179,7 @@ async function save() {
function closeDialog() {
saveForm.value?.resetFields();
isAdd.value = true;
entity.value = { ...defaultEntity };
entity.value = normalizeEntity(defaultEntity);
dialogVisible.value = false;
}
@@ -339,12 +356,19 @@ defineExpose({
type="number"
/>
</ElFormItem>
<ElFormItem
prop="options.rerankEnable"
:label="$t('documentCollection.rerankEnable')"
>
<ElSwitch v-model="entity.options.rerankEnable" />
</ElFormItem>
<ElFormItem
prop="rerankModelId"
:label="$t('documentCollection.rerankLlmId')"
>
<ElSelect
v-model="entity.rerankModelId"
clearable
:placeholder="$t('documentCollection.placeholder.rerankLlm')"
>
<ElOption

View File

@@ -1,9 +1,9 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import {onMounted, reactive, ref} from 'vue';
import { $t } from '@easyflow/locales';
import {$t} from '@easyflow/locales';
import { InfoFilled } from '@element-plus/icons-vue';
import {InfoFilled} from '@element-plus/icons-vue';
import {
ElButton,
ElForm,
@@ -16,7 +16,7 @@ import {
ElTooltip,
} from 'element-plus';
import { api } from '#/api/request';
import {api} from '#/api/request';
const props = defineProps({
documentCollectionId: {
@@ -29,18 +29,21 @@ onMounted(() => {
getDocumentCollectionConfig();
});
const searchEngineEnable = ref(false);
const baseOptions = ref<Record<string, any>>({});
const getDocumentCollectionConfig = () => {
api
.get(`/api/v1/documentCollection/detail?id=${props.documentCollectionId}`)
.then((res) => {
const { data } = res;
searchConfig.docRecallMaxNum = data.options.docRecallMaxNum
? Number(data.options.docRecallMaxNum)
const options = data.options || {};
baseOptions.value = { ...options };
searchConfig.docRecallMaxNum = options.docRecallMaxNum
? Number(options.docRecallMaxNum)
: 5;
searchConfig.simThreshold = data.options.simThreshold
? Number(data.options.simThreshold)
searchConfig.simThreshold = options.simThreshold
? Number(options.simThreshold)
: 0.5;
searchConfig.searchEngineType = data.options.searchEngineType || 'lucene';
searchConfig.searchEngineType = options.searchEngineType || 'lucene';
searchEngineEnable.value = !!data.searchEngineEnable;
});
};
@@ -55,6 +58,7 @@ const submitConfig = () => {
const submitData = {
id: props.documentCollectionId,
options: {
...baseOptions.value,
docRecallMaxNum: searchConfig.docRecallMaxNum,
simThreshold: searchConfig.simThreshold,
searchEngineType: searchConfig.searchEngineType,
@@ -65,6 +69,7 @@ const submitConfig = () => {
api
.post('/api/v1/documentCollection/update', submitData)
.then(() => {
baseOptions.value = { ...submitData.options };
ElMessage.success($t('documentCollectionSearch.message.saveSuccess'));
})
.catch((error) => {