'use client' import { memo, useCallback, useEffect, useMemo } from 'react' import type { FC } from 'react' import { useTranslation } from 'react-i18next' import WeightedScore from './weighted-score' import TopKItem from '@/app/components/base/param-item/top-k-item' import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item' import { RETRIEVE_TYPE } from '@/types/app' import type { DatasetConfigs, } from '@/models/debug' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import { useCurrentProviderAndModel, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import type { ModelConfig } from '@/app/components/workflow/types' import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' import Tooltip from '@/app/components/base/tooltip' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { DataSet, } from '@/models/datasets' import { RerankingModeEnum } from '@/models/datasets' import cn from '@/utils/classnames' import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowledge-retrieval/hooks' import Switch from '@/app/components/base/switch' import Toast from '@/app/components/base/toast' type Props = { datasetConfigs: DatasetConfigs onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void isInWorkflow?: boolean singleRetrievalModelConfig?: ModelConfig onSingleRetrievalModelChange?: (config: ModelConfig) => void onSingleRetrievalModelParamsChange?: (config: ModelConfig) => void selectedDatasets?: DataSet[] } const ConfigContent: FC = ({ datasetConfigs, onChange, isInWorkflow, singleRetrievalModelConfig: singleRetrievalConfig = {} as ModelConfig, onSingleRetrievalModelChange = () => { }, onSingleRetrievalModelParamsChange = () => { }, selectedDatasets = [], }) => { const { t } = useTranslation() const selectedDatasetsMode = useSelectedDatasetsMode(selectedDatasets) const type = datasetConfigs.retrieval_model useEffect(() => { if (type === RETRIEVE_TYPE.oneWay) { onChange({ ...datasetConfigs, retrieval_model: RETRIEVE_TYPE.multiWay, }, isInWorkflow) } }, [type, datasetConfigs, isInWorkflow, onChange]) const { modelList: rerankModelList, defaultModel: rerankDefaultModel, currentModel: isRerankDefaultModelValid, } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank) const { currentModel: currentRerankModel, } = useCurrentProviderAndModel( rerankModelList, rerankDefaultModel ? { ...rerankDefaultModel, provider: rerankDefaultModel.provider.provider, } : undefined, ) const rerankModel = (() => { if (datasetConfigs.reranking_model?.reranking_provider_name) { return { provider_name: datasetConfigs.reranking_model.reranking_provider_name, model_name: datasetConfigs.reranking_model.reranking_model_name, } } else if (rerankDefaultModel) { return { provider_name: rerankDefaultModel.provider.provider, model_name: rerankDefaultModel.model, } } })() const handleParamChange = (key: string, value: number) => { if (key === 'top_k') { onChange({ ...datasetConfigs, top_k: value, }) } else if (key === 'score_threshold') { onChange({ ...datasetConfigs, score_threshold: value, }) } } const handleSwitch = (key: string, enable: boolean) => { if (key === 'top_k') return onChange({ ...datasetConfigs, score_threshold_enabled: enable, }) } const handleWeightedScoreChange = (value: { value: number[] }) => { const configs = { ...datasetConfigs, weights: { ...datasetConfigs.weights!, vector_setting: { ...datasetConfigs.weights!.vector_setting!, vector_weight: value.value[0], }, keyword_setting: { keyword_weight: value.value[1], }, }, } onChange(configs) } const handleRerankModeChange = (mode: RerankingModeEnum) => { onChange({ ...datasetConfigs, reranking_mode: mode, }) } const model = singleRetrievalConfig const rerankingModeOptions = [ { value: RerankingModeEnum.WeightedScore, label: t('dataset.weightedScore.title'), tips: t('dataset.weightedScore.description'), }, { value: RerankingModeEnum.RerankingModel, label: t('common.modelProvider.rerankModel.key'), tips: t('common.modelProvider.rerankModel.tip'), }, ] const showWeightedScore = selectedDatasetsMode.allHighQuality && !selectedDatasetsMode.inconsistentEmbeddingModel const showWeightedScorePanel = showWeightedScore && datasetConfigs.reranking_mode === RerankingModeEnum.WeightedScore && datasetConfigs.weights const selectedRerankMode = datasetConfigs.reranking_mode || RerankingModeEnum.RerankingModel const canManuallyToggleRerank = useMemo(() => { return (selectedDatasetsMode.allInternal && selectedDatasetsMode.allEconomic) || selectedDatasetsMode.allExternal }, [selectedDatasetsMode.allEconomic, selectedDatasetsMode.allExternal, selectedDatasetsMode.allInternal]) const showRerankModel = useMemo(() => { if (!canManuallyToggleRerank) return true else if (canManuallyToggleRerank && !isRerankDefaultModelValid) return false return datasetConfigs.reranking_enable }, [canManuallyToggleRerank, datasetConfigs.reranking_enable]) const handleDisabledSwitchClick = useCallback(() => { if (!currentRerankModel && !showRerankModel) Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') }) }, [currentRerankModel, showRerankModel, t]) useEffect(() => { if (canManuallyToggleRerank && showRerankModel !== datasetConfigs.reranking_enable) { onChange({ ...datasetConfigs, reranking_enable: showRerankModel, }) } }, [canManuallyToggleRerank, showRerankModel, datasetConfigs, onChange]) return (
{t('dataset.retrievalSettings')}
{t('dataset.defaultRetrievalTip')}
{type === RETRIEVE_TYPE.multiWay && ( <>
{t('dataset.rerankSettings')}
{ selectedDatasetsMode.inconsistentEmbeddingModel && (
{t('dataset.inconsistentEmbeddingModelTip')}
) } { selectedDatasetsMode.mixtureInternalAndExternal && (
{t('dataset.mixtureInternalAndExternalTip')}
) } { selectedDatasetsMode.allExternal && (
{t('dataset.allExternalTip')}
) } { selectedDatasetsMode.mixtureHighQualityAndEconomic && (
{t('dataset.mixtureHighQualityAndEconomicTip')}
) } { showWeightedScore && (
{ rerankingModeOptions.map(option => (
handleRerankModeChange(option.value)} >
{option.label}
{option.tips}
} popupClassName='ml-0.5' triggerClassName='ml-0.5 w-3.5 h-3.5' />
)) }
) } { !showWeightedScorePanel && (
{ selectedDatasetsMode.allEconomic && (
{ if (canManuallyToggleRerank) { onChange({ ...datasetConfigs, reranking_enable: v, }) } }} />
) }
{t('common.modelProvider.rerankModel.key')}
{t('common.modelProvider.rerankModel.tip')}
} popupClassName='ml-1' triggerClassName='ml-1 w-4 h-4' />
{ onChange({ ...datasetConfigs, reranking_model: { reranking_provider_name: v.provider, reranking_model_name: v.model, }, }) }} modelList={rerankModelList} />
) } { showWeightedScorePanel && (
) } { !showWeightedScorePanel && (
{ showRerankModel && ( ) }
) } )} {isInWorkflow && type === RETRIEVE_TYPE.oneWay && (
{t('common.modelProvider.systemReasoningModel.key')}
) } ) } export default memo(ConfigContent)