@ -1,6 +1,6 @@
'use client'
'use client'
import type { FC , PropsWithChildren } from 'react'
import type { FC , PropsWithChildren } from 'react'
import React , { useCallback , useEffect , use State } from 'react'
import React , { useCallback , useEffect , use Ref, use State } from 'react'
import { useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useContext } from 'use-context-selector'
import {
import {
@ -10,6 +10,7 @@ import {
} from '@remixicon/react'
} from '@remixicon/react'
import Link from 'next/link'
import Link from 'next/link'
import Image from 'next/image'
import Image from 'next/image'
import { useHover } from 'ahooks'
import SettingCog from '../assets/setting-gear-mod.svg'
import SettingCog from '../assets/setting-gear-mod.svg'
import OrangeEffect from '../assets/option-card-effect-orange.svg'
import OrangeEffect from '../assets/option-card-effect-orange.svg'
import FamilyMod from '../assets/family-mod.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 { SkeletonContanier , SkeletonPoint , SkeletonRectangle , SkeletonRow } from '@/app/components/base/skeleton'
import Tooltip from '@/app/components/base/tooltip'
import Tooltip from '@/app/components/base/tooltip'
import CustomDialog from '@/app/components/base/dialog'
import CustomDialog from '@/app/components/base/dialog'
import { PortalToFollowElem , PortalToFollowElemContent , PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
const TextLabel : FC < PropsWithChildren > = ( props ) = > {
const TextLabel : FC < PropsWithChildren > = ( props ) = > {
return < label className = 'text-text-secondary text-xs font-semibold leading-none' > { props . children } < / label >
return < label className = 'text-text-secondary text-xs font-semibold leading-none' > { props . children } < / label >
@ -559,6 +561,9 @@ const StepTwo = ({
score_threshold : 0.5 ,
score_threshold : 0.5 ,
} as RetrievalConfig )
} as RetrievalConfig )
const economyDomRef = useRef < HTMLDivElement > ( null )
const isHoveringEconomy = useHover ( economyDomRef )
return (
return (
< div className = 'flex w-full max-h-full h-full overflow-y-auto' >
< div className = 'flex w-full max-h-full h-full overflow-y-auto' >
< div className = 'relative h-full w-full overflow-y-scroll' >
< div className = 'relative h-full w-full overflow-y-scroll' >
@ -566,226 +571,231 @@ const StepTwo = ({
< div className = { s . label } > { t ( 'datasetCreation.stepTwo.segmentation' ) } < / div >
< div className = { s . label } > { t ( 'datasetCreation.stepTwo.segmentation' ) } < / div >
< div className = 'max-w-[640px]' >
< div className = 'max-w-[640px]' >
< div className = 'space-y-4' >
< div className = 'space-y-4' >
< OptionCard
{ ( ! datasetId || [ ChuckingMode . text , ChuckingMode . qa ] . includes ( docForm ) )
title = { t ( 'datasetCreation.stepTwo.general' ) }
&& < OptionCard
icon = { < Image src = { SettingCog } alt = { t ( 'datasetCreation.stepTwo.general' ) } / > }
title = { t ( 'datasetCreation.stepTwo.general' ) }
activeHeaderClassName = 'bg-gradient-to-r from-[#EFF0F9] to-[#F9FAFB]'
icon = { < Image src = { SettingCog } alt = { t ( 'datasetCreation.stepTwo.general' ) } / > }
description = { t ( 'datasetCreation.stepTwo.generalTip' ) }
activeHeaderClassName = 'bg-gradient-to-r from-[#EFF0F9] to-[#F9FAFB]'
isActive = {
description = { t ( 'datasetCreation.stepTwo.generalTip' ) }
[ ChuckingMode . text , ChuckingMode . qa ] . includes ( docForm )
isActive = {
}
[ ChuckingMode . text , ChuckingMode . qa ] . includes ( docForm )
onSwitched = { ( ) = >
}
handleChangeDocform ( ChuckingMode . text )
onSwitched = { ( ) = >
}
handleChangeDocform ( ChuckingMode . text )
actions = {
}
< >
actions = {
< Button variant = { 'secondary-accent' } onClick = { ( ) = > updatePreview ( ) } >
< >
< RiSearchEyeLine className = 'h-4 w-4 mr-1.5' / >
< Button variant = { 'secondary-accent' } onClick = { ( ) = > updatePreview ( ) } >
{ t ( 'datasetCreation.stepTwo.previewChunk' ) }
< RiSearchEyeLine className = 'h-4 w-4 mr-1.5' / >
< / Button >
{ t ( 'datasetCreation.stepTwo.previewChunk' ) }
< Button variant = { 'ghost' } onClick = { resetRules } >
< / Button >
{ t ( 'datasetCreation.stepTwo.reset' ) }
< Button variant = { 'ghost' } onClick = { resetRules } >
< / Button >
{ t ( 'datasetCreation.stepTwo.reset' ) }
< / >
< / Button >
}
< / >
>
}
< div className = 'space-y-4' >
noHighlight = { Boolean ( datasetId ) }
< div className = 'flex gap-3' >
>
< DelimiterInput
< div className = 'space-y-4' >
value = { segmentIdentifier }
< div className = 'flex gap-3' >
onChange = { e = > setSegmentIdentifier ( e . target . value ) }
< DelimiterInput
/ >
value = { segmentIdentifier }
< MaxLengthInput
onChange = { e = > setSegmentIdentifier ( e . target . value ) }
value = { maxChunkLength }
onChange = { setMaxChunkLength }
/ >
< OverlapInput
value = { overlap }
min = { 1 }
onChange = { setOverlap }
/ >
< / div >
< div className = 'space-y-2' >
< div className = 'w-full flex flex-col' >
< TextLabel > { t ( 'datasetCreation.stepTwo.rules' ) } < / TextLabel >
< div className = 'mt-4 space-y-2' >
{ rules . map ( rule = > (
< div key = { rule . id } className = { s . ruleItem } onClick = { ( ) = > {
ruleChangeHandle ( rule . id )
} } >
< Checkbox
checked = { rule . enabled }
/ >
< label className = "ml-2 text-sm font-normal cursor-pointer text-gray-800" > { getRuleName ( rule . id ) } < / label >
< / div >
) ) }
< / div >
< / div >
< / div >
{ IS_CE_EDITION && < >
< div className = 'flex items-center' >
< Checkbox
checked = { docForm === ChuckingMode . qa }
onCheck = { ( ) = > {
if ( docForm === ChuckingMode . qa )
handleChangeDocform ( ChuckingMode . text )
else
handleChangeDocform ( ChuckingMode . qa )
} }
className = 'mr-2'
/ >
/ >
< div className = 'flex items-center gap-1' >
< MaxLengthInput
< TextLabel >
value = { maxChunkLength }
{ t ( 'datasetCreation.stepTwo.QALanguage' ) }
onChange = { setMaxChunkLength }
< / TextLabel >
/ >
< div className = 'z-50 relative' >
< OverlapInput
< LanguageSelect
value = { overlap }
currentLanguage = { docLanguage || locale }
min = { 1 }
onSelect = { setDocLanguage }
onChange = { setOverlap }
disabled = { isLanguageSelectDisabled }
/ >
/ >
< / div >
< div className = 'space-y-2' >
< div className = 'w-full flex flex-col' >
< TextLabel > { t ( 'datasetCreation.stepTwo.rules' ) } < / TextLabel >
< div className = 'mt-4 space-y-2' >
{ rules . map ( rule = > (
< div key = { rule . id } className = { s . ruleItem } onClick = { ( ) = > {
ruleChangeHandle ( rule . id )
} } >
< Checkbox
checked = { rule . enabled }
/ >
< label className = "ml-2 text-sm font-normal cursor-pointer text-gray-800" > { getRuleName ( rule . id ) } < / label >
< / div >
) ) }
< / div >
< / div >
< Tooltip popupContent = { t ( 'datasetCreation.stepTwo.QATip' ) } / >
< / div >
< / div >
< / div >
< / div >
{ docForm === ChuckingMode . qa && (
{ IS_CE_EDITION && < >
< div
< div className = 'flex items-center' >
style = { {
< Checkbox
background : 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)' ,
checked = { docForm === ChuckingMode . qa }
} }
onCheck = { ( ) = > {
className = 'h-10 flex items-center gap-2 rounded-xl border-components-panel-border border shadow-shadow-shadow-3 px-3 text-xs'
if ( docForm === ChuckingMode . qa )
>
handleChangeDocform ( ChuckingMode . text )
< RiAlertFill className = 'size-4 text-text-warning-secondary' / >
else
< span className = 'text-sm font-medium text-text-primary' >
handleChangeDocform ( ChuckingMode . qa )
{ t ( 'datasetCreation.stepTwo.QATip' ) }
} }
< / span >
className = 'mr-2'
/ >
< div className = 'flex items-center gap-1' >
< TextLabel >
{ t ( 'datasetCreation.stepTwo.QALanguage' ) }
< / TextLabel >
< div className = 'z-50 relative' >
< LanguageSelect
currentLanguage = { docLanguage || locale }
onSelect = { setDocLanguage }
disabled = { isLanguageSelectDisabled }
/ >
< / div >
< Tooltip popupContent = { t ( 'datasetCreation.stepTwo.QATip' ) } / >
< / div >
< / div >
< / div >
) }
{ docForm === ChuckingMode . qa && (
< / > }
< div
< / div >
style = { {
< / OptionCard >
background : 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)' ,
< OptionCard
} }
title = { t ( 'datasetCreation.stepTwo.parentChild' ) }
className = 'h-10 flex items-center gap-2 rounded-xl border-components-panel-border border shadow-shadow-shadow-3 px-3 text-xs'
icon = { < Image src = { FamilyMod } alt = { t ( 'datasetCreation.stepTwo.parentChild' ) } / > }
>
effectImg = { OrangeEffect . src }
< RiAlertFill className = 'size-4 text-text-warning-secondary' / >
activeHeaderClassName = 'bg-gradient-to-r from-[#F9F1EE] to-[#F9FAFB]'
< span className = 'text-sm font-medium text-text-primary' >
description = { t ( 'datasetCreation.stepTwo.parentChildTip' ) }
{ t ( 'datasetCreation.stepTwo.QATip' ) }
isActive = { docForm === ChuckingMode . parentChild }
< / span >
onSwitched = { ( ) = > handleChangeDocform ( ChuckingMode . parentChild ) }
actions = {
< >
< Button variant = { 'secondary-accent' } onClick = { ( ) = > updatePreview ( ) } >
< RiSearchEyeLine className = 'h-4 w-4 mr-1.5' / >
{ t ( 'datasetCreation.stepTwo.previewChunk' ) }
< / Button >
< Button variant = { 'ghost' } onClick = { resetRules } >
{ t ( 'datasetCreation.stepTwo.reset' ) }
< / Button >
< / >
}
>
< div className = 'space-y-4' >
< div className = 'space-y-2' >
< TextLabel >
{ t ( 'datasetCreation.stepTwo.parentChunkForContext' ) }
< / TextLabel >
< RadioCard
icon = { < Image src = { Note } alt = '' / > }
title = { t ( 'datasetCreation.stepTwo.paragraph' ) }
description = { t ( 'datasetCreation.stepTwo.paragraphTip' ) }
isChosen = { parentChildConfig . chunkForContext === 'paragraph' }
onChosen = { ( ) = > setParentChildConfig (
{
. . . parentChildConfig ,
chunkForContext : 'paragraph' ,
} ,
) }
chosenConfig = {
< div className = 'flex gap-2' >
< DelimiterInput
value = { parentChildConfig . parent . delimiter }
onChange = { e = > setParentChildConfig ( {
. . . parentChildConfig ,
parent : {
. . . parentChildConfig . parent ,
delimiter : e.target.value ,
} ,
} ) }
/ >
< MaxLengthInput
value = { parentChildConfig . parent . maxLength }
onChange = { value = > setParentChildConfig ( {
. . . parentChildConfig ,
parent : {
. . . parentChildConfig . parent ,
maxLength : value ,
} ,
} ) }
/ >
< / div >
< / div >
}
/ >
< RadioCard
icon = { < Image src = { FileList } alt = '' / > }
title = { t ( 'datasetCreation.stepTwo.fullDoc' ) }
description = { t ( 'datasetCreation.stepTwo.fullDocTip' ) }
onChosen = { ( ) = > setParentChildConfig (
{
. . . parentChildConfig ,
chunkForContext : 'full-doc' ,
} ,
) }
) }
isChosen = { parentChildConfig . chunkForContext === 'full-doc' }
< / > }
/ >
< / div >
< / div >
< / OptionCard > }
{
( ! datasetId || docForm === ChuckingMode . parentChild )
&& < OptionCard
title = { t ( 'datasetCreation.stepTwo.parentChild' ) }
icon = { < Image src = { FamilyMod } alt = { t ( 'datasetCreation.stepTwo.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 = {
< >
< Button variant = { 'secondary-accent' } onClick = { ( ) = > updatePreview ( ) } >
< RiSearchEyeLine className = 'h-4 w-4 mr-1.5' / >
{ t ( 'datasetCreation.stepTwo.previewChunk' ) }
< / Button >
< Button variant = { 'ghost' } onClick = { resetRules } >
{ t ( 'datasetCreation.stepTwo.reset' ) }
< / Button >
< / >
}
noHighlight = { Boolean ( datasetId ) }
>
< div className = 'space-y-4' >
< div className = 'space-y-4' >
< TextLabel >
< div className = 'space-y-2' >
{ t ( 'datasetCreation.stepTwo.childChunkForRetrieval' ) }
< TextLabel >
< / TextLabel >
{ t ( 'datasetCreation.stepTwo.parentChunkForContext' ) }
< div className = 'flex gap-3 mt-2' >
< / TextLabel >
< DelimiterInput
< RadioCard
value = { parentChildConfig . child . delimiter }
icon = { < Image src = { Note } alt = '' / > }
onChange = { e = > setParentChildConfig ( {
title = { t ( 'datasetCreation.stepTwo.paragraph' ) }
. . . parentChildConfig ,
description = { t ( 'datasetCreation.stepTwo.paragraphTip' ) }
child : {
isChosen = { parentChildConfig . chunkForContext === 'paragraph' }
. . . parentChildConfig . child ,
onChosen = { ( ) = > setParentChildConfig (
delimiter : e.target.value ,
{
. . . parentChildConfig ,
chunkForContext : 'paragraph' ,
} ,
} ,
} ) }
) }
chosenConfig = {
< div className = 'flex gap-2' >
< DelimiterInput
value = { parentChildConfig . parent . delimiter }
onChange = { e = > setParentChildConfig ( {
. . . parentChildConfig ,
parent : {
. . . parentChildConfig . parent ,
delimiter : e.target.value ,
} ,
} ) }
/ >
< MaxLengthInput
value = { parentChildConfig . parent . maxLength }
onChange = { value = > setParentChildConfig ( {
. . . parentChildConfig ,
parent : {
. . . parentChildConfig . parent ,
maxLength : value ,
} ,
} ) }
/ >
< / div >
}
/ >
/ >
< MaxLengthInput
< RadioCard
value = { parentChildConfig . child . maxLength }
icon = { < Image src = { FileList } alt = '' / > }
onChange = { value = > setParentChildConfig ( {
title = { t ( 'datasetCreation.stepTwo.fullDoc' ) }
. . . parentChildConfig ,
description = { t ( 'datasetCreation.stepTwo.fullDocTip' ) }
child : {
onChosen = { ( ) = > setParentChildConfig (
. . . parentChildConfig . child ,
{
maxLength : value ,
. . . parentChildConfig ,
chunkForContext : 'full-doc' ,
} ,
} ,
} ) }
) }
isChosen = { parentChildConfig . chunkForContext === 'full-doc' }
/ >
/ >
< / div >
< / div >
< div className = 'space-y-2' >
< div className = 'space-y- 4 '>
< TextLabel >
< TextLabel >
{ t ( 'datasetCreation.stepTwo.rules' ) }
{ t ( 'datasetCreation.stepTwo. childChunkForRetrieval ') }
< / TextLabel >
< / TextLabel >
< div className = 'space-y-2 mt-2' >
< div className = 'flex gap-3 mt-2' >
{ rules . map ( rule = > (
< DelimiterInput
< div key = { rule . id } className = { s . ruleItem } onClick = { ( ) = > {
value = { parentChildConfig . child . delimiter }
ruleChangeHandle ( rule . id )
onChange = { e = > setParentChildConfig ( {
} } >
. . . parentChildConfig ,
< Checkbox
child : {
checked = { rule . enabled }
. . . parentChildConfig . child ,
/ >
delimiter : e.target.value ,
< label className = "ml-2 text-sm font-normal cursor-pointer text-gray-800" > { getRuleName ( rule . id ) } < / label >
} ,
< / div >
} ) }
) ) }
/ >
< MaxLengthInput
value = { parentChildConfig . child . maxLength }
onChange = { value = > setParentChildConfig ( {
. . . parentChildConfig ,
child : {
. . . parentChildConfig . child ,
maxLength : value ,
} ,
} ) }
/ >
< / div >
< div className = 'space-y-2' >
< TextLabel >
{ t ( 'datasetCreation.stepTwo.rules' ) }
< / TextLabel >
< div className = 'space-y-2 mt-2' >
{ rules . map ( rule = > (
< div key = { rule . id } className = { s . ruleItem } onClick = { ( ) = > {
ruleChangeHandle ( rule . id )
} } >
< Checkbox
checked = { rule . enabled }
/ >
< label className = "ml-2 text-sm font-normal cursor-pointer text-gray-800" > { getRuleName ( rule . id ) } < / label >
< / div >
) ) }
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / OptionCard > }
< / OptionCard >
< / div >
< / div >
< / div >
< / div >
< Divider className = 'my-5' / >
< Divider className = 'my-5' / >
@ -828,50 +838,69 @@ const StepTwo = ({
) }
) }
{ ( ! hasSetIndexType || ( hasSetIndexType && indexingType === IndexingType . ECONOMICAL ) ) && (
{ ( ! hasSetIndexType || ( hasSetIndexType && indexingType === IndexingType . ECONOMICAL ) ) && (
< div
< PortalToFollowElem
className = { cn (
open = {
s . radioItem ,
isHoveringEconomy && docForm !== ChuckingMode . text
s . indexItem ,
}
! hasSetIndexType && indexType === IndexingType . ECONOMICAL && s . active ,
placement = { 'top' }
hasSetIndexType && s . disabled ,
hasSetIndexType && '!w-full !min-h-[96px]' ,
docForm !== ChuckingMode . text && s . disabled ,
) }
onClick = { changeToEconomicalType }
>
>
< CustomDialog show = { isQAConfirmDialogOpen } onClose = { ( ) = > setIsQAConfirmDialogOpen ( false ) } className = 'w-[432px]' >
< PortalToFollowElemTrigger >
< header className = 'pt-6 mb-4' >
< div
< h2 className = 'text-lg font-semibold' >
className = { cn (
{ t ( 'datasetCreation.stepTwo.qaSwitchHighQualityTipTitle' ) }
s . radioItem ,
< / h2 >
s . indexItem ,
< p className = 'font-normal text-sm mt-2' >
! hasSetIndexType && indexType === IndexingType . ECONOMICAL && s . active ,
{ t ( 'datasetCreation.stepTwo.qaSwitchHighQualityTipContent' ) }
hasSetIndexType && s . disabled ,
< / p >
hasSetIndexType && '!w-full !min-h-[96px]' ,
< / header >
docForm !== ChuckingMode . text && s . disabled ,
< div className = 'flex gap-2 pb-6' >
) }
< Button className = 'ml-auto' onClick = { ( ) = > {
onClick = { changeToEconomicalType }
setIsQAConfirmDialogOpen ( false )
ref = { economyDomRef }
} } >
>
{ t ( 'datasetCreation.stepTwo.cancel' ) }
< CustomDialog show = { isQAConfirmDialogOpen } onClose = { ( ) = > setIsQAConfirmDialogOpen ( false ) } className = 'w-[432px]' >
< / Button >
< header className = 'pt-6 mb-4' >
< Button variant = { 'primary' } onClick = { ( ) = > {
< h2 className = 'text-lg font-semibold' >
setIsQAConfirmDialogOpen ( false )
{ t ( 'datasetCreation.stepTwo.qaSwitchHighQualityTipTitle' ) }
setIndexType ( IndexingType . QUALIFIED )
< / h2 >
setDocForm ( ChuckingMode . qa )
< p className = 'font-normal text-sm mt-2' >
} } >
{ t ( 'datasetCreation.stepTwo.qaSwitchHighQualityTipContent' ) }
{ t ( 'datasetCreation.stepTwo.switch' ) }
< / p >
< / Button >
< / header >
< div className = 'flex gap-2 pb-6' >
< Button className = 'ml-auto' onClick = { ( ) = > {
setIsQAConfirmDialogOpen ( false )
} } >
{ t ( 'datasetCreation.stepTwo.cancel' ) }
< / Button >
< Button variant = { 'primary' } onClick = { ( ) = > {
setIsQAConfirmDialogOpen ( false )
setIndexType ( IndexingType . QUALIFIED )
setDocForm ( ChuckingMode . qa )
} } >
{ t ( 'datasetCreation.stepTwo.switch' ) }
< / Button >
< / div >
< / CustomDialog >
< div className = 'h-8 p-1.5 bg-white rounded-lg border border-components-panel-border-subtle justify-center items-center inline-flex absolute left-5 top-[18px]' >
< Image src = { indexMethodIcon . economical } alt = 'Economical Icon' width = { 20 } height = { 20 } / >
< / div >
{ ! hasSetIndexType && < span className = { cn ( s . radio ) } / > }
< div className = { s . typeHeader } >
< div className = { s . title } > { t ( 'datasetCreation.stepTwo.economical' ) } < / div >
< div className = { s . tip } > { t ( 'datasetCreation.stepTwo.economicalTip' ) } < / div >
< / div >
< / div >
< / div >
< / CustomDialog >
< / PortalToFollowElemTrigger >
< div className = 'h-8 p-1.5 bg-white rounded-lg border border-components-panel-border-subtle justify-center items-center inline-flex absolute left-5 top-[18px]' >
< PortalToFollowElemContent >
< Image src = { indexMethodIcon . economical } alt = 'Economical Icon' width = { 20 } height = { 20 } / >
< div className = 'p-3 bg-white text-xs font-medium text-text-secondary rounded-lg shadow-lg' >
< / div >
{
{ ! hasSetIndexType && < span className = { cn ( s . radio ) } / > }
docForm === ChuckingMode . qa
< div className = { s . typeHeader } >
? t ( 'datasetCreation.stepTwo.notAvailableForQA' )
< div className = { s . title } > { t ( 'datasetCreation.stepTwo.economical' ) } < / div >
: t ( 'datasetCreation.stepTwo.notAvailableForParentChild' )
< div className = { s . tip } > { t ( 'datasetCreation.stepTwo.economicalTip' ) } < / div >
}
< / div >
< / div >
< / div >
< / PortalToFollowElemContent >
< / PortalToFollowElem >
) }
) }
< / div >
< / div >
{ hasSetIndexType && indexType === IndexingType . ECONOMICAL && (
{ hasSetIndexType && indexType === IndexingType . ECONOMICAL && (