Bladeren bron

Feature/support xlsx (#311)

crazywoola 2 jaren geleden
bovenliggende
commit
df26f82536

File diff suppressed because it is too large
+ 22 - 0
web/app/components/datasets/create/assets/csv.svg


+ 18 - 0
web/app/components/datasets/create/assets/xlsx.svg

@@ -0,0 +1,18 @@
+<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_5938_927)">
+<path d="M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z" fill="#169951"/>
+</g>
+<path opacity="0.5" d="M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17 12C17.5523 12 18 12.4477 18 13V18C18 18.5523 17.5523 19 17 19H7C6.44772 19 6 18.5523 6 18V13C6 12.4477 6.44772 12 7 12H17ZM11.5 13H7L7 15H11.5V13ZM12.5 18H17V16H12.5V18ZM11.5 16V18H7L7 16H11.5ZM12.5 15H17V13H12.5V15Z" fill="white" fill-opacity="0.96"/>
+<defs>
+<filter id="filter0_d_5938_927" x="1" y="0" width="22" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5938_927"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5938_927" result="shape"/>
+</filter>
+</defs>
+</svg>

+ 9 - 1
web/app/components/datasets/create/file-uploader/index.module.css

@@ -100,6 +100,14 @@
   background-image: url(../assets/unknow.svg);
   background-size: 32px;
 }
+.fileIcon.csv {
+  background-image: url(../assets/csv.svg);
+}
+
+.fileIcon.xlsx,
+.fileIcon.xls {
+  background-image: url(../assets/xlsx.svg);
+}
 .fileIcon.pdf {
   background-image: url(../assets/pdf.svg);
 }
@@ -168,4 +176,4 @@
 .actionWrapper .buttonWrapper {
   @apply flex items-center;
   display: none;
-}
+}

+ 102 - 102
web/app/components/datasets/create/file-uploader/index.tsx

@@ -1,19 +1,18 @@
 'use client'
-import React, { useState, useRef, useEffect, useCallback } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
 import { useTranslation } from 'react-i18next'
-import type { File as FileEntity } from '@/models/datasets'
 import { useContext } from 'use-context-selector'
+import cn from 'classnames'
+import s from './index.module.css'
+import type { File as FileEntity } from '@/models/datasets'
 import { ToastContext } from '@/app/components/base/toast'
 import Button from '@/app/components/base/button'
 
 import { upload } from '@/service/base'
 
-import cn from 'classnames'
-import s from './index.module.css'
-
 type IFileUploaderProps = {
-  file?: FileEntity;
-  onFileUpdate: (file?: FileEntity) => void;
+  file?: FileEntity
+  onFileUpdate: (file?: FileEntity) => void
 }
 
 const ACCEPTS = [
@@ -23,9 +22,12 @@ const ACCEPTS = [
   '.md',
   '.markdown',
   '.txt',
+  '.xls',
+  '.xlsx',
+  '.csv',
 ]
 
-const MAX_SIZE = 15 * 1024 *1024
+const MAX_SIZE = 15 * 1024 * 1024
 
 const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
   const { t } = useTranslation()
@@ -39,60 +41,55 @@ const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
   const [uploading, setUploading] = useState(false)
   const [percent, setPercent] = useState(0)
 
-  const handleDragEnter = (e: DragEvent) => {
-    e.preventDefault()
-    e.stopPropagation()
-    e.target !== dragRef.current && setDragging(true)
-  }
-  const handleDragOver = (e: DragEvent) => {
-    e.preventDefault()
-    e.stopPropagation()
+  // utils
+  const getFileType = (currentFile: File) => {
+    if (!currentFile)
+      return ''
+
+    const arr = currentFile.name.split('.')
+    return arr[arr.length - 1]
   }
-  const handleDragLeave = (e: DragEvent) => {
-    e.preventDefault()
-    e.stopPropagation()
-    e.target === dragRef.current && setDragging(false)
+  const getFileName = (name: string) => {
+    const arr = name.split('.')
+    return arr.slice(0, -1).join()
   }
-  const handleDrop = (e: DragEvent) => {
-    e.preventDefault()
-    e.stopPropagation()
-    setDragging(false)
-    if (!e.dataTransfer) {
-      return
-    }
-    const files = [...e.dataTransfer.files]
-    if (files.length > 1) {
-      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
-      return;
-    }
-    onFileUpdate()
-    fileUpload(files[0])
+  const getFileSize = (size: number) => {
+    if (size / 1024 < 10)
+      return `${(size / 1024).toFixed(2)}KB`
+
+    return `${(size / 1024 / 1024).toFixed(2)}MB`
   }
 
-  const selectHandle = () => {
-    if (fileUploader.current) {
-      fileUploader.current.click();
-    }
+  const isValid = (file: File) => {
+    const { size } = file
+    const ext = `.${getFileType(file)}`
+    const isValidType = ACCEPTS.includes(ext)
+    if (!isValidType)
+      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.typeError') })
+
+    const isValidSize = size <= MAX_SIZE
+    if (!isValidSize)
+      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.size') })
+
+    return isValidType && isValidSize
   }
-  const removeFile = () => {
-    if (fileUploader.current) {
-      fileUploader.current.value = ''
+  const onProgress = useCallback((e: ProgressEvent) => {
+    if (e.lengthComputable) {
+      const percent = Math.floor(e.loaded / e.total * 100)
+      setPercent(percent)
     }
-    setCurrentFile(undefined)
-    onFileUpdate()
-  }
-  const fileChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
-    const currentFile = e.target.files?.[0]
-    onFileUpdate()
-    fileUpload(currentFile)
+  }, [setPercent])
+  const abort = () => {
+    const currentXHR = uploadPromise.current
+    currentXHR.abort()
   }
   const fileUpload = async (file?: File) => {
-    if (!file) {
+    if (!file)
       return
-    }
-    if (!isValid(file)) {
+
+    if (!isValid(file))
       return
-    }
+
     setCurrentFile(file)
     setUploading(true)
     const formData = new FormData()
@@ -105,7 +102,7 @@ const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
         xhr: currentXHR,
         data: formData,
         onprogress: onProgress,
-      }) as FileEntity;
+      }) as FileEntity
       onFileUpdate(result)
       setUploading(false)
     }
@@ -113,69 +110,72 @@ const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
       setUploading(false)
       // abort handle
       if (xhr.readyState === 0 && xhr.status === 0) {
-        if (fileUploader.current) {
+        if (fileUploader.current)
           fileUploader.current.value = ''
-        }
+
         setCurrentFile(undefined)
-        return 
+        return
       }
       notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.failed') })
-      return
     }
   }
