pull/21398/head
zxhlyh 1 year ago
parent 7898dbd5bf
commit 7bce35913d

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

@ -2,6 +2,7 @@ import {
memo, memo,
useMemo, useMemo,
} from 'react' } from 'react'
import { useTranslation } from 'react-i18next'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout' import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' 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' import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
@ -23,6 +24,7 @@ const EmbeddingModel = ({
onEmbeddingModelChange, onEmbeddingModelChange,
readonly = false, readonly = false,
}: EmbeddingModelProps) => { }: EmbeddingModelProps) => {
const { t } = useTranslation()
const { const {
modelList: embeddingModelList, modelList: embeddingModelList,
} = useModelListAndDefaultModel(ModelTypeEnum.textEmbedding) } = useModelListAndDefaultModel(ModelTypeEnum.textEmbedding)
@ -46,7 +48,7 @@ const handleRerankingModelChange = (model: DefaultModel) => {
return ( return (
<Field <Field
fieldTitleProps={{ fieldTitleProps={{
title: 'Embedding Model', title: t('datasetSettings.form.embeddingModel'),
}} }}
> >
<ModelSelector <ModelSelector

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

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

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

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

@ -3,9 +3,12 @@ import {
useCallback, useCallback,
useMemo, useMemo,
} from 'react' } from 'react'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import WeightedScoreComponent from '@/app/components/app/configuration/dataset-config/params-config/weighted-score' import WeightedScoreComponent from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
import { DEFAULT_WEIGHTED_SCORE } from '@/models/datasets' import { DEFAULT_WEIGHTED_SCORE } from '@/models/datasets'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import { import {
HybridSearchModeEnum, HybridSearchModeEnum,
RetrievalSearchMethodEnum, RetrievalSearchMethodEnum,
@ -33,6 +36,8 @@ type SearchMethodOptionProps = {
onHybridSearchModeChange: (value: HybridSearchModeEnum) => void onHybridSearchModeChange: (value: HybridSearchModeEnum) => void
weightedScore?: WeightedScore weightedScore?: WeightedScore
onWeightedScoreChange: (value: { value: number[] }) => void onWeightedScoreChange: (value: { value: number[] }) => void
rerankingModelEnabled?: boolean
onRerankingModelEnabledChange?: (value: boolean) => void
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps } & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const SearchMethodOption = ({ const SearchMethodOption = ({
readonly, readonly,
@ -44,6 +49,8 @@ const SearchMethodOption = ({
onHybridSearchModeChange, onHybridSearchModeChange,
weightedScore, weightedScore,
onWeightedScoreChange, onWeightedScoreChange,
rerankingModelEnabled,
onRerankingModelEnabledChange,
rerankingModel, rerankingModel,
onRerankingModelChange, onRerankingModelChange,
topK, topK,
@ -53,6 +60,7 @@ const SearchMethodOption = ({
isScoreThresholdEnabled, isScoreThresholdEnabled,
onScoreThresholdEnabledChange, onScoreThresholdEnabledChange,
}: SearchMethodOptionProps) => { }: SearchMethodOptionProps) => {
const { t } = useTranslation()
const Icon = option.icon const Icon = option.icon
const isHybridSearch = option.id === RetrievalSearchMethodEnum.hybrid const isHybridSearch = option.id === RetrievalSearchMethodEnum.hybrid
const isHybridSearchWeightedScoreMode = hybridSearchMode === HybridSearchModeEnum.WeightedScore const isHybridSearchWeightedScoreMode = hybridSearchMode === HybridSearchModeEnum.WeightedScore
@ -82,6 +90,28 @@ const SearchMethodOption = ({
return isActive ? 'border-[1.5px] bg-components-option-card-option-selected-bg' : '' 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 ( return (
<OptionCard <OptionCard
key={option.id} key={option.id}
@ -129,12 +159,31 @@ const SearchMethodOption = ({
) )
} }
{ {
!(isHybridSearch && hybridSearchMode === HybridSearchModeEnum.WeightedScore) && ( 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 <RerankingModelSelector
rerankingModel={rerankingModel} rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange} onRerankingModelChange={onRerankingModelChange}
readonly={readonly} readonly={readonly}
/> />
</div>
) )
} }
<TopKAndScoreThreshold <TopKAndScoreThreshold
@ -145,6 +194,7 @@ const SearchMethodOption = ({
isScoreThresholdEnabled={isScoreThresholdEnabled} isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange} onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
readonly={readonly} readonly={readonly}
hiddenScoreThreshold={searchMethod === RetrievalSearchMethodEnum.invertedIndex}
/> />
</div> </div>
</OptionCard> </OptionCard>

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

@ -1,17 +1,19 @@
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react' import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import type { KnowledgeBaseNodeType } from './types' import type { KnowledgeBaseNodeType } from './types'
import type { NodeProps } from '@/app/components/workflow/types' import type { NodeProps } from '@/app/components/workflow/types'
const Node: FC<NodeProps<KnowledgeBaseNodeType>> = ({ data }) => { const Node: FC<NodeProps<KnowledgeBaseNodeType>> = ({ data }) => {
const { t } = useTranslation()
return ( return (
<div className='mb-1 space-y-0.5 px-3 py-1'> <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='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 className='system-xs-medium grow truncate text-right text-text-secondary' title={data.indexing_technique}>{data.indexing_technique}</div>
</div> </div>
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1.5'> <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 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>
</div> </div>

Loading…
Cancel
Save