Prechádzať zdrojové kódy

调整OCR任务从知识库选择文件时不会重复加入上传列表

yangdr 1 deň pred
rodič
commit
5f42b2e4b2

+ 35 - 11
src/dialogs/OCRDialog.vue

@@ -12,7 +12,7 @@
       </el-form-item>
       <el-form-item label="文件" :label-width="formLabelWidth">
         <el-upload ref="upload" :action="'/api/file/upload/pdf/' + form.job_id" :mutiple="false" :limit="100"
-          :on-preview="handlePreview" :on-remove="handleRemove" :on-success="handleSuccess" :file-list="fileList"
+          :on-preview="handlePreview" :on-remove="handleRemove" :on-success="handleSuccess" v-model:file-list="fileList"
           :on-exceed="handleExceed" :auto-upload="false">
           <el-button @click.stop="knowledgeBase.visible = true" size="small" type="primary">知识库导入</el-button>
           <el-button slot="trigger" size="small" type="primary">上传文件</el-button>
@@ -248,30 +248,54 @@ function handleGetKnowledgeBase() {
 }
 function fetchFile(fileName: string, fileUrl: string) {
   axios.get(fileUrl, { responseType: 'blob' })
-    .then(response => {
+    .then(async response => {
       // upload.value!.clearFiles()
       // 创建文件对象并添加到文件列表
       const rawFile = new File([response.data], fileName, { type: response.data.type });
-      // console.log(rawFile)
-      // fileList.value.push({ name: fileName, size: file.size, raw: file });
       const file = rawFile as UploadRawFile
       file.uid = genFileId()
-      // file = file as UploadRawFile
-      upload.value!.handleStart(file)
+      const fileHashHex = await calculateFileHash(file)
+      let fileExist = false;
+      await Promise.allSettled(fileList.value.map(async (it: any) => {
+        const itFileHashHex = await calculateFileHash(it.raw);
+        if (itFileHashHex === fileHashHex) {
+          fileExist = true;
+          return true;
+        }
+        return false;
+      }))
+      if (fileExist) {
+        ElMessage({
+          message: `文件“${fileName}”已存在上传列表中`,
+          type: 'info',
+          plain: true,
+        })
+      } else {
+        upload.value!.handleStart(file)
+        ElMessage({
+          message: `文件“${fileName}”导入成功`,
+          type: 'success',
+          plain: true,
+        })
+      }
       // knowledgeBase.value.visible = false
-      ElMessage({
-        message: `文件“${fileName}”导入成功`,
-        type: 'success'
-      })
     })
     .catch(error => {
       ElMessage({
         message: `从知识库获取文件“${fileName}”失败`,
         type: 'error'
       })
-      console.error('下载文件失败:', error);
+      console.log(error);
     });
 }
+// 计算文件的hash值
+async function calculateFileHash(file: File) {
+  const arrayBuffer = await file.arrayBuffer(); // 将文件读取为 ArrayBuffer
+  const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer); // 计算哈希值
+  const hashArray = Array.from(new Uint8Array(hashBuffer)); // 将哈希转换为字节数组
+  const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join(''); // 转换为十六进制字符串
+  return hashHex;
+}
 
 function handleImportFiles(filesList: any[]) {
   for (let i = 0; i < filesList.length; i++) {

+ 2 - 2
src/views/GraphView.vue

@@ -109,7 +109,7 @@ import { formatDate } from '@/utils/misc'
 import { getSessionVar, saveSessionVar } from '@/utils/session'
 //从路由参数中获取队列ID
 
-const sessionId = ref("")
+const sessionId = ref<string | undefined>("")
 const ocrDialog = ref()
 const queueSelectDialog = ref()
 const queueId = ref("")
@@ -135,7 +135,7 @@ const jobFileTree = ref({
 const pageData = ref({ page: 1, pages: 1, page_size: 10, total: 0, records: [] })
 const jobFileData = ref([])
 const jobFileInDir = ref([])
-const currentJob = ref({ id: 0, job_category: "USER", job_name: "" })
+const currentJob = ref<any>({ id: 0, job_category: "USER", job_name: "", job_creator: "", job_logs: "", updated: "", created: null })
 const currentActionJob = ref({ id: 0, job_category: "USER", job_name: "" })
 
 const route = useRoute()

+ 29 - 23
src/views/HomeView.vue

@@ -1,54 +1,60 @@
 <template>
-   <el-alert style="margin-bottom: 20px;" title="上传文档,自动提取文本,自动抽取知识,自动构建图谱 支持多种文档格式,如PDF、DOCX等 支持多种知识抽取模型,如LLM、RAG等 支持多种图谱构建模型,如Neo4j、Postgres等" type="success" :closable="false" />
+  <el-alert style="margin-bottom: 20px;"
+    title="上传文档,自动提取文本,自动抽取知识,自动构建图谱 支持多种文档格式,如PDF、DOCX等 支持多种知识抽取模型,如LLM、RAG等 支持多种图谱构建模型,如Neo4j、Postgres等"
+    type="success" :closable="false" />
   <!-- 主要内容区域 -->
-    <el-steps
-    style="margin-bottom: 20px;padding: 33px 8%;"
-    :space="200"
-    simple
-  >
-    <el-step >
+  <el-steps style="margin-bottom: 20px;padding: 33px 8%;" :space="200" simple>
+    <el-step>
       <template #icon>
         <el-icon size="30" color="#40a1ff"><upload-filled /></el-icon>
-        </template> 
+      </template>
       <template #title>
         <div>第一步</div>
         <div>上传文档</div>
         <!-- <span>上传文档</span> -->
       </template>
     </el-step>
-       <el-step status="process">
+    <el-step status="process">
       <template #icon>
-        <el-icon size="30" color="#40a1ff"><TrendCharts /></el-icon>
-        </template> 
+        <el-icon size="30" color="#40a1ff">
+          <TrendCharts />
+        </el-icon>
+      </template>
       <template #title>
         <div>第二步</div>
         <div>文本切片</div>
       </template>
     </el-step>
-       <el-step status="process">
+    <el-step status="process">
       <template #icon>
-        <el-icon size="30" color="#40a1ff"><ChromeFilled /></el-icon>
-        </template> 
+        <el-icon size="30" color="#40a1ff">
+          <ChromeFilled />
+        </el-icon>
+      </template>
       <template #title>
         <div>第三步</div>
         <div>知识抽取</div>
         <!-- <span>上传文档</span> -->
       </template>
     </el-step>
-       <el-step status="process" >
+    <el-step status="process">
       <template #icon>
-        <el-icon size="30" color="#40a1ff"><HelpFilled /></el-icon>
-        </template> 
+        <el-icon size="30" color="#40a1ff">
+          <HelpFilled />
+        </el-icon>
+      </template>
       <template #title>
         <div>第四步</div>
         <div>图谱构建</div>
         <!-- <span>上传文档</span> -->
       </template>
     </el-step>
-       <el-step  status="process">
+    <el-step status="process">
       <template #icon>
-        <el-icon size="30" color="#40a1ff"><Grid /></el-icon>
-        </template> 
+        <el-icon size="30" color="#40a1ff">
+          <Grid />
+        </el-icon>
+      </template>
       <template #title>
         <div>第五步</div>
         <div>查看图谱</div>
@@ -115,7 +121,8 @@
   </el-row> -->
   <el-row style="display: flex;justify-content: space-between;padding: 0 50px;">
     <template v-for="(queue, index) in queuesSummary" :key="index">
-      <el-card shadow="hover" style="width: 40%; margin: 10px; padding: 30px; text-align: center;background: linear-gradient( #eef6ff 0%, #F6F6F9 100%);">
+      <el-card shadow="hover"
+        style="width: 40%; margin: 10px; padding: 30px; text-align: center;background: linear-gradient( #eef6ff 0%, #F6F6F9 100%);">
         <div class="card-header" style="margin-bottom: 10px;">
           <span>{{ formatQueueName(queue.queue_category, queue.queue_name) }}</span>
           <span class="card-status" :class="queue.status === 'running' ? 'status-running' : 'status-idle'">
@@ -144,7 +151,7 @@
 <script setup lang="ts">
 import { ref, onMounted } from 'vue';
 import { getQueueSummary } from '@/api/AgentApi';
-const queuesSummary = ref([]);
+const queuesSummary = ref<any>([]);
 const queueIdNameDict = ref([
   { id: "0", name: "DEFAULT", category: 'SYSTEM', title: "全部工作", },
   { id: "1", name: "OCR", category: 'SYSTEM', title: "PDF文件抽取", },
@@ -243,5 +250,4 @@ onMounted(() => {
     }
   }
 }
-
 </style>

+ 1 - 1
src/views/KMPlatform/Home/Home.vue

@@ -33,7 +33,7 @@ import { useRouter } from 'vue-router'
 import { knowledgeGraphAddr } from "@/utils/config"
 import { getSessionVar } from '@/utils/session'
 const router = useRouter()
-console.log("getSessionVar('knowledageSystem') ", getSessionVar('knowledageSystem'))
+// console.log("getSessionVar('knowledageSystem') ", getSessionVar('knowledageSystem'))
 let process = ref<any>([
   {
     image: "node-icon",

+ 4 - 4
src/views/QueueView.vue

@@ -126,12 +126,12 @@ import { formatDate } from '@/utils/misc'
 import { getSessionVar, saveSessionVar } from '@/utils/session'
 //从路由参数中获取队列ID
 
-const sessionId = ref("")
+const sessionId = ref<any>("")
 const ocrDialog = ref()
 const allowCreateJob = ref(false)
 const queueSelectDialog = ref()
 const textViewDialog = ref()
-const queueId = ref("")
+const queueId = ref<any>("")
 const queueData = ref({ id: "0", queue_category: "", queue_name: "", title: "" })
 const showDrawer = ref(false)
 const showDrawerDirection = ref('rtl')
@@ -155,7 +155,7 @@ const jobFileTree = ref({
 const pageData = ref({ page: 1, pages: 1, page_size: 10, total: 0, records: [] })
 const jobFileData = ref([])
 const jobFileInDir = ref([])
-const currentJob = ref({ id: 0, job_category: "USER", job_name: "" })
+const currentJob = ref<any>({ id: 0, job_category: "USER", job_name: "" })
 const currentActionJob = ref({ id: 0, job_category: "USER", job_name: "" })
 
 const route = useRoute()
@@ -208,7 +208,7 @@ function formatStatus(status: number) {
 }
 function formatFolderName(name: string) {
 
-    var translate = {
+    var translate: any = {
         logs: "日志",
         results: "结果", chunks: "切片", files: "文件",
         ocr_output: "文本转换结果", kb_extract: "知识抽取", kb_build: "知识构建",