Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval

pull/12097/head
twwu 1 year ago
commit 7185fd2d5a

@ -24,30 +24,29 @@ type Props = {
const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1, min = 0, max, value, enable, onChange, hasSwitch, onSwitchChange }) => { const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1, min = 0, max, value, enable, onChange, hasSwitch, onSwitchChange }) => {
return ( return (
<div className={className}> <div className={className}>
<div className="flex items-center h-8 justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center"> <div className="flex items-center">
{hasSwitch && ( {hasSwitch && (
<Switch <Switch
size='md' size='md'
className='mr-2'
defaultValue={enable} defaultValue={enable}
onChange={async (val) => { onChange={async (val) => {
onSwitchChange?.(id, val) onSwitchChange?.(id, val)
}} }}
/> />
)} )}
<span className="mx-1 text-text-secondary text-[13px] leading-[18px] font-medium">{name}</span> <span className="mr-1 text-text-secondary system-sm-semibold">{name}</span>
{!noTooltip && ( {!noTooltip && (
<Tooltip <Tooltip
triggerClassName='w-4 h-4 shrink-0' triggerClassName='w-4 h-4 shrink-0'
popupContent={<div className="w-[200px]">{tip}</div>} popupContent={<div className="w-[200px]">{tip}</div>}
/> />
)} )}
</div> </div>
<div className="flex items-center"></div>
</div> </div>
<div className="mt-2 flex items-center"> <div className="mt-1 flex items-center">
<div className="mr-4 flex shrink-0 items-center"> <div className="mr-3 flex shrink-0 items-center">
<InputNumber <InputNumber
disabled={!enable} disabled={!enable}
type="number" type="number"
@ -62,7 +61,7 @@ const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1,
className='w-[72px]' className='w-[72px]'
/> />
</div> </div>
<div className="flex items-center h-7 grow"> <div className="flex items-center grow">
<Slider <Slider
className='w-full' className='w-full'
disabled={!enable} disabled={!enable}

@ -31,21 +31,21 @@ const RadioCard: FC<Props> = ({
return ( return (
<div <div
className={cn( className={cn(
'border border-components-option-card-option-border bg-components-option-card-option-bg rounded-xl hover:shadow-xs cursor-pointer', 'relative p-3 border-[0.5px] border-components-option-card-option-border bg-components-option-card-option-bg rounded-xl cursor-pointer',
isChosen && 'bg-components-option-card-option-selected-bg border-components-panel-border shadow-xs', isChosen && 'border-[1.5px] bg-components-option-card-option-selected-bg',
className, className,
)} )}
> >
<div className='flex py-3 pl-3 pr-4' onClick={onChosen}> <div className='flex gap-x-2' onClick={onChosen}>
<div className={cn(iconBgClassName, 'mr-3 shrink-0 flex w-8 justify-center h-8 items-center rounded-lg')}> <div className={cn(iconBgClassName, 'shrink-0 flex size-8 justify-center items-center rounded-lg shadow-md')}>
{icon} {icon}
</div> </div>
<div className='grow'> <div className='grow'>
<div className='leading-5 text-sm font-medium text-text-secondary'>{title}</div> <div className='system-sm-semibold text-text-secondary mb-1'>{title}</div>
<div className='leading-[18px] text-xs font-normal text-text-tertiary'>{description}</div> <div className='system-sm-regular text-text-tertiary'>{description}</div>
</div> </div>
{!noRadio && ( {!noRadio && (
<div className='shrink-0 flex items-center h-8'> <div className='absolute top-3 right-3'>
<div className={cn( <div className={cn(
'w-4 h-4 border border-components-radio-border bg-components-radio-bg shadow-xs rounded-full', 'w-4 h-4 border border-components-radio-border bg-components-radio-bg shadow-xs rounded-full',
isChosen && 'border-[5px] border-components-radio-border-checked', isChosen && 'border-[5px] border-components-radio-border-checked',
@ -54,8 +54,11 @@ const RadioCard: FC<Props> = ({
)} )}
</div> </div>
{((isChosen && chosenConfig) || noRadio) && ( {((isChosen && chosenConfig) || noRadio) && (
<div className={cn(chosenConfigWrapClassName, 'p-3')}> <div className='flex gap-x-2 mt-2'>
{chosenConfig} <div className='size-8 shrink-0'></div>
<div className={cn(chosenConfigWrapClassName, 'grow')}>
{chosenConfig}
</div>
</div> </div>
)} )}
</div> </div>

@ -104,7 +104,7 @@ const RetrievalMethodConfig: FC<Props> = ({
title={ title={
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
<div>{t('dataset.retrieval.hybrid_search.title')}</div> <div>{t('dataset.retrieval.hybrid_search.title')}</div>
<Badge text={t('dataset.retrieval.hybrid_search.recommend')!} className='border-text-accent-secondary text-text-accent-secondary ml-2' uppercase /> <Badge text={t('dataset.retrieval.hybrid_search.recommend')!} className='border-text-accent-secondary text-text-accent-secondary ml-1 h-[18px]' uppercase />
</div> </div>
} }
description={t('dataset.retrieval.hybrid_search.description')} isActive={ description={t('dataset.retrieval.hybrid_search.description')} isActive={

@ -120,7 +120,7 @@ const RetrievalParamConfig: FC<Props> = ({
<div> <div>
{!isEconomical && !isHybridSearch && ( {!isEconomical && !isHybridSearch && (
<div> <div>
<div className='flex h-8 items-center text-[13px] font-medium text-gray-900 space-x-2'> <div className='flex items-center space-x-2 mb-2'>
{canToggleRerankModalEnable && ( {canToggleRerankModalEnable && (
<div <div
className='flex items-center' className='flex items-center'
@ -140,7 +140,7 @@ const RetrievalParamConfig: FC<Props> = ({
</div> </div>
)} )}
<div className='flex items-center'> <div className='flex items-center'>
<span className='mr-0.5 text-text-secondary'>{t('common.modelProvider.rerankModel.key')}</span> <span className='mr-0.5 system-sm-semibold text-text-secondary'>{t('common.modelProvider.rerankModel.key')}</span>
<Tooltip <Tooltip
popupContent={ popupContent={
<div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div> <div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>
@ -167,7 +167,7 @@ const RetrievalParamConfig: FC<Props> = ({
)} )}
{ {
!isHybridSearch && ( !isHybridSearch && (
<div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-6')}> <div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-4')}>
<TopKItem <TopKItem
className='grow' className='grow'
value={value.top_k} value={value.top_k}

@ -13,17 +13,6 @@
z-index: 10; z-index: 10;
} }
.form {
@apply px-16 py-8;
}
.form .label {
@apply pb-2 flex items-center text-text-secondary;
font-weight: 500;
font-size: 16px;
line-height: 24px;
}
.segmentationItem { .segmentationItem {
min-height: 68px; min-height: 68px;
} }
@ -249,7 +238,7 @@
} }
.ruleItem { .ruleItem {
@apply flex items-center; @apply flex items-center py-1.5;
} }
.formFooter { .formFooter {

@ -63,7 +63,7 @@ import CustomDialog from '@/app/components/base/dialog'
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' 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 system-sm-semibold'>{props.children}</label>
} }
type StepTwoProps = { type StepTwoProps = {
@ -157,8 +157,8 @@ const StepTwo = ({
const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : currentDataset?.data_source_type const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : currentDataset?.data_source_type
const [segmentationType, setSegmentationType] = useState<SegmentType>(SegmentType.CUSTOM) const [segmentationType, setSegmentationType] = useState<SegmentType>(SegmentType.CUSTOM)
const [segmentIdentifier, doSetSegmentIdentifier] = useState(DEFAULT_SEGMENT_IDENTIFIER) const [segmentIdentifier, doSetSegmentIdentifier] = useState(DEFAULT_SEGMENT_IDENTIFIER)
const setSegmentIdentifier = useCallback((value: string) => { const setSegmentIdentifier = useCallback((value: string, canEmpty?: boolean) => {
doSetSegmentIdentifier(value ? escape(value) : DEFAULT_SEGMENT_IDENTIFIER) doSetSegmentIdentifier(value ? escape(value) : (canEmpty ? '' : DEFAULT_SEGMENT_IDENTIFIER))
}, []) }, [])
const [maxChunkLength, setMaxChunkLength] = useState(DEFAULT_MAXMIMUM_CHUNK_LENGTH) // default chunk length const [maxChunkLength, setMaxChunkLength] = useState(DEFAULT_MAXMIMUM_CHUNK_LENGTH) // default chunk length
const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(4000) const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(4000)
@ -226,11 +226,10 @@ const StepTwo = ({
parentChildConfig.parent.delimiter, parentChildConfig.parent.delimiter,
), ),
max_tokens: parentChildConfig.parent.maxLength, max_tokens: parentChildConfig.parent.maxLength,
chunk_overlap: overlap,
}, },
parent_mode: parentChildConfig.chunkForContext, parent_mode: parentChildConfig.chunkForContext,
subchunk_segmentation: { subchunk_segmentation: {
separator: parentChildConfig.child.delimiter, separator: unescape(parentChildConfig.child.delimiter),
max_tokens: parentChildConfig.child.maxLength, max_tokens: parentChildConfig.child.maxLength,
}, },
}, // api will check this. It will be removed after api refactored. }, // api will check this. It will be removed after api refactored.
@ -550,7 +549,7 @@ const StepTwo = ({
getRulesFromDetail() getRulesFromDetail()
getDefaultMode() getDefaultMode()
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [])
useEffect(() => { useEffect(() => {
@ -578,407 +577,411 @@ const StepTwo = ({
const isHoveringEconomy = useHover(economyDomRef) 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'>
<div className='relative h-full w-full overflow-y-scroll'> <div className={cn('relative h-full w-1/2 py-6 overflow-y-auto', isMobile ? 'px-4' : 'px-12')}>
<div className={cn(s.form, isMobile && '!px-4')}> <div className={'system-md-semibold mb-1'}>{t('datasetCreation.stepTwo.segmentation')}</div>
<div className={s.label}>{t('datasetCreation.stepTwo.segmentation')}</div> {(!datasetId || [ChuckingMode.text, ChuckingMode.qa].includes(currentDataset!.doc_form))
<div className='max-w-[640px]'> && <OptionCard
<div className='space-y-4'> className='bg-background-section mb-2'
{(!datasetId || [ChuckingMode.text, ChuckingMode.qa].includes(currentDataset!.doc_form)) title={t('datasetCreation.stepTwo.general')}
&& <OptionCard icon={<Image width={20} height={20} src={SettingCog} alt={t('datasetCreation.stepTwo.general')} />}
title={t('datasetCreation.stepTwo.general')} activeHeaderClassName='bg-dataset-option-card-blue-gradient'
icon={<Image src={SettingCog} alt={t('datasetCreation.stepTwo.general')} />} description={t('datasetCreation.stepTwo.generalTip')}
activeHeaderClassName='bg-dataset-option-card-blue-gradient' isActive={
description={t('datasetCreation.stepTwo.generalTip')} [ChuckingMode.text, ChuckingMode.qa].includes(
isActive={ datasetId ? currentDataset!.doc_form : docForm,
[ChuckingMode.text, ChuckingMode.qa].includes( )
datasetId ? currentDataset!.doc_form : docForm, }
) onSwitched={() =>
} handleChangeDocform(ChuckingMode.text)
onSwitched={() => }
handleChangeDocform(ChuckingMode.text) actions={
} <>
actions={ <Button variant={'secondary-accent'} onClick={() => updatePreview()}>
<> <RiSearchEyeLine className='h-4 w-4 mr-0.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> }
</> noHighlight={Boolean(datasetId)}
} >
noHighlight={Boolean(datasetId)} <div className='flex flex-col gap-y-4'>
> <div className='flex gap-3'>
<div className='space-y-4'> <DelimiterInput
<div className='flex gap-3'> value={segmentIdentifier}
<DelimiterInput onChange={e => setSegmentIdentifier(e.target.value, true)}
value={segmentIdentifier} />
onChange={e => setSegmentIdentifier(e.target.value)} <MaxLengthInput
/> value={maxChunkLength}
<MaxLengthInput onChange={setMaxChunkLength}
value={maxChunkLength} />
onChange={setMaxChunkLength} <OverlapInput
/> value={overlap}
<OverlapInput min={1}
value={overlap} onChange={setOverlap}
min={1} />
onChange={setOverlap} </div>
<div className='w-full flex flex-col'>
<div className='flex items-center gap-x-2'>
<div className='inline-flex shrink-0'>
<TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
</div>
<Divider className='grow' bgStyle='gradient' />
</div>
<div className='mt-1'>
{rules.map(rule => (
<div key={rule.id} className={s.ruleItem} onClick={() => {
ruleChangeHandle(rule.id)
}}>
<Checkbox
checked={rule.enabled}
/> />
<label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
</div> </div>
<div className='space-y-2'> ))}
<div className='w-full flex flex-col'> {IS_CE_EDITION && <>
<TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel> <div className='flex items-center'>
<div className='mt-4 space-y-2'> <Checkbox
{rules.map(rule => ( checked={docForm === ChuckingMode.qa}
<div key={rule.id} className={s.ruleItem} onClick={() => { onCheck={() => {
ruleChangeHandle(rule.id) if (docForm === ChuckingMode.qa)
}}> handleChangeDocform(ChuckingMode.text)
<Checkbox else
checked={rule.enabled} handleChangeDocform(ChuckingMode.qa)
/> }}
<label className="ml-2 text-sm font-normal cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label> />
</div> <div className='flex items-center gap-1'>
))} <label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">
{t('datasetCreation.stepTwo.useQALanguage')}
</label>
<div className='z-50 relative'>
<LanguageSelect
currentLanguage={docLanguage || locale}
onSelect={setDocLanguage}
disabled={isLanguageSelectDisabled}
/>
</div> </div>
<Tooltip popupContent={t('datasetCreation.stepTwo.QATip')} />
</div> </div>
</div> </div>
{IS_CE_EDITION && <> {docForm === ChuckingMode.qa && (
<div className='flex items-center'> <div
<Checkbox style={{
checked={docForm === ChuckingMode.qa} background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)',
onCheck={() => { }}
if (docForm === ChuckingMode.qa) className='h-10 mt-2 flex items-center gap-2 rounded-xl backdrop-blur-[5px] border-components-panel-border border shadow-xs px-3 text-xs'
handleChangeDocform(ChuckingMode.text) >
else <RiAlertFill className='size-4 text-text-warning-secondary' />
handleChangeDocform(ChuckingMode.qa) <span className='system-xs-medium text-text-primary'>
}} {t('datasetCreation.stepTwo.QATip')}
className='mr-2' </span>
/>
<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 </>}
style={{ </div>
background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)', </div>
}} </div>
className='h-10 flex items-center gap-2 rounded-xl border-components-panel-border border shadow-shadow-shadow-3 px-3 text-xs' </OptionCard>}
> {
<RiAlertFill className='size-4 text-text-warning-secondary' /> (!datasetId || currentDataset!.doc_form === ChuckingMode.parentChild)
<span className='text-sm font-medium text-text-primary'> && <OptionCard
{t('datasetCreation.stepTwo.QATip')} title={t('datasetCreation.stepTwo.parentChild')}
</span> icon={<Image width={20} height={20} src={FamilyMod} alt={t('datasetCreation.stepTwo.parentChild')} />}
</div> effectImg={OrangeEffect.src}
)} activeHeaderClassName='bg-dataset-option-card-orange-gradient'
</>} description={t('datasetCreation.stepTwo.parentChildTip')}
isActive={
datasetId ? currentDataset!.doc_form === ChuckingMode.parentChild : docForm === ChuckingMode.parentChild
}
onSwitched={() => handleChangeDocform(ChuckingMode.parentChild)}
actions={
<>
<Button variant={'secondary-accent'} onClick={() => updatePreview()}>
<RiSearchEyeLine className='h-4 w-4 mr-0.5' />
{t('datasetCreation.stepTwo.previewChunk')}
</Button>
<Button variant={'ghost'} onClick={resetRules}>
{t('datasetCreation.stepTwo.reset')}
</Button>
</>
}
noHighlight={Boolean(datasetId)}
>
<div className='flex flex-col gap-4'>
<div>
<div className='flex items-center gap-x-2'>
<div className='inline-flex shrink-0'>
<TextLabel>{t('datasetCreation.stepTwo.parentChunkForContext')}</TextLabel>
</div> </div>
</OptionCard>} <Divider className='grow' bgStyle='gradient' />
{ </div>
(!datasetId || currentDataset!.doc_form === ChuckingMode.parentChild) <RadioCard className='mt-1'
&& <OptionCard icon={<Image src={Note} alt='' />}
title={t('datasetCreation.stepTwo.parentChild')} title={t('datasetCreation.stepTwo.paragraph')}
icon={<Image src={FamilyMod} alt={t('datasetCreation.stepTwo.parentChild')} />} description={t('datasetCreation.stepTwo.paragraphTip')}
effectImg={OrangeEffect.src} isChosen={parentChildConfig.chunkForContext === 'paragraph'}
activeHeaderClassName='bg-dataset-option-card-orange-gradient' onChosen={() => setParentChildConfig(
description={t('datasetCreation.stepTwo.parentChildTip')} {
isActive={ ...parentChildConfig,
datasetId ? currentDataset!.doc_form === ChuckingMode.parentChild : docForm === ChuckingMode.parentChild chunkForContext: 'paragraph',
} },
onSwitched={() => handleChangeDocform(ChuckingMode.parentChild)} )}
actions={ chosenConfig={
<> <div className='flex gap-3'>
<Button variant={'secondary-accent'} onClick={() => updatePreview()}> <DelimiterInput
<RiSearchEyeLine className='h-4 w-4 mr-1.5' /> value={parentChildConfig.parent.delimiter}
{t('datasetCreation.stepTwo.previewChunk')} onChange={e => setParentChildConfig({
</Button> ...parentChildConfig,
<Button variant={'ghost'} onClick={resetRules}> parent: {
{t('datasetCreation.stepTwo.reset')} ...parentChildConfig.parent,
</Button> delimiter: e.target.value ? escape(e.target.value) : '',
</>
}
noHighlight={Boolean(datasetId)}
>
<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>
}
/> />
<RadioCard <MaxLengthInput
icon={<Image src={FileList} alt='' />} value={parentChildConfig.parent.maxLength}
title={t('datasetCreation.stepTwo.fullDoc')} onChange={value => setParentChildConfig({
description={t('datasetCreation.stepTwo.fullDocTip')} ...parentChildConfig,
onChosen={() => setParentChildConfig( parent: {
{ ...parentChildConfig.parent,
...parentChildConfig, maxLength: value,
chunkForContext: 'full-doc',
}, },
)} })}
isChosen={parentChildConfig.chunkForContext === 'full-doc'}
/> />
</div> </div>
}
/>
<RadioCard className='mt-2'
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 className='space-y-4'> <div>
<TextLabel> <div className='flex items-center gap-x-2'>
{t('datasetCreation.stepTwo.childChunkForRetrieval')} <div className='inline-flex shrink-0'>
</TextLabel> <TextLabel>{t('datasetCreation.stepTwo.childChunkForRetrieval')}</TextLabel>
<div className='flex gap-3 mt-2'>
<DelimiterInput
value={parentChildConfig.child.delimiter}
onChange={e => setParentChildConfig({
...parentChildConfig,
child: {
...parentChildConfig.child,
delimiter: e.target.value,
},
})}
/>
<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-text-secondary">{getRuleName(rule.id)}</label>
</div>
))}
</div>
</div>
</div>
</div> </div>
</OptionCard>} <Divider className='grow' bgStyle='gradient' />
</div>
<div className='flex gap-3 mt-1'>
<DelimiterInput
value={parentChildConfig.child.delimiter}
onChange={e => setParentChildConfig({
...parentChildConfig,
child: {
...parentChildConfig.child,
delimiter: e.target.value ? escape(e.target.value) : '',
},
})}
/>
<MaxLengthInput
value={parentChildConfig.child.maxLength}
onChange={value => setParentChildConfig({
...parentChildConfig,
child: {
...parentChildConfig.child,
maxLength: value,
},
})}
/>
</div>
</div>
<div>
<div className='flex items-center gap-x-2'>
<div className='inline-flex shrink-0'>
<TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
</div>
<Divider className='grow' bgStyle='gradient' />
</div>
<div className='mt-1'>
{rules.map(rule => (
<div key={rule.id} className={s.ruleItem} onClick={() => {
ruleChangeHandle(rule.id)
}}>
<Checkbox
checked={rule.enabled}
/>
<label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
</div>
))}
</div>
</div>
</div> </div>
</div> </OptionCard>}
<Divider className='my-5' /> <Divider className='my-5' />
<div className={s.label}>{t('datasetCreation.stepTwo.indexMode')}</div> <div className={'system-md-semibold mb-1'}>{t('datasetCreation.stepTwo.indexMode')}</div>
<div className='max-w-[640px]'> <div className='flex items-center gap-2 flex-wrap sm:flex-nowrap'>
<div className='flex items-center gap-3 flex-wrap sm:flex-nowrap'> {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.QUALIFIED)) && (
{(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.QUALIFIED)) && ( <OptionCard
<OptionCard title={<p className='flex items-center'>
title={<p className='flex items-center'> {t('datasetCreation.stepTwo.qualified')}
{t('datasetCreation.stepTwo.qualified')} {!hasSetIndexType
{!hasSetIndexType && <Badge className='ml-1' uppercase>{t('datasetCreation.stepTwo.recommend')}</Badge>} && <Badge className={cn('ml-1 h-[18px]', (!hasSetIndexType && indexType === IndexingType.QUALIFIED) ? 'border-text-accent-secondary text-text-accent-secondary' : '')} uppercase>{t('datasetCreation.stepTwo.recommend')}</Badge>}
<span className='ml-auto'> <span className='ml-auto'>
{!hasSetIndexType && <span className={cn(s.radio)} />} {!hasSetIndexType && <span className={cn(s.radio)} />}
</span> </span>
</p>} </p>}
description={t('datasetCreation.stepTwo.qualifiedTip')} description={t('datasetCreation.stepTwo.qualifiedTip')}
icon={<Image src={indexMethodIcon.high_quality} alt='' />} icon={<Image src={indexMethodIcon.high_quality} alt='' />}
isActive={!hasSetIndexType && indexType === IndexingType.QUALIFIED} isActive={!hasSetIndexType && indexType === IndexingType.QUALIFIED}
disabled={!isAPIKeySet || hasSetIndexType} disabled={!isAPIKeySet || hasSetIndexType}
onSwitched={() => { onSwitched={() => {
if (isAPIKeySet) if (isAPIKeySet)
setIndexType(IndexingType.QUALIFIED) setIndexType(IndexingType.QUALIFIED)
}} }}
/> />
)} )}
{(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && ( {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && (
<> <>
<CustomDialog show={isQAConfirmDialogOpen} onClose={() => setIsQAConfirmDialogOpen(false)} className='w-[432px]'> <CustomDialog show={isQAConfirmDialogOpen} onClose={() => setIsQAConfirmDialogOpen(false)} className='w-[432px]'>
<header className='pt-6 mb-4'> <header className='pt-6 mb-4'>
<h2 className='text-lg font-semibold'> <h2 className='text-lg font-semibold'>
{t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')} {t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')}
</h2> </h2>
<p className='font-normal text-sm mt-2'> <p className='font-normal text-sm mt-2'>
{t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')} {t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')}
</p> </p>
</header> </header>
<div className='flex gap-2 pb-6'> <div className='flex gap-2 pb-6'>
<Button className='ml-auto' onClick={() => { <Button className='ml-auto' onClick={() => {
setIsQAConfirmDialogOpen(false) setIsQAConfirmDialogOpen(false)
}}> }}>
{t('datasetCreation.stepTwo.cancel')} {t('datasetCreation.stepTwo.cancel')}
</Button> </Button>
<Button variant={'primary'} onClick={() => { <Button variant={'primary'} onClick={() => {
setIsQAConfirmDialogOpen(false) setIsQAConfirmDialogOpen(false)
setIndexType(IndexingType.QUALIFIED) setIndexType(IndexingType.QUALIFIED)
setDocForm(ChuckingMode.qa) setDocForm(ChuckingMode.qa)
}}> }}>
{t('datasetCreation.stepTwo.switch')} {t('datasetCreation.stepTwo.switch')}
</Button> </Button>
</div> </div>
</CustomDialog> </CustomDialog>
<PortalToFollowElem <PortalToFollowElem
open={ open={
isHoveringEconomy && docForm !== ChuckingMode.text isHoveringEconomy && docForm !== ChuckingMode.text
}
placement={'top'}
>
<PortalToFollowElemTrigger>
<OptionCard
title={t('datasetCreation.stepTwo.economical')}
description={t('datasetCreation.stepTwo.economicalTip')}
icon={<Image src={indexMethodIcon.economical} alt='' />}
isActive={!hasSetIndexType && indexType === IndexingType.ECONOMICAL}
disabled={!isAPIKeySet || hasSetIndexType || docForm !== ChuckingMode.text}
ref={economyDomRef}
onSwitched={() => {
if (isAPIKeySet && docForm === ChuckingMode.text)
setIndexType(IndexingType.ECONOMICAL)
}}
/>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<div className='p-3 bg-components-tooltip-bg border-components-panel-border text-xs font-medium text-text-secondary rounded-lg shadow-lg'>
{
docForm === ChuckingMode.qa
? t('datasetCreation.stepTwo.notAvailableForQA')
: t('datasetCreation.stepTwo.notAvailableForParentChild')
} }
placement={'top'} </div>
> </PortalToFollowElemContent>
<PortalToFollowElemTrigger> </PortalToFollowElem>
<OptionCard </>)}
title={t('datasetCreation.stepTwo.economical')} </div>
description={t('datasetCreation.stepTwo.economicalTip')} {hasSetIndexType && indexType === IndexingType.ECONOMICAL && (
icon={<Image src={indexMethodIcon.economical} alt='' />} <div className='mt-2 text-xs text-gray-500 font-medium'>
isActive={!hasSetIndexType && indexType === IndexingType.ECONOMICAL} {t('datasetCreation.stepTwo.indexSettingTip')}
disabled={!isAPIKeySet || hasSetIndexType || docForm !== ChuckingMode.text} <Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
ref={economyDomRef} </div>
onSwitched={() => { )}
if (isAPIKeySet && docForm === ChuckingMode.text) {/* Embedding model */}
setIndexType(IndexingType.ECONOMICAL) {indexType === IndexingType.QUALIFIED && (
}} <div className='mt-5'>
/> <div className={cn('system-md-semibold mb-1', datasetId && 'flex justify-between items-center')}>{t('datasetSettings.form.embeddingModel')}</div>
</PortalToFollowElemTrigger> <ModelSelector
<PortalToFollowElemContent> readonly={!!datasetId}
<div className='p-3 bg-components-tooltip-bg border-components-panel-border text-xs font-medium text-text-secondary rounded-lg shadow-lg'> defaultModel={embeddingModel}
{ modelList={embeddingModelList}
docForm === ChuckingMode.qa onSelect={(model: DefaultModel) => {
? t('datasetCreation.stepTwo.notAvailableForQA') setEmbeddingModel(model)
: t('datasetCreation.stepTwo.notAvailableForParentChild') }}
} />
</div> {!!datasetId && (
</PortalToFollowElemContent>
</PortalToFollowElem>
</>)}
</div>
{hasSetIndexType && indexType === IndexingType.ECONOMICAL && (
<div className='mt-2 text-xs text-gray-500 font-medium'> <div className='mt-2 text-xs text-gray-500 font-medium'>
{t('datasetCreation.stepTwo.indexSettingTip')} {t('datasetCreation.stepTwo.indexSettingTip')}
<Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link> <Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
</div> </div>
)} )}
{/* Embedding model */} </div>
{indexType === IndexingType.QUALIFIED && ( )}
<div className='mt-6 my-2'> <Divider className='my-5' />
<div className={cn(s.label, datasetId && 'flex justify-between items-center')}>{t('datasetSettings.form.embeddingModel')}</div> {/* Retrieval Method Config */}
<ModelSelector <div>
readonly={!!datasetId} {!datasetId
defaultModel={embeddingModel} ? (
modelList={embeddingModelList} <div className={'mb-1'}>
onSelect={(model: DefaultModel) => { <div className='system-md-semibold mb-0.5'>{t('datasetSettings.form.retrievalSetting.title')}</div>
setEmbeddingModel(model) <div className='body-xs-regular text-text-tertiary'>
}} <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
/> {t('datasetSettings.form.retrievalSetting.longDescription')}
{!!datasetId && ( </div>
<div className='mt-2 text-xs text-gray-500 font-medium'> </div>
{t('datasetCreation.stepTwo.indexSettingTip')} )
<Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link> : (
</div> <div className={cn('system-md-semibold mb-0.5', 'flex justify-between items-center')}>
)} <div>{t('datasetSettings.form.retrievalSetting.title')}</div>
</div> </div>
)} )}
<Divider className='my-5' />
{/* Retrieval Method Config */} <div className=''>
<div> {
{!datasetId getIndexing_technique() === IndexingType.QUALIFIED
? ( ? (
<div className={s.label}> <RetrievalMethodConfig
<div className='shrink-0 mr-4'>{t('datasetSettings.form.retrievalSetting.title')}</div> value={retrievalConfig}
<div className='leading-[18px] text-xs font-normal text-gray-500'> onChange={setRetrievalConfig}
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a> />
{t('datasetSettings.form.retrievalSetting.longDescription')}
</div>
</div>
) )
: ( : (
<div className={cn(s.label, 'flex justify-between items-center')}> <EconomicalRetrievalMethodConfig
<div>{t('datasetSettings.form.retrievalSetting.title')}</div> value={retrievalConfig}
</div> onChange={setRetrievalConfig}
)} />
)
<div className='max-w-[640px]'> }
{
getIndexing_technique() === IndexingType.QUALIFIED
? (
<RetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)
: (
<EconomicalRetrievalMethodConfig
value={retrievalConfig}
onChange={setRetrievalConfig}
/>
)
}
</div>
</div>
{!isSetting
? (
<div className='flex items-center mt-8 py-2'>
<Button onClick={() => onStepChange && onStepChange(-1)}>
<RiArrowLeftLine className='w-4 h-4 mr-1' />
{t('datasetCreation.stepTwo.previousStep')}
</Button>
<Button className='ml-auto' loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.nextStep')}</Button>
</div>
)
: (
<div className='flex items-center mt-8 py-2'>
<Button loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.save')}</Button>
<Button className='ml-2' onClick={onCancel}>{t('datasetCreation.stepTwo.cancel')}</Button>
</div>
)}
</div> </div>
</div> </div>
{!isSetting
? (
<div className='flex items-center mt-8 py-2'>
<Button onClick={() => onStepChange && onStepChange(-1)}>
<RiArrowLeftLine className='w-4 h-4 mr-1' />
{t('datasetCreation.stepTwo.previousStep')}
</Button>
<Button className='ml-auto' loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.nextStep')}</Button>
</div>
)
: (
<div className='flex items-center mt-8 py-2'>
<Button loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.save')}</Button>
<Button className='ml-2' onClick={onCancel}>{t('datasetCreation.stepTwo.cancel')}</Button>
</div>
)}
</div> </div>
<FloatRightContainer isMobile={isMobile} isOpen={true} onClose={() => { }} footer={null}> <FloatRightContainer isMobile={isMobile} isOpen={true} onClose={() => { }} footer={null}>
<PreviewContainer <PreviewContainer
@ -1049,7 +1052,7 @@ const StepTwo = ({
}) as string} /> }) as string} />
</div> </div>
</PreviewHeader>} </PreviewHeader>}
className={cn(s.previewWrap, isMobile && s.isMobile, 'relative h-full overflow-y-scroll')} className={cn('flex shrink-0 w-1/2 relative h-full overflow-y-scroll', isMobile && 'w-full max-w-[524px]')}
mainClassName='space-y-6' mainClassName='space-y-6'
> >
{docForm === ChuckingMode.qa && estimate?.qa_preview && ( {docForm === ChuckingMode.qa && estimate?.qa_preview && (

@ -19,8 +19,8 @@ const FormField: FC<PropsWithChildren<{ label: ReactNode }>> = (props) => {
export const DelimiterInput: FC<InputProps> = (props) => { export const DelimiterInput: FC<InputProps> = (props) => {
const { t } = useTranslation() const { t } = useTranslation()
return <FormField label={<div className='flex'> return <FormField label={<div className='flex items-center mb-1'>
{t('datasetCreation.stepTwo.separator')} <span className='system-sm-semibold mr-0.5'>{t('datasetCreation.stepTwo.separator')}</span>
<Tooltip <Tooltip
popupContent={ popupContent={
<div className='max-w-[200px]'> <div className='max-w-[200px]'>
@ -40,7 +40,7 @@ export const DelimiterInput: FC<InputProps> = (props) => {
export const MaxLengthInput: FC<InputNumberProps> = (props) => { export const MaxLengthInput: FC<InputNumberProps> = (props) => {
const { t } = useTranslation() const { t } = useTranslation()
return <FormField label={<div className='h-[14px]'> return <FormField label={<div className='system-sm-semibold mb-1'>
{t('datasetCreation.stepTwo.maxLength')} {t('datasetCreation.stepTwo.maxLength')}
</div>}> </div>}>
<InputNumber <InputNumber
@ -56,8 +56,8 @@ export const MaxLengthInput: FC<InputNumberProps> = (props) => {
export const OverlapInput: FC<InputNumberProps> = (props) => { export const OverlapInput: FC<InputNumberProps> = (props) => {
const { t } = useTranslation() const { t } = useTranslation()
return <FormField label={<div className='flex'> return <FormField label={<div className='flex items-center mb-1'>
{t('datasetCreation.stepTwo.overlap')} <span className='system-sm-semibold'>{t('datasetCreation.stepTwo.overlap')}</span>
<Tooltip <Tooltip
popupContent={ popupContent={
<div className='max-w-[200px]'> <div className='max-w-[200px]'>

@ -25,16 +25,18 @@ export const OptionCardHeader: FC<OptionCardHeaderProps> = (props) => {
)}> )}>
<div className='size-14 flex items-center justify-center relative overflow-hidden'> <div className='size-14 flex items-center justify-center relative overflow-hidden'>
{isActive && effectImg && <Image src={effectImg} className='absolute top-0 left-0 w-full h-full' alt='' width={56} height={56} />} {isActive && effectImg && <Image src={effectImg} className='absolute top-0 left-0 w-full h-full' alt='' width={56} height={56} />}
<div className='size-8 rounded-lg border p-1.5 shadow border-components-panel-border-subtle justify-center flex bg-background-default-dodge'> <div className='p-1'>
{icon} <div className='size-8 rounded-lg border p-1.5 shadow-md border-components-panel-border-subtle justify-center flex bg-background-default-dodge'>
{icon}
</div>
</div> </div>
</div> </div>
<TriangleArrow <TriangleArrow
className='absolute left-4 -bottom-1.5 text-components-panel-bg' className='absolute left-4 -bottom-1.5 text-components-panel-bg'
/> />
<div className='flex-1 space-y-1 py-3 pr-4'> <div className='flex-1 space-y-0.5 py-3'>
<div className='text-text-secondary text-sm font-semibold leading-tight'>{title}</div> <div className='text-text-secondary system-md-semibold'>{title}</div>
<div className='text-text-tertiary text-xs font-normal leading-none'>{description}</div> <div className='text-text-tertiary system-xs-regular'>{description}</div>
</div> </div>
</div> </div>
} }
@ -57,16 +59,15 @@ export const OptionCard: FC<OptionCardProps> = forwardRef((props, ref) => {
const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, onClick, noHighlight, disabled, ...rest } = props const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, onClick, noHighlight, disabled, ...rest } = props
return <div return <div
className={classNames( className={classNames(
'rounded-xl border bg-components-option-card-option-bg', 'rounded-xl bg-components-option-card-option-bg shadow-xs',
(isActive && !noHighlight) (isActive && !noHighlight)
? 'border-components-option-card-option-selected-border' ? 'border-[1.5px] border-components-option-card-option-selected-border'
: 'border-components-option-card-option-border', : 'border border-components-option-card-option-border',
disabled && 'opacity-50', disabled && 'opacity-50',
className, className,
)} )}
style={{ style={{
...style, ...style,
borderWidth: 1.5,
}} }}
onClick={(e) => { onClick={(e) => {
if (!isActive) if (!isActive)
@ -85,7 +86,7 @@ export const OptionCard: FC<OptionCardProps> = forwardRef((props, ref) => {
effectImg={effectImg} effectImg={effectImg}
/> />
{/** Body */} {/** Body */}
{isActive && (children || actions) && <div className='p-3'> {isActive && (children || actions) && <div className='py-3 px-4'>
{children} {children}
{actions && <div className='flex gap-2 mt-4'> {actions && <div className='flex gap-2 mt-4'>
{actions} {actions}

@ -20,7 +20,9 @@ export const Topbar: FC<TopbarProps> = (props) => {
const { t } = useTranslation() const { t } = useTranslation()
return <div className={classNames('flex h-[52px] items-center justify-between relative border-b border-b-divider-subtle', className)}> return <div className={classNames('flex h-[52px] items-center justify-between relative border-b border-b-divider-subtle', className)}>
<Link href={'/datasets'} className="h-12 pl-2 pr-6 py-2 justify-start items-center gap-1 inline-flex"> <Link href={'/datasets'} className="h-12 pl-2 pr-6 py-2 justify-start items-center gap-1 inline-flex">
<RiArrowLeftLine className='size-4 mr-2 text-text-primary' /> <div className='p-2'>
<RiArrowLeftLine className='size-4 text-text-primary' />
</div>
<p className="text-text-primary system-sm-semibold-uppercase"> <p className="text-text-primary system-sm-semibold-uppercase">
{t('datasetCreation.steps.header.creation')} {t('datasetCreation.steps.header.creation')}
</p> </p>

@ -23,7 +23,7 @@ import type { CreateDocumentReq } from '@/models/datasets'
import { DataSourceType } from '@/models/datasets' import { DataSourceType } from '@/models/datasets'
import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed' import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import cn from '@/utils/classnames'
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => { const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}> return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
<path d="M10.8332 5.83333L9.90355 3.9741C9.63601 3.439 9.50222 3.17144 9.30265 2.97597C9.12615 2.80311 8.91344 2.67164 8.6799 2.59109C8.41581 2.5 8.11668 2.5 7.51841 2.5H4.33317C3.39975 2.5 2.93304 2.5 2.57652 2.68166C2.26292 2.84144 2.00795 3.09641 1.84816 3.41002C1.6665 3.76654 1.6665 4.23325 1.6665 5.16667V5.83333M1.6665 5.83333H14.3332C15.7333 5.83333 16.4334 5.83333 16.9681 6.10582C17.4386 6.3455 17.821 6.72795 18.0607 7.19836C18.3332 7.73314 18.3332 8.4332 18.3332 9.83333V13.5C18.3332 14.9001 18.3332 15.6002 18.0607 16.135C17.821 16.6054 17.4386 16.9878 16.9681 17.2275C16.4334 17.5 15.7333 17.5 14.3332 17.5H5.6665C4.26637 17.5 3.56631 17.5 3.03153 17.2275C2.56112 16.9878 2.17867 16.6054 1.93899 16.135C1.6665 15.6002 1.6665 14.9001 1.6665 13.5V5.83333ZM9.99984 14.1667V9.16667M7.49984 11.6667H12.4998" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M10.8332 5.83333L9.90355 3.9741C9.63601 3.439 9.50222 3.17144 9.30265 2.97597C9.12615 2.80311 8.91344 2.67164 8.6799 2.59109C8.41581 2.5 8.11668 2.5 7.51841 2.5H4.33317C3.39975 2.5 2.93304 2.5 2.57652 2.68166C2.26292 2.84144 2.00795 3.09641 1.84816 3.41002C1.6665 3.76654 1.6665 4.23325 1.6665 5.16667V5.83333M1.6665 5.83333H14.3332C15.7333 5.83333 16.4334 5.83333 16.9681 6.10582C17.4386 6.3455 17.821 6.72795 18.0607 7.19836C18.3332 7.73314 18.3332 8.4332 18.3332 9.83333V13.5C18.3332 14.9001 18.3332 15.6002 18.0607 16.135C17.821 16.6054 17.4386 16.9878 16.9681 17.2275C16.4334 17.5 15.7333 17.5 14.3332 17.5H5.6665C4.26637 17.5 3.56631 17.5 3.03153 17.2275C2.56112 16.9878 2.17867 16.6054 1.93899 16.135C1.6665 15.6002 1.6665 14.9001 1.6665 13.5V5.83333ZM9.99984 14.1667V9.16667M7.49984 11.6667H12.4998" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
@ -239,10 +239,10 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
<IndexFailed datasetId={datasetId} /> <IndexFailed datasetId={datasetId} />
{embeddingAvailable && ( {embeddingAvailable && (
<Button variant='primary' onClick={routeToDocCreate} className='shrink-0'> <Button variant='primary' onClick={routeToDocCreate} className='shrink-0'>
<PlusIcon className='h-4 w-4 mr-2 stroke-current' /> <PlusIcon className={cn('h-4 w-4 mr-2 stroke-current')} />
{isDataSourceNotion && t('datasetDocuments.list.addPages')} {isDataSourceNotion && t('datasetDocuments.list.addPages')}
{isDataSourceWeb && t('datasetDocuments.list.addUrl')} {isDataSourceWeb && t('datasetDocuments.list.addUrl')}
{isDataSourceFile && t('datasetDocuments.list.addFile')} {(!dataset?.data_source_type || isDataSourceFile) && t('datasetDocuments.list.addFile')}
</Button> </Button>
)} )}
</div> </div>

@ -19,11 +19,11 @@ const ChildChunks: FC<Props> = ({
<div <div
className={!isShowAll ? 'line-clamp-2' : ''} className={!isShowAll ? 'line-clamp-2' : ''}
> >
<div className='inline-flex items-center relative top-[-3px]'> <div className='inline-flex items-center relative top-[-2px]'>
<div className='flex items-center h-[24px] bg-state-accent-solid system-2xs-semibold-uppercase text-text-primary-on-surface px-1'>C-{position}</div> <div className='flex items-center h-[20.5px] bg-state-accent-solid system-2xs-semibold-uppercase text-text-primary-on-surface px-1'>C-{position}</div>
<Score value={score} besideChunkName /> <Score value={score} besideChunkName />
</div> </div>
<SliceContent className='bg-state-accent-hover group-hover:bg-state-accent-hover text-text-secondary font-normal'>{content}</SliceContent> <SliceContent className='py-0.5 bg-state-accent-hover group-hover:bg-state-accent-hover text-sm text-text-secondary font-normal'>{content}</SliceContent>
</div> </div>
) )
} }

@ -38,8 +38,8 @@ const ChunkDetailModal: FC<Props> = ({
onClose={onHide} onClose={onHide}
className={cn(isParentChildRetrieval ? '!min-w-[1200px]' : '!min-w-[720px]')} className={cn(isParentChildRetrieval ? '!min-w-[1200px]' : '!min-w-[720px]')}
> >
<div className='mt-4 flex pb-6'> <div className='mt-4 flex'>
<div> <div className='w-full'>
{/* Meta info */} {/* Meta info */}
<div className='flex justify-between items-center'> <div className='flex justify-between items-center'>
<div className='grow flex items-center space-x-2'> <div className='grow flex items-center space-x-2'>

@ -13,7 +13,7 @@ const Score: FC<Props> = ({
besideChunkName, besideChunkName,
}) => { }) => {
return ( return (
<div className={cn('relative items-center px-[5px] border border-components-progress-bar-border overflow-hidden', besideChunkName ? 'border-l-0 h-[25px]' : 'h-[20px] rounded-md')}> <div className={cn('relative items-center px-[5px] border border-components-progress-bar-border overflow-hidden', besideChunkName ? 'border-l-0 h-[20.5px]' : 'h-[20px] rounded-md')}>
<div className={cn('absolute top-0 left-0 h-full bg-util-colors-blue-brand-blue-brand-100 border-r-[1.5px] border-components-progress-brand-progress', value === 1 && 'border-r-0')} style={{ width: `${value * 100}%` }} /> <div className={cn('absolute top-0 left-0 h-full bg-util-colors-blue-brand-blue-brand-100 border-r-[1.5px] border-components-progress-brand-progress', value === 1 && 'border-r-0')} style={{ width: `${value * 100}%` }} />
<div className={cn('relative flex items-center h-full space-x-0.5 text-util-colors-blue-brand-blue-brand-700')}> <div className={cn('relative flex items-center h-full space-x-0.5 text-util-colors-blue-brand-blue-brand-700')}>
<div className='system-2xs-medium-uppercase'>score</div> <div className='system-2xs-medium-uppercase'>score</div>

@ -136,6 +136,7 @@ const translation = {
QATitle: 'Segmenting in Question & Answer format', QATitle: 'Segmenting in Question & Answer format',
QATip: 'Enable this option will consume more tokens', QATip: 'Enable this option will consume more tokens',
QALanguage: 'Segment using', QALanguage: 'Segment using',
useQALanguage: 'Chunk using Q&A format in',
estimateCost: 'Estimation', estimateCost: 'Estimation',
estimateSegment: 'Estimated chunks', estimateSegment: 'Estimated chunks',
segmentCount: 'chunks', segmentCount: 'chunks',

@ -136,6 +136,7 @@ const translation = {
QATitle: '采用 Q&A 分段模式', QATitle: '采用 Q&A 分段模式',
QATip: '开启后将会消耗额外的 token', QATip: '开启后将会消耗额外的 token',
QALanguage: '分段使用', QALanguage: '分段使用',
useQALanguage: '使用 Q&A 分段,语言',
estimateCost: '执行嵌入预估消耗', estimateCost: '执行嵌入预估消耗',
estimateSegment: '预估分段数', estimateSegment: '预估分段数',
segmentCount: '段', segmentCount: '段',

Loading…
Cancel
Save