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,9 +54,12 @@ 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'>
<div className='size-8 shrink-0'></div>
<div className={cn(chosenConfigWrapClassName, 'grow')}>
{chosenConfig} {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.
@ -578,16 +577,14 @@ 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>
<div className='max-w-[640px]'>
<div className='space-y-4'>
{(!datasetId || [ChuckingMode.text, ChuckingMode.qa].includes(currentDataset!.doc_form)) {(!datasetId || [ChuckingMode.text, ChuckingMode.qa].includes(currentDataset!.doc_form))
&& <OptionCard && <OptionCard
className='bg-background-section mb-2'
title={t('datasetCreation.stepTwo.general')} title={t('datasetCreation.stepTwo.general')}
icon={<Image src={SettingCog} alt={t('datasetCreation.stepTwo.general')} />} icon={<Image width={20} height={20} src={SettingCog} alt={t('datasetCreation.stepTwo.general')} />}
activeHeaderClassName='bg-dataset-option-card-blue-gradient' activeHeaderClassName='bg-dataset-option-card-blue-gradient'
description={t('datasetCreation.stepTwo.generalTip')} description={t('datasetCreation.stepTwo.generalTip')}
isActive={ isActive={
@ -601,7 +598,7 @@ const StepTwo = ({
actions={ actions={
<> <>
<Button variant={'secondary-accent'} onClick={() => updatePreview()}> <Button variant={'secondary-accent'} onClick={() => updatePreview()}>
<RiSearchEyeLine className='h-4 w-4 mr-1.5' /> <RiSearchEyeLine className='h-4 w-4 mr-0.5' />
{t('datasetCreation.stepTwo.previewChunk')} {t('datasetCreation.stepTwo.previewChunk')}
</Button> </Button>
<Button variant={'ghost'} onClick={resetRules}> <Button variant={'ghost'} onClick={resetRules}>
@ -611,11 +608,11 @@ const StepTwo = ({
} }
noHighlight={Boolean(datasetId)} noHighlight={Boolean(datasetId)}
> >
<div className='space-y-4'> <div className='flex flex-col gap-y-4'>
<div className='flex gap-3'> <div className='flex gap-3'>
<DelimiterInput <DelimiterInput
value={segmentIdentifier} value={segmentIdentifier}
onChange={e => setSegmentIdentifier(e.target.value)} onChange={e => setSegmentIdentifier(e.target.value, true)}
/> />
<MaxLengthInput <MaxLengthInput
value={maxChunkLength} value={maxChunkLength}
@ -627,10 +624,14 @@ const StepTwo = ({
onChange={setOverlap} onChange={setOverlap}
/> />
</div> </div>
<div className='space-y-2'>
<div className='w-full flex flex-col'> <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> <TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
<div className='mt-4 space-y-2'> </div>
<Divider className='grow' bgStyle='gradient' />
</div>
<div className='mt-1'>
{rules.map(rule => ( {rules.map(rule => (
<div key={rule.id} className={s.ruleItem} onClick={() => { <div key={rule.id} className={s.ruleItem} onClick={() => {
ruleChangeHandle(rule.id) ruleChangeHandle(rule.id)
@ -638,12 +639,9 @@ const StepTwo = ({
<Checkbox <Checkbox
checked={rule.enabled} checked={rule.enabled}
/> />
<label className="ml-2 text-sm font-normal cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label> <label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
</div> </div>
))} ))}
</div>
</div>
</div>
{IS_CE_EDITION && <> {IS_CE_EDITION && <>
<div className='flex items-center'> <div className='flex items-center'>
<Checkbox <Checkbox
@ -654,12 +652,11 @@ const StepTwo = ({
else else
handleChangeDocform(ChuckingMode.qa) handleChangeDocform(ChuckingMode.qa)
}} }}
className='mr-2'
/> />
<div className='flex items-center gap-1'> <div className='flex items-center gap-1'>
<TextLabel> <label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">
{t('datasetCreation.stepTwo.QALanguage')} {t('datasetCreation.stepTwo.useQALanguage')}
</TextLabel> </label>
<div className='z-50 relative'> <div className='z-50 relative'>
<LanguageSelect <LanguageSelect
currentLanguage={docLanguage || locale} currentLanguage={docLanguage || locale}
@ -675,22 +672,24 @@ const StepTwo = ({
style={{ style={{
background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)', background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)',
}} }}
className='h-10 flex items-center gap-2 rounded-xl border-components-panel-border border shadow-shadow-shadow-3 px-3 text-xs' 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'
> >
<RiAlertFill className='size-4 text-text-warning-secondary' /> <RiAlertFill className='size-4 text-text-warning-secondary' />
<span className='text-sm font-medium text-text-primary'> <span className='system-xs-medium text-text-primary'>
{t('datasetCreation.stepTwo.QATip')} {t('datasetCreation.stepTwo.QATip')}
</span> </span>
</div> </div>
)} )}
</>} </>}
</div> </div>
</div>
</div>
</OptionCard>} </OptionCard>}
{ {
(!datasetId || currentDataset!.doc_form === ChuckingMode.parentChild) (!datasetId || currentDataset!.doc_form === ChuckingMode.parentChild)
&& <OptionCard && <OptionCard
title={t('datasetCreation.stepTwo.parentChild')} title={t('datasetCreation.stepTwo.parentChild')}
icon={<Image src={FamilyMod} alt={t('datasetCreation.stepTwo.parentChild')} />} icon={<Image width={20} height={20} src={FamilyMod} alt={t('datasetCreation.stepTwo.parentChild')} />}
effectImg={OrangeEffect.src} effectImg={OrangeEffect.src}
activeHeaderClassName='bg-dataset-option-card-orange-gradient' activeHeaderClassName='bg-dataset-option-card-orange-gradient'
description={t('datasetCreation.stepTwo.parentChildTip')} description={t('datasetCreation.stepTwo.parentChildTip')}
@ -701,7 +700,7 @@ const StepTwo = ({
actions={ actions={
<> <>
<Button variant={'secondary-accent'} onClick={() => updatePreview()}> <Button variant={'secondary-accent'} onClick={() => updatePreview()}>
<RiSearchEyeLine className='h-4 w-4 mr-1.5' /> <RiSearchEyeLine className='h-4 w-4 mr-0.5' />
{t('datasetCreation.stepTwo.previewChunk')} {t('datasetCreation.stepTwo.previewChunk')}
</Button> </Button>
<Button variant={'ghost'} onClick={resetRules}> <Button variant={'ghost'} onClick={resetRules}>
@ -711,12 +710,15 @@ const StepTwo = ({
} }
noHighlight={Boolean(datasetId)} noHighlight={Boolean(datasetId)}
> >
<div className='space-y-4'> <div className='flex flex-col gap-4'>
<div className='space-y-2'> <div>
<TextLabel> <div className='flex items-center gap-x-2'>
{t('datasetCreation.stepTwo.parentChunkForContext')} <div className='inline-flex shrink-0'>
</TextLabel> <TextLabel>{t('datasetCreation.stepTwo.parentChunkForContext')}</TextLabel>
<RadioCard </div>
<Divider className='grow' bgStyle='gradient' />
</div>
<RadioCard className='mt-1'
icon={<Image src={Note} alt='' />} icon={<Image src={Note} alt='' />}
title={t('datasetCreation.stepTwo.paragraph')} title={t('datasetCreation.stepTwo.paragraph')}
description={t('datasetCreation.stepTwo.paragraphTip')} description={t('datasetCreation.stepTwo.paragraphTip')}
@ -728,14 +730,14 @@ const StepTwo = ({
}, },
)} )}
chosenConfig={ chosenConfig={
<div className='flex gap-2'> <div className='flex gap-3'>
<DelimiterInput <DelimiterInput
value={parentChildConfig.parent.delimiter} value={parentChildConfig.parent.delimiter}
onChange={e => setParentChildConfig({ onChange={e => setParentChildConfig({
...parentChildConfig, ...parentChildConfig,
parent: { parent: {
...parentChildConfig.parent, ...parentChildConfig.parent,
delimiter: e.target.value, delimiter: e.target.value ? escape(e.target.value) : '',
}, },
})} })}
/> />
@ -752,7 +754,7 @@ const StepTwo = ({
</div> </div>
} }
/> />
<RadioCard <RadioCard className='mt-2'
icon={<Image src={FileList} alt='' />} icon={<Image src={FileList} alt='' />}
title={t('datasetCreation.stepTwo.fullDoc')} title={t('datasetCreation.stepTwo.fullDoc')}
description={t('datasetCreation.stepTwo.fullDocTip')} description={t('datasetCreation.stepTwo.fullDocTip')}
@ -766,18 +768,21 @@ const StepTwo = ({
/> />
</div> </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'> </div>
<Divider className='grow' bgStyle='gradient' />
</div>
<div className='flex gap-3 mt-1'>
<DelimiterInput <DelimiterInput
value={parentChildConfig.child.delimiter} value={parentChildConfig.child.delimiter}
onChange={e => setParentChildConfig({ onChange={e => setParentChildConfig({
...parentChildConfig, ...parentChildConfig,
child: { child: {
...parentChildConfig.child, ...parentChildConfig.child,
delimiter: e.target.value, delimiter: e.target.value ? escape(e.target.value) : '',
}, },
})} })}
/> />
@ -792,12 +797,15 @@ const StepTwo = ({
})} })}
/> />
</div> </div>
</div>
<div className='space-y-2'> <div>
<TextLabel> <div className='flex items-center gap-x-2'>
{t('datasetCreation.stepTwo.rules')} <div className='inline-flex shrink-0'>
</TextLabel> <TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
<div className='space-y-2 mt-2'> </div>
<Divider className='grow' bgStyle='gradient' />
</div>
<div className='mt-1'>
{rules.map(rule => ( {rules.map(rule => (
<div key={rule.id} className={s.ruleItem} onClick={() => { <div key={rule.id} className={s.ruleItem} onClick={() => {
ruleChangeHandle(rule.id) ruleChangeHandle(rule.id)
@ -805,25 +813,22 @@ const StepTwo = ({
<Checkbox <Checkbox
checked={rule.enabled} checked={rule.enabled}
/> />
<label className="ml-2 text-sm font-normal cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label> <label className="ml-2 system-sm-regular cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
</div> </div>
))} ))}
</div> </div>
</div> </div>
</div> </div>
</div>
</OptionCard>} </OptionCard>}
</div>
</div>
<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 && <Badge className='ml-1' uppercase>{t('datasetCreation.stepTwo.recommend')}</Badge>} {!hasSetIndexType
&& <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>
@ -905,8 +910,8 @@ const StepTwo = ({
)} )}
{/* Embedding model */} {/* Embedding model */}
{indexType === IndexingType.QUALIFIED && ( {indexType === IndexingType.QUALIFIED && (
<div className='mt-6 my-2'> <div className='mt-5'>
<div className={cn(s.label, datasetId && 'flex justify-between items-center')}>{t('datasetSettings.form.embeddingModel')}</div> <div className={cn('system-md-semibold mb-1', datasetId && 'flex justify-between items-center')}>{t('datasetSettings.form.embeddingModel')}</div>
<ModelSelector <ModelSelector
readonly={!!datasetId} readonly={!!datasetId}
defaultModel={embeddingModel} defaultModel={embeddingModel}
@ -928,21 +933,21 @@ const StepTwo = ({
<div> <div>
{!datasetId {!datasetId
? ( ? (
<div className={s.label}> <div className={'mb-1'}>
<div className='shrink-0 mr-4'>{t('datasetSettings.form.retrievalSetting.title')}</div> <div className='system-md-semibold mb-0.5'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='leading-[18px] text-xs font-normal text-gray-500'> <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> <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')} {t('datasetSettings.form.retrievalSetting.longDescription')}
</div> </div>
</div> </div>
) )
: ( : (
<div className={cn(s.label, 'flex justify-between items-center')}> <div className={cn('system-md-semibold mb-0.5', 'flex justify-between items-center')}>
<div>{t('datasetSettings.form.retrievalSetting.title')}</div> <div>{t('datasetSettings.form.retrievalSetting.title')}</div>
</div> </div>
)} )}
<div className='max-w-[640px]'> <div className=''>
{ {
getIndexing_technique() === IndexingType.QUALIFIED getIndexing_technique() === IndexingType.QUALIFIED
? ( ? (
@ -978,8 +983,6 @@ const StepTwo = ({
</div> </div>
)} )}
</div> </div>
</div>
</div>
<FloatRightContainer isMobile={isMobile} isOpen={true} onClose={() => { }} footer={null}> <FloatRightContainer isMobile={isMobile} isOpen={true} onClose={() => { }} footer={null}>
<PreviewContainer <PreviewContainer
header={<PreviewHeader header={<PreviewHeader
@ -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'>
<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} {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