+
= ({
{
isHybridSearch && (
<>
-
+
{
rerankingModeOptions.map(option => (
-
handleChangeRerankMode(option.value)}
- icon={}
- title={option.label}
- description={option.tips}
- className='flex-1'
- />
+ className={cn(
+ 'flex items-center justify-center mb-4 w-[calc((100%-8px)/2)] h-8 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg cursor-pointer system-sm-medium text-text-secondary',
+ value.reranking_mode === RerankingModeEnum.WeightedScore && option.value === RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
+ value.reranking_mode !== RerankingModeEnum.WeightedScore && option.value !== RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
+ )}
+ onClick={() => handleChangeRerankMode(option.value)}
+ >
+ {option.label}
+ {option.tips}}
+ triggerClassName='ml-0.5 w-3.5 h-3.5'
+ />
+
))
}
diff --git a/web/app/components/datasets/create/assets/family-mod.svg b/web/app/components/datasets/create/assets/family-mod.svg
deleted file mode 100644
index b1c4e6f566e54f..00000000000000
--- a/web/app/components/datasets/create/assets/family-mod.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/file-list-3-fill.svg b/web/app/components/datasets/create/assets/file-list-3-fill.svg
deleted file mode 100644
index a4e6c4da9783e8..00000000000000
--- a/web/app/components/datasets/create/assets/file-list-3-fill.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/gold.svg b/web/app/components/datasets/create/assets/gold.svg
deleted file mode 100644
index b48ac0eae5de02..00000000000000
--- a/web/app/components/datasets/create/assets/gold.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/note-mod.svg b/web/app/components/datasets/create/assets/note-mod.svg
deleted file mode 100644
index b9e81f6bd533b5..00000000000000
--- a/web/app/components/datasets/create/assets/note-mod.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/option-card-effect-blue.svg b/web/app/components/datasets/create/assets/option-card-effect-blue.svg
deleted file mode 100644
index 00a8afad8b1b23..00000000000000
--- a/web/app/components/datasets/create/assets/option-card-effect-blue.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/option-card-effect-orange.svg b/web/app/components/datasets/create/assets/option-card-effect-orange.svg
deleted file mode 100644
index d833764f0cba63..00000000000000
--- a/web/app/components/datasets/create/assets/option-card-effect-orange.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/option-card-effect-purple.svg b/web/app/components/datasets/create/assets/option-card-effect-purple.svg
deleted file mode 100644
index a7857f8e570f05..00000000000000
--- a/web/app/components/datasets/create/assets/option-card-effect-purple.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/pattern-recognition-mod.svg b/web/app/components/datasets/create/assets/pattern-recognition-mod.svg
deleted file mode 100644
index 1083e888ed6820..00000000000000
--- a/web/app/components/datasets/create/assets/pattern-recognition-mod.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/piggy-bank-mod.svg b/web/app/components/datasets/create/assets/piggy-bank-mod.svg
deleted file mode 100644
index b1120ad9a9c249..00000000000000
--- a/web/app/components/datasets/create/assets/piggy-bank-mod.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/progress-indicator.svg b/web/app/components/datasets/create/assets/progress-indicator.svg
deleted file mode 100644
index 3c997136360595..00000000000000
--- a/web/app/components/datasets/create/assets/progress-indicator.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/rerank.svg b/web/app/components/datasets/create/assets/rerank.svg
deleted file mode 100644
index 409b52e6e23804..00000000000000
--- a/web/app/components/datasets/create/assets/rerank.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/web/app/components/datasets/create/assets/research-mod.svg b/web/app/components/datasets/create/assets/research-mod.svg
deleted file mode 100644
index 1f0bb3423351a1..00000000000000
--- a/web/app/components/datasets/create/assets/research-mod.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/selection-mod.svg b/web/app/components/datasets/create/assets/selection-mod.svg
deleted file mode 100644
index 2d0dd3b5f74a4f..00000000000000
--- a/web/app/components/datasets/create/assets/selection-mod.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/assets/setting-gear-mod.svg b/web/app/components/datasets/create/assets/setting-gear-mod.svg
deleted file mode 100644
index c782caade88e15..00000000000000
--- a/web/app/components/datasets/create/assets/setting-gear-mod.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
\ No newline at end of file
diff --git a/web/app/components/datasets/create/embedding-process/index.module.css b/web/app/components/datasets/create/embedding-process/index.module.css
index f2ab4d85a27210..1ebb006b543ac2 100644
--- a/web/app/components/datasets/create/embedding-process/index.module.css
+++ b/web/app/components/datasets/create/embedding-process/index.module.css
@@ -14,7 +14,24 @@
border-radius: 6px;
overflow: hidden;
}
-
+.sourceItem.error {
+ background: #FEE4E2;
+}
+.sourceItem.success {
+ background: #D1FADF;
+}
+.progressbar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background-color: #B2CCFF;
+}
+.sourceItem .info {
+ display: flex;
+ align-items: center;
+ z-index: 1;
+}
.sourceItem .info .name {
font-weight: 500;
font-size: 12px;
@@ -38,6 +55,13 @@
color: #05603A;
}
+
+.cost {
+ @apply flex justify-between items-center text-xs text-gray-700;
+}
+.embeddingStatus {
+ @apply flex items-center justify-between text-gray-900 font-medium text-sm mr-2;
+}
.commonIcon {
@apply w-3 h-3 mr-1 inline-block align-middle;
}
@@ -57,33 +81,35 @@
@apply text-xs font-medium;
}
-.unknownFileIcon {
+.fileIcon {
+ @apply w-4 h-4 mr-1 bg-center bg-no-repeat;
background-image: url(../assets/unknown.svg);
+ background-size: 16px;
}
-.csv {
+.fileIcon.csv {
background-image: url(../assets/csv.svg);
}
-.docx {
+.fileIcon.docx {
background-image: url(../assets/docx.svg);
}
-.xlsx,
-.xls {
+.fileIcon.xlsx,
+.fileIcon.xls {
background-image: url(../assets/xlsx.svg);
}
-.pdf {
+.fileIcon.pdf {
background-image: url(../assets/pdf.svg);
}
-.html,
-.htm {
+.fileIcon.html,
+.fileIcon.htm {
background-image: url(../assets/html.svg);
}
-.md,
-.markdown {
+.fileIcon.md,
+.fileIcon.markdown {
background-image: url(../assets/md.svg);
}
-.txt {
+.fileIcon.txt {
background-image: url(../assets/txt.svg);
}
-.json {
+.fileIcon.json {
background-image: url(../assets/json.svg);
}
diff --git a/web/app/components/datasets/create/embedding-process/index.tsx b/web/app/components/datasets/create/embedding-process/index.tsx
index 201333ffce4cbe..7786582085c16d 100644
--- a/web/app/components/datasets/create/embedding-process/index.tsx
+++ b/web/app/components/datasets/create/embedding-process/index.tsx
@@ -6,44 +6,32 @@ import { useTranslation } from 'react-i18next'
import { omit } from 'lodash-es'
import { ArrowRightIcon } from '@heroicons/react/24/solid'
import {
- RiCheckboxCircleFill,
RiErrorWarningFill,
- RiLoader2Fill,
- RiTerminalBoxLine,
} from '@remixicon/react'
-import Image from 'next/image'
-import { indexMethodIcon, retrievalIcon } from '../icons'
-import { IndexingType } from '../step-two'
-import DocumentFileIcon from '../../common/document-file-icon'
+import s from './index.module.css'
import cn from '@/utils/classnames'
import { FieldInfo } from '@/app/components/datasets/documents/detail/metadata'
import Button from '@/app/components/base/button'
import type { FullDocumentDetail, IndexingStatusResponse, ProcessRuleResponse } from '@/models/datasets'
import { fetchIndexingStatusBatch as doFetchIndexingStatus, fetchProcessRule } from '@/service/datasets'
-import { DataSourceType, ProcessMode } from '@/models/datasets'
+import { DataSourceType } from '@/models/datasets'
import NotionIcon from '@/app/components/base/notion-icon'
import PriorityLabel from '@/app/components/billing/priority-label'
import { Plan } from '@/app/components/billing/type'
import { ZapFast } from '@/app/components/base/icons/src/vender/solid/general'
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
import { useProviderContext } from '@/context/provider-context'
-import { sleep } from '@/utils'
-import { RETRIEVE_METHOD } from '@/types/app'
import Tooltip from '@/app/components/base/tooltip'
+import { sleep } from '@/utils'
type Props = {
datasetId: string
batchId: string
documents?: FullDocumentDetail[]
indexingType?: string
- retrievalMethod?: string
}
-const RuleDetail: FC<{
- sourceData?: ProcessRuleResponse
- indexingType?: string
- retrievalMethod?: string
-}> = ({ sourceData, indexingType, retrievalMethod }) => {
+const RuleDetail: FC<{ sourceData?: ProcessRuleResponse }> = ({ sourceData }) => {
const { t } = useTranslation()
const segmentationRuleMap = {
@@ -63,47 +51,29 @@ const RuleDetail: FC<{
return t('datasetCreation.stepTwo.removeStopwords')
}
- const isNumber = (value: unknown) => {
- return typeof value === 'number'
- }
-
const getValue = useCallback((field: string) => {
let value: string | number | undefined = '-'
- const maxTokens = isNumber(sourceData?.rules?.segmentation?.max_tokens)
- ? sourceData.rules.segmentation.max_tokens
- : value
- const childMaxTokens = isNumber(sourceData?.rules?.subchunk_segmentation?.max_tokens)
- ? sourceData.rules.subchunk_segmentation.max_tokens
- : value
switch (field) {
case 'mode':
- value = !sourceData?.mode
- ? value
- : sourceData.mode === ProcessMode.general
- ? (t('datasetDocuments.embedding.custom') as string)
- : `${t('datasetDocuments.embedding.hierarchical')} · ${sourceData?.rules?.parent_mode === 'paragraph'
- ? t('dataset.parentMode.paragraph')
- : t('dataset.parentMode.fullDoc')}`
+ value = sourceData?.mode === 'automatic' ? (t('datasetDocuments.embedding.automatic') as string) : (t('datasetDocuments.embedding.custom') as string)
break
case 'segmentLength':
- value = !sourceData?.mode
- ? value
- : sourceData.mode === ProcessMode.general
- ? maxTokens
- : `${t('datasetDocuments.embedding.parentMaxTokens')} ${maxTokens}; ${t('datasetDocuments.embedding.childMaxTokens')} ${childMaxTokens}`
+ value = sourceData?.rules?.segmentation?.max_tokens
break
default:
- value = !sourceData?.mode
- ? value
- : sourceData?.rules?.pre_processing_rules?.filter(rule =>
- rule.enabled).map(rule => getRuleName(rule.id)).join(',')
+ value = sourceData?.mode === 'automatic'
+ ? (t('datasetDocuments.embedding.automatic') as string)
+ // eslint-disable-next-line array-callback-return
+ : sourceData?.rules?.pre_processing_rules?.map((rule) => {
+ if (rule.enabled)
+ return getRuleName(rule.id)
+ }).filter(Boolean).join(';')
break
}
return value
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [sourceData])
- return
+ return
{Object.keys(segmentationRuleMap).map((field) => {
return
})}
-
- }
- />
-
- }
- />
}
-const EmbeddingProcess: FC
= ({ datasetId, batchId, documents = [], indexingType, retrievalMethod }) => {
+const EmbeddingProcess: FC = ({ datasetId, batchId, documents = [], indexingType }) => {
const { t } = useTranslation()
const { enableBilling, plan } = useProviderContext()
@@ -190,7 +127,6 @@ const EmbeddingProcess: FC = ({ datasetId, batchId, documents = [], index
}
useEffect(() => {
- setIsStopQuery(false)
startQueryStatus()
return () => {
stopQueryStatus()
@@ -210,9 +146,6 @@ const EmbeddingProcess: FC = ({ datasetId, batchId, documents = [], index
const navToDocumentList = () => {
router.push(`/datasets/${datasetId}/documents`)
}
- const navToApiDocs = () => {
- router.push('/datasets?category=api')
- }
const isEmbedding = useMemo(() => {
return indexingStatusBatchDetail.some(indexingStatusDetail => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || ''))
@@ -244,17 +177,13 @@ const EmbeddingProcess: FC = ({ datasetId, batchId, documents = [], index
return doc?.data_source_info.notion_page_icon
}
- const isSourceEmbedding = (detail: IndexingStatusResponse) =>
- ['indexing', 'splitting', 'parsing', 'cleaning', 'waiting'].includes(detail.indexing_status || '')
+ const isSourceEmbedding = (detail: IndexingStatusResponse) => ['indexing', 'splitting', 'parsing', 'cleaning', 'waiting'].includes(detail.indexing_status || '')
return (
<>
-
-
- {isEmbedding &&
-
- {t('datasetDocuments.embedding.processing')}
-
}
+
+
+ {isEmbedding && t('datasetDocuments.embedding.processing')}
{isEmbeddingCompleted && t('datasetDocuments.embedding.completed')}
@@ -271,80 +200,69 @@ const EmbeddingProcess: FC
= ({ datasetId, batchId, documents = [], index
)
}
-
+
{indexingStatusBatchDetail.map(indexingStatusDetail => (
{isSourceEmbedding(indexingStatusDetail) && (
-
+
)}
-
+
{getSourceType(indexingStatusDetail.id) === DataSourceType.FILE && (
- //
-
+
)}
{getSourceType(indexingStatusDetail.id) === DataSourceType.NOTION && (
)}
-
-
- {getSourceName(indexingStatusDetail.id)}
-
- {
- enableBilling && (
-
- )
- }
-
+
{getSourceName(indexingStatusDetail.id)}
+ {
+ enableBilling && (
+
+ )
+ }
+
+
{isSourceEmbedding(indexingStatusDetail) && (
-
{`${getSourcePercent(indexingStatusDetail)}%`}
+
{`${getSourcePercent(indexingStatusDetail)}%`}
)}
- {indexingStatusDetail.indexing_status === 'error' && (
+ {indexingStatusDetail.indexing_status === 'error' && indexingStatusDetail.error && (
+ {indexingStatusDetail.error}
+
+ )}
>
-
-
-
+
+ Error
+
+
)}
+ {indexingStatusDetail.indexing_status === 'error' && !indexingStatusDetail.error && (
+
+ Error
+
+ )}
{indexingStatusDetail.indexing_status === 'completed' && (
-
+
100%
)}
))}
-
-
-
-
+
+
>
diff --git a/web/app/components/datasets/create/file-preview/index.module.css b/web/app/components/datasets/create/file-preview/index.module.css
index 929002e1e2985c..d87522e6d0bd4c 100644
--- a/web/app/components/datasets/create/file-preview/index.module.css
+++ b/web/app/components/datasets/create/file-preview/index.module.css
@@ -1,6 +1,6 @@
.filePreview {
@apply flex flex-col border-l border-gray-200 shrink-0;
- width: 100%;
+ width: 528px;
background-color: #fcfcfd;
}
@@ -48,6 +48,5 @@
}
.fileContent {
white-space: pre-line;
- word-break: break-all;
}
\ No newline at end of file
diff --git a/web/app/components/datasets/create/file-preview/index.tsx b/web/app/components/datasets/create/file-preview/index.tsx
index cb1f1d6908c4ef..e20af64386c509 100644
--- a/web/app/components/datasets/create/file-preview/index.tsx
+++ b/web/app/components/datasets/create/file-preview/index.tsx
@@ -44,7 +44,7 @@ const FilePreview = ({
}, [file])
return (
-
+
{t('datasetCreation.stepOne.filePreview')}
@@ -59,7 +59,7 @@ const FilePreview = ({
{loading &&
}
{!loading && (
-
{previewContent}
+
{previewContent}
)}
diff --git a/web/app/components/datasets/create/file-uploader/index.module.css b/web/app/components/datasets/create/file-uploader/index.module.css
index 7d29f2ef9c2b51..bf5b7dcaf5b9b7 100644
--- a/web/app/components/datasets/create/file-uploader/index.module.css
+++ b/web/app/components/datasets/create/file-uploader/index.module.css
@@ -1,3 +1,68 @@
+.fileUploader {
+ @apply mb-6;
+}
+
+.fileUploader .title {
+ @apply mb-2;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #344054;
+}
+
+.fileUploader .tip {
+ font-weight: 400;
+ font-size: 12px;
+ line-height: 18px;
+ color: #667085;
+}
+
+.uploader {
+ @apply relative box-border flex justify-center items-center mb-2 p-3;
+ flex-direction: column;
+ max-width: 640px;
+ min-height: 80px;
+ background: #F9FAFB;
+ border: 1px dashed #EAECF0;
+ border-radius: 12px;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #667085;
+}
+
+.uploader.dragging {
+ background: #F5F8FF;
+ border: 1px dashed #B2CCFF;
+}
+
+.uploader .draggingCover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.uploader .uploadIcon {
+ content: '';
+ display: block;
+ margin-right: 8px;
+ width: 24px;
+ height: 24px;
+ background: center no-repeat url(../assets/upload-cloud-01.svg);
+ background-size: contain;
+}
+
+.uploader .browse {
+ @apply pl-1 cursor-pointer;
+ color: #155eef;
+}
+
+.fileList {
+ @apply space-y-2;
+}
+
.file {
@apply box-border relative flex items-center justify-between;
padding: 8px 12px 8px 8px;
@@ -128,4 +193,4 @@
.file:hover .actionWrapper .remove {
display: block;
-}
+}
\ No newline at end of file
diff --git a/web/app/components/datasets/create/file-uploader/index.tsx b/web/app/components/datasets/create/file-uploader/index.tsx
index e42a24cfef52d3..adb4bed0d167ed 100644
--- a/web/app/components/datasets/create/file-uploader/index.tsx
+++ b/web/app/components/datasets/create/file-uploader/index.tsx
@@ -3,12 +3,10 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import useSWR from 'swr'
-import { RiDeleteBinLine, RiUploadCloud2Line } from '@remixicon/react'
-import DocumentFileIcon from '../../common/document-file-icon'
+import s from './index.module.css'
import cn from '@/utils/classnames'
import type { CustomFile as File, FileItem } from '@/models/datasets'
import { ToastContext } from '@/app/components/base/toast'
-import SimplePieChart from '@/app/components/base/simple-pie-chart'
import { upload } from '@/service/base'
import { fetchFileUploadConfig } from '@/service/common'
@@ -16,8 +14,6 @@ import { fetchSupportFileTypes } from '@/service/datasets'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { IS_CE_EDITION } from '@/config'
-import { useAppContext } from '@/context/app-context'
-import { Theme } from '@/types/app'
const FILES_NUMBER_LIMIT = 20
@@ -226,9 +222,6 @@ const FileUploader = ({
initialUpload(files.filter(isValid))
}, [isValid, initialUpload])
- const { theme } = useAppContext()
- const chartColor = useMemo(() => theme === Theme.dark ? '#5289ff' : '#296dff', [theme])
-
useEffect(() => {
dropRef.current?.addEventListener('dragenter', handleDragEnter)
dropRef.current?.addEventListener('dragover', handleDragOver)
@@ -243,12 +236,12 @@ const FileUploader = ({
}, [handleDrop])
return (
-
+
{!hideUpload && (
)}
-
{t('datasetCreation.stepOne.uploader.title')}
-
+
{t('datasetCreation.stepOne.uploader.title')}
{!hideUpload && (
-
-
-
+
+
+
{t('datasetCreation.stepOne.uploader.button')}
- {supportTypes.length > 0 && (
-
- )}
+
-
{t('datasetCreation.stepOne.uploader.tip', {
+
{t('datasetCreation.stepOne.uploader.tip', {
size: fileUploadConfig.file_size_limit,
supportTypes: supportTypesShowNames,
})}
- {dragging &&
}
+ {dragging &&
}
)}
-
-
+
{fileList.map((fileItem, index) => (
fileItem.file?.id && onPreview(fileItem.file)}
className={cn(
- 'flex items-center h-12 max-w-[640px] bg-components-panel-on-panel-item-bg text-xs leading-3 text-text-tertiary border border-components-panel-border rounded-lg shadow-xs',
- // 'border-state-destructive-border bg-state-destructive-hover',
+ s.file,
+ fileItem.progress < 100 && s.uploading,
)}
>
-
-
-
-
-
-
- {getFileType(fileItem.file)}
- ·
- {getFileSize(fileItem.file.size)}
- {/* ·
- 10k characters */}
-
+ {fileItem.progress < 100 && (
+
+ )}
+
+
+
{fileItem.file.name}
+
{getFileSize(fileItem.file.size)}
-
- {/*
-
- */}
+
{(fileItem.progress < 100 && fileItem.progress >= 0) && (
- //
{`${fileItem.progress}%`}
-
+
{`${fileItem.progress}%`}
+ )}
+ {fileItem.progress === 100 && (
+
{
+ e.stopPropagation()
+ removeFile(fileItem.fileID)
+ }} />
)}
- {
- e.stopPropagation()
- removeFile(fileItem.fileID)
- }}>
-
-
))}
diff --git a/web/app/components/datasets/create/icons.ts b/web/app/components/datasets/create/icons.ts
deleted file mode 100644
index 80c4b6c944778b..00000000000000
--- a/web/app/components/datasets/create/icons.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import GoldIcon from './assets/gold.svg'
-import Piggybank from './assets/piggy-bank-mod.svg'
-import Selection from './assets/selection-mod.svg'
-import Research from './assets/research-mod.svg'
-import PatternRecognition from './assets/pattern-recognition-mod.svg'
-
-export const indexMethodIcon = {
- high_quality: GoldIcon,
- economical: Piggybank,
-}
-
-export const retrievalIcon = {
- vector: Selection,
- fullText: Research,
- hybrid: PatternRecognition,
-}
diff --git a/web/app/components/datasets/create/index.tsx b/web/app/components/datasets/create/index.tsx
index 9556b9fad5780e..98098445c7695c 100644
--- a/web/app/components/datasets/create/index.tsx
+++ b/web/app/components/datasets/create/index.tsx
@@ -3,10 +3,10 @@ import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppUnavailable from '../../base/app-unavailable'
import { ModelTypeEnum } from '../../header/account-setting/model-provider-page/declarations'
+import StepsNavBar from './steps-nav-bar'
import StepOne from './step-one'
import StepTwo from './step-two'
import StepThree from './step-three'
-import { Topbar } from './top-bar'
import { DataSourceType } from '@/models/datasets'
import type { CrawlOptions, CrawlResultItem, DataSet, FileItem, createDocumentResponse } from '@/models/datasets'
import { fetchDataSource } from '@/service/common'
@@ -36,7 +36,6 @@ const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
const [dataSourceType, setDataSourceType] = useState
(DataSourceType.FILE)
const [step, setStep] = useState(1)
const [indexingTypeCache, setIndexTypeCache] = useState('')
- const [retrievalMethodCache, setRetrievalMethodCache] = useState('')
const [fileList, setFiles] = useState([])
const [result, setResult] = useState()
const [hasError, setHasError] = useState(false)
@@ -81,9 +80,6 @@ const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
const updateResultCache = (res?: createDocumentResponse) => {
setResult(res)
}
- const updateRetrievalMethodCache = (method: string) => {
- setRetrievalMethodCache(method)
- }
const nextStep = useCallback(() => {
setStep(step + 1)
@@ -122,29 +118,33 @@ const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
return
return (
-
-
-
- {step === 1 &&
setShowAccountSettingModal({ payload: 'data-source' })}
- datasetId={datasetId}
- dataSourceType={dataSourceType}
- dataSourceTypeDisable={!!detail?.data_source_type}
- changeType={setDataSourceType}
- files={fileList}
- updateFile={updateFile}
- updateFileList={updateFileList}
- notionPages={notionPages}
- updateNotionPages={updateNotionPages}
- onStepChange={nextStep}
- websitePages={websitePages}
- updateWebsitePages={setWebsitePages}
- onWebsiteCrawlProviderChange={setWebsiteCrawlProvider}
- onWebsiteCrawlJobIdChange={setWebsiteCrawlJobId}
- crawlOptions={crawlOptions}
- onCrawlOptionsChange={setCrawlOptions}
- />}
+
+
+
+
+
+
+ setShowAccountSettingModal({ payload: 'data-source' })}
+ datasetId={datasetId}
+ dataSourceType={dataSourceType}
+ dataSourceTypeDisable={!!detail?.data_source_type}
+ changeType={setDataSourceType}
+ files={fileList}
+ updateFile={updateFile}
+ updateFileList={updateFileList}
+ notionPages={notionPages}
+ updateNotionPages={updateNotionPages}
+ onStepChange={nextStep}
+ websitePages={websitePages}
+ updateWebsitePages={setWebsitePages}
+ onWebsiteCrawlProviderChange={setWebsiteCrawlProvider}
+ onWebsiteCrawlJobIdChange={setWebsiteCrawlJobId}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={setCrawlOptions}
+ />
+
{(step === 2 && (!datasetId || (datasetId && !!detail))) &&
setShowAccountSettingModal({ payload: 'provider' })}
@@ -158,7 +158,6 @@ const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
websiteCrawlJobId={websiteCrawlJobId}
onStepChange={changeStep}
updateIndexingTypeCache={updateIndexingTypeCache}
- updateRetrievalMethodCache={updateRetrievalMethodCache}
updateResultCache={updateResultCache}
crawlOptions={crawlOptions}
/>}
@@ -166,7 +165,6 @@ const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
datasetId={datasetId}
datasetName={detail?.name}
indexingType={detail?.indexing_technique || indexingTypeCache}
- retrievalMethod={detail?.retrieval_model_dict?.search_method || retrievalMethodCache}
creationCache={result}
/>}
diff --git a/web/app/components/datasets/create/notion-page-preview/index.tsx b/web/app/components/datasets/create/notion-page-preview/index.tsx
index f658f213e85f17..8225e56f0400e4 100644
--- a/web/app/components/datasets/create/notion-page-preview/index.tsx
+++ b/web/app/components/datasets/create/notion-page-preview/index.tsx
@@ -44,7 +44,7 @@ const NotionPagePreview = ({
}, [currentPage])
return (
-
+
{t('datasetCreation.stepOne.pagePreview')}
@@ -64,7 +64,7 @@ const NotionPagePreview = ({
{loading &&
}
{!loading && (
-
{previewContent}
+
{previewContent}
)}
diff --git a/web/app/components/datasets/create/step-one/index.module.css b/web/app/components/datasets/create/step-one/index.module.css
index bb8dd9b895c9b5..4e3cf67cd6c65b 100644
--- a/web/app/components/datasets/create/step-one/index.module.css
+++ b/web/app/components/datasets/create/step-one/index.module.css
@@ -2,19 +2,21 @@
position: sticky;
top: 0;
left: 0;
- padding: 42px 64px 12px 0;
+ padding: 42px 64px 12px;
font-weight: 600;
font-size: 18px;
line-height: 28px;
+ color: #101828;
}
.form {
position: relative;
padding: 12px 64px;
+ background-color: #fff;
}
.dataSourceItem {
- @apply box-border relative grow shrink-0 flex items-center p-3 h-14 bg-white rounded-xl cursor-pointer;
+ @apply box-border relative shrink-0 flex items-center mr-3 p-3 h-14 bg-white rounded-xl cursor-pointer;
border: 0.5px solid #EAECF0;
box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
font-weight: 500;
@@ -22,32 +24,27 @@
line-height: 20px;
color: #101828;
}
-
.dataSourceItem:hover {
background-color: #f5f8ff;
border: 0.5px solid #B2CCFF;
box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
}
-
.dataSourceItem.active {
background-color: #f5f8ff;
border: 1.5px solid #528BFF;
box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06);
}
-
.dataSourceItem.disabled {
background-color: #f9fafb;
border: 0.5px solid #EAECF0;
box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
cursor: default;
}
-
.dataSourceItem.disabled:hover {
background-color: #f9fafb;
border: 0.5px solid #EAECF0;
box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
}
-
.comingTag {
@apply flex justify-center items-center bg-white;
position: absolute;
@@ -62,7 +59,6 @@
line-height: 18px;
color: #444CE7;
}
-
.datasetIcon {
@apply flex mr-2 w-8 h-8 rounded-lg bg-center bg-no-repeat;
background-color: #F5FAFF;
@@ -70,18 +66,15 @@
background-size: 16px;
border: 0.5px solid #D1E9FF;
}
-
.dataSourceItem:active .datasetIcon,
.dataSourceItem:hover .datasetIcon {
background-color: #F5F8FF;
border: 0.5px solid #E0EAFF;
}
-
.datasetIcon.notion {
background-image: url(../assets/notion.svg);
background-size: 20px;
}
-
.datasetIcon.web {
background-image: url(../assets/web.svg);
}
@@ -97,12 +90,29 @@
background-color: #eaecf0;
}
+.OtherCreationOption {
+ @apply flex items-center cursor-pointer;
+ font-weight: 500;
+ font-size: 13px;
+ line-height: 18px;
+ color: #155EEF;
+}
+.OtherCreationOption::before {
+ content: '';
+ display: block;
+ margin-right: 4px;
+ width: 16px;
+ height: 16px;
+ background: center no-repeat url(../assets/folder-plus.svg);
+ background-size: contain;
+}
+
.notionConnectionTip {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 24px;
- width: 640px;
+ max-width: 640px;
background: #F9FAFB;
border-radius: 16px;
}
@@ -128,7 +138,6 @@
line-height: 24px;
color: #374151;
}
-
.notionConnectionTip .title::after {
content: '';
position: absolute;
@@ -139,7 +148,6 @@
background: center no-repeat url(../assets/Icon-3-dots.svg);
background-size: contain;
}
-
.notionConnectionTip .tip {
margin-bottom: 20px;
font-style: normal;
@@ -147,4 +155,4 @@
font-size: 13px;
line-height: 18px;
color: #6B7280;
-}
\ No newline at end of file
+}
diff --git a/web/app/components/datasets/create/step-one/index.tsx b/web/app/components/datasets/create/step-one/index.tsx
index 2cca003b397207..643932e9ae21d5 100644
--- a/web/app/components/datasets/create/step-one/index.tsx
+++ b/web/app/components/datasets/create/step-one/index.tsx
@@ -1,7 +1,6 @@
'use client'
import React, { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { RiArrowRightLine, RiFolder6Line } from '@remixicon/react'
import FilePreview from '../file-preview'
import FileUploader from '../file-uploader'
import NotionPagePreview from '../notion-page-preview'
@@ -18,7 +17,6 @@ import { NotionPageSelector } from '@/app/components/base/notion-page-selector'
import { useDatasetDetailContext } from '@/context/dataset-detail'
import { useProviderContext } from '@/context/provider-context'
import VectorSpaceFull from '@/app/components/billing/vector-space-full'
-import classNames from '@/utils/classnames'
type IStepOneProps = {
datasetId?: string
@@ -122,174 +120,143 @@ const StepOne = ({
return true
if (isShowVectorSpaceFull)
return true
- return false
- }, [files, isShowVectorSpaceFull])
+ return false
+ }, [files])
return (
-
-
-
- {
- shouldShowDataSourceTypeList && (
-
{t('datasetCreation.steps.one')}
- )
- }
- {
- shouldShowDataSourceTypeList && (
-
-
{
- if (dataSourceTypeDisable)
- return
- changeType(DataSourceType.FILE)
- hideFilePreview()
- hideNotionPagePreview()
- }}
- >
-
- {t('datasetCreation.stepOne.dataSourceType.file')}
-
-
{
- if (dataSourceTypeDisable)
- return
- changeType(DataSourceType.NOTION)
- hideFilePreview()
- hideNotionPagePreview()
- }}
- >
-
- {t('datasetCreation.stepOne.dataSourceType.notion')}
-
-
changeType(DataSourceType.WEB)}
- >
-
- {t('datasetCreation.stepOne.dataSourceType.web')}
-
+
+ {
+ shouldShowDataSourceTypeList && (
+
{t('datasetCreation.steps.one')}
+ )
+ }
+
+ {
+ shouldShowDataSourceTypeList && (
+
+
{
+ if (dataSourceTypeDisable)
+ return
+ changeType(DataSourceType.FILE)
+ hideFilePreview()
+ hideNotionPagePreview()
+ }}
+ >
+
+ {t('datasetCreation.stepOne.dataSourceType.file')}
- )
- }
- {dataSourceType === DataSourceType.FILE && (
- <>
-
- {isShowVectorSpaceFull && (
-
-
-
- )}
-
- {/*
*/}
-
+
{
+ if (dataSourceTypeDisable)
+ return
+ changeType(DataSourceType.NOTION)
+ hideFilePreview()
+ hideNotionPagePreview()
+ }}
+ >
+
+ {t('datasetCreation.stepOne.dataSourceType.notion')}
- >
- )}
- {dataSourceType === DataSourceType.NOTION && (
- <>
- {!hasConnection &&
}
- {hasConnection && (
- <>
-
- page.page_id)}
- onSelect={updateNotionPages}
- onPreview={updateCurrentPage}
- />
-
- {isShowVectorSpaceFull && (
-
-
-
- )}
-
- {/* */}
-
-
- >
- )}
- >
- )}
- {dataSourceType === DataSourceType.WEB && (
- <>
-
-
+
changeType(DataSourceType.WEB)}
+ >
+
+ {t('datasetCreation.stepOne.dataSourceType.web')}
+
+
+ )
+ }
+ {dataSourceType === DataSourceType.FILE && (
+ <>
+
+ {isShowVectorSpaceFull && (
+
+
- {isShowVectorSpaceFull && (
-
-
+ )}
+
+ >
+ )}
+ {dataSourceType === DataSourceType.NOTION && (
+ <>
+ {!hasConnection &&
}
+ {hasConnection && (
+ <>
+
+ page.page_id)}
+ onSelect={updateNotionPages}
+ onPreview={updateCurrentPage}
+ />
- )}
-
- {/*
*/}
-
+ {isShowVectorSpaceFull && (
+
+
+
+ )}
+
+ >
+ )}
+ >
+ )}
+ {dataSourceType === DataSourceType.WEB && (
+ <>
+
+
+
+ {isShowVectorSpaceFull && (
+
+
- >
- )}
- {!datasetId && (
- <>
-
-
-
- {t('datasetCreation.stepOne.emptyDatasetCreation')}
-
- >
- )}
-
-
+ )}
+
+ >
+ )}
+ {!datasetId && (
+ <>
+
+
{t('datasetCreation.stepOne.emptyDatasetCreation')}
+ >
+ )}
+
-
- {currentFile && }
- {currentNotionPage && }
- {currentWebsite && }
-
+ {currentFile &&
}
+ {currentNotionPage &&
}
+ {currentWebsite &&
}
)
}
diff --git a/web/app/components/datasets/create/step-three/index.tsx b/web/app/components/datasets/create/step-three/index.tsx
index 8d979616d13b21..804a196ed5ac44 100644
--- a/web/app/components/datasets/create/step-three/index.tsx
+++ b/web/app/components/datasets/create/step-three/index.tsx
@@ -1,51 +1,45 @@
'use client'
import React from 'react'
import { useTranslation } from 'react-i18next'
-import { RiBookOpenLine } from '@remixicon/react'
import EmbeddingProcess from '../embedding-process'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import type { FullDocumentDetail, createDocumentResponse } from '@/models/datasets'
-import AppIcon from '@/app/components/base/app-icon'
type StepThreeProps = {
datasetId?: string
datasetName?: string
indexingType?: string
- retrievalMethod?: string
creationCache?: createDocumentResponse
}
-const StepThree = ({ datasetId, datasetName, indexingType, creationCache, retrievalMethod }: StepThreeProps) => {
+const StepThree = ({ datasetId, datasetName, indexingType, creationCache }: StepThreeProps) => {
const { t } = useTranslation()
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
return (
-
-
-
+
+
+
{!datasetId && (
<>
-
-
{t('datasetCreation.stepThree.creationTitle')}
-
{t('datasetCreation.stepThree.creationContent')}
-
-
-
-
{t('datasetCreation.stepThree.label')}
-
{datasetName || creationCache?.dataset?.name}
-
-
+
+
{t('datasetCreation.stepThree.creationTitle')}
+
{t('datasetCreation.stepThree.creationContent')}
+
{t('datasetCreation.stepThree.label')}
+
{datasetName || creationCache?.dataset?.name}
-
+
>
)}
{datasetId && (
-
-
{t('datasetCreation.stepThree.additionTitle')}
-
{`${t('datasetCreation.stepThree.additionP1')} ${datasetName || creationCache?.dataset?.name} ${t('datasetCreation.stepThree.additionP2')}`}
+
+
{t('datasetCreation.stepThree.additionTitle')}
+
{`${t('datasetCreation.stepThree.additionP1')} ${datasetName || creationCache?.dataset?.name} ${t('datasetCreation.stepThree.additionP2')}`}
)}
- {!isMobile && (
-
-
-
-
-
-
{t('datasetCreation.stepThree.sideTipTitle')}
-
{t('datasetCreation.stepThree.sideTipContent')}
-
+ {!isMobile &&
+
+
+
{t('datasetCreation.stepThree.sideTipTitle')}
+
{t('datasetCreation.stepThree.sideTipContent')}
- )}
+
}
)
}
diff --git a/web/app/components/datasets/create/step-two/index.module.css b/web/app/components/datasets/create/step-two/index.module.css
index 178cbeba857dad..f89d6d67ea7088 100644
--- a/web/app/components/datasets/create/step-two/index.module.css
+++ b/web/app/components/datasets/create/step-two/index.module.css
@@ -13,6 +13,18 @@
z-index: 10;
}
+.form {
+ @apply px-16 pb-8;
+}
+
+.form .label {
+ @apply pt-6 pb-2 flex items-center;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #344054;
+}
+
.segmentationItem {
min-height: 68px;
}
@@ -63,10 +75,6 @@
cursor: pointer;
}
-.disabled {
- cursor: not-allowed !important;
-}
-
.indexItem.disabled:hover {
background-color: #fcfcfd;
border-color: #f2f4f7;
@@ -79,7 +87,8 @@
}
.radioItem {
- @apply relative mb-2 rounded-xl border border-components-option-card-option-border cursor-pointer bg-components-option-card-option-bg;
+ @apply relative mb-2 rounded-xl border border-gray-100 cursor-pointer;
+ background-color: #fcfcfd;
}
.radioItem.segmentationItem.custom {
@@ -137,7 +146,7 @@
}
.typeIcon.economical {
- background-image: url(../assets/piggy-bank-mod.svg);
+ background-image: url(../assets/piggy-bank-01.svg);
}
.radioItem .radio {
@@ -238,7 +247,7 @@
}
.ruleItem {
- @apply flex items-center py-1.5;
+ @apply flex items-center;
}
.formFooter {
@@ -385,6 +394,19 @@
max-width: 524px;
}
+.previewHeader {
+ position: sticky;
+ top: 0;
+ left: 0;
+ padding-top: 42px;
+ background-color: #fff;
+ font-weight: 600;
+ font-size: 18px;
+ line-height: 28px;
+ color: #101828;
+ z-index: 10;
+}
+
/*
* `fixed` must under `previewHeader` because of style override would not work
*/
@@ -410,4 +432,4 @@
font-size: 12px;
line-height: 18px;
}
-}
+}
\ No newline at end of file
diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx
index 0d7202967a5e9f..f915c68fef0345 100644
--- a/web/app/components/datasets/create/step-two/index.tsx
+++ b/web/app/components/datasets/create/step-two/index.tsx
@@ -1,80 +1,65 @@
'use client'
-import type { FC, PropsWithChildren } from 'react'
-import React, { useCallback, useEffect, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
+import { useBoolean } from 'ahooks'
+import { XMarkIcon } from '@heroicons/react/20/solid'
+import { RocketLaunchIcon } from '@heroicons/react/24/outline'
import {
- RiAlertFill,
- RiArrowLeftLine,
- RiSearchEyeLine,
+ RiCloseLine,
} from '@remixicon/react'
import Link from 'next/link'
-import Image from 'next/image'
-import { useHover } from 'ahooks'
-import SettingCog from '../assets/setting-gear-mod.svg'
-import OrangeEffect from '../assets/option-card-effect-orange.svg'
-import FamilyMod from '../assets/family-mod.svg'
-import Note from '../assets/note-mod.svg'
-import FileList from '../assets/file-list-3-fill.svg'
-import { indexMethodIcon } from '../icons'
-import { PreviewContainer } from '../../preview/container'
-import { ChunkContainer, QAPreview } from '../../chunk'
-import { PreviewHeader } from '../../preview/header'
-import { FormattedText } from '../../formatted-text/formatted'
-import { PreviewSlice } from '../../formatted-text/flavours/preview-slice'
-import PreviewDocumentPicker from '../../common/document-picker/preview-document-picker'
+import { groupBy } from 'lodash-es'
+import PreviewItem, { PreviewType } from './preview-item'
+import LanguageSelect from './language-select'
import s from './index.module.css'
import unescape from './unescape'
import escape from './escape'
-import { OptionCard } from './option-card'
-import LanguageSelect from './language-select'
-import { DelimiterInput, MaxLengthInput, OverlapInput } from './inputs'
import cn from '@/utils/classnames'
-import type { CrawlOptions, CrawlResultItem, CreateDocumentReq, CustomFile, DocumentItem, FullDocumentDetail, ParentMode, PreProcessingRule, ProcessRule, Rules, createDocumentResponse } from '@/models/datasets'
-
+import type { CrawlOptions, CrawlResultItem, CreateDocumentReq, CustomFile, FileIndexingEstimateResponse, FullDocumentDetail, IndexingEstimateParams, NotionInfo, PreProcessingRule, ProcessRule, Rules, createDocumentResponse } from '@/models/datasets'
+import {
+ createDocument,
+ createFirstDocument,
+ fetchFileIndexingEstimate as didFetchFileIndexingEstimate,
+ fetchDefaultProcessRule,
+} from '@/service/datasets'
import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Loading from '@/app/components/base/loading'
import FloatRightContainer from '@/app/components/base/float-right-container'
import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
import { type RetrievalConfig } from '@/types/app'
import { ensureRerankModelSelected, isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
import Toast from '@/app/components/base/toast'
+import { formatNumber } from '@/utils/format'
import type { NotionPage } from '@/models/common'
import { DataSourceProvider } from '@/models/common'
-import { ChunkingMode, DataSourceType, RerankingModeEnum } from '@/models/datasets'
+import { DataSourceType, DocForm } from '@/models/datasets'
+import NotionIcon from '@/app/components/base/notion-icon'
+import Switch from '@/app/components/base/switch'
+import { MessageChatSquare } from '@/app/components/base/icons/src/public/common'
import { useDatasetDetailContext } from '@/context/dataset-detail'
import I18n from '@/context/i18n'
+import { IS_CE_EDITION } from '@/config'
import { RETRIEVE_METHOD } from '@/types/app'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Tooltip from '@/app/components/base/tooltip'
import { useDefaultModel, useModelList, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { LanguagesSupported } from '@/i18n/language'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
-import Checkbox from '@/app/components/base/checkbox'
-import RadioCard from '@/app/components/base/radio-card'
-import { IS_CE_EDITION } from '@/config'
-import Divider from '@/app/components/base/divider'
-import { getNotionInfo, getWebsiteInfo, useCreateDocument, useCreateFirstDocument, useFetchDefaultProcessRule, useFetchFileIndexingEstimateForFile, useFetchFileIndexingEstimateForNotion, useFetchFileIndexingEstimateForWeb } from '@/service/knowledge/use-create-dataset'
-import Badge from '@/app/components/base/badge'
-import { SkeletonContainer, SkeletonPoint, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton'
-import Tooltip from '@/app/components/base/tooltip'
-import CustomDialog from '@/app/components/base/dialog'
-import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
-import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
-
-const TextLabel: FC
= (props) => {
- return
-}
+import { Globe01 } from '@/app/components/base/icons/src/vender/line/mapsAndTravel'
+type ValueOf = T[keyof T]
type StepTwoProps = {
isSetting?: boolean
documentDetail?: FullDocumentDetail
isAPIKeySet: boolean
onSetting: () => void
datasetId?: string
- indexingType?: IndexingType
- retrievalMethod?: string
+ indexingType?: ValueOf
dataSourceType: DataSourceType
files: CustomFile[]
notionPages?: NotionPage[]
@@ -84,48 +69,21 @@ type StepTwoProps = {
websiteCrawlJobId?: string
onStepChange?: (delta: number) => void
updateIndexingTypeCache?: (type: string) => void
- updateRetrievalMethodCache?: (method: string) => void
updateResultCache?: (res: createDocumentResponse) => void
onSave?: () => void
onCancel?: () => void
}
-export enum SegmentType {
+enum SegmentType {
AUTO = 'automatic',
CUSTOM = 'custom',
}
-export enum IndexingType {
+enum IndexingType {
QUALIFIED = 'high_quality',
ECONOMICAL = 'economy',
}
const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n'
-const DEFAULT_MAXMIMUM_CHUNK_LENGTH = 500
-const DEFAULT_OVERLAP = 50
-
-type ParentChildConfig = {
- chunkForContext: ParentMode
- parent: {
- delimiter: string
- maxLength: number
- }
- child: {
- delimiter: string
- maxLength: number
- }
-}
-
-const defaultParentChildConfig: ParentChildConfig = {
- chunkForContext: 'paragraph',
- parent: {
- delimiter: '\\n\\n',
- maxLength: 500,
- },
- child: {
- delimiter: '\\n',
- maxLength: 200,
- },
-}
const StepTwo = ({
isSetting,
@@ -146,7 +104,6 @@ const StepTwo = ({
updateResultCache,
onSave,
onCancel,
- updateRetrievalMethodCache,
}: StepTwoProps) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
@@ -154,166 +111,66 @@ const StepTwo = ({
const isMobile = media === MediaType.mobile
const { dataset: currentDataset, mutateDatasetRes } = useDatasetDetailContext()
-
- const isInUpload = Boolean(currentDataset)
- const isUploadInEmptyDataset = isInUpload && !currentDataset?.doc_form
- const isNotUploadInEmptyDataset = !isUploadInEmptyDataset
- const isInInit = !isInUpload && !isSetting
-
const isInCreatePage = !datasetId || (datasetId && !currentDataset?.data_source_type)
const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : currentDataset?.data_source_type
- const [segmentationType, setSegmentationType] = useState(SegmentType.CUSTOM)
+ const scrollRef = useRef(null)
+ const [scrolled, setScrolled] = useState(false)
+ const previewScrollRef = useRef(null)
+ const [previewScrolled, setPreviewScrolled] = useState(false)
+ const [segmentationType, setSegmentationType] = useState(SegmentType.AUTO)
const [segmentIdentifier, doSetSegmentIdentifier] = useState(DEFAULT_SEGMENT_IDENTIFIER)
- const setSegmentIdentifier = useCallback((value: string, canEmpty?: boolean) => {
- doSetSegmentIdentifier(value ? escape(value) : (canEmpty ? '' : DEFAULT_SEGMENT_IDENTIFIER))
+ const setSegmentIdentifier = useCallback((value: string) => {
+ doSetSegmentIdentifier(value ? escape(value) : DEFAULT_SEGMENT_IDENTIFIER)
}, [])
- const [maxChunkLength, setMaxChunkLength] = useState(DEFAULT_MAXMIMUM_CHUNK_LENGTH) // default chunk length
+ const [maxChunkLength, setMaxChunkLength] = useState(4000) // default chunk length
const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(4000)
- const [overlap, setOverlap] = useState(DEFAULT_OVERLAP)
+ const [overlap, setOverlap] = useState(50)
const [rules, setRules] = useState([])
const [defaultConfig, setDefaultConfig] = useState()
const hasSetIndexType = !!indexingType
- const [indexType, setIndexType] = useState(
+ const [indexType, setIndexType] = useState>(
(indexingType
|| isAPIKeySet)
? IndexingType.QUALIFIED
: IndexingType.ECONOMICAL,
)
-
- const [previewFile, setPreviewFile] = useState(
- (datasetId && documentDetail)
- ? documentDetail.file
- : files[0],
- )
- const [previewNotionPage, setPreviewNotionPage] = useState(
- (datasetId && documentDetail)
- ? documentDetail.notion_page
- : notionPages[0],
- )
-
- const [previewWebsitePage, setPreviewWebsitePage] = useState(
- (datasetId && documentDetail)
- ? documentDetail.website_page
- : websitePages[0],
- )
-
- // QA Related
- const [isLanguageSelectDisabled, _setIsLanguageSelectDisabled] = useState(false)
- const [isQAConfirmDialogOpen, setIsQAConfirmDialogOpen] = useState(false)
- const [docForm, setDocForm] = useState(
- (datasetId && documentDetail) ? documentDetail.doc_form as ChunkingMode : ChunkingMode.text,
+ const [isLanguageSelectDisabled, setIsLanguageSelectDisabled] = useState(false)
+ const [docForm, setDocForm] = useState(
+ (datasetId && documentDetail) ? documentDetail.doc_form : DocForm.TEXT,
)
- const handleChangeDocform = (value: ChunkingMode) => {
- if (value === ChunkingMode.qa && indexType === IndexingType.ECONOMICAL) {
- setIsQAConfirmDialogOpen(true)
- return
- }
- if (value === ChunkingMode.parentChild && indexType === IndexingType.ECONOMICAL)
- setIndexType(IndexingType.QUALIFIED)
- setDocForm(value)
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- currentEstimateMutation.reset()
- }
-
const [docLanguage, setDocLanguage] = useState(
(datasetId && documentDetail) ? documentDetail.doc_language : (locale !== LanguagesSupported[1] ? 'English' : 'Chinese'),
)
+ const [QATipHide, setQATipHide] = useState(false)
+ const [previewSwitched, setPreviewSwitched] = useState(false)
+ const [showPreview, { setTrue: setShowPreview, setFalse: hidePreview }] = useBoolean()
+ const [customFileIndexingEstimate, setCustomFileIndexingEstimate] = useState(null)
+ const [automaticFileIndexingEstimate, setAutomaticFileIndexingEstimate] = useState(null)
- const [parentChildConfig, setParentChildConfig] = useState(defaultParentChildConfig)
+ const fileIndexingEstimate = (() => {
+ return segmentationType === SegmentType.AUTO ? automaticFileIndexingEstimate : customFileIndexingEstimate
+ })()
+ const [isCreating, setIsCreating] = useState(false)
- const getIndexing_technique = () => indexingType || indexType
- const currentDocForm = currentDataset?.doc_form || docForm
+ const scrollHandle = (e: Event) => {
+ if ((e.target as HTMLDivElement).scrollTop > 0)
+ setScrolled(true)
- const getProcessRule = (): ProcessRule => {
- if (currentDocForm === ChunkingMode.parentChild) {
- return {
- rules: {
- pre_processing_rules: rules,
- segmentation: {
- separator: unescape(
- parentChildConfig.parent.delimiter,
- ),
- max_tokens: parentChildConfig.parent.maxLength,
- },
- parent_mode: parentChildConfig.chunkForContext,
- subchunk_segmentation: {
- separator: unescape(parentChildConfig.child.delimiter),
- max_tokens: parentChildConfig.child.maxLength,
- },
- },
- mode: 'hierarchical',
- } as ProcessRule
- }
- return {
- rules: {
- pre_processing_rules: rules,
- segmentation: {
- separator: unescape(segmentIdentifier),
- max_tokens: maxChunkLength,
- chunk_overlap: overlap,
- },
- }, // api will check this. It will be removed after api refactored.
- mode: segmentationType,
- } as ProcessRule
+ else
+ setScrolled(false)
}
- const fileIndexingEstimateQuery = useFetchFileIndexingEstimateForFile({
- docForm: currentDocForm,
- docLanguage,
- dataSourceType: DataSourceType.FILE,
- files: previewFile
- ? [files.find(file => file.name === previewFile.name)!]
- : files,
- indexingTechnique: getIndexing_technique() as any,
- processRule: getProcessRule(),
- dataset_id: datasetId!,
- })
- const notionIndexingEstimateQuery = useFetchFileIndexingEstimateForNotion({
- docForm: currentDocForm,
- docLanguage,
- dataSourceType: DataSourceType.NOTION,
- notionPages: [previewNotionPage],
- indexingTechnique: getIndexing_technique() as any,
- processRule: getProcessRule(),
- dataset_id: datasetId || '',
- })
-
- const websiteIndexingEstimateQuery = useFetchFileIndexingEstimateForWeb({
- docForm: currentDocForm,
- docLanguage,
- dataSourceType: DataSourceType.WEB,
- websitePages: [previewWebsitePage],
- crawlOptions,
- websiteCrawlProvider,
- websiteCrawlJobId,
- indexingTechnique: getIndexing_technique() as any,
- processRule: getProcessRule(),
- dataset_id: datasetId || '',
- })
-
- const currentEstimateMutation = dataSourceType === DataSourceType.FILE
- ? fileIndexingEstimateQuery
- : dataSourceType === DataSourceType.NOTION
- ? notionIndexingEstimateQuery
- : websiteIndexingEstimateQuery
-
- const fetchEstimate = useCallback(() => {
- if (dataSourceType === DataSourceType.FILE)
- fileIndexingEstimateQuery.mutate()
-
- if (dataSourceType === DataSourceType.NOTION)
- notionIndexingEstimateQuery.mutate()
+ const previewScrollHandle = (e: Event) => {
+ if ((e.target as HTMLDivElement).scrollTop > 0)
+ setPreviewScrolled(true)
- if (dataSourceType === DataSourceType.WEB)
- websiteIndexingEstimateQuery.mutate()
- }, [dataSourceType, fileIndexingEstimateQuery, notionIndexingEstimateQuery, websiteIndexingEstimateQuery])
-
- const estimate
- = dataSourceType === DataSourceType.FILE
- ? fileIndexingEstimateQuery.data
- : dataSourceType === DataSourceType.NOTION
- ? notionIndexingEstimateQuery.data
- : websiteIndexingEstimateQuery.data
+ else
+ setPreviewScrolled(false)
+ }
+ const getFileName = (name: string) => {
+ const arr = name.split('.')
+ return arr.slice(0, -1).join('.')
+ }
const getRuleName = (key: string) => {
if (key === 'remove_extra_spaces')
@@ -341,20 +198,128 @@ const StepTwo = ({
if (defaultConfig) {
setSegmentIdentifier(defaultConfig.segmentation.separator)
setMaxChunkLength(defaultConfig.segmentation.max_tokens)
- setOverlap(defaultConfig.segmentation.chunk_overlap!)
+ setOverlap(defaultConfig.segmentation.chunk_overlap)
setRules(defaultConfig.pre_processing_rules)
}
- setParentChildConfig(defaultParentChildConfig)
}
- const updatePreview = () => {
- if (segmentationType === SegmentType.CUSTOM && maxChunkLength > 4000) {
- Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck') })
+ const fetchFileIndexingEstimate = async (docForm = DocForm.TEXT, language?: string) => {
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
+ const res = await didFetchFileIndexingEstimate(getFileIndexingEstimateParams(docForm, language)!)
+ if (segmentationType === SegmentType.CUSTOM)
+ setCustomFileIndexingEstimate(res)
+ else
+ setAutomaticFileIndexingEstimate(res)
+ }
+
+ const confirmChangeCustomConfig = () => {
+ if (segmentationType === SegmentType.CUSTOM && maxChunkLength > limitMaxChunkLength) {
+ Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck', { limit: limitMaxChunkLength }) })
return
}
- fetchEstimate()
+ setCustomFileIndexingEstimate(null)
+ setShowPreview()
+ fetchFileIndexingEstimate()
+ setPreviewSwitched(false)
+ }
+
+ const getIndexing_technique = () => indexingType || indexType
+
+ const getProcessRule = () => {
+ const processRule: ProcessRule = {
+ rules: {} as any, // api will check this. It will be removed after api refactored.
+ mode: segmentationType,
+ }
+ if (segmentationType === SegmentType.CUSTOM) {
+ const ruleObj = {
+ pre_processing_rules: rules,
+ segmentation: {
+ separator: unescape(segmentIdentifier),
+ max_tokens: maxChunkLength,
+ chunk_overlap: overlap,
+ },
+ }
+ processRule.rules = ruleObj
+ }
+ return processRule
+ }
+
+ const getNotionInfo = () => {
+ const workspacesMap = groupBy(notionPages, 'workspace_id')
+ const workspaces = Object.keys(workspacesMap).map((workspaceId) => {
+ return {
+ workspaceId,
+ pages: workspacesMap[workspaceId],
+ }
+ })
+ return workspaces.map((workspace) => {
+ return {
+ workspace_id: workspace.workspaceId,
+ pages: workspace.pages.map((page) => {
+ const { page_id, page_name, page_icon, type } = page
+ return {
+ page_id,
+ page_name,
+ page_icon,
+ type,
+ }
+ }),
+ }
+ }) as NotionInfo[]
+ }
+
+ const getWebsiteInfo = () => {
+ return {
+ provider: websiteCrawlProvider,
+ job_id: websiteCrawlJobId,
+ urls: websitePages.map(page => page.source_url),
+ only_main_content: crawlOptions?.only_main_content,
+ }
}
+ const getFileIndexingEstimateParams = (docForm: DocForm, language?: string): IndexingEstimateParams | undefined => {
+ if (dataSourceType === DataSourceType.FILE) {
+ return {
+ info_list: {
+ data_source_type: dataSourceType,
+ file_info_list: {
+ file_ids: files.map(file => file.id) as string[],
+ },
+ },
+ indexing_technique: getIndexing_technique() as string,
+ process_rule: getProcessRule(),
+ doc_form: docForm,
+ doc_language: language || docLanguage,
+ dataset_id: datasetId as string,
+ }
+ }
+ if (dataSourceType === DataSourceType.NOTION) {
+ return {
+ info_list: {
+ data_source_type: dataSourceType,
+ notion_info_list: getNotionInfo(),
+ },
+ indexing_technique: getIndexing_technique() as string,
+ process_rule: getProcessRule(),
+ doc_form: docForm,
+ doc_language: language || docLanguage,
+ dataset_id: datasetId as string,
+ }
+ }
+ if (dataSourceType === DataSourceType.WEB) {
+ return {
+ info_list: {
+ data_source_type: dataSourceType,
+ website_info_list: getWebsiteInfo(),
+ },
+ indexing_technique: getIndexing_technique() as string,
+ process_rule: getProcessRule(),
+ doc_form: docForm,
+ doc_language: language || docLanguage,
+ dataset_id: datasetId as string,
+ }
+ }
+ }
const {
modelList: rerankModelList,
defaultModel: rerankDefaultModel,
@@ -386,14 +351,13 @@ const StepTwo = ({
if (isSetting) {
params = {
original_document_id: documentDetail?.id,
- doc_form: currentDocForm,
+ doc_form: docForm,
doc_language: docLanguage,
process_rule: getProcessRule(),
// eslint-disable-next-line @typescript-eslint/no-use-before-define
retrieval_model: retrievalConfig, // Readonly. If want to changed, just go to settings page.
embedding_model: embeddingModel.model, // Readonly
embedding_model_provider: embeddingModel.provider, // Readonly
- indexing_technique: getIndexing_technique(),
} as CreateDocumentReq
}
else { // create
@@ -413,12 +377,8 @@ const StepTwo = ({
}
const postRetrievalConfig = ensureRerankModelSelected({
rerankDefaultModel: rerankDefaultModel!,
- retrievalConfig: {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- ...retrievalConfig,
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- reranking_enable: retrievalConfig.reranking_mode === RerankingModeEnum.RerankingModel,
- },
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
+ retrievalConfig,
indexMethod: indexMethod as string,
})
params = {
@@ -430,7 +390,7 @@ const StepTwo = ({
},
indexing_technique: getIndexing_technique(),
process_rule: getProcessRule(),
- doc_form: currentDocForm,
+ doc_form: docForm,
doc_language: docLanguage,
retrieval_model: postRetrievalConfig,
@@ -443,36 +403,29 @@ const StepTwo = ({
}
}
if (dataSourceType === DataSourceType.NOTION)
- params.data_source.info_list.notion_info_list = getNotionInfo(notionPages)
+ params.data_source.info_list.notion_info_list = getNotionInfo()
- if (dataSourceType === DataSourceType.WEB) {
- params.data_source.info_list.website_info_list = getWebsiteInfo({
- websiteCrawlProvider,
- websiteCrawlJobId,
- websitePages,
- })
- }
+ if (dataSourceType === DataSourceType.WEB)
+ params.data_source.info_list.website_info_list = getWebsiteInfo()
}
return params
}
- const fetchDefaultProcessRuleMutation = useFetchDefaultProcessRule({
- onSuccess(data) {
- const separator = data.rules.segmentation.separator
+ const getRules = async () => {
+ try {
+ const res = await fetchDefaultProcessRule({ url: '/datasets/process-rule' })
+ const separator = res.rules.segmentation.separator
setSegmentIdentifier(separator)
- setMaxChunkLength(data.rules.segmentation.max_tokens)
- setOverlap(data.rules.segmentation.chunk_overlap!)
- setRules(data.rules.pre_processing_rules)
- setDefaultConfig(data.rules)
- setLimitMaxChunkLength(data.limits.indexing_max_segmentation_tokens_length)
- },
- onError(error) {
- Toast.notify({
- type: 'error',
- message: `${error}`,
- })
- },
- })
+ setMaxChunkLength(res.rules.segmentation.max_tokens)
+ setLimitMaxChunkLength(res.limits.indexing_max_segmentation_tokens_length)
+ setOverlap(res.rules.segmentation.chunk_overlap)
+ setRules(res.rules.pre_processing_rules)
+ setDefaultConfig(res.rules)
+ }
+ catch (err) {
+ console.log(err)
+ }
+ }
const getRulesFromDetail = () => {
if (documentDetail) {
@@ -482,7 +435,7 @@ const StepTwo = ({
const overlap = rules.segmentation.chunk_overlap
setSegmentIdentifier(separator)
setMaxChunkLength(max)
- setOverlap(overlap!)
+ setOverlap(overlap)
setRules(rules.pre_processing_rules)
setDefaultConfig(rules)
}
@@ -490,81 +443,119 @@ const StepTwo = ({
const getDefaultMode = () => {
if (documentDetail)
- // @ts-expect-error fix after api refactored
setSegmentationType(documentDetail.dataset_process_rule.mode)
}
- const createFirstDocumentMutation = useCreateFirstDocument({
- onError(error) {
- Toast.notify({
- type: 'error',
- message: `${error}`,
- })
- },
- })
- const createDocumentMutation = useCreateDocument(datasetId!, {
- onError(error) {
+ const createHandle = async () => {
+ if (isCreating)
+ return
+ setIsCreating(true)
+ try {
+ let res
+ const params = getCreationParams()
+ if (!params)
+ return false
+
+ setIsCreating(true)
+ if (!datasetId) {
+ res = await createFirstDocument({
+ body: params as CreateDocumentReq,
+ })
+ updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
+ updateResultCache && updateResultCache(res)
+ }
+ else {
+ res = await createDocument({
+ datasetId,
+ body: params as CreateDocumentReq,
+ })
+ updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
+ updateResultCache && updateResultCache(res)
+ }
+ if (mutateDatasetRes)
+ mutateDatasetRes()
+ onStepChange && onStepChange(+1)
+ isSetting && onSave && onSave()
+ }
+ catch (err) {
Toast.notify({
type: 'error',
- message: `${error}`,
+ message: `${err}`,
})
- },
- })
-
- const isCreating = createFirstDocumentMutation.isPending || createDocumentMutation.isPending
+ }
+ finally {
+ setIsCreating(false)
+ }
+ }
- const createHandle = async () => {
- const params = getCreationParams()
- if (!params)
- return false
+ const handleSwitch = (state: boolean) => {
+ if (state)
+ setDocForm(DocForm.QA)
+ else
+ setDocForm(DocForm.TEXT)
+ }
- if (!datasetId) {
- await createFirstDocumentMutation.mutateAsync(
- params,
- {
- onSuccess(data) {
- updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
- updateResultCache && updateResultCache(data)
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- updateRetrievalMethodCache && updateRetrievalMethodCache(retrievalConfig.search_method as string)
- },
- },
- )
+ const previewSwitch = async (language?: string) => {
+ setPreviewSwitched(true)
+ setIsLanguageSelectDisabled(true)
+ if (segmentationType === SegmentType.AUTO)
+ setAutomaticFileIndexingEstimate(null)
+ else
+ setCustomFileIndexingEstimate(null)
+ try {
+ await fetchFileIndexingEstimate(DocForm.QA, language)
}
- else {
- await createDocumentMutation.mutateAsync(params, {
- onSuccess(data) {
- updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
- updateResultCache && updateResultCache(data)
- },
- })
+ finally {
+ setIsLanguageSelectDisabled(false)
}
- if (mutateDatasetRes)
- mutateDatasetRes()
- onStepChange && onStepChange(+1)
- isSetting && onSave && onSave()
}
- const changeToEconomicalType = () => {
- if (docForm !== ChunkingMode.text)
- return
+ const handleSelect = (language: string) => {
+ setDocLanguage(language)
+ // Switch language, re-cutter
+ if (docForm === DocForm.QA && previewSwitched)
+ previewSwitch(language)
+ }
- if (!hasSetIndexType)
+ const changeToEconomicalType = () => {
+ if (!hasSetIndexType) {
setIndexType(IndexingType.ECONOMICAL)
+ setDocForm(DocForm.TEXT)
+ }
}
useEffect(() => {
// fetch rules
if (!isSetting) {
- fetchDefaultProcessRuleMutation.mutate('/datasets/process-rule')
+ getRules()
}
else {
getRulesFromDetail()
getDefaultMode()
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
+ useEffect(() => {
+ scrollRef.current?.addEventListener('scroll', scrollHandle)
+ return () => {
+ scrollRef.current?.removeEventListener('scroll', scrollHandle)
+ }
+ }, [])
+
+ useLayoutEffect(() => {
+ if (showPreview) {
+ previewScrollRef.current?.addEventListener('scroll', previewScrollHandle)
+ return () => {
+ previewScrollRef.current?.removeEventListener('scroll', previewScrollHandle)
+ }
+ }
+ }, [showPreview])
+
+ useEffect(() => {
+ if (indexingType === IndexingType.ECONOMICAL && docForm === DocForm.QA)
+ setDocForm(DocForm.TEXT)
+ }, [indexingType, docForm])
+
useEffect(() => {
// get indexing type by props
if (indexingType)
@@ -574,6 +565,20 @@ const StepTwo = ({
setIndexType(isAPIKeySet ? IndexingType.QUALIFIED : IndexingType.ECONOMICAL)
}, [isAPIKeySet, indexingType, datasetId])
+ useEffect(() => {
+ if (segmentationType === SegmentType.AUTO) {
+ setAutomaticFileIndexingEstimate(null)
+ !isMobile && setShowPreview()
+ fetchFileIndexingEstimate()
+ setPreviewSwitched(false)
+ }
+ else {
+ hidePreview()
+ setCustomFileIndexingEstimate(null)
+ setPreviewSwitched(false)
+ }
+ }, [segmentationType, indexType])
+
const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict || {
search_method: RETRIEVE_METHOD.semantic,
reranking_enable: false,
@@ -586,589 +591,433 @@ const StepTwo = ({
score_threshold: 0.5,
} as RetrievalConfig)
- const economyDomRef = useRef(null)
- const isHoveringEconomy = useHover(economyDomRef)
-
return (
-
-
{t('datasetCreation.stepTwo.segmentation')}
- {((isInUpload && [ChunkingMode.text, ChunkingMode.qa].includes(currentDataset!.doc_form))
- || isUploadInEmptyDataset
- || isInInit)
- &&
}
- activeHeaderClassName='bg-dataset-option-card-blue-gradient'
- description={t('datasetCreation.stepTwo.generalTip')}
- isActive={
- [ChunkingMode.text, ChunkingMode.qa].includes(currentDocForm)
- }
- onSwitched={() =>
- handleChangeDocform(ChunkingMode.text)
- }
- actions={
- <>
-
-
- >
- }
- noHighlight={isInUpload && isNotUploadInEmptyDataset}
- >
-
-
-
setSegmentIdentifier(e.target.value, true)}
- />
-
-
+
+
+
{t('datasetCreation.steps.two')}
+ {(isMobile || !showPreview) && (
+
+ )}
+
+
+
{t('datasetCreation.stepTwo.segmentation')}
+
+
setSegmentationType(SegmentType.AUTO)}
+ >
+
+
+
+
{t('datasetCreation.stepTwo.auto')}
+
{t('datasetCreation.stepTwo.autoDescription')}
-
-
-
- {t('datasetCreation.stepTwo.rules')}
+
+
setSegmentationType(SegmentType.CUSTOM)}
+ >
+
+
+
+
{t('datasetCreation.stepTwo.custom')}
+
{t('datasetCreation.stepTwo.customDescription')}
+
+ {segmentationType === SegmentType.CUSTOM && (
+
+
+
+
+ {t('datasetCreation.stepTwo.separator')}
+
+ {t('datasetCreation.stepTwo.separatorTip')}
+
+ }
+ />
+
+
setSegmentIdentifier(e.target.value)}
+ />
+
-
-
-
- {rules.map(rule => (
-
{
- ruleChangeHandle(rule.id)
- }}>
-
+
+
{t('datasetCreation.stepTwo.maxLength')}
+
setMaxChunkLength(parseInt(e.target.value.replace(/^0+/, ''), 10))}
/>
-
- ))}
- {IS_CE_EDITION && <>
-
-
-
{
- if (currentDataset?.doc_form)
- return
- if (docForm === ChunkingMode.qa)
- handleChangeDocform(ChunkingMode.text)
- else
- handleChangeDocform(ChunkingMode.qa)
- }}>
-
+
+
+
+ {t('datasetCreation.stepTwo.overlap')}
+
+ {t('datasetCreation.stepTwo.overlapTip')}
+
+ }
/>
-
-
setOverlap(parseInt(e.target.value.replace(/^0+/, ''), 10))}
/>
-
- {currentDocForm === ChunkingMode.qa && (
-
-
-
- {t('datasetCreation.stepTwo.QATip')}
-
-
- )}
- >}
-
-
-
- }
- {
- (
- (isInUpload && currentDataset!.doc_form === ChunkingMode.parentChild)
- || isUploadInEmptyDataset
- || isInInit
- )
- &&
}
- effectImg={OrangeEffect.src}
- activeHeaderClassName='bg-dataset-option-card-orange-gradient'
- description={t('datasetCreation.stepTwo.parentChildTip')}
- isActive={currentDocForm === ChunkingMode.parentChild}
- onSwitched={() => handleChangeDocform(ChunkingMode.parentChild)}
- actions={
- <>
-
-
- >
- }
- noHighlight={isInUpload && isNotUploadInEmptyDataset}
- >
-
-
-
-
- {t('datasetCreation.stepTwo.parentChunkForContext')}
-
-
-
}
- title={t('datasetCreation.stepTwo.paragraph')}
- description={t('datasetCreation.stepTwo.paragraphTip')}
- isChosen={parentChildConfig.chunkForContext === 'paragraph'}
- onChosen={() => setParentChildConfig(
- {
- ...parentChildConfig,
- chunkForContext: 'paragraph',
- },
- )}
- chosenConfig={
-
-
setParentChildConfig({
- ...parentChildConfig,
- parent: {
- ...parentChildConfig.parent,
- delimiter: e.target.value ? escape(e.target.value) : '',
- },
- })}
- />
- setParentChildConfig({
- ...parentChildConfig,
- parent: {
- ...parentChildConfig.parent,
- maxLength: value,
- },
- })}
- />
+
+
+
{t('datasetCreation.stepTwo.rules')}
+ {rules.map(rule => (
+
+ ruleChangeHandle(rule.id)} className="w-4 h-4 rounded border-gray-300 text-blue-700 focus:ring-blue-700" />
+
+
+ ))}
- }
- />
-
}
- title={t('datasetCreation.stepTwo.fullDoc')}
- description={t('datasetCreation.stepTwo.fullDocTip')}
- onChosen={() => setParentChildConfig(
- {
- ...parentChildConfig,
- chunkForContext: 'full-doc',
- },
- )}
- isChosen={parentChildConfig.chunkForContext === 'full-doc'}
- />
-
-
-
-
-
- {t('datasetCreation.stepTwo.childChunkForRetrieval')}
-
-
-
- setParentChildConfig({
- ...parentChildConfig,
- child: {
- ...parentChildConfig.child,
- delimiter: e.target.value ? escape(e.target.value) : '',
- },
- })}
- />
- setParentChildConfig({
- ...parentChildConfig,
- child: {
- ...parentChildConfig.child,
- maxLength: value,
- },
- })}
- />
-
-
-
-
-
-
{t('datasetCreation.stepTwo.rules')}
+
+
+
-
-
- {rules.map(rule => (
-
{
- ruleChangeHandle(rule.id)
- }}>
-
-
-
- ))}
-
-
+ )}
- }
-
- {t('datasetCreation.stepTwo.indexMode')}
-
- {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.QUALIFIED)) && (
-
- {t('datasetCreation.stepTwo.qualified')}
-
- {t('datasetCreation.stepTwo.recommend')}
-
-
+
+ {t('datasetCreation.stepTwo.indexMode')}
+
+
+ {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.QUALIFIED)) && (
+
{
+ if (isAPIKeySet)
+ setIndexType(IndexingType.QUALIFIED)
+ }}
+ >
+
{!hasSetIndexType && }
-
-
}
- description={t('datasetCreation.stepTwo.qualifiedTip')}
- icon={
}
- isActive={!hasSetIndexType && indexType === IndexingType.QUALIFIED}
- disabled={!isAPIKeySet || hasSetIndexType}
- onSwitched={() => {
- if (isAPIKeySet)
- setIndexType(IndexingType.QUALIFIED)
- }}
- />
- )}
-
- {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && (
- <>
-
setIsQAConfirmDialogOpen(false)} className='w-[432px]'>
-
-
-
-
+
+
+ {t('datasetCreation.stepTwo.qualified')}
+ {!hasSetIndexType && {t('datasetCreation.stepTwo.recommend')}}
+
+
{t('datasetCreation.stepTwo.qualifiedTip')}
+
+ {!isAPIKeySet && (
+
+ {t('datasetCreation.stepTwo.warning')}
+ {t('datasetCreation.stepTwo.click')}
+
+ )}
-
-
-
- }
- isActive={!hasSetIndexType && indexType === IndexingType.ECONOMICAL}
- disabled={!isAPIKeySet || hasSetIndexType || docForm !== ChunkingMode.text}
- ref={economyDomRef}
- onSwitched={() => {
- if (isAPIKeySet && docForm === ChunkingMode.text)
- setIndexType(IndexingType.ECONOMICAL)
- }}
- />
-
-
-
- {
- docForm === ChunkingMode.qa
- ? t('datasetCreation.stepTwo.notAvailableForQA')
- : t('datasetCreation.stepTwo.notAvailableForParentChild')
- }
+ )}
+
+ {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && (
+
+
+ {!hasSetIndexType &&
}
+
+
{t('datasetCreation.stepTwo.economical')}
+
{t('datasetCreation.stepTwo.economicalTip')}
-
-
- >)}
-
- {!hasSetIndexType && indexType === IndexingType.QUALIFIED && (
-
-
{t('datasetCreation.stepTwo.highQualityTip')}
-
- )}
- {hasSetIndexType && indexType === IndexingType.ECONOMICAL && (
-
- {t('datasetCreation.stepTwo.indexSettingTip')}
- {t('datasetCreation.stepTwo.datasetSettingLink')}
-
- )}
- {/* Embedding model */}
- {indexType === IndexingType.QUALIFIED && (
-
-
{t('datasetSettings.form.embeddingModel')}
-
{
- setEmbeddingModel(model)
- }}
- />
- {!!datasetId && (
-
+ {hasSetIndexType && indexType === IndexingType.ECONOMICAL && (
+
{t('datasetCreation.stepTwo.indexSettingTip')}
- {t('datasetCreation.stepTwo.datasetSettingLink')}
+ {t('datasetCreation.stepTwo.datasetSettingLink')}
)}
-
- )}
-
- {/* Retrieval Method Config */}
-
- {!datasetId
- ? (
-
-
{t('datasetSettings.form.retrievalSetting.title')}
-
-
{t('datasetSettings.form.retrievalSetting.learnMore')}
- {t('datasetSettings.form.retrievalSetting.longDescription')}
+ {IS_CE_EDITION && indexType === IndexingType.QUALIFIED && (
+
+
+
+
+
+
+
{t('datasetCreation.stepTwo.QATitle')}
+
+ {t('datasetCreation.stepTwo.QALanguage')}
+
+
+
+
+
+
+ {docForm === DocForm.QA && !QATipHide && (
+
+ {t('datasetCreation.stepTwo.QATip')}
+ setQATipHide(true)} />
+
+ )}
- )
- : (
-
-
{t('datasetSettings.form.retrievalSetting.title')}
+ )}
+ {/* Embedding model */}
+ {indexType === IndexingType.QUALIFIED && (
+
+
{t('datasetSettings.form.embeddingModel')}
+
{
+ setEmbeddingModel(model)
+ }}
+ />
+ {!!datasetId && (
+
+ {t('datasetCreation.stepTwo.indexSettingTip')}
+ {t('datasetCreation.stepTwo.datasetSettingLink')}
+
+ )}
)}
-
-
- {
- getIndexing_technique() === IndexingType.QUALIFIED
+ {/* Retrieval Method Config */}
+
+ {!datasetId
? (
-
+
+
{t('datasetSettings.form.retrievalSetting.title')}
+
+
)
: (
-
- )
- }
-
-
+
+
{t('datasetSettings.form.retrievalSetting.title')}
+
+ )}
- {!isSetting
- ? (
-
-
-
-
- )
- : (
-
-
-
+
+ {
+ getIndexing_technique() === IndexingType.QUALIFIED
+ ? (
+
+ )
+ : (
+
+ )
+ }
+
- )}
-
-
{ }} footer={null}>
-
-
- {dataSourceType === DataSourceType.FILE
- &&
>}
- onChange={(selected) => {
- currentEstimateMutation.reset()
- setPreviewFile(selected)
- currentEstimateMutation.mutate()
- }}
- // when it is from setting, it just has one file
- value={isSetting ? (files[0]! as Required) : previewFile}
- />
- }
- {dataSourceType === DataSourceType.NOTION
- && ({
- id: page.page_id,
- name: page.page_name,
- extension: 'md',
- }))
- }
- onChange={(selected) => {
- currentEstimateMutation.reset()
- const selectedPage = notionPages.find(page => page.page_id === selected.id)
- setPreviewNotionPage(selectedPage!)
- currentEstimateMutation.mutate()
- }}
- value={{
- id: previewNotionPage?.page_id || '',
- name: previewNotionPage?.page_name || '',
- extension: 'md',
- }}
- />
- }
- {dataSourceType === DataSourceType.WEB
- && ({
- id: page.source_url,
- name: page.title,
- extension: 'md',
- }))
- }
- onChange={(selected) => {
- currentEstimateMutation.reset()
- const selectedPage = websitePages.find(page => page.source_url === selected.id)
- setPreviewWebsitePage(selectedPage!)
- currentEstimateMutation.mutate()
- }}
- value={
- {
- id: previewWebsitePage?.source_url || '',
- name: previewWebsitePage?.title || '',
- extension: 'md',
- }
+
+
+
+ {dataSourceType === DataSourceType.FILE && (
+ <>
+
{t('datasetCreation.stepTwo.fileSource')}
+
+
+ {getFileName(files[0].name || '')}
+ {files.length > 1 && (
+
+ {t('datasetCreation.stepTwo.other')}
+ {files.length - 1}
+ {t('datasetCreation.stepTwo.fileUnit')}
+
+ )}
+
+ >
+ )}
+ {dataSourceType === DataSourceType.NOTION && (
+ <>
+
{t('datasetCreation.stepTwo.notionSource')}
+
+
+ {notionPages[0]?.page_name}
+ {notionPages.length > 1 && (
+
+ {t('datasetCreation.stepTwo.other')}
+ {notionPages.length - 1}
+ {t('datasetCreation.stepTwo.notionUnit')}
+
+ )}
+
+ >
+ )}
+ {dataSourceType === DataSourceType.WEB && (
+ <>
+
{t('datasetCreation.stepTwo.websiteSource')}
+
+
+ {websitePages[0].source_url}
+ {websitePages.length > 1 && (
+
+ {t('datasetCreation.stepTwo.other')}
+ {websitePages.length - 1}
+ {t('datasetCreation.stepTwo.webpageUnit')}
+
+ )}
+
+ >
+ )}
+
+
+
+
{t('datasetCreation.stepTwo.estimateSegment')}
+
+ {
+ fileIndexingEstimate
+ ? (
+
{formatNumber(fileIndexingEstimate.total_segments)}
+ )
+ : (
+
{t('datasetCreation.stepTwo.calculating')}
+ )
}
- />
- }
- {
- currentDocForm !== ChunkingMode.qa
- &&
- }
+
+
- }
- className={cn('flex shrink-0 w-1/2 p-4 pr-0 relative h-full', isMobile && 'w-full max-w-[524px]')}
- mainClassName='space-y-6'
- >
- {currentDocForm === ChunkingMode.qa && estimate?.qa_preview && (
- estimate?.qa_preview.map((item, index) => (
-
-
-
- ))
- )}
- {currentDocForm === ChunkingMode.text && estimate?.preview && (
- estimate?.preview.map((item, index) => (
-
- {item.content}
-
- ))
- )}
- {currentDocForm === ChunkingMode.parentChild && currentEstimateMutation.data?.preview && (
- estimate?.preview?.map((item, index) => {
- const indexForLabel = index + 1
- return (
-
-
- {item.child_chunks.map((child, index) => {
- const indexForLabel = index + 1
- return (
-
- )
- })}
-
-
+ {!isSetting
+ ? (
+
+
+
+
+
)
- })
- )}
- {currentEstimateMutation.isIdle && (
-
-
-
-
- {t('datasetCreation.stepTwo.previewChunkTip')}
-
+ : (
+
+
+
+
+ )}
+
+
+
+
+ {showPreview &&
+
+
+
+
{t('datasetCreation.stepTwo.previewTitle')}
+ {docForm === DocForm.QA && !previewSwitched && (
+
+ )}
+
+
+
- )}
- {currentEstimateMutation.isPending && (
-
- {Array.from({ length: 10 }, (_, i) => (
-
-
-
-
-
-
-
-
-
-
- ))}
+ {docForm === DocForm.QA && !previewSwitched && (
+
+ {t('datasetCreation.stepTwo.previewSwitchTipStart')}
+ {t('datasetCreation.stepTwo.previewSwitchTipEnd')}
+
+ )}
+
+
+ {previewSwitched && docForm === DocForm.QA && fileIndexingEstimate?.qa_preview && (
+ <>
+ {fileIndexingEstimate?.qa_preview.map((item, index) => (
+
+ ))}
+ >
+ )}
+ {(docForm === DocForm.TEXT || !previewSwitched) && fileIndexingEstimate?.preview && (
+ <>
+ {fileIndexingEstimate?.preview.map((item, index) => (
+
+ ))}
+ >
+ )}
+ {previewSwitched && docForm === DocForm.QA && !fileIndexingEstimate?.qa_preview && (
+
+
+
+ )}
+ {!previewSwitched && !fileIndexingEstimate?.preview && (
+
+
+
+ )}
+
+
}
+ {!showPreview && (
+
+
+
+
{t('datasetCreation.stepTwo.sideTipTitle')}
+
+
{t('datasetCreation.stepTwo.sideTipP1')}
+
{t('datasetCreation.stepTwo.sideTipP2')}
+
{t('datasetCreation.stepTwo.sideTipP3')}
+
{t('datasetCreation.stepTwo.sideTipP4')}
+
- )}
-
+
+ )}
)
diff --git a/web/app/components/datasets/create/step-two/inputs.tsx b/web/app/components/datasets/create/step-two/inputs.tsx
deleted file mode 100644
index 4231f6242dca20..00000000000000
--- a/web/app/components/datasets/create/step-two/inputs.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import type { FC, PropsWithChildren, ReactNode } from 'react'
-import { useTranslation } from 'react-i18next'
-import type { InputProps } from '@/app/components/base/input'
-import Input from '@/app/components/base/input'
-import Tooltip from '@/app/components/base/tooltip'
-import type { InputNumberProps } from '@/app/components/base/input-number'
-import { InputNumber } from '@/app/components/base/input-number'
-
-const TextLabel: FC = (props) => {
- return
-}
-
-const FormField: FC> = (props) => {
- return
- {props.label}
- {props.children}
-
-}
-
-export const DelimiterInput: FC = (props) => {
- const { t } = useTranslation()
- return
- {t('datasetCreation.stepTwo.separator')}
-
- {props.tooltip || t('datasetCreation.stepTwo.separatorTip')}
-
- }
- />
-
}>
-
-
-}
-
-export const MaxLengthInput: FC
= (props) => {
- const { t } = useTranslation()
- return
- {t('datasetCreation.stepTwo.maxLength')}
- }>
-
-
-}
-
-export const OverlapInput: FC = (props) => {
- const { t } = useTranslation()
- return
- {t('datasetCreation.stepTwo.overlap')}
-
- {t('datasetCreation.stepTwo.overlapTip')}
-
- }
- />
- }>
-
-
-}
diff --git a/web/app/components/datasets/create/step-two/language-select/index.tsx b/web/app/components/datasets/create/step-two/language-select/index.tsx
index 9cbf1a40d133fc..41f3e0abb55b6e 100644
--- a/web/app/components/datasets/create/step-two/language-select/index.tsx
+++ b/web/app/components/datasets/create/step-two/language-select/index.tsx
@@ -1,7 +1,7 @@
'use client'
import type { FC } from 'react'
import React from 'react'
-import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
+import { RiArrowDownSLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import Popover from '@/app/components/base/popover'
import { languages } from '@/i18n/language'
@@ -22,40 +22,25 @@ const LanguageSelect: FC
= ({
manualClose
trigger='click'
disabled={disabled}
- popupClassName='z-20'
htmlContent={
-
+
{languages.filter(language => language.supported).map(({ prompt_name }) => (
onSelect(prompt_name)}
- >
- {prompt_name}
- {(currentLanguage === prompt_name) && }
+ className='py-2 px-3 mx-1 flex items-center gap-2 hover:bg-gray-100 rounded-lg cursor-pointer text-gray-700 text-sm'
+ onClick={() => onSelect(prompt_name)}>{prompt_name}
))}
}
btnElement={
-
-
- {currentLanguage}
-
-
+
+ {currentLanguage}
+
}
- btnClassName={() => cn(
- '!border-0 rounded-md !px-1.5 !py-1 !mx-1 !bg-components-button-tertiary-bg !hover:bg-components-button-tertiary-bg',
- disabled ? 'bg-components-button-tertiary-bg-disabled' : '',
- )}
- className='!w-[140px] h-fit !z-20 !translate-x-0 !left-1'
+ btnClassName={open => cn('!border-0 !px-0 !py-0 !bg-inherit !hover:bg-inherit', open ? 'text-blue-600' : 'text-gray-500')}
+ className='!w-[120px] h-fit !z-20 !translate-x-0 !left-[-16px]'
/>
)
}
diff --git a/web/app/components/datasets/create/step-two/option-card.tsx b/web/app/components/datasets/create/step-two/option-card.tsx
deleted file mode 100644
index b27be757b30d9d..00000000000000
--- a/web/app/components/datasets/create/step-two/option-card.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { type ComponentProps, type FC, type ReactNode, forwardRef } from 'react'
-import Image from 'next/image'
-import classNames from '@/utils/classnames'
-
-const TriangleArrow: FC
> = props => (
-
-)
-
-type OptionCardHeaderProps = {
- icon: ReactNode
- title: ReactNode
- description: string
- isActive?: boolean
- activeClassName?: string
- effectImg?: string
- disabled?: boolean
-}
-
-export const OptionCardHeader: FC = (props) => {
- const { icon, title, description, isActive, activeClassName, effectImg, disabled } = props
- return
-
- {isActive && effectImg &&
}
-
-
-
-
-
{title}
-
{description}
-
-
-}
-
-type OptionCardProps = {
- icon: ReactNode
- className?: string
- activeHeaderClassName?: string
- title: ReactNode
- description: string
- isActive?: boolean
- actions?: ReactNode
- effectImg?: string
- onSwitched?: () => void
- noHighlight?: boolean
- disabled?: boolean
-} & Omit, 'title' | 'onClick'>
-
-export const OptionCard: FC = forwardRef((props, ref) => {
- const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, noHighlight, disabled, ...rest } = props
- return {
- if (!isActive && !disabled)
- onSwitched?.()
- }}
- {...rest}
- ref={ref}
- >
-
- {/** Body */}
- {isActive && (children || actions) &&
- {children}
- {actions &&
- {actions}
-
- }
-
}
-
-})
-
-OptionCard.displayName = 'OptionCard'
diff --git a/web/app/components/datasets/create/stepper/index.tsx b/web/app/components/datasets/create/stepper/index.tsx
deleted file mode 100644
index 317c1a76eecf57..00000000000000
--- a/web/app/components/datasets/create/stepper/index.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { type FC, Fragment } from 'react'
-import type { Step } from './step'
-import { StepperStep } from './step'
-
-export type StepperProps = {
- steps: Step[]
- activeIndex: number
-}
-
-export const Stepper: FC = (props) => {
- const { steps, activeIndex } = props
- return
- {steps.map((step, index) => {
- const isLast = index === steps.length - 1
- return (
-
-
- {!isLast && }
-
- )
- })}
-
-}
diff --git a/web/app/components/datasets/create/stepper/step.tsx b/web/app/components/datasets/create/stepper/step.tsx
deleted file mode 100644
index c230de1a6e748b..00000000000000
--- a/web/app/components/datasets/create/stepper/step.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import type { FC } from 'react'
-import classNames from '@/utils/classnames'
-
-export type Step = {
- name: string
-}
-
-export type StepperStepProps = Step & {
- index: number
- activeIndex: number
-}
-
-export const StepperStep: FC = (props) => {
- const { name, activeIndex, index } = props
- const isActive = index === activeIndex
- const isDisabled = activeIndex < index
- const label = isActive ? `STEP ${index + 1}` : `${index + 1}`
- return
-}
diff --git a/web/app/components/datasets/create/top-bar/index.tsx b/web/app/components/datasets/create/top-bar/index.tsx
deleted file mode 100644
index 20ba7158db5ed8..00000000000000
--- a/web/app/components/datasets/create/top-bar/index.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import type { FC } from 'react'
-import { RiArrowLeftLine } from '@remixicon/react'
-import Link from 'next/link'
-import { useTranslation } from 'react-i18next'
-import { Stepper, type StepperProps } from '../stepper'
-import classNames from '@/utils/classnames'
-
-export type TopbarProps = Pick & {
- className?: string
-}
-
-const STEP_T_MAP: Record = {
- 1: 'datasetCreation.steps.one',
- 2: 'datasetCreation.steps.two',
- 3: 'datasetCreation.steps.three',
-}
-
-export const Topbar: FC = (props) => {
- const { className, ...rest } = props
- const { t } = useTranslation()
- return
-
-
-
-
-
- {t('datasetCreation.steps.header.creation')}
-
-
-
- ({
- name: t(STEP_T_MAP[i + 1]),
- }))}
- {...rest}
- />
-
-
-}
diff --git a/web/app/components/datasets/create/website/base/error-message.tsx b/web/app/components/datasets/create/website/base/error-message.tsx
index f061c4624e90f2..aa337ec4bf5323 100644
--- a/web/app/components/datasets/create/website/base/error-message.tsx
+++ b/web/app/components/datasets/create/website/base/error-message.tsx
@@ -18,7 +18,7 @@ const ErrorMessage: FC = ({
return (
{errorMsg && (
diff --git a/web/app/components/datasets/create/website/jina-reader/index.tsx b/web/app/components/datasets/create/website/jina-reader/index.tsx
index 1c133f935c076b..51d77d712140b7 100644
--- a/web/app/components/datasets/create/website/jina-reader/index.tsx
+++ b/web/app/components/datasets/create/website/jina-reader/index.tsx
@@ -94,6 +94,7 @@ const JinaReader: FC
= ({
const waitForCrawlFinished = useCallback(async (jobId: string) => {
try {
const res = await checkJinaReaderTaskStatus(jobId) as any
+ console.log('res', res)
if (res.status === 'completed') {
return {
isError: false,
diff --git a/web/app/components/datasets/create/website/preview.tsx b/web/app/components/datasets/create/website/preview.tsx
index 5180a834423014..65abe83ed771ac 100644
--- a/web/app/components/datasets/create/website/preview.tsx
+++ b/web/app/components/datasets/create/website/preview.tsx
@@ -18,7 +18,7 @@ const WebsitePreview = ({
const { t } = useTranslation()
return (
-
+
{t('datasetCreation.stepOne.pagePreview')}
@@ -32,7 +32,7 @@ const WebsitePreview = ({
{payload.source_url}
-
{payload.markdown}
+
{payload.markdown}
)
diff --git a/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx b/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
index 6602244a480a49..36216aa7c89658 100644
--- a/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
+++ b/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
@@ -7,7 +7,7 @@ import {
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
-import { ChunkingMode } from '@/models/datasets'
+import { DocForm } from '@/models/datasets'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
@@ -32,18 +32,18 @@ const CSV_TEMPLATE_CN = [
['内容 2'],
]
-const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
+const CSVDownload: FC<{ docForm: DocForm }> = ({ docForm }) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const { CSVDownloader, Type } = useCSVDownloader()
const getTemplate = () => {
if (locale === LanguagesSupported[1]) {
- if (docForm === ChunkingMode.qa)
+ if (docForm === DocForm.QA)
return CSV_TEMPLATE_QA_CN
return CSV_TEMPLATE_CN
}
- if (docForm === ChunkingMode.qa)
+ if (docForm === DocForm.QA)
return CSV_TEMPLATE_QA_EN
return CSV_TEMPLATE_EN
}
@@ -52,7 +52,7 @@ const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
{t('share.generation.csvStructureTitle')}
- {docForm === ChunkingMode.qa && (
+ {docForm === DocForm.QA && (
@@ -72,7 +72,7 @@ const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
)}
- {docForm === ChunkingMode.text && (
+ {docForm === DocForm.TEXT && (
@@ -97,7 +97,7 @@ const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
bom={true}
data={getTemplate()}
>
-
+
{t('datasetDocuments.list.batchModal.template')}
diff --git a/web/app/components/datasets/documents/detail/batch-modal/index.tsx b/web/app/components/datasets/documents/detail/batch-modal/index.tsx
index c666ba67152988..139a364cb40292 100644
--- a/web/app/components/datasets/documents/detail/batch-modal/index.tsx
+++ b/web/app/components/datasets/documents/detail/batch-modal/index.tsx
@@ -7,11 +7,11 @@ import CSVUploader from './csv-uploader'
import CSVDownloader from './csv-downloader'
import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
-import type { ChunkingMode } from '@/models/datasets'
+import type { DocForm } from '@/models/datasets'
export type IBatchModalProps = {
isShow: boolean
- docForm: ChunkingMode
+ docForm: DocForm
onCancel: () => void
onConfirm: (file: File) => void
}
diff --git a/web/app/components/datasets/documents/detail/completed/InfiniteVirtualList.tsx b/web/app/components/datasets/documents/detail/completed/InfiniteVirtualList.tsx
new file mode 100644
index 00000000000000..7b510bcf21b626
--- /dev/null
+++ b/web/app/components/datasets/documents/detail/completed/InfiniteVirtualList.tsx
@@ -0,0 +1,98 @@
+import type { CSSProperties, FC } from 'react'
+import React from 'react'
+import { FixedSizeList as List } from 'react-window'
+import InfiniteLoader from 'react-window-infinite-loader'
+import SegmentCard from './SegmentCard'
+import s from './style.module.css'
+import type { SegmentDetailModel } from '@/models/datasets'
+
+type IInfiniteVirtualListProps = {
+ hasNextPage?: boolean // Are there more items to load? (This information comes from the most recent API request.)
+ isNextPageLoading: boolean // Are we currently loading a page of items? (This may be an in-flight flag in your Redux store for example.)
+ items: Array
// Array of items loaded so far.
+ loadNextPage: () => Promise // Callback function responsible for loading the next page of items.
+ onClick: (detail: SegmentDetailModel) => void
+ onChangeSwitch: (segId: string, enabled: boolean) => Promise
+ onDelete: (segId: string) => Promise
+ archived?: boolean
+ embeddingAvailable: boolean
+}
+
+const InfiniteVirtualList: FC = ({
+ hasNextPage,
+ isNextPageLoading,
+ items,
+ loadNextPage,
+ onClick: onClickCard,
+ onChangeSwitch,
+ onDelete,
+ archived,
+ embeddingAvailable,
+}) => {
+ // If there are more items to be loaded then add an extra row to hold a loading indicator.
+ const itemCount = hasNextPage ? items.length + 1 : items.length
+
+ // Only load 1 page of items at a time.
+ // Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
+ const loadMoreItems = isNextPageLoading ? () => { } : loadNextPage
+
+ // Every row is loaded except for our loading indicator row.
+ const isItemLoaded = (index: number) => !hasNextPage || index < items.length
+
+ // Render an item or a loading indicator.
+ const Item = ({ index, style }: { index: number; style: CSSProperties }) => {
+ let content
+ if (!isItemLoaded(index)) {
+ content = (
+ <>
+ {[1, 2, 3].map(v => (
+
+ ))}
+ >
+ )
+ }
+ else {
+ content = items[index].map(segItem => (
+ onClickCard(segItem)}
+ onChangeSwitch={onChangeSwitch}
+ onDelete={onDelete}
+ loading={false}
+ archived={archived}
+ embeddingAvailable={embeddingAvailable}
+ />
+ ))
+ }
+
+ return (
+
+ {content}
+
+ )
+ }
+
+ return (
+
+ {({ onItemsRendered, ref }) => (
+
+ {Item}
+
+ )}
+
+ )
+}
+export default InfiniteVirtualList
diff --git a/web/app/components/datasets/documents/detail/completed/SegmentCard.tsx b/web/app/components/datasets/documents/detail/completed/SegmentCard.tsx
index 264d62b68a4f32..5b76acc9360c69 100644
--- a/web/app/components/datasets/documents/detail/completed/SegmentCard.tsx
+++ b/web/app/components/datasets/documents/detail/completed/SegmentCard.tsx
@@ -6,9 +6,9 @@ import {
RiDeleteBinLine,
} from '@remixicon/react'
import { StatusItem } from '../../list'
-import style from '../../style.module.css'
+import { DocumentTitle } from '../index'
import s from './style.module.css'
-import { SegmentIndexTag } from './common/segment-index-tag'
+import { SegmentIndexTag } from './index'
import cn from '@/utils/classnames'
import Confirm from '@/app/components/base/confirm'
import Switch from '@/app/components/base/switch'
@@ -31,22 +31,6 @@ const ProgressBar: FC<{ percent: number; loading: boolean }> = ({ percent, loadi
)
}
-type DocumentTitleProps = {
- extension?: string
- name?: string
- iconCls?: string
- textCls?: string
- wrapperCls?: string
-}
-
-const DocumentTitle: FC = ({ extension, name, iconCls, textCls, wrapperCls }) => {
- const localExtension = extension?.toLowerCase() || name?.split('.')?.pop()?.toLowerCase()
- return
-}
-
export type UsageScene = 'doc' | 'hitTesting'
type ISegmentCardProps = {
diff --git a/web/app/components/datasets/documents/detail/completed/child-segment-detail.tsx b/web/app/components/datasets/documents/detail/completed/child-segment-detail.tsx
deleted file mode 100644
index 085bfddc163415..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/child-segment-detail.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import React, { type FC, useMemo, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import {
- RiCloseLine,
- RiExpandDiagonalLine,
-} from '@remixicon/react'
-import ActionButtons from './common/action-buttons'
-import ChunkContent from './common/chunk-content'
-import Dot from './common/dot'
-import { SegmentIndexTag } from './common/segment-index-tag'
-import { useSegmentListContext } from './index'
-import type { ChildChunkDetail, ChunkingMode } from '@/models/datasets'
-import { useEventEmitterContextContext } from '@/context/event-emitter'
-import { formatNumber } from '@/utils/format'
-import classNames from '@/utils/classnames'
-import Divider from '@/app/components/base/divider'
-import { formatTime } from '@/utils/time'
-
-type IChildSegmentDetailProps = {
- chunkId: string
- childChunkInfo?: Partial & { id: string }
- onUpdate: (segmentId: string, childChunkId: string, content: string) => void
- onCancel: () => void
- docForm: ChunkingMode
-}
-
-/**
- * Show all the contents of the segment
- */
-const ChildSegmentDetail: FC = ({
- chunkId,
- childChunkInfo,
- onUpdate,
- onCancel,
- docForm,
-}) => {
- const { t } = useTranslation()
- const [content, setContent] = useState(childChunkInfo?.content || '')
- const { eventEmitter } = useEventEmitterContextContext()
- const [loading, setLoading] = useState(false)
- const fullScreen = useSegmentListContext(s => s.fullScreen)
- const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen)
-
- eventEmitter?.useSubscription((v) => {
- if (v === 'update-child-segment')
- setLoading(true)
- if (v === 'update-child-segment-done')
- setLoading(false)
- })
-
- const handleCancel = () => {
- onCancel()
- setContent(childChunkInfo?.content || '')
- }
-
- const handleSave = () => {
- onUpdate(chunkId, childChunkInfo?.id || '', content)
- }
-
- const wordCountText = useMemo(() => {
- const count = content.length
- return `${formatNumber(count)} ${t('datasetDocuments.segment.characters', { count })}`
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [content.length])
-
- const EditTimeText = useMemo(() => {
- const timeText = formatTime({
- date: (childChunkInfo?.updated_at ?? 0) * 1000,
- dateFormat: 'MM/DD/YYYY h:mm:ss',
- })
- return `${t('datasetDocuments.segment.editedAt')} ${timeText}`
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [childChunkInfo?.updated_at])
-
- return (
-
-
-
-
{t('datasetDocuments.segment.editChildChunk')}
-
-
-
- {wordCountText}
-
-
- {EditTimeText}
-
-
-
-
- {fullScreen && (
- <>
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
- setContent(content)}
- isEditMode={true}
- />
-
-
- {!fullScreen && (
-
- )}
-
- )
-}
-
-export default React.memo(ChildSegmentDetail)
diff --git a/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx b/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx
deleted file mode 100644
index 1615ea98cf045a..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx
+++ /dev/null
@@ -1,195 +0,0 @@
-import { type FC, useMemo, useState } from 'react'
-import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
-import { useTranslation } from 'react-i18next'
-import { EditSlice } from '../../../formatted-text/flavours/edit-slice'
-import { useDocumentContext } from '../index'
-import { FormattedText } from '../../../formatted-text/formatted'
-import Empty from './common/empty'
-import FullDocListSkeleton from './skeleton/full-doc-list-skeleton'
-import { useSegmentListContext } from './index'
-import type { ChildChunkDetail } from '@/models/datasets'
-import Input from '@/app/components/base/input'
-import classNames from '@/utils/classnames'
-import Divider from '@/app/components/base/divider'
-import { formatNumber } from '@/utils/format'
-
-type IChildSegmentCardProps = {
- childChunks: ChildChunkDetail[]
- parentChunkId: string
- handleInputChange?: (value: string) => void
- handleAddNewChildChunk?: (parentChunkId: string) => void
- enabled: boolean
- onDelete?: (segId: string, childChunkId: string) => Promise
- onClickSlice?: (childChunk: ChildChunkDetail) => void
- total?: number
- inputValue?: string
- onClearFilter?: () => void
- isLoading?: boolean
- focused?: boolean
-}
-
-const ChildSegmentList: FC = ({
- childChunks,
- parentChunkId,
- handleInputChange,
- handleAddNewChildChunk,
- enabled,
- onDelete,
- onClickSlice,
- total,
- inputValue,
- onClearFilter,
- isLoading,
- focused = false,
-}) => {
- const { t } = useTranslation()
- const parentMode = useDocumentContext(s => s.parentMode)
- const currChildChunk = useSegmentListContext(s => s.currChildChunk)
-
- const [collapsed, setCollapsed] = useState(true)
-
- const toggleCollapse = () => {
- setCollapsed(!collapsed)
- }
-
- const isParagraphMode = useMemo(() => {
- return parentMode === 'paragraph'
- }, [parentMode])
-
- const isFullDocMode = useMemo(() => {
- return parentMode === 'full-doc'
- }, [parentMode])
-
- const contentOpacity = useMemo(() => {
- return (enabled || focused) ? '' : 'opacity-50 group-hover/card:opacity-100'
- }, [enabled, focused])
-
- const totalText = useMemo(() => {
- const isSearch = inputValue !== '' && isFullDocMode
- if (!isSearch) {
- const text = isFullDocMode
- ? !total
- ? '--'
- : formatNumber(total)
- : formatNumber(childChunks.length)
- const count = isFullDocMode
- ? text === '--'
- ? 0
- : total
- : childChunks.length
- return `${text} ${t('datasetDocuments.segment.childChunks', { count })}`
- }
- else {
- const text = !total ? '--' : formatNumber(total)
- const count = text === '--' ? 0 : total
- return `${count} ${t('datasetDocuments.segment.searchResults', { count })}`
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [isFullDocMode, total, childChunks.length, inputValue])
-
- return (
-
- {isFullDocMode ?
: null}
-
-
{
- event.stopPropagation()
- toggleCollapse()
- }}
- >
- {
- isParagraphMode
- ? collapsed
- ? (
-
- )
- : ()
- : null
- }
- {totalText}
- ·
-
-
- {isFullDocMode
- ?
handleInputChange?.(e.target.value)}
- onClear={() => handleInputChange?.('')}
- />
- : null}
-
- {isLoading ?
: null}
- {((isFullDocMode && !isLoading) || !collapsed)
- ?
- {isParagraphMode && (
-
- )}
- {childChunks.length > 0
- ?
- {childChunks.map((childChunk) => {
- const edited = childChunk.updated_at !== childChunk.created_at
- const focused = currChildChunk?.childChunkInfo?.id === childChunk.id
- return onDelete?.(childChunk.segment_id, childChunk.id)}
- labelClassName={focused ? 'bg-state-accent-solid text-text-primary-on-surface' : ''}
- labelInnerClassName={'text-[10px] font-semibold align-bottom leading-6'}
- contentClassName={classNames('!leading-6', focused ? 'bg-state-accent-hover-alt text-text-primary' : '')}
- showDivider={false}
- onClick={(e) => {
- e.stopPropagation()
- onClickSlice?.(childChunk)
- }}
- offsetOptions={({ rects }) => {
- return {
- mainAxis: isFullDocMode ? -rects.floating.width : 12 - rects.floating.width,
- crossAxis: (20 - rects.floating.height) / 2,
- }
- }}
- />
- })}
-
- : inputValue !== ''
- ?
-
-
- : null
- }
-
- : null}
-
- )
-}
-
-export default ChildSegmentList
diff --git a/web/app/components/datasets/documents/detail/completed/common/action-buttons.tsx b/web/app/components/datasets/documents/detail/completed/common/action-buttons.tsx
deleted file mode 100644
index 1238d98a9c5025..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/common/action-buttons.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import React, { type FC, useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import { useKeyPress } from 'ahooks'
-import { useDocumentContext } from '../../index'
-import Button from '@/app/components/base/button'
-import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
-
-type IActionButtonsProps = {
- handleCancel: () => void
- handleSave: () => void
- loading: boolean
- actionType?: 'edit' | 'add'
- handleRegeneration?: () => void
- isChildChunk?: boolean
-}
-
-const ActionButtons: FC = ({
- handleCancel,
- handleSave,
- loading,
- actionType = 'edit',
- handleRegeneration,
- isChildChunk = false,
-}) => {
- const { t } = useTranslation()
- const mode = useDocumentContext(s => s.mode)
- const parentMode = useDocumentContext(s => s.parentMode)
-
- useKeyPress(['esc'], (e) => {
- e.preventDefault()
- handleCancel()
- })
-
- useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.s`, (e) => {
- e.preventDefault()
- if (loading)
- return
- handleSave()
- }
- , { exactMatch: true, useCapture: true })
-
- const isParentChildParagraphMode = useMemo(() => {
- return mode === 'hierarchical' && parentMode === 'paragraph'
- }, [mode, parentMode])
-
- return (
-
-
- {(isParentChildParagraphMode && actionType === 'edit' && !isChildChunk)
- ?
- : null
- }
-
-
- )
-}
-
-ActionButtons.displayName = 'ActionButtons'
-
-export default React.memo(ActionButtons)
diff --git a/web/app/components/datasets/documents/detail/completed/common/add-another.tsx b/web/app/components/datasets/documents/detail/completed/common/add-another.tsx
deleted file mode 100644
index 444560e55f7f6b..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/common/add-another.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import React, { type FC } from 'react'
-import { useTranslation } from 'react-i18next'
-import classNames from '@/utils/classnames'
-import Checkbox from '@/app/components/base/checkbox'
-
-type AddAnotherProps = {
- className?: string
- isChecked: boolean
- onCheck: () => void
-}
-
-const AddAnother: FC = ({
- className,
- isChecked,
- onCheck,
-}) => {
- const { t } = useTranslation()
-
- return (
-
-
- {t('datasetDocuments.segment.addAnother')}
-
- )
-}
-
-export default React.memo(AddAnother)
diff --git a/web/app/components/datasets/documents/detail/completed/common/batch-action.tsx b/web/app/components/datasets/documents/detail/completed/common/batch-action.tsx
deleted file mode 100644
index 3dd3689b64fb43..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/common/batch-action.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import React, { type FC } from 'react'
-import { RiArchive2Line, RiCheckboxCircleLine, RiCloseCircleLine, RiDeleteBinLine } from '@remixicon/react'
-import { useTranslation } from 'react-i18next'
-import { useBoolean } from 'ahooks'
-import Divider from '@/app/components/base/divider'
-import classNames from '@/utils/classnames'
-import Confirm from '@/app/components/base/confirm'
-
-const i18nPrefix = 'dataset.batchAction'
-type IBatchActionProps = {
- className?: string
- selectedIds: string[]
- onBatchEnable: () => void
- onBatchDisable: () => void
- onBatchDelete: () => Promise
- onArchive?: () => void
- onCancel: () => void
-}
-
-const BatchAction: FC = ({
- className,
- selectedIds,
- onBatchEnable,
- onBatchDisable,
- onArchive,
- onBatchDelete,
- onCancel,
-}) => {
- const { t } = useTranslation()
- const [isShowDeleteConfirm, {
- setTrue: showDeleteConfirm,
- setFalse: hideDeleteConfirm,
- }] = useBoolean(false)
- const [isDeleting, {
- setTrue: setIsDeleting,
- }] = useBoolean(false)
-
- const handleBatchDelete = async () => {
- setIsDeleting()
- await onBatchDelete()
- hideDeleteConfirm()
- }
- return (
-
-
-
-
- {selectedIds.length}
-
- {t(`${i18nPrefix}.selected`)}
-
-
-
-
-
-
-
-
-
-
- {onArchive && (
-
-
-
-
- )}
-
-
-
-
-
-
-
-
- {
- isShowDeleteConfirm && (
-
- )
- }
-
- )
-}
-
-export default React.memo(BatchAction)
diff --git a/web/app/components/datasets/documents/detail/completed/common/chunk-content.tsx b/web/app/components/datasets/documents/detail/completed/common/chunk-content.tsx
deleted file mode 100644
index e6403fa12fd0aa..00000000000000
--- a/web/app/components/datasets/documents/detail/completed/common/chunk-content.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react'
-import type { ComponentProps, FC } from 'react'
-import { useTranslation } from 'react-i18next'
-import { ChunkingMode } from '@/models/datasets'
-import classNames from '@/utils/classnames'
-
-type IContentProps = ComponentProps<'textarea'>
-
-const Textarea: FC = React.memo(({
- value,
- placeholder,
- className,
- disabled,
- ...rest
-}) => {
- return (
-
- )
-})
-
-Textarea.displayName = 'Textarea'
-
-type IAutoResizeTextAreaProps = ComponentProps<'textarea'> & {
- containerRef: React.RefObject
- labelRef: React.RefObject
-}
-
-const AutoResizeTextArea: FC = React.memo(({
- className,
- placeholder,
- value,
- disabled,
- containerRef,
- labelRef,
- ...rest
-}) => {
- const textareaRef = useRef(null)
- const observerRef = useRef()
- const [maxHeight, setMaxHeight] = useState(0)
-
- useEffect(() => {
- const textarea = textareaRef.current
- if (!textarea)
- return
- textarea.style.height = 'auto'
- const lineHeight = parseInt(getComputedStyle(textarea).lineHeight)
- const textareaHeight = Math.max(textarea.scrollHeight, lineHeight)
- textarea.style.height = `${textareaHeight}px`
- }, [value])
-
- useEffect(() => {
- const container = containerRef.current
- const label = labelRef.current
- if (!container || !label)
- return
- const updateMaxHeight = () => {
- const containerHeight = container.clientHeight
- const labelHeight = label.clientHeight
- const padding = 32
- const space = 12
- const maxHeight = Math.floor((containerHeight - 2 * labelHeight - padding - space) / 2)
- setMaxHeight(maxHeight)
- }
- updateMaxHeight()
- observerRef.current = new ResizeObserver(updateMaxHeight)
- observerRef.current.observe(container)
- return () => {
- observerRef.current?.disconnect()
- }
- }, [])
-
- return (
-
- )
-})
-
-AutoResizeTextArea.displayName = 'AutoResizeTextArea'
-
-type IQATextAreaProps = {
- question: string
- answer?: string
- onQuestionChange: (question: string) => void
- onAnswerChange?: (answer: string) => void
- isEditMode?: boolean
-}
-
-const QATextArea: FC = React.memo(({
- question,
- answer,
- onQuestionChange,
- onAnswerChange,
- isEditMode = true,
-}) => {
- const { t } = useTranslation()
- const containerRef = useRef(null)
- const labelRef = useRef(null)
-
- return (
-
-
QUESTION
-
onQuestionChange(e.target.value)}
- disabled={!isEditMode}
- containerRef={containerRef}
- labelRef={labelRef}
- />
- ANSWER
- onAnswerChange?.(e.target.value)}
- disabled={!isEditMode}
- autoFocus
- containerRef={containerRef}
- labelRef={labelRef}
- />
-
- )
-})
-
-QATextArea.displayName = 'QATextArea'
-
-type IChunkContentProps = {
- question: string
- answer?: string
- onQuestionChange: (question: string) => void
- onAnswerChange?: (answer: string) => void
- isEditMode?: boolean
- docForm: ChunkingMode
-}
-
-const ChunkContent: FC = ({
- question,
- answer,
- onQuestionChange,
- onAnswerChange,
- isEditMode,
- docForm,
-}) => {
- const { t } = useTranslation()
-
- if (docForm === ChunkingMode.qa) {
- return
- }
-
- return (
-