'use client' import type { FC } from 'react' import type { RetrievalConfig } from '@/types/app' import { cn } from '@langgenius/dify-ui/cn' import { RadioGroup } from '@langgenius/dify-ui/radio' import { Switch } from '@langgenius/dify-ui/switch' import { toast } from '@langgenius/dify-ui/toast' import * as React from 'react' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import WeightedScore from '@/app/components/app/configuration/dataset-config/params-config/weighted-score' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { Infotip } from '@/app/components/base/infotip' import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item' import TopKItem from '@/app/components/base/param-item/top-k-item' import RadioCard from '@/app/components/base/radio-card' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { useCurrentProviderAndModel, useModelListAndDefaultModel, } from '@/app/components/header/account-setting/model-provider-page/hooks' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import { DEFAULT_WEIGHTED_SCORE, RerankingModeEnum, WeightedScoreEnum } from '@/models/datasets' import { RETRIEVE_METHOD } from '@/types/app' import ProgressIndicator from '../../create/assets/progress-indicator.svg' import Reranking from '../../create/assets/rerank.svg' type Props = Readonly<{ type: RETRIEVE_METHOD value: RetrievalConfig showMultiModalTip?: boolean disabled?: boolean onChange: (value: RetrievalConfig) => void }> const RetrievalParamConfig: FC = ({ type, value, showMultiModalTip = false, disabled = false, onChange, }) => { const { t } = useTranslation() const canToggleRerankModalEnable = type !== RETRIEVE_METHOD.hybrid const isEconomical = type === RETRIEVE_METHOD.keywordSearch const isHybridSearch = type === RETRIEVE_METHOD.hybrid const { modelList: rerankModelList } = useModelListAndDefaultModel(ModelTypeEnum.rerank) const { currentModel } = useCurrentProviderAndModel(rerankModelList, { provider: value.reranking_model?.reranking_provider_name ?? '', model: value.reranking_model?.reranking_model_name ?? '', }) const handleToggleRerankEnable = useCallback( (enable: boolean) => { if (disabled) return if (enable && !currentModel) toast.error(t(($) => $['errorMsg.rerankModelRequired'], { ns: 'workflow' })) onChange({ ...value, reranking_enable: enable, }) }, [currentModel, disabled, onChange, t, value], ) const rerankModel = useMemo(() => { return { provider_name: value.reranking_model.reranking_provider_name, model_name: value.reranking_model.reranking_model_name, } }, [value.reranking_model]) const handleChangeRerankMode = (v: RerankingModeEnum) => { if (disabled) return if (v === value.reranking_mode) return const result = { ...value, reranking_mode: v, } if (!result.weights && v === RerankingModeEnum.WeightedScore) { result.weights = { weight_type: WeightedScoreEnum.Customized, vector_setting: { vector_weight: DEFAULT_WEIGHTED_SCORE.other.semantic, embedding_provider_name: '', embedding_model_name: '', }, keyword_setting: { keyword_weight: DEFAULT_WEIGHTED_SCORE.other.keyword, }, } } if (v === RerankingModeEnum.RerankingModel && !currentModel) toast.error(t(($) => $['errorMsg.rerankModelRequired'], { ns: 'workflow' })) onChange(result) } const rerankingModeOptions = [ { value: RerankingModeEnum.WeightedScore, label: t(($) => $['weightedScore.title'], { ns: 'dataset' }), tips: t(($) => $['weightedScore.description'], { ns: 'dataset' }), }, { value: RerankingModeEnum.RerankingModel, label: t(($) => $['modelProvider.rerankModel.key'], { ns: 'common' }), tips: t(($) => $['modelProvider.rerankModel.tip'], { ns: 'common' }), }, ] return (
{!isEconomical && !isHybridSearch && (
{canToggleRerankModalEnable && ( )}
{t(($) => $['modelProvider.rerankModel.key'], { ns: 'common' })} $['modelProvider.rerankModel.tip'], { ns: 'common' })} popupClassName="w-[200px]" > {t(($) => $['modelProvider.rerankModel.tip'], { ns: 'common' })}
{value.reranking_enable && ( <> { if (disabled) return onChange({ ...value, reranking_model: { reranking_provider_name: v.provider, reranking_model_name: v.model, }, }) }} readonly={disabled} /> {showMultiModalTip && (
{t(($) => $['form.retrievalSetting.multiModalTip'], { ns: 'datasetSettings' })}
)} )}
)} {!isHybridSearch && (
{ if (disabled) return onChange({ ...value, top_k: v, }) }} enable={true} disabled={disabled} /> {!isEconomical && !(value.search_method === RETRIEVE_METHOD.fullText && !value.reranking_enable) && ( { if (disabled) return onChange({ ...value, score_threshold: v, }) }} enable={value.score_threshold_enabled} hasSwitch={true} disabled={disabled} onSwitchChange={(_key, v) => { if (disabled) return onChange({ ...value, score_threshold_enabled: v, }) }} /> )}
)} {isHybridSearch && ( <> aria-label={t(($) => $['modelProvider.rerankModel.key'], { ns: 'common' })} value={value.reranking_mode} onValueChange={handleChangeRerankMode} className="mb-4 flex gap-2" > {rerankingModeOptions.map((option) => ( key={option.value} value={option.value} icon={ } title={option.label} description={option.tips} className="flex-1" /> ))} {value.reranking_mode === RerankingModeEnum.WeightedScore && ( { if (disabled) return onChange({ ...value, weights: { ...value.weights!, vector_setting: { ...value.weights!.vector_setting, vector_weight: v.value[0]!, }, keyword_setting: { ...value.weights!.keyword_setting, keyword_weight: v.value[1]!, }, }, }) }} /> )} {value.reranking_mode !== RerankingModeEnum.WeightedScore && ( <> { if (disabled) return onChange({ ...value, reranking_model: { reranking_provider_name: v.provider, reranking_model_name: v.model, }, }) }} readonly={disabled} /> {showMultiModalTip && (
{t(($) => $['form.retrievalSetting.multiModalTip'], { ns: 'datasetSettings' })}
)} )}
{ if (disabled) return onChange({ ...value, top_k: v, }) }} enable={true} disabled={disabled} /> { if (disabled) return onChange({ ...value, score_threshold: v, }) }} enable={value.score_threshold_enabled} hasSwitch={true} disabled={disabled} onSwitchChange={(_key, v) => { if (disabled) return onChange({ ...value, score_threshold_enabled: v, }) }} />
)}
) } export default React.memo(RetrievalParamConfig)