From b8ced5102c291fe16b2b7d0a11b91c3cd5fa6f0e Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 14:29:50 +0800 Subject: [PATCH 01/12] feat: new retrieval result ui --- .../base/file-uploader/file-type-icon.tsx | 4 +- .../documents/detail/completed/index.tsx | 37 +++++---- .../datasets/hit-testing/assets/test-data.ts | 12 ++- .../components/child-chunks-item.tsx | 31 +++++++ .../components/chunk-detail-modal.tsx | 83 +++++++++++++++++++ .../hit-testing/components/result-item.tsx | 77 ++++++++++++++++- .../datasets/hit-testing/components/score.tsx | 22 +++++ .../components/datasets/hit-testing/index.tsx | 16 +--- web/models/datasets.ts | 6 ++ 9 files changed, 249 insertions(+), 39 deletions(-) create mode 100644 web/app/components/datasets/hit-testing/components/child-chunks-item.tsx create mode 100644 web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx create mode 100644 web/app/components/datasets/hit-testing/components/score.tsx diff --git a/web/app/components/base/file-uploader/file-type-icon.tsx b/web/app/components/base/file-uploader/file-type-icon.tsx index 193a630dee..4e31ab66a8 100644 --- a/web/app/components/base/file-uploader/file-type-icon.tsx +++ b/web/app/components/base/file-uploader/file-type-icon.tsx @@ -82,8 +82,8 @@ const FileTypeIcon = ({ size = 'sm', className, }: FileTypeIconProps) => { - const Icon = FILE_TYPE_ICON_MAP[type].component || FileAppearanceTypeEnum.custom - const color = FILE_TYPE_ICON_MAP[type].color + const Icon = FILE_TYPE_ICON_MAP[type]?.component || FileAppearanceTypeEnum.custom + const color = FILE_TYPE_ICON_MAP[type]?.color || FILE_TYPE_ICON_MAP.custom.color return } diff --git a/web/app/components/datasets/documents/detail/completed/index.tsx b/web/app/components/datasets/documents/detail/completed/index.tsx index 0b5414a816..5cc8b3258d 100644 --- a/web/app/components/datasets/documents/detail/completed/index.tsx +++ b/web/app/components/datasets/documents/detail/completed/index.tsx @@ -42,21 +42,22 @@ type SegmentListContextValue = { const SegmentListContext = createContext({ isCollapsed: true, - toggleCollapsed: () => {}, + toggleCollapsed: () => { }, fullScreen: false, - toggleFullScreen: () => {}, + toggleFullScreen: () => { }, }) export const useSegmentListContext = (selector: (value: SegmentListContextValue) => any) => { return useContextSelector(SegmentListContext, selector) } -export const SegmentIndexTag: FC<{ positionId?: string | number; label?: string; className?: string }> = React.memo(({ positionId, label, className }) => { +export const SegmentIndexTag: FC<{ positionId?: string | number; label?: string; className?: string; isParentChildRetrieval?: boolean }> = React.memo(({ positionId, label, className, isParentChildRetrieval }) => { + const prefix = `${isParentChildRetrieval ? 'Parent-' : ''}Chunk` const localPositionId = useMemo(() => { const positionIdStr = String(positionId) if (positionIdStr.length >= 3) - return `Chunk-${positionId}` - return `Chunk-${positionIdStr.padStart(2, '0')}` + return `${prefix}-${positionId}` + return `${prefix}-${positionIdStr.padStart(2, '0')}` }, [positionId]) return (
@@ -179,7 +180,7 @@ const Completed: FC = ({ setSegments([]) setSelectedSegmentIds([]) invalidSegmentList() - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const onClickCard = (detail: SegmentDetailModel, isEditMode = false) => { @@ -210,7 +211,7 @@ const Completed: FC = ({ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }, }) - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [datasetId, documentId, selectedSegmentIds, segments]) const { mutateAsync: deleteSegment } = useDeleteSegment() @@ -226,7 +227,7 @@ const Completed: FC = ({ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }, }) - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [datasetId, documentId, selectedSegmentIds]) const onCancelBatchOperation = useCallback(() => { @@ -337,7 +338,7 @@ const Completed: FC = ({ resetList() currentPage !== totalPages && setCurrentPage(totalPages) } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [segmentListData, limit, currentPage]) return ( @@ -388,7 +389,7 @@ const Completed: FC = ({ /> {}} + handleInputChange={() => { }} enabled={!archived} />
@@ -443,14 +444,14 @@ const Completed: FC = ({ {/* Batch Action Buttons */} {selectedSegmentIds.length > 0 - && } + && } ) } diff --git a/web/app/components/datasets/hit-testing/assets/test-data.ts b/web/app/components/datasets/hit-testing/assets/test-data.ts index 39a9788afa..623f7e587c 100644 --- a/web/app/components/datasets/hit-testing/assets/test-data.ts +++ b/web/app/components/datasets/hit-testing/assets/test-data.ts @@ -1,4 +1,6 @@ -export const generalResultData = [ +import type { HitTesting } from '@/models/datasets' + +export const generalResultData: HitTesting[] = [ { segment: { id: 'b621b153-f8a7-4e85-bd3d-07feaf61bd9e', @@ -40,7 +42,13 @@ export const generalResultData = [ doc_type: null, }, }, - child_chunks: null, + child_chunks: [ + { + id: '1', + score: 0.8771945, + content: 'It is quite natural for academics who are continuously told to “publish or perish” to want to always create something from scratch that is their own fresh creation.', + }, + ], score: 0.8771945, tsne_position: null, }, diff --git a/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx new file mode 100644 index 0000000000..b685689b2e --- /dev/null +++ b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx @@ -0,0 +1,31 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { SliceContent, SliceLabel } from '../../formatted-text/flavours/shared' +import cn from '@/utils/classnames' +import type { HitTestingChildChunk } from '@/models/datasets' + +type Props = { + payload: HitTestingChildChunk + isShowAll: boolean +} + +const ChildChunks: FC = ({ + payload, + isShowAll, +}) => { + const { t } = useTranslation() + const { id, score, content } = payload + return ( +
+ + {id} {score} + + + {content} + +
+ ) +} +export default React.memo(ChildChunks) diff --git a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx new file mode 100644 index 0000000000..d7c5264c03 --- /dev/null +++ b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx @@ -0,0 +1,83 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { SegmentIndexTag } from '../../documents/detail/completed' +import Score from './score' +import ChildChunksItem from './child-chunks-item' +import Modal from '@/app/components/base/modal' +import type { HitTesting } from '@/models/datasets' +import FileIcon from '@/app/components/base/file-uploader/file-type-icon' +import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types' +import cn from '@/utils/classnames' + +type Props = { + payload: HitTesting + onHide: () => void +} + +const ChunkDetailModal: FC = ({ + payload, + onHide, +}) => { + const { t } = useTranslation() + const { segment, score, child_chunks } = payload + const { position, word_count, content, keywords, document } = segment + const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0) + const extension = document.name.split('.').slice(0, -1)[0] as FileAppearanceTypeEnum + + return ( + +
+
+ {/* Meta info */} +
+
+ +
·
+
+ + {document.name} +
+
+ +
+
+ {content} +
+ {!isParentChildRetrieval && keywords && keywords.length > 0 && ( +
+
{t('dataset.keywords')}
+ {keywords.map(keyword => ( +
{keyword}
+ ))} +
+ )} +
+ + {isParentChildRetrieval && ( +
+
{t('dataset.hitChunks', { num: child_chunks.length })}
+
+ {child_chunks.map(item => ( + + ))} +
+
+ )} +
+
+ ) +} + +export default React.memo(ChunkDetailModal) diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index 35d9d1bdf9..29c61e9de7 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -2,9 +2,17 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' +import { RiArrowDownSLine, RiArrowRightSLine, RiArrowRightUpLine } from '@remixicon/react' +import { useBoolean } from 'ahooks' import { SegmentIndexTag } from '../../documents/detail/completed' +import Score from './score' +import ChildChunkItem from './child-chunks-item' +import ChunkDetailModal from './chunk-detail-modal' import type { HitTesting } from '@/models/datasets' import cn from '@/utils/classnames' +import FileIcon from '@/app/components/base/file-uploader/file-type-icon' +import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types' + type Props = { payload: HitTesting } @@ -13,20 +21,81 @@ const ResultItem: FC = ({ payload, }) => { const { t } = useTranslation() - const { segment } = payload - const { position, word_count } = segment + const { segment, score, child_chunks } = payload + const { position, word_count, content, keywords, document } = segment + const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0) + const extension = document.name.split('.').slice(0, -1)[0] as FileAppearanceTypeEnum + const [isFold, { + toggle: toggleFold, + }] = useBoolean(false) + const Icon = isFold ? RiArrowRightSLine : RiArrowDownSLine + + const [isShowDetailModal, { + setTrue: showDetailModal, + setFalse: hideDetailModal, + }] = useBoolean(false) return (
+ {/* Meta info */}
- +
·
{word_count} {t('datasetDocuments.segment.characters')}
- {/* Score */} +
+ {/* Main */} +
+
{content}
+ {isParentChildRetrieval && ( +
+
+ +
{t('dataset.hitChunks', { num: child_chunks.length })}
+
+ {child_chunks.map(item => ( + + ))} +
+ )} + {!isParentChildRetrieval && keywords && keywords.length > 0 && ( +
+ {keywords.map(keyword => ( +
{keyword}
+ ))} +
+ )} +
+ {/* Foot */} +
+
+ + {document.name} +
+
+
{t('dataset.open')}
+ +
+
+ + { + isShowDetailModal && ( + + ) + }
) } diff --git a/web/app/components/datasets/hit-testing/components/score.tsx b/web/app/components/datasets/hit-testing/components/score.tsx new file mode 100644 index 0000000000..650ecd497f --- /dev/null +++ b/web/app/components/datasets/hit-testing/components/score.tsx @@ -0,0 +1,22 @@ +'use client' +import type { FC } from 'react' +import React from 'react' + +type Props = { + value: number +} + +const Score: FC = ({ + value, +}) => { + return ( +
+
+
+
score
+
{value.toFixed(2)}
+
+
+ ) +} +export default React.memo(Score) diff --git a/web/app/components/datasets/hit-testing/index.tsx b/web/app/components/datasets/hit-testing/index.tsx index bf3c02a84f..0aef53cd6d 100644 --- a/web/app/components/datasets/hit-testing/index.tsx +++ b/web/app/components/datasets/hit-testing/index.tsx @@ -12,6 +12,7 @@ import s from './style.module.css' import HitDetail from './hit-detail' import ModifyRetrievalModal from './modify-retrieval-modal' import { generalResultData } from './assets/test-data' +import ResultItem from './components/result-item' import cn from '@/utils/classnames' import type { ExternalKnowledgeBaseHitTestingResponse, ExternalKnowledgeBaseHitTesting as ExternalKnowledgeBaseHitTestingType, HitTestingResponse, HitTesting as HitTestingType } from '@/models/datasets' import Loading from '@/app/components/base/loading' @@ -83,20 +84,9 @@ const HitTesting: FC = ({ datasetId }: Props) => {
{results.map((record, idx) => ( - onClickCard(record)} + payload={record} /> ))}
diff --git a/web/models/datasets.ts b/web/models/datasets.ts index 10495f19e7..72e7d3751d 100644 --- a/web/models/datasets.ts +++ b/web/models/datasets.ts @@ -479,10 +479,16 @@ export type HitTestingRecord = { created_at: number } +export type HitTestingChildChunk = { + id: string + content: string + score: number +} export type HitTesting = { segment: Segment score: number tsne_position: TsnePosition + child_chunks?: HitTestingChildChunk[] | null } export type ExternalKnowledgeBaseHitTesting = { From 361a007f4246847309c5deffddcde1efbc197af8 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 14:42:14 +0800 Subject: [PATCH 02/12] feat: tags --- .../documents/detail/completed/common/tag.tsx | 5 +++-- .../hit-testing/components/chunk-detail-modal.tsx | 12 ++++++++---- .../datasets/hit-testing/components/result-item.tsx | 8 +++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/web/app/components/datasets/documents/detail/completed/common/tag.tsx b/web/app/components/datasets/documents/detail/completed/common/tag.tsx index 9517d38f1e..c88bffc736 100644 --- a/web/app/components/datasets/documents/detail/completed/common/tag.tsx +++ b/web/app/components/datasets/documents/detail/completed/common/tag.tsx @@ -1,8 +1,9 @@ import React from 'react' +import cn from '@/utils/classnames' -const Tag = ({ text }: { text: string }) => { +const Tag = ({ text, className }: { text: string; className?: string }) => { return ( -
+
# {text}
diff --git a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx index d7c5264c03..51c6ec0343 100644 --- a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx +++ b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx @@ -3,6 +3,7 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' import { SegmentIndexTag } from '../../documents/detail/completed' +import Dot from '../../documents/detail/completed/common/dot' import Score from './score' import ChildChunksItem from './child-chunks-item' import Modal from '@/app/components/base/modal' @@ -10,6 +11,7 @@ import type { HitTesting } from '@/models/datasets' import FileIcon from '@/app/components/base/file-uploader/file-type-icon' import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types' import cn from '@/utils/classnames' +import Tag from '@/app/components/datasets/documents/detail/completed/common/tag' type Props = { payload: HitTesting @@ -44,7 +46,7 @@ const ChunkDetailModal: FC = ({ positionId={position} className={cn('w-fit group-hover:opacity-100')} /> -
·
+
{document.name} @@ -58,9 +60,11 @@ const ChunkDetailModal: FC = ({ {!isParentChildRetrieval && keywords && keywords.length > 0 && (
{t('dataset.keywords')}
- {keywords.map(keyword => ( -
{keyword}
- ))} +
+ {keywords.map(keyword => ( + + ))} +
)}
diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index 29c61e9de7..9da7206601 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiArrowRightSLine, RiArrowRightUpLine } from '@remixicon/react' import { useBoolean } from 'ahooks' import { SegmentIndexTag } from '../../documents/detail/completed' +import Dot from '../../documents/detail/completed/common/dot' import Score from './score' import ChildChunkItem from './child-chunks-item' import ChunkDetailModal from './chunk-detail-modal' @@ -12,6 +13,7 @@ import type { HitTesting } from '@/models/datasets' import cn from '@/utils/classnames' import FileIcon from '@/app/components/base/file-uploader/file-type-icon' import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types' +import Tag from '@/app/components/datasets/documents/detail/completed/common/tag' type Props = { payload: HitTesting @@ -45,7 +47,7 @@ const ResultItem: FC = ({ positionId={position} className={cn('w-fit group-hover:opacity-100')} /> -
·
+
{word_count} {t('datasetDocuments.segment.characters')}
@@ -66,9 +68,9 @@ const ResultItem: FC = ({
)} {!isParentChildRetrieval && keywords && keywords.length > 0 && ( -
+
{keywords.map(keyword => ( -
{keyword}
+ ))}
)} From 17ae100342d8809d5827b479a2a03f936def618f Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 15:15:04 +0800 Subject: [PATCH 03/12] chore: result main --- .../hit-testing/components/result-item.tsx | 6 +-- .../components/datasets/hit-testing/index.tsx | 41 ++++++++----------- .../datasets/hit-testing/style.module.css | 2 +- web/i18n/en-US/dataset-hit-testing.ts | 2 +- web/i18n/zh-Hans/dataset-hit-testing.ts | 2 +- 5 files changed, 23 insertions(+), 30 deletions(-) diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index 9da7206601..e1e51bfbe9 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -38,9 +38,9 @@ const ResultItem: FC = ({ }] = useBoolean(false) return ( -
+
{/* Meta info */} -
+
= ({
{/* Main */} -
+
{content}
{isParentChildRetrieval && (
diff --git a/web/app/components/datasets/hit-testing/index.tsx b/web/app/components/datasets/hit-testing/index.tsx index 0aef53cd6d..f82edf0267 100644 --- a/web/app/components/datasets/hit-testing/index.tsx +++ b/web/app/components/datasets/hit-testing/index.tsx @@ -65,33 +65,26 @@ const HitTesting: FC = ({ datasetId }: Props) => { const total = recordsRes?.total || 0 - const onClickCard = (detail: HitTestingType) => { - setCurrParagraph({ paraInfo: detail, showModal: true }) - } - - const onClickExternalCard = (detail: ExternalKnowledgeBaseHitTestingType) => { - setExternalCurrParagraph({ paraInfo: detail, showModal: true }) - } const { dataset: currentDataset } = useContext(DatasetDetailContext) const isExternal = currentDataset?.provider === 'external' const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig) const [isShowModifyRetrievalModal, setIsShowModifyRetrievalModal] = useState(false) const [isShowRightPanel, { setTrue: showRightPanel, setFalse: hideRightPanel, set: setShowRightPanel }] = useBoolean(!isMobile) - const renderHitResults = (results: any[], onClickCard: (record: any) => void) => ( - <> -
{t('datasetHitTesting.hit.title')}
-
-
- {results.map((record, idx) => ( - - ))} -
+ const renderHitResults = (results: any[]) => ( +
+
+ {t('datasetHitTesting.hit.title', { num: results.length })}
- +
+ {results.map((record, idx) => ( + + ))} +
+
) const renderEmptyState = () => ( @@ -180,8 +173,8 @@ const HitTesting: FC = ({ datasetId }: Props) => { )}
-
- {renderHitResults(generalResultData, onClickCard)} +
+ {renderHitResults(generalResultData)} {submitLoading ?
= ({ datasetId }: Props) => { return renderEmptyState() if (hitResult?.records.length) - return renderHitResults(hitResult.records, onClickCard) + return renderHitResults(hitResult.records) - return renderHitResults(externalHitResult?.records || [], onClickExternalCard) + return renderHitResults(externalHitResult?.records || []) })() ) } diff --git a/web/app/components/datasets/hit-testing/style.module.css b/web/app/components/datasets/hit-testing/style.module.css index 1e90902a70..7d83b8abb6 100644 --- a/web/app/components/datasets/hit-testing/style.module.css +++ b/web/app/components/datasets/hit-testing/style.module.css @@ -5,7 +5,7 @@ @apply flex-1 h-full; } .leftDiv { - @apply border-r border-gray-100 px-6 py-3 flex flex-col; + @apply px-6 py-3 flex flex-col; } .rightDiv { @apply flex flex-col; diff --git a/web/i18n/en-US/dataset-hit-testing.ts b/web/i18n/en-US/dataset-hit-testing.ts index 6dbfa47fee..385d68c771 100644 --- a/web/i18n/en-US/dataset-hit-testing.ts +++ b/web/i18n/en-US/dataset-hit-testing.ts @@ -19,7 +19,7 @@ const translation = { testing: 'Testing', }, hit: { - title: 'RETRIEVAL PARAGRAPHS', + title: '{{num}} Retrieved Chunks', emptyTip: 'Retrieval Testing results will show here', }, noRecentTip: 'No recent query results here', diff --git a/web/i18n/zh-Hans/dataset-hit-testing.ts b/web/i18n/zh-Hans/dataset-hit-testing.ts index 09cfdc2824..6aba135c71 100644 --- a/web/i18n/zh-Hans/dataset-hit-testing.ts +++ b/web/i18n/zh-Hans/dataset-hit-testing.ts @@ -19,7 +19,7 @@ const translation = { testing: '测试', }, hit: { - title: '召回段落', + title: '{{num}} 个召回段落', emptyTip: '召回测试结果将展示在这里', }, noRecentTip: '最近无查询结果', From 149cfaafc516469314b359ff2676486bb7350e8f Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Wed, 11 Dec 2024 15:45:05 +0800 Subject: [PATCH 04/12] feat: add switch to high quan dialog --- .../datasets/create/step-two/index.module.css | 2 +- .../datasets/create/step-two/index.tsx | 30 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) 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 db4c616363..bda6138153 100644 --- a/web/app/components/datasets/create/step-two/index.module.css +++ b/web/app/components/datasets/create/step-two/index.module.css @@ -76,7 +76,7 @@ } .disabled { - cursor: not-allowed; + cursor: not-allowed !important; } .indexItem.disabled:hover { diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 023f555681..7c80bfb859 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -58,6 +58,7 @@ import { getNotionInfo, getWebsiteInfo, useCreateDocument, useCreateFirstDocumen import Badge from '@/app/components/base/badge' import { SkeletonContanier, SkeletonPoint, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton' import Tooltip from '@/app/components/base/tooltip' +import CustomDialog from '@/app/components/base/dialog' const TextLabel: FC = (props) => { return @@ -175,16 +176,19 @@ const StepTwo = ({ ) // QA Related - const [isLanguageSelectDisabled, setIsLanguageSelectDisabled] = useState(false) + const [isLanguageSelectDisabled, _setIsLanguageSelectDisabled] = useState(false) + const [isQAConfirmDialogOpen, setIsQAConfirmDialogOpen] = useState(false) const [docForm, setDocForm] = useState( (datasetId && documentDetail) ? documentDetail.doc_form as ChuckingMode : ChuckingMode.text, ) const handleChangeDocform = (value: ChuckingMode) => { + if (value === ChuckingMode.qa && indexType === IndexingType.ECONOMICAL) { + setIsQAConfirmDialogOpen(true) + return + } setDocForm(value) // eslint-disable-next-line @typescript-eslint/no-use-before-define currentEstimateMutation.reset() - if (value === ChuckingMode.parentChild) - setIndexType(IndexingType.QUALIFIED) } const [docLanguage, setDocLanguage] = useState( @@ -832,10 +836,28 @@ const StepTwo = ({ !hasSetIndexType && indexType === IndexingType.ECONOMICAL && s.active, hasSetIndexType && s.disabled, hasSetIndexType && '!w-full !min-h-[96px]', - docForm === ChuckingMode.parentChild && s.disabled, + docForm !== ChuckingMode.text && s.disabled, )} onClick={changeToEconomicalType} > + setIsQAConfirmDialogOpen(false)} className='w-[432px]'> +
+

Q&A Format Requires High-quality Indexing Method

+

Currently, only high-quality index method supports Q&A format chunking. Would you like to switch to high-quality mode?

+
+
+ + +
+
Economical Icon
From 599345879e07d85fefe52b6c38fa557374d0e5d9 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 16:34:32 +0800 Subject: [PATCH 05/12] feat: result ui --- .../datasets/hit-testing/assets/test-data.ts | 5 ++++ .../components/child-chunks-item.tsx | 21 ++++++++--------- .../components/chunk-detail-modal.tsx | 20 ++++++++-------- .../hit-testing/components/result-item.tsx | 23 +++++++++++-------- .../datasets/hit-testing/components/score.tsx | 7 ++++-- web/i18n/en-US/dataset-hit-testing.ts | 4 ++++ web/i18n/zh-Hans/dataset-hit-testing.ts | 4 ++++ 7 files changed, 53 insertions(+), 31 deletions(-) diff --git a/web/app/components/datasets/hit-testing/assets/test-data.ts b/web/app/components/datasets/hit-testing/assets/test-data.ts index 623f7e587c..035bfcc827 100644 --- a/web/app/components/datasets/hit-testing/assets/test-data.ts +++ b/web/app/components/datasets/hit-testing/assets/test-data.ts @@ -48,6 +48,11 @@ export const generalResultData: HitTesting[] = [ score: 0.8771945, content: 'It is quite natural for academics who are continuously told to “publish or perish” to want to always create something from scratch that is their own fresh creation.', }, + { + id: '2', + score: 0.5, + content: 'It is quite natural for ', + }, ], score: 0.8771945, tsne_position: null, diff --git a/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx index b685689b2e..f6be610114 100644 --- a/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx +++ b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx @@ -1,9 +1,8 @@ 'use client' import type { FC } from 'react' import React from 'react' -import { useTranslation } from 'react-i18next' -import { SliceContent, SliceLabel } from '../../formatted-text/flavours/shared' -import cn from '@/utils/classnames' +import { SliceContent } from '../../formatted-text/flavours/shared' +import Score from './score' import type { HitTestingChildChunk } from '@/models/datasets' type Props = { @@ -15,16 +14,16 @@ const ChildChunks: FC = ({ payload, isShowAll, }) => { - const { t } = useTranslation() const { id, score, content } = payload return ( -
- - {id} {score} - - - {content} - +
+
+
C-{id}
+ +
+ {content}
) } diff --git a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx index 51c6ec0343..18e89f5890 100644 --- a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx +++ b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx @@ -13,6 +13,8 @@ import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader import cn from '@/utils/classnames' import Tag from '@/app/components/datasets/documents/detail/completed/common/tag' +const i18nPrefix = 'datasetHitTesting' + type Props = { payload: HitTesting onHide: () => void @@ -24,19 +26,19 @@ const ChunkDetailModal: FC = ({ }) => { const { t } = useTranslation() const { segment, score, child_chunks } = payload - const { position, word_count, content, keywords, document } = segment + const { position, content, keywords, document } = segment const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0) const extension = document.name.split('.').slice(0, -1)[0] as FileAppearanceTypeEnum - + const maxHeighClassName = 'max-h-[752px] overflow-y-auto' return ( -
+
{/* Meta info */}
@@ -54,12 +56,12 @@ const ChunkDetailModal: FC = ({
-
+
{content}
{!isParentChildRetrieval && keywords && keywords.length > 0 && ( -
-
{t('dataset.keywords')}
+
+
{t(`${i18nPrefix}.keyword`)}
{keywords.map(keyword => ( @@ -71,8 +73,8 @@ const ChunkDetailModal: FC = ({ {isParentChildRetrieval && (
-
{t('dataset.hitChunks', { num: child_chunks.length })}
-
+
{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}
+
{child_chunks.map(item => ( ))} diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index e1e51bfbe9..e8f85baf9f 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -15,6 +15,7 @@ import FileIcon from '@/app/components/base/file-uploader/file-type-icon' import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types' import Tag from '@/app/components/datasets/documents/detail/completed/common/tag' +const i18nPrefix = 'datasetHitTesting' type Props = { payload: HitTesting } @@ -54,17 +55,21 @@ const ResultItem: FC = ({
{/* Main */} -
-
{content}
+
+
{content}
{isParentChildRetrieval && ( -
+
-
{t('dataset.hitChunks', { num: child_chunks.length })}
+
{t(`${i18nPrefix}.dataset.hitChunks`, { num: child_chunks.length })}
+
+
+ {child_chunks.map(item => ( +
+ +
+ ))}
- {child_chunks.map(item => ( - - ))}
)} {!isParentChildRetrieval && keywords && keywords.length > 0 && ( @@ -76,7 +81,7 @@ const ResultItem: FC = ({ )}
{/* Foot */} -
+
{document.name} @@ -85,7 +90,7 @@ const ResultItem: FC = ({ className='flex items-center space-x-1 cursor-pointer text-text-tertiary' onClick={showDetailModal} > -
{t('dataset.open')}
+
{t(`${i18nPrefix}.open`)}
diff --git a/web/app/components/datasets/hit-testing/components/score.tsx b/web/app/components/datasets/hit-testing/components/score.tsx index 650ecd497f..bcbcabf20e 100644 --- a/web/app/components/datasets/hit-testing/components/score.tsx +++ b/web/app/components/datasets/hit-testing/components/score.tsx @@ -1,18 +1,21 @@ 'use client' import type { FC } from 'react' import React from 'react' +import cn from '@/utils/classnames' type Props = { value: number + besideChunkName?: boolean } const Score: FC = ({ value, + besideChunkName, }) => { return ( -
+
-
+
score
{value.toFixed(2)}
diff --git a/web/i18n/en-US/dataset-hit-testing.ts b/web/i18n/en-US/dataset-hit-testing.ts index 385d68c771..8b8629e90a 100644 --- a/web/i18n/en-US/dataset-hit-testing.ts +++ b/web/i18n/en-US/dataset-hit-testing.ts @@ -25,6 +25,10 @@ const translation = { noRecentTip: 'No recent query results here', viewChart: 'View VECTOR CHART', viewDetail: 'View Detail', + chunkDetail: 'Chunk Detail', + hitChunks: 'Hit {{num}} child chunks', + open: 'Open', + keyword: 'Keywords', } export default translation diff --git a/web/i18n/zh-Hans/dataset-hit-testing.ts b/web/i18n/zh-Hans/dataset-hit-testing.ts index 6aba135c71..caf88acc76 100644 --- a/web/i18n/zh-Hans/dataset-hit-testing.ts +++ b/web/i18n/zh-Hans/dataset-hit-testing.ts @@ -25,6 +25,10 @@ const translation = { noRecentTip: '最近无查询结果', viewChart: '查看向量图表', viewDetail: '查看详情', + chunkDetail: '段落详情', + hitChunks: '命中 {{num}} 个子段落', + open: '打开', + keyword: '关键词', } export default translation From f969dce345a26c33d3d6f14bf955c52886e23204 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Wed, 11 Dec 2024 16:50:32 +0800 Subject: [PATCH 06/12] feat: switch to high quan modal --- .../datasets/create/step-two/index.tsx | 21 +++++++++++-------- web/i18n/en-US/dataset-creation.ts | 3 +++ web/i18n/zh-Hans/dataset-creation.ts | 3 +++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 7c80bfb859..b87c1bf9e2 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -517,14 +517,11 @@ const StepTwo = ({ } const changeToEconomicalType = () => { - if (docForm === ChuckingMode.parentChild) + if (docForm !== ChuckingMode.text) return - if (!hasSetIndexType) { + if (!hasSetIndexType) setIndexType(IndexingType.ECONOMICAL) - if (docForm === ChuckingMode.qa) - handleChangeDocform(ChuckingMode.text) - } } useEffect(() => { @@ -842,19 +839,25 @@ const StepTwo = ({ > setIsQAConfirmDialogOpen(false)} className='w-[432px]'>
-

Q&A Format Requires High-quality Indexing Method

-

Currently, only high-quality index method supports Q&A format chunking. Would you like to switch to high-quality mode?

+

+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')} +

+

+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')} +

+ }}> + {t('datasetCreation.stepTwo.cancel')} +
diff --git a/web/i18n/en-US/dataset-creation.ts b/web/i18n/en-US/dataset-creation.ts index 014f9a1a93..cbd02d10eb 100644 --- a/web/i18n/en-US/dataset-creation.ts +++ b/web/i18n/en-US/dataset-creation.ts @@ -166,6 +166,9 @@ const translation = { datasetSettingLink: 'Knowledge settings.', previewChunkTip: 'Click the \'Preview Chunk\' button on the left to load the preview', previewChunkCount: '{{count}} Estimated chunks', + switch: 'Switch', + qaSwitchHighQualityTipTitle: 'Q&A Format Requires High-quality Indexing Method', + qaSwitchHighQualityTipContent: 'Currently, only high-quality index method supports Q&A format chunking. Would you like to switch to high-quality mode?', }, stepThree: { creationTitle: '🎉 Knowledge created', diff --git a/web/i18n/zh-Hans/dataset-creation.ts b/web/i18n/zh-Hans/dataset-creation.ts index c8f64777fb..5fa9beaf76 100644 --- a/web/i18n/zh-Hans/dataset-creation.ts +++ b/web/i18n/zh-Hans/dataset-creation.ts @@ -166,6 +166,9 @@ const translation = { datasetSettingLink: '知识库设置。', previewChunkTip: '点击左侧的“预览块”按钮来加载预览', previewChunkCount: '{{count}} 预估块', + switch: '切换', + qaSwitchHighQualityTipTitle: 'Q&A 格式需要高质量的索引方法', + qaSwitchHighQualityTipContent: '目前,只有高质量的索引方法支持 Q&A 格式分块。您要切换到高质量模式吗?', }, stepThree: { creationTitle: '🎉 知识库已创建', From 41039f09bfccaaf88cc76221b0923cbf9d0564c8 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Wed, 11 Dec 2024 16:55:11 +0800 Subject: [PATCH 07/12] fix: switch to parent child not use qualified --- web/app/components/datasets/create/step-two/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index b87c1bf9e2..8bd10ea1de 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -186,6 +186,8 @@ const StepTwo = ({ setIsQAConfirmDialogOpen(true) return } + if (value === ChuckingMode.parentChild && indexType === IndexingType.ECONOMICAL) + setIndexType(IndexingType.QUALIFIED) setDocForm(value) // eslint-disable-next-line @typescript-eslint/no-use-before-define currentEstimateMutation.reset() From f22c608c89bdcf0f5eed1e33c2bc7166ae8375cd Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 17:48:13 +0800 Subject: [PATCH 08/12] fix: tiny css problem --- .../components/base/file-uploader/file-type-icon.tsx | 4 ++-- .../datasets/hit-testing/assets/test-data.ts | 6 +++--- .../hit-testing/components/child-chunks-item.tsx | 8 ++++---- .../hit-testing/components/chunk-detail-modal.tsx | 10 +++++----- .../datasets/hit-testing/components/result-item.tsx | 8 ++++---- .../datasets/hit-testing/components/score.tsx | 6 +++--- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/web/app/components/base/file-uploader/file-type-icon.tsx b/web/app/components/base/file-uploader/file-type-icon.tsx index 4e31ab66a8..de9166d2ae 100644 --- a/web/app/components/base/file-uploader/file-type-icon.tsx +++ b/web/app/components/base/file-uploader/file-type-icon.tsx @@ -82,8 +82,8 @@ const FileTypeIcon = ({ size = 'sm', className, }: FileTypeIconProps) => { - const Icon = FILE_TYPE_ICON_MAP[type]?.component || FileAppearanceTypeEnum.custom - const color = FILE_TYPE_ICON_MAP[type]?.color || FILE_TYPE_ICON_MAP.custom.color + const Icon = FILE_TYPE_ICON_MAP[type]?.component || FileAppearanceTypeEnum.document + const color = FILE_TYPE_ICON_MAP[type]?.color || FILE_TYPE_ICON_MAP[FileAppearanceTypeEnum.document].color return } diff --git a/web/app/components/datasets/hit-testing/assets/test-data.ts b/web/app/components/datasets/hit-testing/assets/test-data.ts index 035bfcc827..74f27908b8 100644 --- a/web/app/components/datasets/hit-testing/assets/test-data.ts +++ b/web/app/components/datasets/hit-testing/assets/test-data.ts @@ -54,7 +54,7 @@ export const generalResultData: HitTesting[] = [ content: 'It is quite natural for ', }, ], - score: 0.8771945, + score: 0.99, tsne_position: null, }, { @@ -99,7 +99,7 @@ export const generalResultData: HitTesting[] = [ }, }, child_chunks: null, - score: 0.8642928, + score: 1, tsne_position: null, }, { @@ -144,7 +144,7 @@ export const generalResultData: HitTesting[] = [ }, }, child_chunks: null, - score: 0.80618876, + score: 0.2, tsne_position: null, }, ] diff --git a/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx index f6be610114..052d270b3f 100644 --- a/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx +++ b/web/app/components/datasets/hit-testing/components/child-chunks-item.tsx @@ -19,11 +19,11 @@ const ChildChunks: FC = ({
-
-
C-{id}
- +
+
C-{id}
+
- {content} + {content}
) } diff --git a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx index 18e89f5890..5b5f42a6af 100644 --- a/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx +++ b/web/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx @@ -28,8 +28,8 @@ const ChunkDetailModal: FC = ({ const { segment, score, child_chunks } = payload const { position, content, keywords, document } = segment const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0) - const extension = document.name.split('.').slice(0, -1)[0] as FileAppearanceTypeEnum - const maxHeighClassName = 'max-h-[752px] overflow-y-auto' + const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum + const maxHeighClassName = 'max-h-[min(752px,_80vh)] overflow-y-auto' return ( = ({ onClose={onHide} className={cn(isParentChildRetrieval ? '!min-w-[1200px]' : '!min-w-[720px]')} > -
+
{/* Meta info */}
@@ -49,7 +49,7 @@ const ChunkDetailModal: FC = ({ className={cn('w-fit group-hover:opacity-100')} /> -
+
{document.name}
@@ -62,7 +62,7 @@ const ChunkDetailModal: FC = ({ {!isParentChildRetrieval && keywords && keywords.length > 0 && (
{t(`${i18nPrefix}.keyword`)}
-
+
{keywords.map(keyword => ( ))} diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index e8f85baf9f..6e2827857a 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -27,7 +27,7 @@ const ResultItem: FC = ({ const { segment, score, child_chunks } = payload const { position, word_count, content, keywords, document } = segment const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0) - const extension = document.name.split('.').slice(0, -1)[0] as FileAppearanceTypeEnum + const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum const [isFold, { toggle: toggleFold, }] = useBoolean(false) @@ -61,7 +61,7 @@ const ResultItem: FC = ({
-
{t(`${i18nPrefix}.dataset.hitChunks`, { num: child_chunks.length })}
+
{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}
{child_chunks.map(item => ( @@ -73,7 +73,7 @@ const ResultItem: FC = ({
)} {!isParentChildRetrieval && keywords && keywords.length > 0 && ( -
+
{keywords.map(keyword => ( ))} @@ -82,7 +82,7 @@ const ResultItem: FC = ({
{/* Foot */}
-
+
{document.name}
diff --git a/web/app/components/datasets/hit-testing/components/score.tsx b/web/app/components/datasets/hit-testing/components/score.tsx index bcbcabf20e..6f48edd4bd 100644 --- a/web/app/components/datasets/hit-testing/components/score.tsx +++ b/web/app/components/datasets/hit-testing/components/score.tsx @@ -13,9 +13,9 @@ const Score: FC = ({ besideChunkName, }) => { return ( -
-
-
+
+
+
score
{value.toFixed(2)}
From 3f6aee6c51aec32f7b338e7948d0808aa1eb496d Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Wed, 11 Dec 2024 18:01:02 +0800 Subject: [PATCH 09/12] feat: economy hover effect & upload page --- .../datasets/create/step-two/index.tsx | 529 +++++++++--------- .../datasets/create/step-two/option-card.tsx | 7 +- web/i18n/en-US/dataset-creation.ts | 2 + web/i18n/zh-Hans/dataset-creation.ts | 2 + 4 files changed, 287 insertions(+), 253 deletions(-) diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 8bd10ea1de..01cf933f30 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC, PropsWithChildren } from 'react' -import React, { useCallback, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import { @@ -10,6 +10,7 @@ import { } 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' @@ -59,6 +60,7 @@ import Badge from '@/app/components/base/badge' import { SkeletonContanier, 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' const TextLabel: FC = (props) => { return @@ -559,6 +561,9 @@ const StepTwo = ({ score_threshold: 0.5, } as RetrievalConfig) + const economyDomRef = useRef(null) + const isHoveringEconomy = useHover(economyDomRef) + return (
@@ -566,226 +571,231 @@ const StepTwo = ({
{t('datasetCreation.stepTwo.segmentation')}
- } - activeHeaderClassName='bg-gradient-to-r from-[#EFF0F9] to-[#F9FAFB]' - description={t('datasetCreation.stepTwo.generalTip')} - isActive={ - [ChuckingMode.text, ChuckingMode.qa].includes(docForm) - } - onSwitched={() => - handleChangeDocform(ChuckingMode.text) - } - actions={ - <> - - - - } - > -
-
- setSegmentIdentifier(e.target.value)} - /> - - -
-
-
- {t('datasetCreation.stepTwo.rules')} -
- {rules.map(rule => ( -
{ - ruleChangeHandle(rule.id) - }}> - - -
- ))} -
-
-
- {IS_CE_EDITION && <> -
- { - if (docForm === ChuckingMode.qa) - handleChangeDocform(ChuckingMode.text) - else - handleChangeDocform(ChuckingMode.qa) - }} - className='mr-2' - /> -
- - {t('datasetCreation.stepTwo.QALanguage')} - -
- -
- -
-
- {docForm === ChuckingMode.qa && ( -
- - - {t('datasetCreation.stepTwo.QATip')} - -
- )} - } -
-
- } - effectImg={OrangeEffect.src} - activeHeaderClassName='bg-gradient-to-r from-[#F9F1EE] to-[#F9FAFB]' - description={t('datasetCreation.stepTwo.parentChildTip')} - isActive={docForm === ChuckingMode.parentChild} - onSwitched={() => handleChangeDocform(ChuckingMode.parentChild)} - actions={ - <> - - - - } - > -
-
- - {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, - }, - })} - /> - setParentChildConfig({ - ...parentChildConfig, - parent: { - ...parentChildConfig.parent, - maxLength: value, - }, - })} - /> -
- } - /> - } - title={t('datasetCreation.stepTwo.fullDoc')} - description={t('datasetCreation.stepTwo.fullDocTip')} - onChosen={() => setParentChildConfig( - { - ...parentChildConfig, - chunkForContext: 'full-doc', - }, - )} - isChosen={parentChildConfig.chunkForContext === 'full-doc'} - /> -
- + {(!datasetId || [ChuckingMode.text, ChuckingMode.qa].includes(docForm)) + && } + activeHeaderClassName='bg-gradient-to-r from-[#EFF0F9] to-[#F9FAFB]' + description={t('datasetCreation.stepTwo.generalTip')} + isActive={ + [ChuckingMode.text, ChuckingMode.qa].includes(docForm) + } + onSwitched={() => + handleChangeDocform(ChuckingMode.text) + } + actions={ + <> + + + + } + noHighlight={Boolean(datasetId)} + >
- - {t('datasetCreation.stepTwo.childChunkForRetrieval')} - -
+
setParentChildConfig({ - ...parentChildConfig, - child: { - ...parentChildConfig.child, - delimiter: e.target.value, - }, - })} + value={segmentIdentifier} + onChange={e => setSegmentIdentifier(e.target.value)} /> setParentChildConfig({ - ...parentChildConfig, - child: { - ...parentChildConfig.child, - maxLength: value, + value={maxChunkLength} + onChange={setMaxChunkLength} + /> + +
+
+
+ {t('datasetCreation.stepTwo.rules')} +
+ {rules.map(rule => ( +
{ + ruleChangeHandle(rule.id) + }}> + + +
+ ))} +
+
+
+ {IS_CE_EDITION && <> +
+ { + if (docForm === ChuckingMode.qa) + handleChangeDocform(ChuckingMode.text) + else + handleChangeDocform(ChuckingMode.qa) + }} + className='mr-2' + /> +
+ + {t('datasetCreation.stepTwo.QALanguage')} + +
+ +
+ +
+
+ {docForm === ChuckingMode.qa && ( +
+ + + {t('datasetCreation.stepTwo.QATip')} + +
+ )} + } +
+ } + { + (!datasetId || docForm === ChuckingMode.parentChild) + && } + effectImg={OrangeEffect.src} + activeHeaderClassName='bg-gradient-to-r from-[#F9F1EE] to-[#F9FAFB]' + description={t('datasetCreation.stepTwo.parentChildTip')} + isActive={docForm === ChuckingMode.parentChild} + onSwitched={() => handleChangeDocform(ChuckingMode.parentChild)} + actions={ + <> + + + + } + noHighlight={Boolean(datasetId)} + > +
+
+ + {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, + }, + })} + /> + setParentChildConfig({ + ...parentChildConfig, + parent: { + ...parentChildConfig.parent, + maxLength: value, + }, + })} + /> +
+ } + /> + } + title={t('datasetCreation.stepTwo.fullDoc')} + description={t('datasetCreation.stepTwo.fullDocTip')} + onChosen={() => setParentChildConfig( + { + ...parentChildConfig, + chunkForContext: 'full-doc', + }, + )} + isChosen={parentChildConfig.chunkForContext === 'full-doc'} />
-
+
- {t('datasetCreation.stepTwo.rules')} + {t('datasetCreation.stepTwo.childChunkForRetrieval')} -
- {rules.map(rule => ( -
{ - ruleChangeHandle(rule.id) - }}> - - -
- ))} +
+ setParentChildConfig({ + ...parentChildConfig, + child: { + ...parentChildConfig.child, + delimiter: e.target.value, + }, + })} + /> + setParentChildConfig({ + ...parentChildConfig, + child: { + ...parentChildConfig.child, + maxLength: value, + }, + })} + /> +
+ +
+ + {t('datasetCreation.stepTwo.rules')} + +
+ {rules.map(rule => ( +
{ + ruleChangeHandle(rule.id) + }}> + + +
+ ))} +
-
- + }
@@ -828,50 +838,69 @@ const StepTwo = ({ )} {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && ( -
- setIsQAConfirmDialogOpen(false)} className='w-[432px]'> -
-

- {t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')} -

-

- {t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')} -

-
-
- - + +
+ setIsQAConfirmDialogOpen(false)} className='w-[432px]'> +
+

+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')} +

+

+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')} +

+
+
+ + +
+
+
+ Economical Icon +
+ {!hasSetIndexType && } +
+
{t('datasetCreation.stepTwo.economical')}
+
{t('datasetCreation.stepTwo.economicalTip')}
+
- -
- Economical Icon -
- {!hasSetIndexType && } -
-
{t('datasetCreation.stepTwo.economical')}
-
{t('datasetCreation.stepTwo.economicalTip')}
-
-
+ + +
+ { + docForm === ChuckingMode.qa + ? t('datasetCreation.stepTwo.notAvailableForQA') + : t('datasetCreation.stepTwo.notAvailableForParentChild') + } +
+
+ )}
{hasSetIndexType && indexType === IndexingType.ECONOMICAL && ( diff --git a/web/app/components/datasets/create/step-two/option-card.tsx b/web/app/components/datasets/create/step-two/option-card.tsx index 466fa78111..ba84d335c3 100644 --- a/web/app/components/datasets/create/step-two/option-card.tsx +++ b/web/app/components/datasets/create/step-two/option-card.tsx @@ -51,14 +51,15 @@ type OptionCardProps = { actions?: ReactNode effectImg?: string onSwitched?: () => void + noHighlight?: boolean } & Omit, 'title'> export const OptionCard: FC = (props) => { - const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, onClick, ...rest } = props + const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, onClick, noHighlight, ...rest } = props return
= (props) => { icon={icon} title={title} description={description} - isActive={isActive} + isActive={isActive && !noHighlight} activeClassName={activeHeaderClassName} effectImg={effectImg} /> diff --git a/web/i18n/en-US/dataset-creation.ts b/web/i18n/en-US/dataset-creation.ts index cbd02d10eb..514738e9da 100644 --- a/web/i18n/en-US/dataset-creation.ts +++ b/web/i18n/en-US/dataset-creation.ts @@ -169,6 +169,8 @@ const translation = { switch: 'Switch', qaSwitchHighQualityTipTitle: 'Q&A Format Requires High-quality Indexing Method', qaSwitchHighQualityTipContent: 'Currently, only high-quality index method supports Q&A format chunking. Would you like to switch to high-quality mode?', + notAvailableForParentChild: 'Not available for Parent-child Index', + notAvailableForQA: 'Not available for Q&A Index', }, stepThree: { creationTitle: '🎉 Knowledge created', diff --git a/web/i18n/zh-Hans/dataset-creation.ts b/web/i18n/zh-Hans/dataset-creation.ts index 5fa9beaf76..48e1b4e7f2 100644 --- a/web/i18n/zh-Hans/dataset-creation.ts +++ b/web/i18n/zh-Hans/dataset-creation.ts @@ -169,6 +169,8 @@ const translation = { switch: '切换', qaSwitchHighQualityTipTitle: 'Q&A 格式需要高质量的索引方法', qaSwitchHighQualityTipContent: '目前,只有高质量的索引方法支持 Q&A 格式分块。您要切换到高质量模式吗?', + notAvailableForParentChild: '不支持父子索引', + notAvailableForQA: '不支持 Q&A 索引', }, stepThree: { creationTitle: '🎉 知识库已创建', From 49a48910cdd15fb1b6310e382d8989aa46e795a4 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 18:01:55 +0800 Subject: [PATCH 10/12] chore: hit result toggle btn --- .../hit-testing/components/result-item.tsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx index 6e2827857a..627564d110 100644 --- a/web/app/components/datasets/hit-testing/components/result-item.tsx +++ b/web/app/components/datasets/hit-testing/components/result-item.tsx @@ -59,17 +59,19 @@ const ResultItem: FC = ({
{content}
{isParentChildRetrieval && (
-
+
-
{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}
-
-
- {child_chunks.map(item => ( -
- -
- ))} +
{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}
+ {!isFold && ( +
+ {child_chunks.map(item => ( +
+ +
+ ))} +
+ )}
)} {!isParentChildRetrieval && keywords && keywords.length > 0 && ( @@ -103,7 +105,7 @@ const ResultItem: FC = ({ /> ) } -
+
) } export default React.memo(ResultItem) From 4f6bc542809223fc08b6fd58648e226f036c161f Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Wed, 11 Dec 2024 18:05:05 +0800 Subject: [PATCH 11/12] fix: update file type casting in PreviewDocumentPicker --- web/app/components/datasets/create/step-two/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 01cf933f30..5a3d8536dc 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -993,7 +993,7 @@ const StepTwo = ({ >
({ name: file.name!, id: file.id!, extension: 'pdf' }))} + files={files as Array>} onChange={(selected) => { currentEstimateMutation.reset() setPreviewFile(selected) From d88bb7042703d358166055430a1577948a09c5dd Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 11 Dec 2024 18:13:34 +0800 Subject: [PATCH 12/12] fix: loding and empty css --- .../components/datasets/hit-testing/index.tsx | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/web/app/components/datasets/hit-testing/index.tsx b/web/app/components/datasets/hit-testing/index.tsx index f82edf0267..2a0a4aeb8a 100644 --- a/web/app/components/datasets/hit-testing/index.tsx +++ b/web/app/components/datasets/hit-testing/index.tsx @@ -11,7 +11,6 @@ import Textarea from './textarea' import s from './style.module.css' import HitDetail from './hit-detail' import ModifyRetrievalModal from './modify-retrieval-modal' -import { generalResultData } from './assets/test-data' import ResultItem from './components/result-item' import cn from '@/utils/classnames' import type { ExternalKnowledgeBaseHitTestingResponse, ExternalKnowledgeBaseHitTesting as ExternalKnowledgeBaseHitTestingType, HitTestingResponse, HitTesting as HitTestingType } from '@/models/datasets' @@ -25,6 +24,8 @@ import DatasetDetailContext from '@/context/dataset-detail' import type { RetrievalConfig } from '@/types/app' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useTimestamp from '@/hooks/use-timestamp' +import docStyle from '@/app/components/datasets/documents/detail/completed/style.module.css' + const limit = 10 type Props = { @@ -88,14 +89,12 @@ const HitTesting: FC = ({ datasetId }: Props) => { ) const renderEmptyState = () => ( - // for test -
- //
- //
- //
- // {t('datasetHitTesting.hit.emptyTip')} - //
- //
+
+
+
+ {t('datasetHitTesting.hit.emptyTip')} +
+
) useEffect(() => { @@ -174,20 +173,13 @@ const HitTesting: FC = ({ datasetId }: Props) => {
- {renderHitResults(generalResultData)} + {/* {renderHitResults(generalResultData)} */} {submitLoading - ?
- - -
+ ? : ( (() => { if (!hitResult?.records.length && !externalHitResult?.records.length)