|
@@ -7,24 +7,26 @@
|
|
|
:close-on-click-modal="false"
|
|
:close-on-click-modal="false"
|
|
|
:close-on-press-escape="false"
|
|
:close-on-press-escape="false"
|
|
|
>
|
|
>
|
|
|
- <!-- 连接配置 -->
|
|
|
|
|
- <el-form v-if="!connected" :model="configForm" label-width="100px" label-position="left" class="sample-center-form">
|
|
|
|
|
- <el-form-item label="API 地址" required>
|
|
|
|
|
- <el-input v-model="configForm.base_url" placeholder="https://sample-center.example.com" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item label="App ID" required>
|
|
|
|
|
- <el-input v-model="configForm.app_id" placeholder="应用标识" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item label="App Secret" required>
|
|
|
|
|
- <el-input v-model="configForm.app_secret" type="password" placeholder="应用密钥" show-password />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item>
|
|
|
|
|
- <el-button type="primary" @click="connect" :loading="connecting">连接</el-button>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-form>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 知识库列表 -->
|
|
|
|
|
- <div v-else>
|
|
|
|
|
|
|
+ <!-- 步骤一:连接配置 -->
|
|
|
|
|
+ <div v-if="step === 1">
|
|
|
|
|
+ <el-form :model="configForm" label-width="100px" label-position="left" class="sample-center-form">
|
|
|
|
|
+ <el-form-item label="API 地址" required>
|
|
|
|
|
+ <el-input v-model="configForm.base_url" placeholder="https://sample-center.example.com" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="App ID" required>
|
|
|
|
|
+ <el-input v-model="configForm.app_id" placeholder="应用标识" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="App Secret" required>
|
|
|
|
|
+ <el-input v-model="configForm.app_secret" type="password" placeholder="应用密钥" show-password />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" @click="connect" :loading="connecting">连接</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 步骤二:选择知识库 -->
|
|
|
|
|
+ <div v-else-if="step === 2">
|
|
|
<el-table :data="kbList" v-loading="loadingKB" style="width: 100%">
|
|
<el-table :data="kbList" v-loading="loadingKB" style="width: 100%">
|
|
|
<el-table-column prop="name" label="知识库名称" min-width="200" />
|
|
<el-table-column prop="name" label="知识库名称" min-width="200" />
|
|
|
<el-table-column prop="document_count" label="文档数量" width="100" />
|
|
<el-table-column prop="document_count" label="文档数量" width="100" />
|
|
@@ -43,29 +45,83 @@
|
|
|
</el-table>
|
|
</el-table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ <!-- 步骤三:填写本地知识库信息 -->
|
|
|
|
|
+ <div v-else-if="step === 3">
|
|
|
|
|
+ <el-form ref="createFormRef" :model="createForm" :rules="createRules" label-position="top">
|
|
|
|
|
+ <el-form-item label="关联的样本中心知识库">
|
|
|
|
|
+ <el-input :model-value="selectedKB?.name" disabled />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="知识库名称" prop="name">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="createForm.name"
|
|
|
|
|
+ placeholder="请输入知识库名称"
|
|
|
|
|
+ maxlength="64"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ @blur="createForm.name = createForm.name.trim()"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="知识库描述" prop="desc">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="createForm.desc"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ placeholder="请输入知识库描述"
|
|
|
|
|
+ maxlength="256"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ :autosize="{ minRows: 3 }"
|
|
|
|
|
+ @blur="createForm.desc = createForm.desc.trim()"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="向量模型" prop="embedding_model_id">
|
|
|
|
|
+ <ModelSelect
|
|
|
|
|
+ v-model="createForm.embedding_model_id"
|
|
|
|
|
+ placeholder="请选择向量模型"
|
|
|
|
|
+ :options="modelOptions"
|
|
|
|
|
+ @submit-model="loadEmbeddingModels"
|
|
|
|
|
+ :model-type="'EMBEDDING'"
|
|
|
|
|
+ showFooter
|
|
|
|
|
+ ></ModelSelect>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<template #footer>
|
|
<template #footer>
|
|
|
<span class="dialog-footer">
|
|
<span class="dialog-footer">
|
|
|
- <el-button @click="dialogVisible = false" :loading="loading">取消</el-button>
|
|
|
|
|
- <el-button v-if="connected" @click="connected = false">返回</el-button>
|
|
|
|
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
+ <el-button v-if="step > 1" @click="prevStep">上一步</el-button>
|
|
|
|
|
+ <el-button v-if="step === 3" type="primary" @click="submitCreate" :loading="submitting">
|
|
|
|
|
+ 创建
|
|
|
|
|
+ </el-button>
|
|
|
</span>
|
|
</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref } from 'vue'
|
|
|
|
|
|
|
+import { ref, reactive } from 'vue'
|
|
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
import { ElMessage } from 'element-plus'
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
|
|
+import { groupBy } from 'lodash'
|
|
|
import { getSampleCenterKBList } from '@/api/knowledge/sample-center'
|
|
import { getSampleCenterKBList } from '@/api/knowledge/sample-center'
|
|
|
import type { SampleCenterKB } from '@/api/knowledge/sample-center'
|
|
import type { SampleCenterKB } from '@/api/knowledge/sample-center'
|
|
|
|
|
+import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
|
|
|
|
+import ModelSelect from '@/components/model-select/index.vue'
|
|
|
|
|
+import { MsgSuccess } from '@/utils/message'
|
|
|
|
|
+import useStore from '@/stores'
|
|
|
|
|
|
|
|
-const emit = defineEmits(['select'])
|
|
|
|
|
|
|
+const emit = defineEmits(['refresh'])
|
|
|
|
|
+const router = useRouter()
|
|
|
|
|
+const { user } = useStore()
|
|
|
|
|
|
|
|
const dialogVisible = ref(false)
|
|
const dialogVisible = ref(false)
|
|
|
-const connected = ref(false)
|
|
|
|
|
|
|
+const step = ref(1)
|
|
|
const connecting = ref(false)
|
|
const connecting = ref(false)
|
|
|
-const loading = ref(false)
|
|
|
|
|
const loadingKB = ref(false)
|
|
const loadingKB = ref(false)
|
|
|
|
|
+const submitting = ref(false)
|
|
|
const kbList = ref<SampleCenterKB[]>([])
|
|
const kbList = ref<SampleCenterKB[]>([])
|
|
|
|
|
+const selectedKB = ref<SampleCenterKB | null>(null)
|
|
|
|
|
+const modelOptions = ref<any[]>([])
|
|
|
|
|
+const currentFolder = ref<any>(null)
|
|
|
|
|
|
|
|
const configForm = ref({
|
|
const configForm = ref({
|
|
|
base_url: '',
|
|
base_url: '',
|
|
@@ -73,10 +129,25 @@ const configForm = ref({
|
|
|
app_secret: '',
|
|
app_secret: '',
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-const open = () => {
|
|
|
|
|
|
|
+const createFormRef = ref<FormInstance>()
|
|
|
|
|
+const createForm = ref({
|
|
|
|
|
+ name: '',
|
|
|
|
|
+ desc: '',
|
|
|
|
|
+ embedding_model_id: '',
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const createRules = reactive<FormRules>({
|
|
|
|
|
+ name: [{ required: true, message: '请输入知识库名称', trigger: 'blur' }],
|
|
|
|
|
+ embedding_model_id: [{ required: true, message: '请选择向量模型', trigger: 'change' }],
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const open = (folder?: any) => {
|
|
|
|
|
+ currentFolder.value = folder
|
|
|
dialogVisible.value = true
|
|
dialogVisible.value = true
|
|
|
- connected.value = false
|
|
|
|
|
|
|
+ step.value = 1
|
|
|
kbList.value = []
|
|
kbList.value = []
|
|
|
|
|
+ selectedKB.value = null
|
|
|
|
|
+ createForm.value = { name: '', desc: '', embedding_model_id: '' }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const connect = async () => {
|
|
const connect = async () => {
|
|
@@ -92,7 +163,7 @@ const connect = async () => {
|
|
|
page_size: 100,
|
|
page_size: 100,
|
|
|
})
|
|
})
|
|
|
kbList.value = res.data?.items || []
|
|
kbList.value = res.data?.items || []
|
|
|
- connected.value = true
|
|
|
|
|
|
|
+ step.value = 2
|
|
|
} catch (e: any) {
|
|
} catch (e: any) {
|
|
|
ElMessage.error(e?.message || '连接失败,请检查配置')
|
|
ElMessage.error(e?.message || '连接失败,请检查配置')
|
|
|
} finally {
|
|
} finally {
|
|
@@ -101,11 +172,75 @@ const connect = async () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const selectKB = (row: SampleCenterKB) => {
|
|
const selectKB = (row: SampleCenterKB) => {
|
|
|
- emit('select', {
|
|
|
|
|
- ...row,
|
|
|
|
|
- config: configForm.value,
|
|
|
|
|
- })
|
|
|
|
|
- dialogVisible.value = false
|
|
|
|
|
|
|
+ selectedKB.value = row
|
|
|
|
|
+ // 用样本中心知识库名称作为默认名称
|
|
|
|
|
+ createForm.value.name = row.name
|
|
|
|
|
+ createForm.value.desc = `关联样本中心知识库:${row.name}`
|
|
|
|
|
+ step.value = 3
|
|
|
|
|
+ // 加载向量模型列表
|
|
|
|
|
+ loadEmbeddingModels()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const loadEmbeddingModels = () => {
|
|
|
|
|
+ loadSharedApi({ type: 'model', systemType: 'workspace' })
|
|
|
|
|
+ .getSelectModelList({ model_type: 'EMBEDDING' })
|
|
|
|
|
+ .then((res: any) => {
|
|
|
|
|
+ modelOptions.value = groupBy(res?.data, 'provider')
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const prevStep = () => {
|
|
|
|
|
+ if (step.value === 3) {
|
|
|
|
|
+ step.value = 2
|
|
|
|
|
+ } else if (step.value === 2) {
|
|
|
|
|
+ step.value = 1
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const submitCreate = async () => {
|
|
|
|
|
+ if (!createFormRef.value) return
|
|
|
|
|
+ const valid = await createFormRef.value.validate().catch(() => false)
|
|
|
|
|
+ if (!valid) return
|
|
|
|
|
+
|
|
|
|
|
+ submitting.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const knowledgeData = {
|
|
|
|
|
+ folder_id: currentFolder.value?.id || user.getWorkspaceId(),
|
|
|
|
|
+ name: createForm.value.name,
|
|
|
|
|
+ desc: createForm.value.desc,
|
|
|
|
|
+ embedding_model_id: createForm.value.embedding_model_id,
|
|
|
|
|
+ type: 5, // KnowledgeType.SAMPLE_CENTER
|
|
|
|
|
+ meta: {
|
|
|
|
|
+ sample_center: {
|
|
|
|
|
+ base_url: configForm.value.base_url,
|
|
|
|
|
+ app_id: configForm.value.app_id,
|
|
|
|
|
+ app_secret: configForm.value.app_secret,
|
|
|
|
|
+ kb_id: selectedKB.value?.id,
|
|
|
|
|
+ kb_name: selectedKB.value?.name,
|
|
|
|
|
+ parent_table: selectedKB.value?.parent_table,
|
|
|
|
|
+ child_table: selectedKB.value?.child_table,
|
|
|
|
|
+ metadata_schema: selectedKB.value?.metadata_schema,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const res = await loadSharedApi({ type: 'knowledge', systemType: 'workspace' })
|
|
|
|
|
+ .postKnowledge(knowledgeData, submitting)
|
|
|
|
|
+
|
|
|
|
|
+ await user.profile()
|
|
|
|
|
+ MsgSuccess('样本中心知识库创建成功')
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+ emit('refresh')
|
|
|
|
|
+
|
|
|
|
|
+ // 跳转到知识库文档页
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ path: `/knowledge/${res.data.id}/${currentFolder.value?.id || 'shared'}/5/document`,
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch (e: any) {
|
|
|
|
|
+ ElMessage.error(e?.message || '创建失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ submitting.value = false
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
defineExpose({ open })
|
|
defineExpose({ open })
|