-  const onProgress = useCallback((e: ProgressEvent) => {
-    if (e.lengthComputable) {
-      const percent = Math.floor(e.loaded / e.total * 100)
-      setPercent(percent)
-    }
-  }, [setPercent])
-  const abort = () => {
-    const currentXHR = uploadPromise.current
-    currentXHR.abort();
+  const handleDragEnter = (e: DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    e.target !== dragRef.current && setDragging(true)
+  }
+  const handleDragOver = (e: DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
   }
+  const handleDragLeave = (e: DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    e.target === dragRef.current && setDragging(false)
+  }
+  const handleDrop = (e: DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    setDragging(false)
+    if (!e.dataTransfer)
+      return
 
-  // utils
-  const getFileType = (currentFile: File) => {
-    if (!currentFile) {
-      return ''
+    const files = [...e.dataTransfer.files]
+    if (files.length > 1) {
+      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
+      return
     }
-    const arr = currentFile.name.split('.')
-    return arr[arr.length-1]
+    onFileUpdate()
+    fileUpload(files[0])
   }
-  const getFileName = (name: string) => {
-    const arr = name.split('.')
-    return arr.slice(0, -1).join()
+
+  const selectHandle = () => {
+    if (fileUploader.current)
+      fileUploader.current.click()
   }
-  const getFileSize = (size: number) => {
-    if (size / 1024 < 10) {
-      return `${(size / 1024).toFixed(2)}KB`
-    }
-    return `${(size / 1024 / 1024).toFixed(2)}MB`
+  const removeFile = () => {
+    if (fileUploader.current)
+      fileUploader.current.value = ''
+
+    setCurrentFile(undefined)
+    onFileUpdate()
   }
-  const isValid = (file: File) => {
-    const { size } = file
-    const ext = `.${getFileType(file)}`
-    const isValidType = ACCEPTS.includes(ext)
-    if (!isValidType) {
-      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.typeError') })
-    }
-    const isValidSize = size <= MAX_SIZE;
-    if (!isValidSize) {
-      notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.size') })
-    }
-    return isValidType && isValidSize;
+  const fileChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const currentFile = e.target.files?.[0]
+    onFileUpdate()
+    fileUpload(currentFile)
   }
 
   useEffect(() => {
-    dropRef.current?.addEventListener('dragenter', handleDragEnter);
-    dropRef.current?.addEventListener('dragover', handleDragOver);
-    dropRef.current?.addEventListener('dragleave', handleDragLeave);
-    dropRef.current?.addEventListener('drop', handleDrop);
+    dropRef.current?.addEventListener('dragenter', handleDragEnter)
+    dropRef.current?.addEventListener('dragover', handleDragOver)
+    dropRef.current?.addEventListener('dragleave', handleDragLeave)
+    dropRef.current?.addEventListener('drop', handleDrop)
     return () => {
-      dropRef.current?.removeEventListener('dragenter', handleDragEnter);
-      dropRef.current?.removeEventListener('dragover', handleDragOver);
-      dropRef.current?.removeEventListener('dragleave', handleDragLeave);
-      dropRef.current?.removeEventListener('drop', handleDrop);
+      dropRef.current?.removeEventListener('dragenter', handleDragEnter)
+      dropRef.current?.removeEventListener('dragover', handleDragOver)
+      dropRef.current?.removeEventListener('dragleave', handleDragLeave)
+      dropRef.current?.removeEventListener('drop', handleDrop)
     }
   }, [])
 
@@ -202,7 +202,7 @@ const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
       {currentFile && (
         <div className={cn(s.file, uploading && s.uploading)}>
           {uploading && (
-            <div className={s.progressbar} style={{ width: `${percent}%`}}/>
+            <div className={s.progressbar} style={{ width: `${percent}%` }}/>
           )}
           <div className={cn(s.fileIcon, s[getFileType(currentFile)])}/>
           <div className={s.fileInfo}>
@@ -264,4 +264,4 @@ const FileUploader = ({ file, onFileUpdate }: IFileUploaderProps) => {
   )
 }
 
-export default FileUploader;
+export default FileUploader

+ 10 - 1
web/app/components/datasets/create/step-two/index.module.css

@@ -292,6 +292,15 @@
   background-image: url(../assets/pdf.svg);
 }
 
+.fileIcon.csv {
+  background-image: url(../assets/csv.svg);
+}
+
+.fileIcon.xlsx,
+.fileIcon.xls {
+  background-image: url(../assets/xlsx.svg);
+}
+
 .fileIcon.html,
 .fileIcon.htm {
   background-image: url(../assets/html.svg);
@@ -379,4 +388,4 @@
   line-height: 28px;
   color: #101828;
   z-index: 10;
-}
+}

File diff suppressed because it is too large
+ 22 - 0
web/app/components/datasets/documents/assets/csv.svg


+ 18 - 0
web/app/components/datasets/documents/assets/xlsx.svg

@@ -0,0 +1,18 @@
+<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_5938_927)">
+<path d="M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z" fill="#169951"/>
+</g>
+<path opacity="0.5" d="M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17 12C17.5523 12 18 12.4477 18 13V18C18 18.5523 17.5523 19 17 19H7C6.44772 19 6 18.5523 6 18V13C6 12.4477 6.44772 12 7 12H17ZM11.5 13H7L7 15H11.5V13ZM12.5 18H17V16H12.5V18ZM11.5 16V18H7L7 16H11.5ZM12.5 15H17V13H12.5V15Z" fill="white" fill-opacity="0.96"/>
+<defs>
+<filter id="filter0_d_5938_927" x="1" y="0" width="22" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5938_927"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5938_927" result="shape"/>
+</filter>
+</defs>
+</svg>

+ 9 - 0
web/app/components/datasets/documents/style.module.css

@@ -75,6 +75,15 @@
 .markdownIcon {
   background-image: url(./assets/md.svg);
 }
+.xlsIcon {
+  background-image: url(./assets/xlsx.svg);
+}
+.xlsxIcon {
+  background-image: url(./assets/xlsx.svg);
+}
+.csvIcon {
+  background-image: url(./assets/csv.svg);
+}
 .statusItemDetail {
   @apply h-8 font-medium border border-gray-200 inline-flex items-center rounded-lg pl-3 pr-4 mr-2;
 }

+ 1 - 1
web/i18n/lang/dataset-creation.en.ts

@@ -22,7 +22,7 @@ const translation = {
       title: 'Upload text file',
       button: 'Drag and drop file, or',
       browse: 'Browse',
-      tip: 'Supports txt, html, markdown, and pdf.',
+      tip: 'Supports txt, html, markdown, xlsx, xls, and pdf.',
       validation: {
         typeError: 'File type not supported',
         size: 'File too large. Maximum is 15MB',

+ 1 - 1
web/i18n/lang/dataset-creation.zh.ts

@@ -22,7 +22,7 @@ const translation = {
       title: '上传文本文件',
       button: '拖拽文件至此,或者',
       browse: '选择文件',
-      tip: '已支持 TXT, HTML, Markdown, PDF',
+      tip: '已支持 TXT, HTML, Markdown, PDF, XLSX, XLS',
       validation: {
         typeError: '文件类型不支持',
         size: '文件太大了,不能超过 15MB',

+ 190 - 190
web/i18n/lang/dataset-documents.en.ts

@@ -1,23 +1,23 @@
 const translation = {
   list: {
-    title: "Documents",
-    desc: "All files of the dataset are shown here, and the entire dataset can be linked to Dify citations or indexed via the Chat plugin.",
-    addFile: "add file",
+    title: 'Documents',
+    desc: 'All files of the dataset are shown here, and the entire dataset can be linked to Dify citations or indexed via the Chat plugin.',
+    addFile: 'add file',
     table: {
       header: {
-        fileName: "FILE NAME",
-        words: "WORDS",
-        hitCount: "HIT COUNT",
-        uploadTime: "UPLOAD TIME",
-        status: "STATUS",
-        action: "ACTION",
+        fileName: 'FILE NAME',
+        words: 'WORDS',
+        hitCount: 'HIT COUNT',
+        uploadTime: 'UPLOAD TIME',
+        status: 'STATUS',
+        action: 'ACTION',
       },
     },
     action: {
       uploadFile: 'Upload new file',
       settings: 'Segment settings',
       archive: 'Archive',
-      delete: "Delete",
+      delete: 'Delete',
       enableWarning: 'Archived file cannot be enabled',
     },
     index: {
@@ -38,48 +38,48 @@ const translation = {
       archived: 'Archived',
     },
     empty: {
-      title: "There is no documentation yet",
+      title: 'There is no documentation yet',
       upload: {
-        tip: "You can upload files, sync from the website, or from webb apps like Notion, GitHub, etc.",
+        tip: 'You can upload files, sync from the website, or from webb apps like Notion, GitHub, etc.',
       },
       sync: {
-        tip: "Dify will periodically download files from your Notion and complete processing.",
+        tip: 'Dify will periodically download files from your Notion and complete processing.',
       },
     },
     delete: {
       title: 'Are you sure Delete?',
-      content: 'If you need to resume processing later, you will continue from where you left off'
-    }
+      content: 'If you need to resume processing later, you will continue from where you left off',
+    },
   },
   metadata: {
-    title: "Metadata",
-    desc: "Labeling metadata for documents allows AI to access them in a timely manner and exposes the source of references for users.",
+    title: 'Metadata',
+    desc: 'Labeling metadata for documents allows AI to access them in a timely manner and exposes the source of references for users.',
     dateTimeFormat: 'MMMM D, YYYY hh:mm A',
-    docTypeSelectTitle: "Please select a document type",
-    docTypeChangeTitle: "Change document type",
+    docTypeSelectTitle: 'Please select a document type',
+    docTypeChangeTitle: 'Change document type',
     docTypeSelectWarning:
-      "If the document type is changed, the now filled metadata will no longer be preserved",
-    firstMetaAction: "Let's go",
+      'If the document type is changed, the now filled metadata will no longer be preserved',
+    firstMetaAction: 'Let\'s go',
     placeholder: {
       add: 'Add ',
       select: 'Select ',
     },
     source: {
       upload_file: 'Upload File',
-      notion: "Sync form Notion",
-      github: "Sync form Github",
+      notion: 'Sync form Notion',
+      github: 'Sync form Github',
     },
     type: {
-      book: "Book",
-      webPage: "Web Page",
-      paper: "Paper",
-      socialMediaPost: "Social Media Post",
-      personalDocument: "Personal Document",
-      businessDocument: "Business Document",
-      IMChat: "IM Chat",
-      wikipediaEntry: "Wikipedia Entry",
-      notion: "Sync form Notion",
-      github: "Sync form Github",
+      book: 'Book',
+      webPage: 'Web Page',
+      paper: 'Paper',
+      socialMediaPost: 'Social Media Post',
+      personalDocument: 'Personal Document',
+      businessDocument: 'Business Document',
+      IMChat: 'IM Chat',
+      wikipediaEntry: 'Wikipedia Entry',
+      notion: 'Sync form Notion',
+      github: 'Sync form Github',
       technicalParameters: 'Technical Parameters',
     },
     field: {
@@ -90,102 +90,102 @@ const translation = {
         processClean: 'Text Process Clean',
       },
       book: {
-        title: "Title",
-        language: "Language",
-        author: "Author",
-        publisher: "Publisher",
-        publicationDate: "Publication Date",
-        ISBN: "ISBN",
-        category: "Category",
+        title: 'Title',
+        language: 'Language',
+        author: 'Author',
+        publisher: 'Publisher',
+        publicationDate: 'Publication Date',
+        ISBN: 'ISBN',
+        category: 'Category',
       },
       webPage: {
-        title: "Title",
-        url: "URL",
-        language: "Language",
-        authorPublisher: "Author/Publisher",
-        publishDate: "Publish Date",
-        topicsKeywords: "Topics/Keywords",
-        description: "Description",
+        title: 'Title',
+        url: 'URL',
+        language: 'Language',
+        authorPublisher: 'Author/Publisher',
+        publishDate: 'Publish Date',
+        topicsKeywords: 'Topics/Keywords',
+        description: 'Description',
       },
       paper: {
-        title: "Title",
-        language: "Language",
-        author: "Author",
-        publishDate: "Publish Date",
-        journalConferenceName: "Journal/Conference Name",
-        volumeIssuePage: "Volume/Issue/Page",
-        DOI: "DOI",
-        topicsKeywords: "Topics/Keywords",
-        abstract: "Abstract",
+        title: 'Title',
+        language: 'Language',
+        author: 'Author',
+        publishDate: 'Publish Date',
+        journalConferenceName: 'Journal/Conference Name',
+        volumeIssuePage: 'Volume/Issue/Page',
+        DOI: 'DOI',
+        topicsKeywords: 'Topics/Keywords',
+        abstract: 'Abstract',
       },
       socialMediaPost: {
-        platform: "Platform",
-        authorUsername: "Author/Username",
-        publishDate: "Publish Date",
-        postURL: "Post URL",
-        topicsTags: "Topics/Tags",
+        platform: 'Platform',
+        authorUsername: 'Author/Username',
+        publishDate: 'Publish Date',
+        postURL: 'Post URL',
+        topicsTags: 'Topics/Tags',
       },
       personalDocument: {
-        title: "Title",
-        author: "Author",
-        creationDate: "Creation Date",
-        lastModifiedDate: "Last Modified Date",
-        documentType: "Document Type",
-        tagsCategory: "Tags/Category",
+        title: 'Title',
+        author: 'Author',
+        creationDate: 'Creation Date',
+        lastModifiedDate: 'Last Modified Date',
+        documentType: 'Document Type',
+        tagsCategory: 'Tags/Category',
       },
       businessDocument: {
-        title: "Title",
-        author: "Author",
-        creationDate: "Creation Date",
-        lastModifiedDate: "Last Modified Date",
-        documentType: "Document Type",
-        departmentTeam: "Department/Team",
+        title: 'Title',
+        author: 'Author',
+        creationDate: 'Creation Date',
+        lastModifiedDate: 'Last Modified Date',
+        documentType: 'Document Type',
+        departmentTeam: 'Department/Team',
       },
       IMChat: {
-        chatPlatform: "Chat Platform",
-        chatPartiesGroupName: "Chat Parties/Group Name",
-        participants: "Participants",
-        startDate: "Start Date",
-        endDate: "End Date",
-        topicsKeywords: "Topics/Keywords",
-        fileType: "File Type",
+        chatPlatform: 'Chat Platform',
+        chatPartiesGroupName: 'Chat Parties/Group Name',
+        participants: 'Participants',
+        startDate: 'Start Date',
+        endDate: 'End Date',
+        topicsKeywords: 'Topics/Keywords',
+        fileType: 'File Type',
       },
       wikipediaEntry: {
-        title: "Title",
-        language: "Language",
-        webpageURL: "Webpage URL",
-        editorContributor: "Editor/Contributor",
-        lastEditDate: "Last Edit Date",
-        summaryIntroduction: "Summary/Introduction",
+        title: 'Title',
+        language: 'Language',
+        webpageURL: 'Webpage URL',
+        editorContributor: 'Editor/Contributor',
+        lastEditDate: 'Last Edit Date',
+        summaryIntroduction: 'Summary/Introduction',
       },
       notion: {
-        title: "Title",
-        language: "Language",
-        author: "Author",
-        createdTime: "Created Time",
-        lastModifiedTime: "Last Modified Time",
-        url: "URL",
-        tag: "Tag",
-        description: "Description",
+        title: 'Title',
+        language: 'Language',
+        author: 'Author',
+        createdTime: 'Created Time',
+        lastModifiedTime: 'Last Modified Time',
+        url: 'URL',
+        tag: 'Tag',
+        description: 'Description',
       },
       github: {
-        repoName: "Repo Name",
-        repoDesc: "Repo Description",
-        repoOwner: "Repo Owner",
-        fileName: "File Name",
-        filePath: "File Path",
-        programmingLang: "Programming Language",
-        url: "URL",
-        license: "License",
-        lastCommitTime: "Last Commit Time",
-        lastCommitAuthor: "Last Commit Author",
+        repoName: 'Repo Name',
+        repoDesc: 'Repo Description',
+        repoOwner: 'Repo Owner',
+        fileName: 'File Name',
+        filePath: 'File Path',
+        programmingLang: 'Programming Language',
+        url: 'URL',
+        license: 'License',
+        lastCommitTime: 'Last Commit Time',
+        lastCommitAuthor: 'Last Commit Author',
       },
       originInfo: {
-        originalFilename: "Original filename",
-        originalFileSize: "Original file size",
-        uploadDate: "Upload date",
-        lastUpdateDate: "Last update date",
-        source: "Source",
+        originalFilename: 'Original filename',
+        originalFileSize: 'Original file size',
+        uploadDate: 'Upload date',
+        lastUpdateDate: 'Last update date',
+        source: 'Source',
       },
       technicalParameters: {
         segmentSpecification: 'Segment specification',
@@ -194,92 +194,92 @@ const translation = {
         paragraphs: 'Paragraphs',
         hitCount: 'Hit count',
         embeddingTime: 'Embedding time',
-        embeddedSpend: 'Embedded spend'
-      }
+        embeddedSpend: 'Embedded spend',
+      },
     },
     languageMap: {
-      zh: "Chinese",
-      en: "English",
-      es: "Spanish",
-      fr: "French",
-      de: "German",
-      ja: "Japanese",
-      ko: "Korean",
-      ru: "Russian",
-      ar: "Arabic",
-      pt: "Portuguese",
-      it: "Italian",
-      nl: "Dutch",
-      pl: "Polish",
-      sv: "Swedish",
-      tr: "Turkish",
-      he: "Hebrew",
-      hi: "Hindi",
-      da: "Danish",
-      fi: "Finnish",
-      no: "Norwegian",
-      hu: "Hungarian",
-      el: "Greek",
-      cs: "Czech",
-      th: "Thai",
-      id: "Indonesian",
+      zh: 'Chinese',
+      en: 'English',
+      es: 'Spanish',
+      fr: 'French',
+      de: 'German',
+      ja: 'Japanese',
+      ko: 'Korean',
+      ru: 'Russian',
+      ar: 'Arabic',
+      pt: 'Portuguese',
+      it: 'Italian',
+      nl: 'Dutch',
+      pl: 'Polish',
+      sv: 'Swedish',
+      tr: 'Turkish',
+      he: 'Hebrew',
+      hi: 'Hindi',
+      da: 'Danish',
+      fi: 'Finnish',
+      no: 'Norwegian',
+      hu: 'Hungarian',
+      el: 'Greek',
+      cs: 'Czech',
+      th: 'Thai',
+      id: 'Indonesian',
     },
     categoryMap: {
       book: {
-        fiction: "Fiction",
-        biography: "Biography",
-        history: "History",
-        science: "Science",
-        technology: "Technology",
-        education: "Education",
-        philosophy: "Philosophy",
-        religion: "Religion",
-        socialSciences: "SocialSciences",
-        art: "Art",
-        travel: "Travel",
-        health: "Health",
-        selfHelp: "SelfHelp",
-        businessEconomics: "BusinessEconomics",
-        cooking: "Cooking",
-        childrenYoungAdults: "ChildrenYoungAdults",
-        comicsGraphicNovels: "ComicsGraphicNovels",
-        poetry: "Poetry",
-        drama: "Drama",
-        other: "Other",
+        fiction: 'Fiction',
+        biography: 'Biography',
+        history: 'History',
+        science: 'Science',
+        technology: 'Technology',
+        education: 'Education',
+        philosophy: 'Philosophy',
+        religion: 'Religion',
+        socialSciences: 'SocialSciences',
+        art: 'Art',
+        travel: 'Travel',
+        health: 'Health',
+        selfHelp: 'SelfHelp',
+        businessEconomics: 'BusinessEconomics',
+        cooking: 'Cooking',
+        childrenYoungAdults: 'ChildrenYoungAdults',
+        comicsGraphicNovels: 'ComicsGraphicNovels',
+        poetry: 'Poetry',
+        drama: 'Drama',
+        other: 'Other',
       },
       personalDoc: {
-        notes: "Notes",
-        blogDraft: "Blog Draft",
-        diary: "Diary",
-        researchReport: "Research Report",
-        bookExcerpt: "Book Excerpt",
-        schedule: "Schedule",
-        list: "List",
-        projectOverview: "Project Overview",
-        photoCollection: "Photo Collection",
-        creativeWriting: "Creative Writing",
-        codeSnippet: "Code Snippet",
-        designDraft: "Design Draft",
-        personalResume: "Personal Resume",
-        other: "Other",
+        notes: 'Notes',
+        blogDraft: 'Blog Draft',
+        diary: 'Diary',
+        researchReport: 'Research Report',
+        bookExcerpt: 'Book Excerpt',
+        schedule: 'Schedule',
+        list: 'List',
+        projectOverview: 'Project Overview',
+        photoCollection: 'Photo Collection',
+        creativeWriting: 'Creative Writing',
+        codeSnippet: 'Code Snippet',
+        designDraft: 'Design Draft',
+        personalResume: 'Personal Resume',
+        other: 'Other',
       },
       businessDoc: {
-        meetingMinutes: "Meeting Minutes",
-        researchReport: "Research Report",
-        proposal: "Proposal",
-        employeeHandbook: "Employee Handbook",
-        trainingMaterials: "Training Materials",
-        requirementsDocument: "Requirements Document",
-        designDocument: "Design Document",
-        productSpecification: "Product Specification",
-        financialReport: "Financial Report",
-        marketAnalysis: "Market Analysis",
-        projectPlan: "Project Plan",
-        teamStructure: "Team Structure",
-        policiesProcedures: "Policies & Procedures",
-        contractsAgreements: "Contracts & Agreements",
-        emailCorrespondence: "Email Correspondence",
-        other: "Other",
+        meetingMinutes: 'Meeting Minutes',
+        researchReport: 'Research Report',
+        proposal: 'Proposal',
+        employeeHandbook: 'Employee Handbook',
+        trainingMaterials: 'Training Materials',
+        requirementsDocument: 'Requirements Document',
+        designDocument: 'Design Document',
+        productSpecification: 'Product Specification',
+        financialReport: 'Financial Report',
+        marketAnalysis: 'Market Analysis',
+        projectPlan: 'Project Plan',
+        teamStructure: 'Team Structure',
+        policiesProcedures: 'Policies & Procedures',
+        contractsAgreements: 'Contracts & Agreements',
+        emailCorrespondence: 'Email Correspondence',
+        other: 'Other',
       },
     },
   },
@@ -300,7 +300,7 @@ const translation = {
     resume: 'Resume processing',
     automatic: 'Automatic',
     custom: 'Custom',
-    previewTip: 'Paragraph preview will be available after embedding is complete'
+    previewTip: 'Paragraph preview will be available after embedding is complete',
   },
   segment: {
     paragraphs: 'Paragraphs',
@@ -308,7 +308,7 @@ const translation = {
     characters: 'characters',
     hitCount: 'hit count',
     vectorHash: 'Vector hash: ',
-  }
-};
+  },
+}
 
-export default translation;
+export default translation

+ 189 - 189
web/i18n/lang/dataset-documents.zh.ts

@@ -1,23 +1,23 @@
 const translation = {
   list: {
-    title: "文档",
-    desc: "数据集的所有文件都在这里显示,整个数据集都可以链接到 Dify 引用或通过 Chat 插件进行索引。",
-    addFile: "添加文件",
+    title: '文档',
+    desc: '数据集的所有文件都在这里显示,整个数据集都可以链接到 Dify 引用或通过 Chat 插件进行索引。',
+    addFile: '添加文件',
     table: {
       header: {
-        fileName: "文件名",
-        words: "字符数",
-        hitCount: "命中次数",
-        uploadTime: "上传时间",
-        status: "状态",
-        action: "操作",
+        fileName: '文件名',
+        words: '字符数',
+        hitCount: '命中次数',
+        uploadTime: '上传时间',
+        status: '状态',
+        action: '操作',
       },
     },
     action: {
       uploadFile: '上传新文件',
       settings: '分段设置',
       archive: '归档',
-      delete: "删除",
+      delete: '删除',
       enableWarning: '归档的文件无法启用',
     },
     index: {
@@ -38,47 +38,47 @@ const translation = {
       archived: '已归档',
     },
     empty: {
-      title: "还没有文档",
+      title: '还没有文档',
       upload: {
-        tip: "您可以上传文件,从网站同步,或者从网络应用程序(如概念、GitHub 等)同步。",
+        tip: '您可以上传文件,从网站同步,或者从网络应用程序(如概念、GitHub 等)同步。',
       },
       sync: {
-        tip: "Dify 会定期从您的 Notion 中下载文件并完成处理。",
+        tip: 'Dify 会定期从您的 Notion 中下载文件并完成处理。',
       },
     },
     delete: {
       title: '确定删除吗?',
-      content: '如果您需要稍后恢复处理,您将从您离开的地方继续'
-    }
+      content: '如果您需要稍后恢复处理,您将从您离开的地方继续',
+    },
   },
   metadata: {
-    title: "元数据",
-    desc: "标记文档的元数据允许 AI 及时访问它们并为用户公开参考来源。",
+    title: '元数据',
+    desc: '标记文档的元数据允许 AI 及时访问它们并为用户公开参考来源。',
     dateTimeFormat: 'YYYY-MM-DD HH:mm',
-    docTypeSelectTitle: "请选择一种文档类型",
-    docTypeChangeTitle: "更换文档类型",
-    docTypeSelectWarning: "如果更改文档类型,将不再保留现在填充的元数据",
-    firstMetaAction: "开始",
+    docTypeSelectTitle: '请选择一种文档类型',
+    docTypeChangeTitle: '更换文档类型',
+    docTypeSelectWarning: '如果更改文档类型,将不再保留现在填充的元数据',
+    firstMetaAction: '开始',
     placeholder: {
       add: '输入',
       select: '选择',
     },
     source: {
       upload_file: '文件上传',
-      notion: "从 Notion 同步的文档",
-      github: "从 Github 同步的代码",
+      notion: '从 Notion 同步的文档',
+      github: '从 Github 同步的代码',
     },
     type: {
-      book: "书籍",
-      webPage: "网页",
-      paper: "论文",
-      socialMediaPost: "社交媒体帖子",
-      personalDocument: "个人文档",
-      businessDocument: "商务文档",
-      IMChat: "IM 聊天记录",
-      wikipediaEntry: "维基百科条目",
-      notion: "从 Notion 同步的文档",
-      github: "从 Github 同步的代码",
+      book: '书籍',
+      webPage: '网页',
+      paper: '论文',
+      socialMediaPost: '社交媒体帖子',
+      personalDocument: '个人文档',
+      businessDocument: '商务文档',
+      IMChat: 'IM 聊天记录',
+      wikipediaEntry: '维基百科条目',
+      notion: '从 Notion 同步的文档',
+      github: '从 Github 同步的代码',
       technicalParameters: '技术参数',
     },
     field: {
@@ -89,102 +89,102 @@ const translation = {
         processClean: '文本预处理与清洗',
       },
       book: {
-        title: "标题",
-        language: "语言",
-        author: "作者",
-        publisher: "出版商",
-        publicationDate: "出版日期",
-        ISBN: "ISBN",
-        category: "类别",
+        title: '标题',
+        language: '语言',
+        author: '作者',
+        publisher: '出版商',
+        publicationDate: '出版日期',
+        ISBN: 'ISBN',
+        category: '类别',
       },
       webPage: {
-        title: "标题",
-        url: "网址",
-        language: "语言",
-        authorPublisher: "作者/出版商",
-        publishDate: "发布日期",
-        topicsKeywords: "主题/关键词",
-        description: "描述",
+        title: '标题',
+        url: '网址',
+        language: '语言',
+        authorPublisher: '作者/出版商',
+        publishDate: '发布日期',
+        topicsKeywords: '主题/关键词',
+        description: '描述',
       },
       paper: {
-        title: "标题",
-        language: "语言",
-        author: "作者",
-        publishDate: "发布日期",
-        journalConferenceName: "期刊/会议名称",
-        volumeIssuePage: "卷/期/页码",
-        DOI: "DOI",
-        topicsKeywords: "主题/关键词",
-        abstract: "摘要",
+        title: '标题',
+        language: '语言',
+        author: '作者',
+        publishDate: '发布日期',
+        journalConferenceName: '期刊/会议名称',
+        volumeIssuePage: '卷/期/页码',
+        DOI: 'DOI',
+        topicsKeywords: '主题/关键词',
+        abstract: '摘要',
       },
       socialMediaPost: {
-        platform: "平台",
-        authorUsername: "作者/用户名",
-        publishDate: "发布日期",
-        postURL: "帖子网址",
-        topicsTags: "主题/标签",
+        platform: '平台',
+        authorUsername: '作者/用户名',
+        publishDate: '发布日期',
+        postURL: '帖子网址',
+        topicsTags: '主题/标签',
       },
       personalDocument: {
-        title: "标题",
-        author: "作者",
-        creationDate: "创建日期",
-        lastModifiedDate: "最后修改日期",
-        documentType: "文档类型",
-        tagsCategory: "标签/类别",
+        title: '标题',
+        author: '作者',
+        creationDate: '创建日期',
+        lastModifiedDate: '最后修改日期',
+        documentType: '文档类型',
+        tagsCategory: '标签/类别',
       },
       businessDocument: {
-        title: "标题",
-        author: "作者",
-        creationDate: "创建日期",
-        lastModifiedDate: "最后修改日期",
-        documentType: "文档类型",
-        departmentTeam: "部门/团队",
+        title: '标题',
+        author: '作者',
+        creationDate: '创建日期',
+        lastModifiedDate: '最后修改日期',
+        documentType: '文档类型',
+        departmentTeam: '部门/团队',
       },
       IMChat: {
-        chatPlatform: "聊天平台",
-        chatPartiesGroupName: "聊天参与方/群组名称",
-        participants: "参与者",
-        startDate: "开始日期",
-        endDate: "结束日期",
-        topicsKeywords: "主题/关键词",
-        fileType: "文件类型",
+        chatPlatform: '聊天平台',
+        chatPartiesGroupName: '聊天参与方/群组名称',
+        participants: '参与者',
+        startDate: '开始日期',
+        endDate: '结束日期',
+        topicsKeywords: '主题/关键词',
+        fileType: '文件类型',
       },
       wikipediaEntry: {
-        title: "标题",
-        language: "语言",
-        webpageURL: "网页网址",
-        editorContributor: "编辑/贡献者",
-        lastEditDate: "最后编辑日期",
-        summaryIntroduction: "摘要/介绍",
+        title: '标题',
+        language: '语言',
+        webpageURL: '网页网址',
+        editorContributor: '编辑/贡献者',
+        lastEditDate: '最后编辑日期',
+        summaryIntroduction: '摘要/介绍',
       },
       notion: {
-        title: "标题",
-        language: "语言",
-        author: "作者",
-        createdTime: "创建时间",
-        lastModifiedTime: "最后修改时间",
-        url: "网址",
-        tag: "标签",
-        description: "描述",
+        title: '标题',
+        language: '语言',
+        author: '作者',
+        createdTime: '创建时间',
+        lastModifiedTime: '最后修改时间',
+        url: '网址',
+        tag: '标签',
+        description: '描述',
       },
       github: {
-        repoName: "仓库名",
-        repoDesc: "仓库描述",
-        repoOwner: "仓库所有者",
-        fileName: "文件名",
-        filePath: "文件路径",
-        programmingLang: "编程语言",
-        url: "网址",
-        license: "许可证",
-        lastCommitTime: "最后提交时间",
-        lastCommitAuthor: "最后提交者",
+        repoName: '仓库名',
+        repoDesc: '仓库描述',
+        repoOwner: '仓库所有者',
+        fileName: '文件名',
+        filePath: '文件路径',
+        programmingLang: '编程语言',
+        url: '网址',
+        license: '许可证',
+        lastCommitTime: '最后提交时间',
+        lastCommitAuthor: '最后提交者',
       },
       originInfo: {
-        originalFilename: "原始文件名称",
-        originalFileSize: "原始文件大小",
-        uploadDate: "上传日期",
-        lastUpdateDate: "最后更新日期",
-        source: "来源",
+        originalFilename: '原始文件名称',
+        originalFileSize: '原始文件大小',
+        uploadDate: '上传日期',
+        lastUpdateDate: '最后更新日期',
+        source: '来源',
       },
       technicalParameters: {
         segmentSpecification: '分段规则',
@@ -194,91 +194,91 @@ const translation = {
         hitCount: '命中次数',
         embeddingTime: '嵌入时间',
         embeddedSpend: '嵌入花费',
-      }
+      },
     },
     languageMap: {
-      zh: "中文",
-      en: "英文",
-      es: "西班牙语",
-      fr: "法语",
-      de: "德语",
-      ja: "日语",
-      ko: "韩语",
-      ru: "俄语",
-      ar: "阿拉伯语",
-      pt: "葡萄牙语",
-      it: "意大利语",
-      nl: "荷兰语",
-      pl: "波兰语",
-      sv: "瑞典语",
-      tr: "土耳其语",
-      he: "希伯来语",
-      hi: "印地语",
-      da: "丹麦语",
-      fi: "芬兰语",
-      no: "挪威语",
-      hu: "匈牙利语",
-      el: "希腊语",
-      cs: "捷克语",
-      th: "泰语",
-      id: "印度尼西亚语",
+      zh: '中文',
+      en: '英文',
+      es: '西班牙语',
+      fr: '法语',
+      de: '德语',
+      ja: '日语',
+      ko: '韩语',
+      ru: '俄语',
+      ar: '阿拉伯语',
+      pt: '葡萄牙语',
+      it: '意大利语',
+      nl: '荷兰语',
+      pl: '波兰语',
+      sv: '瑞典语',
+      tr: '土耳其语',
+      he: '希伯来语',
+      hi: '印地语',
+      da: '丹麦语',
+      fi: '芬兰语',
+      no: '挪威语',
+      hu: '匈牙利语',
+      el: '希腊语',
+      cs: '捷克语',
+      th: '泰语',
+      id: '印度尼西亚语',
     },
     categoryMap: {
       book: {
-        fiction: "小说",
-        biography: "传记",
-        history: "历史",
-        science: "科学",
-        technology: "技术",
-        education: "教育",
-        philosophy: "哲学",
-        religion: "宗教",
-        socialSciences: "社会科学",
-        art: "艺术",
-        travel: "旅行",
-        health: "健康",
-        selfHelp: "自助",
-        businessEconomics: "商业/经济",
-        cooking: "烹饪",
-        childrenYoungAdults: "儿童/青少年",
-        comicsGraphicNovels: "漫画/图形小说",
-        poetry: "诗歌",
-        drama: "戏剧",
-        other: "其他",
+        fiction: '小说',
+        biography: '传记',
+        history: '历史',
+        science: '科学',
+        technology: '技术',
+        education: '教育',
+        philosophy: '哲学',
+        religion: '宗教',
+        socialSciences: '社会科学',
+        art: '艺术',
+        travel: '旅行',
+        health: '健康',
+        selfHelp: '自助',
+        businessEconomics: '商业/经济',
+        cooking: '烹饪',
+        childrenYoungAdults: '儿童/青少年',
+        comicsGraphicNovels: '漫画/图形小说',
+        poetry: '诗歌',
+        drama: '戏剧',
+        other: '其他',
       },
       personalDoc: {
-        notes: "笔记",
-        blogDraft: "博客草稿",
-        diary: "日记",
-        researchReport: "研究报告",
-        bookExcerpt: "书籍摘录",
-        schedule: "日程安排",
-        list: "列表",
-        projectOverview: "项目概述",
-        photoCollection: "照片集",
-        creativeWriting: "创意写作",
-        codeSnippet: "代码片段",
-        designDraft: "设计草稿",
-        personalResume: "个人简历",
-        other: "其他",
+        notes: '笔记',
+        blogDraft: '博客草稿',
+        diary: '日记',
+        researchReport: '研究报告',
+        bookExcerpt: '书籍摘录',
+        schedule: '日程安排',
+        list: '列表',
+        projectOverview: '项目概述',
+        photoCollection: '照片集',
+        creativeWriting: '创意写作',
+        codeSnippet: '代码片段',
+        designDraft: '设计草稿',
+        personalResume: '个人简历',
+        other: '其他',
       },
       businessDoc: {
-        meetingMinutes: "会议纪要",
-        researchReport: "研究报告",
-        proposal: "提案",
-        employeeHandbook: "员工手册",
-        trainingMaterials: "培训材料",
-        requirementsDocument: "需求文档",
-        designDocument: "设计文档",
-        productSpecification: "产品规格",
-        financialReport: "财务报告",
-        marketAnalysis: "市场分析",
-        projectPlan: "项目计划",
-        teamStructure: "团队结构",
-        policiesProcedures: "政策和流程",
-        contractsAgreements: "合同和协议",
-        emailCorrespondence: "邮件往来",
-        other: "其他",
+        meetingMinutes: '会议纪要',
+        researchReport: '研究报告',
+        proposal: '提案',
+        employeeHandbook: '员工手册',
+        trainingMaterials: '培训材料',
+        requirementsDocument: '需求文档',
+        designDocument: '设计文档',
+        productSpecification: '产品规格',
+        financialReport: '财务报告',
+        marketAnalysis: '市场分析',
+        projectPlan: '项目计划',
+        teamStructure: '团队结构',
+        policiesProcedures: '政策和流程',
+        contractsAgreements: '合同和协议',
+        emailCorrespondence: '邮件往来',
+        other: '其他',
       },
     },
   },
@@ -299,7 +299,7 @@ const translation = {
     resume: '恢复处理',
     automatic: '自动',
     custom: '自定义',
-    previewTip: '段落预览将在嵌入完成后可用'
+    previewTip: '段落预览将在嵌入完成后可用',
   },
   segment: {
     paragraphs: '段落',
@@ -307,7 +307,7 @@ const translation = {
     characters: '字符',
     hitCount: '命中次数',
     vectorHash: '向量哈希:',
-  }
-};
+  },
+}
 
-export default translation;
+export default translation