This commit is contained in:
zxhlyh 2025-05-19 18:08:27 +08:00
parent 7898dbd5bf
commit 7bce35913d
10 changed files with 149 additions and 79 deletions

View File

@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next'
import {
GeneralChunk,
ParentChildChunk,
@ -8,6 +9,7 @@ import { ChunkStructureEnum } from '../../types'
import type { Option } from './type'
export const useChunkStructure = () => {
const { t } = useTranslation()
const GeneralOption: Option = {
id: ChunkStructureEnum.general,
icon: (isActive: boolean) => (
@ -17,8 +19,8 @@ export const useChunkStructure = () => {
isActive && 'text-util-colors-indigo-indigo-600',
)} />
),
title: 'General',
description: 'General text chunking mode, the chunks retrieved and recalled are the same.',
title: t('datasetCreation.stepTwo.general'),
description: t('datasetCreation.stepTwo.generalTip'),
effectColor: 'blue',
}
const ParentChildOption: Option = {
@ -31,8 +33,8 @@ export const useChunkStructure = () => {
)}
/>
),
title: 'Parent-Child',
description: 'Parent-child text chunking mode, the chunks retrieved and recalled are different.',
title: t('datasetCreation.stepTwo.parentChild'),
description: t('datasetCreation.stepTwo.parentChildTip'),
effectColor: 'blue-light',
}
const QuestionAnswerOption: Option = {

View File

@ -2,6 +2,7 @@ import {
memo,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
@ -23,30 +24,31 @@ const EmbeddingModel = ({
onEmbeddingModelChange,
readonly = false,
}: EmbeddingModelProps) => {
const { t } = useTranslation()
const {
modelList: embeddingModelList,
} = useModelListAndDefaultModel(ModelTypeEnum.textEmbedding)
const embeddingModelConfig = useMemo(() => {
if (!embeddingModel || !embeddingModelProvider)
return undefined
const embeddingModelConfig = useMemo(() => {
if (!embeddingModel || !embeddingModelProvider)
return undefined
return {
providerName: embeddingModelProvider,
modelName: embeddingModel,
return {
providerName: embeddingModelProvider,
modelName: embeddingModel,
}
}, [embeddingModel, embeddingModelProvider])
const handleRerankingModelChange = (model: DefaultModel) => {
onEmbeddingModelChange?.({
embeddingModelProvider: model.provider,
embeddingModel: model.model,
})
}
}, [embeddingModel, embeddingModelProvider])
const handleRerankingModelChange = (model: DefaultModel) => {
onEmbeddingModelChange?.({
embeddingModelProvider: model.provider,
embeddingModel: model.model,
})
}
return (
<Field
fieldTitleProps={{
title: 'Embedding Model',
title: t('datasetSettings.form.embeddingModel'),
}}
>
<ModelSelector

View File

@ -52,7 +52,7 @@ const IndexMethod = ({
return (
<Field
fieldTitleProps={{
title: 'Index method',
title: t('datasetCreation.stepTwo.indexMode'),
}}
>
<div className='space-y-1'>

View File

@ -3,6 +3,7 @@ import {
memo,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import Badge from '@/app/components/base/badge'
import {
@ -53,6 +54,7 @@ const OptionCard = memo(({
onClick,
readonly,
}) => {
const { t } = useTranslation()
const isActive = useMemo(() => {
return id === selectedId
}, [id, selectedId])
@ -103,7 +105,7 @@ const OptionCard = memo(({
{
isRecommended && (
<Badge className='ml-1 h-4 border-text-accent-secondary text-text-accent-secondary'>
Recommend
{t('datasetCreation.stepTwo.recommend')}
</Badge>
)
}

View File

@ -1,4 +1,5 @@
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import {
FullTextSearch,
HybridSearch,
@ -15,57 +16,58 @@ import type {
} from './type'
export const useRetrievalSetting = (indexMethod: IndexMethodEnum) => {
const { t } = useTranslation()
const VectorSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.semantic,
icon: VectorSearch as any,
title: 'Vector Search',
description: 'Generate query embeddings and search for the text chunk most similar to its vector representation.',
title: t('dataset.retrieval.semantic_search.title'),
description: t('dataset.retrieval.semantic_search.description'),
effectColor: 'purple',
}
}, [])
}, [t])
const FullTextSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.fullText,
icon: FullTextSearch as any,
title: 'Full-Text Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
title: t('dataset.retrieval.full_text_search.title'),
description: t('dataset.retrieval.full_text_search.description'),
effectColor: 'purple',
}
}, [])
}, [t])
const HybridSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.hybrid,
icon: HybridSearch as any,
title: 'Hybrid Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
title: t('dataset.retrieval.hybrid_search.title'),
description: t('dataset.retrieval.hybrid_search.description'),
effectColor: 'purple',
}
}, [])
}, [t])
const InvertedIndexOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.invertedIndex,
icon: HybridSearch as any,
title: 'Inverted Index',
description: 'Use inverted index to search for the most relevant text chunks.',
title: t('dataset.retrieval.invertedIndex.title'),
description: t('dataset.retrieval.invertedIndex.description'),
effectColor: 'purple',
}
}, [])
}, [t])
const WeightedScoreModeOption: HybridSearchModeOption = useMemo(() => {
return {
id: HybridSearchModeEnum.WeightedScore,
title: 'Weighted Score',
description: 'By adjusting the weights assigned, this rerank strategy determines whether to prioritize semantic or keyword matching.',
title: t('dataset.weightedScore.title'),
description: t('dataset.weightedScore.description'),
}
}, [])
}, [t])
const RerankModelModeOption: HybridSearchModeOption = useMemo(() => {
return {
id: HybridSearchModeEnum.RerankingModel,
title: 'Rerank Model',
description: 'Rerank model will reorder the candidate document list based on the semantic match with user query, improving the results of semantic ranking.',
title: t('common.modelProvider.rerankModel.key'),
description: t('common.modelProvider.rerankModel.tip'),
}
}, [])
}, [t])
return useMemo(() => ({
options: indexMethod === IndexMethodEnum.ECONOMICAL ? [

View File

@ -1,6 +1,7 @@
import {
memo,
} from 'react'
import { useTranslation } from 'react-i18next'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import type {
HybridSearchModeEnum,
@ -22,6 +23,8 @@ type RetrievalSettingProps = {
onRetrievalSearchMethodChange: (value: RetrievalSearchMethodEnum) => void
hybridSearchMode: HybridSearchModeEnum
onHybridSearchModeChange: (value: HybridSearchModeEnum) => void
rerankingModelEnabled?: boolean
onRerankingModelEnabledChange?: (value: boolean) => void
weightedScore?: WeightedScore
onWeightedScoreChange: (value: { value: number[] }) => void
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
@ -35,6 +38,8 @@ const RetrievalSetting = ({
onHybridSearchModeChange,
weightedScore,
onWeightedScoreChange,
rerankingModelEnabled,
onRerankingModelEnabledChange,
rerankingModel,
onRerankingModelChange,
topK,
@ -44,6 +49,7 @@ const RetrievalSetting = ({
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
}: RetrievalSettingProps) => {
const { t } = useTranslation()
const {
options,
hybridSearchModeOptions,
@ -52,16 +58,10 @@ const RetrievalSetting = ({
return (
<Field
fieldTitleProps={{
title: 'Retrieval Setting',
title: t('datasetSettings.form.retrievalSetting.title'),
subTitle: (
<div className='body-xs-regular flex items-center text-text-tertiary'>
<a
href=''
className='text-text-accent'
target='_blank'
>
Learn more
</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>
&nbsp;
about retrieval method.
</div>
@ -87,6 +87,8 @@ const RetrievalSetting = ({
onScoreThresholdChange={onScoreThresholdChange}
isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
rerankingModelEnabled={rerankingModelEnabled}
onRerankingModelEnabledChange={onRerankingModelEnabledChange}
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
readonly={readonly}

View File

@ -3,9 +3,12 @@ import {
useCallback,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import WeightedScoreComponent from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
import { DEFAULT_WEIGHTED_SCORE } from '@/models/datasets'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import {
HybridSearchModeEnum,
RetrievalSearchMethodEnum,
@ -33,6 +36,8 @@ type SearchMethodOptionProps = {
onHybridSearchModeChange: (value: HybridSearchModeEnum) => void
weightedScore?: WeightedScore
onWeightedScoreChange: (value: { value: number[] }) => void
rerankingModelEnabled?: boolean
onRerankingModelEnabledChange?: (value: boolean) => void
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const SearchMethodOption = ({
readonly,
@ -44,6 +49,8 @@ const SearchMethodOption = ({
onHybridSearchModeChange,
weightedScore,
onWeightedScoreChange,
rerankingModelEnabled,
onRerankingModelEnabledChange,
rerankingModel,
onRerankingModelChange,
topK,
@ -53,6 +60,7 @@ const SearchMethodOption = ({
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
}: SearchMethodOptionProps) => {
const { t } = useTranslation()
const Icon = option.icon
const isHybridSearch = option.id === RetrievalSearchMethodEnum.hybrid
const isHybridSearchWeightedScoreMode = hybridSearchMode === HybridSearchModeEnum.WeightedScore
@ -82,6 +90,28 @@ const SearchMethodOption = ({
return isActive ? 'border-[1.5px] bg-components-option-card-option-selected-bg' : ''
}, [])
const showRerankModelSelectorSwitch = useMemo(() => {
if (searchMethod === RetrievalSearchMethodEnum.semantic)
return true
if (searchMethod === RetrievalSearchMethodEnum.fullText)
return true
return false
}, [searchMethod])
const showRerankModelSelector = useMemo(() => {
if (searchMethod === RetrievalSearchMethodEnum.semantic)
return true
if (searchMethod === RetrievalSearchMethodEnum.fullText)
return true
if (searchMethod === RetrievalSearchMethodEnum.hybrid && hybridSearchMode !== HybridSearchModeEnum.WeightedScore)
return true
return false
}, [hybridSearchMode, searchMethod])
return (
<OptionCard
key={option.id}
@ -129,12 +159,31 @@ const SearchMethodOption = ({
)
}
{
!(isHybridSearch && hybridSearchMode === HybridSearchModeEnum.WeightedScore) && (
<RerankingModelSelector
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
readonly={readonly}
/>
showRerankModelSelector && (
<div>
{
showRerankModelSelectorSwitch && (
<div className='system-sm-semibold mb-1 flex items-center text-text-secondary'>
<Switch
className='mr-1'
defaultValue={rerankingModelEnabled}
onChange={onRerankingModelEnabledChange}
disabled={readonly}
/>
{t('common.modelProvider.rerankModel.key')}
<Tooltip
triggerClassName='ml-0.5 shrink-0 w-3.5 h-3.5'
popupContent={t('common.modelProvider.rerankModel.tip')}
/>
</div>
)
}
<RerankingModelSelector
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
readonly={readonly}
/>
</div>
)
}
<TopKAndScoreThreshold
@ -145,6 +194,7 @@ const SearchMethodOption = ({
isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
readonly={readonly}
hiddenScoreThreshold={searchMethod === RetrievalSearchMethodEnum.invertedIndex}
/>
</div>
</OptionCard>

View File

@ -1,4 +1,5 @@
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import Tooltip from '@/app/components/base/tooltip'
import Input from '@/app/components/base/input'
import Switch from '@/app/components/base/switch'
@ -11,6 +12,7 @@ export type TopKAndScoreThresholdProps = {
isScoreThresholdEnabled?: boolean
onScoreThresholdEnabledChange?: (value: boolean) => void
readonly?: boolean
hiddenScoreThreshold?: boolean
}
const TopKAndScoreThreshold = ({
topK,
@ -20,7 +22,9 @@ const TopKAndScoreThreshold = ({
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
readonly,
hiddenScoreThreshold,
}: TopKAndScoreThresholdProps) => {
const { t } = useTranslation()
const handleTopKChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value)
if (Number.isNaN(value))
@ -39,10 +43,10 @@ const TopKAndScoreThreshold = ({
<div className='grid grid-cols-2 gap-4'>
<div>
<div className='system-xs-medium mb-0.5 flex h-6 items-center text-text-secondary'>
Top k
{t('appDebug.datasetConfig.top_k')}
<Tooltip
triggerClassName='ml-0.5 shrink-0 w-3.5 h-3.5'
popupContent='top k'
popupContent={t('appDebug.datasetConfig.top_kTip')}
/>
</div>
<Input
@ -52,29 +56,33 @@ const TopKAndScoreThreshold = ({
disabled={readonly}
/>
</div>
<div>
<div className='mb-0.5 flex h-6 items-center'>
<Switch
className='mr-2'
defaultValue={isScoreThresholdEnabled}
onChange={onScoreThresholdEnabledChange}
disabled={readonly}
/>
<div className='system-sm-medium grow truncate text-text-secondary'>
Score Threshold
{
!hiddenScoreThreshold && (
<div>
<div className='mb-0.5 flex h-6 items-center'>
<Switch
className='mr-2'
defaultValue={isScoreThresholdEnabled}
onChange={onScoreThresholdEnabledChange}
disabled={readonly}
/>
<div className='system-sm-medium grow truncate text-text-secondary'>
{t('appDebug.datasetConfig.score_threshold')}
</div>
<Tooltip
triggerClassName='shrink-0 ml-0.5 w-3.5 h-3.5'
popupContent={t('appDebug.datasetConfig.score_thresholdTip')}
/>
</div>
<Input
type='number'
value={scoreThreshold}
onChange={handleScoreThresholdChange}
disabled={readonly || !isScoreThresholdEnabled}
/>
</div>
<Tooltip
triggerClassName='shrink-0 ml-0.5 w-3.5 h-3.5'
popupContent='Score Threshold'
/>
</div>
<Input
type='number'
value={scoreThreshold}
onChange={handleScoreThresholdChange}
disabled={readonly}
/>
</div>
)
}
</div>
)
}

View File

@ -1,17 +1,19 @@
import type { FC } from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import type { KnowledgeBaseNodeType } from './types'
import type { NodeProps } from '@/app/components/workflow/types'
const Node: FC<NodeProps<KnowledgeBaseNodeType>> = ({ data }) => {
const { t } = useTranslation()
return (
<div className='mb-1 space-y-0.5 px-3 py-1'>
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1.5'>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>Index method</div>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>{t('datasetCreation.stepTwo.indexMode')}</div>
<div className='system-xs-medium grow truncate text-right text-text-secondary' title={data.indexing_technique}>{data.indexing_technique}</div>
</div>
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1.5'>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>Retrieval Method</div>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='system-xs-medium grow truncate text-right text-text-secondary' title={data.retrieval_model.search_method}>{data.retrieval_model.search_method}</div>
</div>
</div>