mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-08 10:26:48 +08:00
feat(knowledge): 实现知识库文件上传和预处理功能
- 新增文件上传接口和相关组件 - 实现文件上传、预处理和保存功能 - 添加预处理结果预览功能 -优化知识库详情展示,增加文件内容和关键词显示 - 实现知识库文件删除功能 - TODO 拆分的文档展示 还需要调整 可能会把tags 放在标题上 需要修改样式
This commit is contained in:
@@ -56,6 +56,15 @@ export function minerUBbox(params) {
|
||||
params: params
|
||||
})
|
||||
}
|
||||
//minerU 获取文档处理状态
|
||||
export function minerUQuery(params) {
|
||||
return request({
|
||||
url: getUrl('/dataset/document/query'),
|
||||
method: 'get',
|
||||
params: params,
|
||||
noLoading: true
|
||||
})
|
||||
}
|
||||
//minerU 获取markdown
|
||||
export function minerUMarkDown(params) {
|
||||
return getUrl(`document/mineru/md?documentId=${params.documentId}`)
|
||||
@@ -139,9 +148,40 @@ export function updateRuleExtractSplit(data) {
|
||||
|
||||
//知识库文件上传-自定义
|
||||
export function uploadFileByCustom(data) {
|
||||
return getUrl(`/datasetDocumentEx/uploadFileByCustom`, 'jifen')
|
||||
return request({
|
||||
url: getUrl(`/datasetDocumentEx/uploadFileByCustom`),
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
//知识库文件上传-通用
|
||||
export function uploadFileByTemplate(data) {
|
||||
return getUrl(`/datasetDocumentEx/uploadFileByTemplate`, 'jifen')
|
||||
return request({
|
||||
url: getUrl(`/datasetDocumentEx/uploadFileByTemplate`),
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 知识库文件详情
|
||||
export function datasetQuerySegments(data) {
|
||||
return request({
|
||||
url: getUrl(`/datasetDocumentEx/querySegments`, 'jifen'),
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
// 知识库文件删除
|
||||
export function datasetQueryDelete(data) {
|
||||
return request({
|
||||
url: getUrl(`/datasetDocumentEx/delete?documentId=${data.id}`, 'jifen'),
|
||||
method: 'delete',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ function startLoading() {
|
||||
}
|
||||
function endLoading() {
|
||||
//使用Element loading-close 方法
|
||||
loading.close()
|
||||
if (loading) {
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
|
||||
// request interceptor
|
||||
@@ -32,9 +34,11 @@ service.interceptors.request.use(
|
||||
if (loading) {
|
||||
endLoading()
|
||||
}
|
||||
|
||||
console.log(config.noLoading)
|
||||
//linkage 接口
|
||||
// config.type 可以从api的接口地址定义 可以不触发loading
|
||||
if (config.type != false) {
|
||||
if (config.noLoading != true) {
|
||||
startLoading()
|
||||
}
|
||||
return config
|
||||
@@ -48,7 +52,7 @@ service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data
|
||||
endLoading()
|
||||
if(!res.content){
|
||||
if (!res.content) {
|
||||
Message({
|
||||
message: res.message,
|
||||
type: 'error',
|
||||
@@ -75,7 +79,7 @@ service.interceptors.response.use(
|
||||
})
|
||||
} else {
|
||||
Message({
|
||||
message: res.content.message || 'Error',
|
||||
message: res.content.message || res.content.resultMessage || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
@@ -91,8 +95,8 @@ service.interceptors.response.use(
|
||||
return false
|
||||
} else {
|
||||
res.content.result = '0'
|
||||
res.result = String(res.result?res.result:0)
|
||||
res.code = String(res.code ? res.code: 0 )
|
||||
res.result = String(res.result ? res.result : 0)
|
||||
res.code = String(res.code ? res.code : 0)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,25 @@ export const documentSourceOptions = [
|
||||
value: '1'
|
||||
}
|
||||
]
|
||||
|
||||
export const segmentedModeOptions = [
|
||||
{
|
||||
label: '传统分段模式',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
label: 'Q&A分段模式',
|
||||
value: '1'
|
||||
}
|
||||
]
|
||||
|
||||
export const segmentedModeOptionsMap = [
|
||||
{
|
||||
label: '是',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
label: '否',
|
||||
value: '1'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<div style="height: 100%;">
|
||||
<div class="mv10 mh20 text-right" v-if="isEdit">
|
||||
<el-button type="primary" size="medium" @click="saveMarkDown">保存并处理</el-button>
|
||||
<el-button size="medium">取消</el-button>
|
||||
<el-button type="primary" size="medium" @click="saveMarkDown" :disabled="finishedMiner">保存并处理</el-button>
|
||||
</div>
|
||||
<div :class="!isEdit ? 'mt10 flex' : 'flex'" style="height:calc(100% - 35px);flex:1">
|
||||
<iframe
|
||||
@@ -11,7 +10,7 @@
|
||||
:src="`${iframeSrc}/pdfjs-dist/web/viewer.html?file=${encodeURIComponent(prdUrl)}`"
|
||||
class="miner-u el-card is-always-shadow ml20"
|
||||
></iframe>
|
||||
<div style="flex:1;" class="mh20 miner-u-md">
|
||||
<div style="flex:1;" class="mh20 miner-u-md" v-loading="finishedMiner" element-loading-text="正在识别中...">
|
||||
<el-tabs type="border-card" style="height: 100%;overflow: hidden" @tab-click="changeTab">
|
||||
<el-tab-pane label="预览" style="overflow:scroll;">
|
||||
<div v-html="markdownHtml" class="view-body" id="viewBody" ref="viewBody"></div>
|
||||
@@ -27,7 +26,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getPdfUrl, minerUBbox, minerUMarkDown, minerUMarkDownUpdate } from '@/api/generatedApi/index'
|
||||
import { getPdfUrl, minerUBbox, minerUMarkDown, minerUMarkDownUpdate, minerUQuery } from '@/api/generatedApi/index'
|
||||
import { DEFAULT_COLOR_SECTION, PDF_COLOR_PICKER } from './pdf-color'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import markdownItKatex from 'markdown-it-katex'
|
||||
@@ -40,6 +39,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
tableIdCounter: 0,
|
||||
finishedMiner: false,
|
||||
prdUrl: ``,
|
||||
iframeSrc: window.location.origin,
|
||||
bboxList: [],
|
||||
@@ -103,7 +103,18 @@ export default {
|
||||
default: true
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
watch: {
|
||||
documentId: {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.getMinerUStatus()
|
||||
|
||||
this.prdUrl = getPdfUrl({ documentId: newVal })
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
components: {},
|
||||
filters: {},
|
||||
methods: {
|
||||
@@ -171,9 +182,10 @@ export default {
|
||||
minerUMarkDownUpdate({
|
||||
documentId: this.documentId,
|
||||
newMd: pre
|
||||
}).then(res => {
|
||||
this.$emit('saveMarkDown', true)
|
||||
})
|
||||
},
|
||||
|
||||
// 给文件增加色块
|
||||
formatJson(data) {
|
||||
return data.map(item => {
|
||||
@@ -245,13 +257,36 @@ export default {
|
||||
'*'
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
// 获取识别状态
|
||||
getMinerUStatus() {
|
||||
this.finishedMiner = true
|
||||
minerUQuery({ id: this.documentId }).then(res => {
|
||||
console.log(res)
|
||||
|
||||
let mineruStatus = res.content.content.mineruStatus
|
||||
switch (mineruStatus) {
|
||||
case 0:
|
||||
case '0':
|
||||
setTimeout(() => {
|
||||
this.getMinerUStatus()
|
||||
}, 1000)
|
||||
break
|
||||
case 1:
|
||||
case '1':
|
||||
this.finishedMiner = false
|
||||
this.getPDFDetailBbox()
|
||||
this.getPDFDetailMarkDown()
|
||||
break
|
||||
default:
|
||||
this.finishedMiner = false
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPDFDetailBbox()
|
||||
this.getPDFDetailMarkDown()
|
||||
this.prdUrl = getPdfUrl({ documentId: this.documentId })
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
// 监听 iframe 的 postMessage 事件
|
||||
window.addEventListener('message', event => {
|
||||
|
||||
@@ -13,17 +13,7 @@
|
||||
</el-form-item>
|
||||
<!-- 文件上传-->
|
||||
<el-form-item label="" required prop="file">
|
||||
<el-upload
|
||||
drag
|
||||
:action="form.radio === '1' ? uploadFileByCustom() : uploadFileByTemplate()"
|
||||
:headers="headers"
|
||||
class="upload-demo"
|
||||
:on-success="handleUploadSuccess"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:show-file-list="false"
|
||||
:file-list="fieldList"
|
||||
:data="form"
|
||||
>
|
||||
<div @click="createFiled" class="upload-demo">
|
||||
<el-empty v-if="!uploadLoading">
|
||||
<template #description>
|
||||
<p>点击或将文件拖拽到这里上传</p>
|
||||
@@ -31,7 +21,7 @@
|
||||
</template>
|
||||
</el-empty>
|
||||
<div v-else v-loading="uploadLoading" :element-loading-text="'文件上传中...'" style="height: 100%"></div>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 本地文件 -->
|
||||
@@ -80,8 +70,7 @@ export default {
|
||||
name: 'preprocessing',
|
||||
data() {
|
||||
return {
|
||||
uploadFileByCustom,
|
||||
uploadFileByTemplate,
|
||||
filed: null,
|
||||
uploadLoading: false,
|
||||
headers: {},
|
||||
fieldList: [],
|
||||
@@ -92,7 +81,7 @@ export default {
|
||||
datasetId: this.$route.query.datasetId
|
||||
},
|
||||
previewDialogVisible: false, // 添加对话框显示控制变量
|
||||
documentId: null
|
||||
documentId: '1361400636462174208'
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
@@ -104,6 +93,41 @@ export default {
|
||||
this.$emit('getFileType', this.form.radio)
|
||||
},
|
||||
downloadTemplate() {},
|
||||
|
||||
// 生成filed
|
||||
createFiled() {
|
||||
let input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.onchange = e => {
|
||||
// this.$emit('getFile', e.target.files[0])
|
||||
this.filed = e.target.files[0]
|
||||
}
|
||||
input.click()
|
||||
},
|
||||
|
||||
uploadFiled() {
|
||||
let formData = new FormData()
|
||||
formData.append('file', this.filed)
|
||||
formData.append('datasetId', this.form.datasetId)
|
||||
let api = this.form.radio === '1' ? uploadFileByCustom : uploadFileByTemplate
|
||||
if (this.form.radio === '1') {
|
||||
formData.append('beMinerU', this.form.beMinerU)
|
||||
formData.append('beOcr', this.form.beOcr)
|
||||
}
|
||||
api(formData).then(response => {
|
||||
this.documentId = response.content.content
|
||||
// 向上导入documentId
|
||||
this.$emit('getDocumentId', this.documentId)
|
||||
// 文件内容
|
||||
this.$emit('getUploadDetail', response.content.content)
|
||||
// 表单内容
|
||||
this.$emit('getForm', this.form, this.$refs.processForm)
|
||||
if (this.form.beMinerU) {
|
||||
this.$emit('beMinerU', true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleUploadSuccess(response, file) {
|
||||
this.fieldList = [file]
|
||||
this.uploadLoading = false
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
</el-steps>
|
||||
|
||||
<div class="components">
|
||||
<step-preprocessing v-if="active === 0" @getForm="getForm" @getDocumentId="getDocumentId" @beMinerU="beMinerU"></step-preprocessing>
|
||||
<step-split-config ref="splitConfig" v-if="active === 1"></step-split-config>
|
||||
<step-words v-if="active === 2"></step-words>
|
||||
<step-preprocessing v-show="active === 0" @getForm="getForm" @getDocumentId="getDocumentId" ref="stepPreProcessing"></step-preprocessing>
|
||||
<step-split-config ref="splitConfig" v-show="active === 1"></step-split-config>
|
||||
<step-words v-show="active === 2"></step-words>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
<el-button size="medium" @click="active--" v-if="active >= 1">上一步</el-button>
|
||||
<!-- <el-button type="primary" size="medium" @click="active++" v-if="active < 2">下一步</el-button>-->
|
||||
<el-button type="primary" size="medium" @click="nextStep" v-if="active < 2">下一步</el-button>
|
||||
<el-button type="primary" size="medium">取消</el-button>
|
||||
<el-button type="primary" size="medium" @click="$router.history.go(-1)">取消</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 添加预处理结果预览对话框 -->
|
||||
<el-drawer :visible.sync="visible" size="80%" title="预处理结果预览">
|
||||
<div style="height:calc(100% - 55px);">
|
||||
<r-miner-u :documentId="documentId"></r-miner-u>
|
||||
<r-miner-u :documentId="documentId" @saveMarkDown="saveMarkDown"></r-miner-u>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@@ -47,9 +47,9 @@ export default {
|
||||
name: 'create',
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
visible: false,
|
||||
active: 0,
|
||||
documentId: '1361352503568994304'
|
||||
documentId: '1361407835582337024'
|
||||
}
|
||||
},
|
||||
props: {},
|
||||
@@ -61,17 +61,30 @@ export default {
|
||||
},
|
||||
filters: {},
|
||||
methods: {
|
||||
beMinerU() {
|
||||
this.visible = true
|
||||
saveMarkDown() {
|
||||
this.visible = false
|
||||
this.active++
|
||||
},
|
||||
beMinerU() {
|
||||
setTimeout(() => {
|
||||
this.visible = true
|
||||
})
|
||||
},
|
||||
getForm(form) {
|
||||
if (form.beMinerU) {
|
||||
this.beMinerU()
|
||||
} else {
|
||||
this.saveMarkDown()
|
||||
}
|
||||
},
|
||||
getForm() {},
|
||||
fetchApi() {},
|
||||
getDocumentId(id) {
|
||||
this.documentId = id
|
||||
},
|
||||
nextStep() {
|
||||
if (this.active === 0) {
|
||||
this.active++
|
||||
// this.active++
|
||||
this.$refs.stepPreProcessing.uploadFiled()
|
||||
} else if (this.active === 1) {
|
||||
this.$refs.splitConfig.nextStep()
|
||||
}
|
||||
|
||||
@@ -86,29 +86,50 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-drawer :visible.sync="drawer" size="50%" :title="descriptions.knowledgeName">
|
||||
<div class="flex mh20">
|
||||
<el-drawer :visible.sync="drawer" size="80%" :title="descriptions.knowledgeName">
|
||||
<div class="flex ph20 align-items-b" style="width: 100%">
|
||||
<div>
|
||||
<el-descriptions class="margin-top" :column="1" border>
|
||||
<el-descriptions-item label="分段模式:"> </el-descriptions-item>
|
||||
<el-descriptions-item label="是否使用预处理:"> </el-descriptions-item>
|
||||
<el-descriptions-item label="是否使用ocr协助处理:"> </el-descriptions-item>
|
||||
<el-descriptions-item label="分段模式:">
|
||||
{{ segmentedMode | filterSegmentedMode }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="是否使用预处理:">
|
||||
{{ descriptions.useMineru | filterUseMineru }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="是否使用ocr协助处理:">
|
||||
{{ descriptions.mineruUseOcr | filterUseMineru }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="知识拆分规则:"> </el-descriptions-item>
|
||||
<el-descriptions-item label="知识题词规则:"> </el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<div></div>
|
||||
<div style="width:80%" class="ml20">
|
||||
<el-collapse v-model="activeName" accordion>
|
||||
<el-collapse-item v-for="(item, index) in descriptions.data" :name="index" style="width: 100%" :key="index">
|
||||
<div slot="title" class="flex" style="width: 100%">
|
||||
<div class="ellipsis-title" style="flex:1">{{ item.content }}</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ item.content }}
|
||||
</div>
|
||||
<div class="mt20" style="flex:1">
|
||||
<el-tag v-for="(tags, index) in item.keywords" :label="tags" size="mini" type="info" class="mr10 " :key="index">{{ tags }}</el-tag>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getDatasetById, datasetUpdate, datasetsExPages } from '@/api/generatedApi/index'
|
||||
import { documentSourceOptions } from '@/assets/js/utils/utilOptions'
|
||||
import { getDatasetById, datasetUpdate, datasetsExPages, datasetQuerySegments, datasetQueryDelete } from '@/api/generatedApi/index'
|
||||
import { documentSourceOptions, segmentedModeOptionsMap } from '@/assets/js/utils/utilOptions'
|
||||
export default {
|
||||
name: 'index',
|
||||
data() {
|
||||
return {
|
||||
activeName: -1,
|
||||
drawer: false,
|
||||
editKnowledge: false,
|
||||
form: {
|
||||
@@ -239,8 +260,34 @@ export default {
|
||||
},
|
||||
// 查看文档详情
|
||||
viewDocumentDetail(row) {
|
||||
this.descriptions = row
|
||||
this.drawer = true
|
||||
datasetQuerySegments({ documentId: row.id }).then(res => {
|
||||
if (res) {
|
||||
this.descriptions = {
|
||||
...row,
|
||||
...res.content.content
|
||||
}
|
||||
this.drawer = true
|
||||
}
|
||||
})
|
||||
},
|
||||
// 删除文件
|
||||
deleteKnowledge(row) {
|
||||
this.$messageBox(
|
||||
() => {
|
||||
datasetQueryDelete({ id: row.id }).then(res => {
|
||||
if (res) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
this.page = 1
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
'是否确认删除当前知识文件?',
|
||||
'warning'
|
||||
)
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -253,6 +300,10 @@ export default {
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
filterUseMineru(val) {
|
||||
let item = segmentedModeOptionsMap.find(item => item.value === String(val))
|
||||
return item ? item.label : '否'
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
@@ -323,7 +374,9 @@ export default {
|
||||
type: 'danger',
|
||||
size: 'mini'
|
||||
},
|
||||
on: {}
|
||||
on: {
|
||||
click: () => this.deleteKnowledge(params.row)
|
||||
}
|
||||
},
|
||||
'删除'
|
||||
),
|
||||
@@ -349,4 +402,19 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.ellipsis-title {
|
||||
// 最多展示一行 省略号展示
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
//width: 50%;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user