252 lines
5.8 KiB
Vue
252 lines
5.8 KiB
Vue
<script setup lang="ts">
|
||
import { onMounted, ref, watch } from 'vue';
|
||
|
||
import { $t } from '@easyflow/locales';
|
||
|
||
import {
|
||
ElButton,
|
||
ElCard,
|
||
ElForm,
|
||
ElFormItem,
|
||
ElInputNumber,
|
||
ElMessage,
|
||
ElOption,
|
||
ElSelect,
|
||
ElSwitch,
|
||
} from 'element-plus';
|
||
|
||
import { api } from '#/api/request';
|
||
import { buildKnowledgePath } from '#/views/ai/documentCollection/share-path';
|
||
|
||
const props = defineProps({
|
||
knowledgeId: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
detailData: {
|
||
type: Object as any,
|
||
default: () => ({}),
|
||
},
|
||
requestClient: {
|
||
type: Object as any,
|
||
default: () => api,
|
||
},
|
||
endpointPrefix: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
manageable: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
});
|
||
|
||
const emit = defineEmits(['reload']);
|
||
|
||
const form = ref<any>({
|
||
knowledgeId: '',
|
||
vectorEmbedModelId: '',
|
||
rerankModelId: '',
|
||
rerankEnable: false,
|
||
docRecallMaxNum: 5,
|
||
simThreshold: 0.6,
|
||
rebuildVectors: false,
|
||
});
|
||
|
||
const embeddingModels = ref<any[]>([]);
|
||
const rerankModels = ref<any[]>([]);
|
||
const saving = ref(false);
|
||
|
||
const syncForm = () => {
|
||
const options = props.detailData?.options || {};
|
||
form.value = {
|
||
knowledgeId: props.knowledgeId,
|
||
vectorEmbedModelId: props.detailData?.vectorEmbedModelId || '',
|
||
rerankModelId: props.detailData?.rerankModelId || '',
|
||
rerankEnable:
|
||
options?.rerankEnable === undefined
|
||
? !!props.detailData?.rerankModelId
|
||
: !!options.rerankEnable,
|
||
docRecallMaxNum: Number(options?.docRecallMaxNum || 5),
|
||
simThreshold: Number(options?.simThreshold || 0.6),
|
||
rebuildVectors: false,
|
||
};
|
||
};
|
||
|
||
watch(
|
||
() => [props.detailData, props.knowledgeId],
|
||
() => {
|
||
syncForm();
|
||
},
|
||
{ immediate: true, deep: true },
|
||
);
|
||
|
||
const loadModels = async () => {
|
||
const [embeddingRes, rerankRes] = await Promise.all([
|
||
props.requestClient.get(
|
||
buildKnowledgePath(
|
||
props.endpointPrefix,
|
||
'/api/v1/documentCollection/modelList',
|
||
),
|
||
{ params: { modelType: 'embeddingModel' } },
|
||
),
|
||
props.requestClient.get(
|
||
buildKnowledgePath(
|
||
props.endpointPrefix,
|
||
'/api/v1/documentCollection/modelList',
|
||
),
|
||
{ params: { modelType: 'rerankModel' } },
|
||
),
|
||
]);
|
||
embeddingModels.value = embeddingRes?.data || [];
|
||
rerankModels.value = rerankRes?.data || [];
|
||
};
|
||
|
||
const handleSave = async () => {
|
||
saving.value = true;
|
||
try {
|
||
const res = await props.requestClient.post(
|
||
buildKnowledgePath(
|
||
props.endpointPrefix,
|
||
'/api/v1/documentCollection/shareConfigUpdate',
|
||
),
|
||
form.value,
|
||
);
|
||
if (res.errorCode === 0) {
|
||
ElMessage.success($t('message.saveOkMessage'));
|
||
emit('reload');
|
||
}
|
||
} finally {
|
||
saving.value = false;
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
loadModels();
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<ElCard shadow="never" class="share-config-card">
|
||
<template #header>
|
||
<div class="share-config-card__header">
|
||
<div>
|
||
<div class="share-config-card__title">受限配置</div>
|
||
<div class="share-config-card__desc">
|
||
仅开放模型切换、检索参数与向量重建
|
||
</div>
|
||
<div v-if="!props.manageable" class="share-config-card__tip">
|
||
当前分享仅支持查看,不允许修改配置
|
||
</div>
|
||
</div>
|
||
<ElButton
|
||
v-if="props.manageable"
|
||
type="primary"
|
||
:loading="saving"
|
||
@click="handleSave"
|
||
>
|
||
{{ $t('button.save') }}
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
|
||
<ElForm label-position="top" class="share-config-form">
|
||
<ElFormItem :label="$t('documentCollection.vectorEmbedLlmId')">
|
||
<ElSelect v-model="form.vectorEmbedModelId" :disabled="!props.manageable">
|
||
<ElOption
|
||
v-for="item in embeddingModels"
|
||
:key="item.id"
|
||
:label="item.title"
|
||
:value="item.id"
|
||
/>
|
||
</ElSelect>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem :label="$t('documentCollection.rerankLlmId')">
|
||
<ElSelect v-model="form.rerankModelId" clearable :disabled="!props.manageable">
|
||
<ElOption
|
||
v-for="item in rerankModels"
|
||
:key="item.id"
|
||
:label="item.title"
|
||
:value="item.id"
|
||
/>
|
||
</ElSelect>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem :label="$t('documentCollection.rerankEnable')">
|
||
<ElSwitch v-model="form.rerankEnable" :disabled="!props.manageable" />
|
||
</ElFormItem>
|
||
|
||
<ElFormItem :label="$t('documentCollectionSearch.docRecallMaxNum.label')">
|
||
<ElInputNumber
|
||
v-model="form.docRecallMaxNum"
|
||
:min="1"
|
||
:max="50"
|
||
:disabled="!props.manageable"
|
||
/>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem :label="$t('documentCollectionSearch.simThreshold.label')">
|
||
<ElInputNumber
|
||
v-model="form.simThreshold"
|
||
:min="0"
|
||
:max="1"
|
||
:step="0.01"
|
||
:disabled="!props.manageable"
|
||
/>
|
||
</ElFormItem>
|
||
|
||
<ElFormItem label="保存后重建向量">
|
||
<ElSwitch v-model="form.rebuildVectors" :disabled="!props.manageable" />
|
||
</ElFormItem>
|
||
</ElForm>
|
||
</ElCard>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.share-config-card {
|
||
border-radius: 16px;
|
||
}
|
||
|
||
.share-config-card__header {
|
||
display: flex;
|
||
gap: 16px;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.share-config-card__title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.share-config-card__desc {
|
||
margin-top: 4px;
|
||
font-size: 13px;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.share-config-card__tip {
|
||
margin-top: 6px;
|
||
font-size: 12px;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.share-config-form {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 0 16px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.share-config-form {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.share-config-card__header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
}
|
||
</style>
|