| 'use client' |
| import type { FC } from 'react' |
| import React, { useCallback } from 'react' |
| import { useTranslation } from 'react-i18next' |
|
|
| import cn from '@/utils/classnames' |
| import TopKItem from '@/app/components/base/param-item/top-k-item' |
| import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item' |
| import { RETRIEVE_METHOD } from '@/types/app' |
| import Switch from '@/app/components/base/switch' |
| import Tooltip from '@/app/components/base/tooltip' |
| import type { RetrievalConfig } from '@/types/app' |
| import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' |
| import { useCurrentProviderAndModel, useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' |
| import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' |
| import { |
| DEFAULT_WEIGHTED_SCORE, |
| RerankingModeEnum, |
| WeightedScoreEnum, |
| } from '@/models/datasets' |
| import WeightedScore from '@/app/components/app/configuration/dataset-config/params-config/weighted-score' |
| import Toast from '@/app/components/base/toast' |
|
|
| type Props = { |
| type: RETRIEVE_METHOD |
| value: RetrievalConfig |
| onChange: (value: RetrievalConfig) => void |
| } |
|
|
| const RetrievalParamConfig: FC<Props> = ({ |
| type, |
| value, |
| onChange, |
| }) => { |
| const { t } = useTranslation() |
| const canToggleRerankModalEnable = type !== RETRIEVE_METHOD.hybrid |
| const isEconomical = type === RETRIEVE_METHOD.invertedIndex |
| const { |
| defaultModel: rerankDefaultModel, |
| modelList: rerankModelList, |
| } = useModelListAndDefaultModel(ModelTypeEnum.rerank) |
|
|
| const { |
| currentModel, |
| } = useCurrentProviderAndModel( |
| rerankModelList, |
| rerankDefaultModel |
| ? { |
| ...rerankDefaultModel, |
| provider: rerankDefaultModel.provider.provider, |
| } |
| : undefined, |
| ) |
|
|
| const handleDisabledSwitchClick = useCallback(() => { |
| if (!currentModel) |
| Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') }) |
| }, [currentModel, rerankDefaultModel, t]) |
|
|
| const isHybridSearch = type === RETRIEVE_METHOD.hybrid |
|
|
| const rerankModel = (() => { |
| if (value.reranking_model) { |
| return { |
| provider_name: value.reranking_model.reranking_provider_name, |
| model_name: value.reranking_model.reranking_model_name, |
| } |
| } |
| else if (rerankDefaultModel) { |
| return { |
| provider_name: rerankDefaultModel.provider.provider, |
| model_name: rerankDefaultModel.model, |
| } |
| } |
| })() |
|
|
| const handleChangeRerankMode = (v: RerankingModeEnum) => { |
| 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, |
| }, |
| } |
| } |
| onChange(result) |
| } |
|
|
| 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'), |
| }, |
| ] |
|
|
| return ( |
| <div> |
| {!isEconomical && !isHybridSearch && ( |
| <div> |
| <div className='flex h-8 items-center text-[13px] font-medium text-gray-900 space-x-2'> |
| {canToggleRerankModalEnable && ( |
| <div |
| className='flex items-center' |
| onClick={handleDisabledSwitchClick} |
| > |
| <Switch |
| size='md' |
| defaultValue={currentModel ? value.reranking_enable : false} |
| onChange={(v) => { |
| onChange({ |
| ...value, |
| reranking_enable: v, |
| }) |
| }} |
| disabled={!currentModel} |
| /> |
| </div> |
| )} |
| <div className='flex items-center'> |
| <span className='mr-0.5'>{t('common.modelProvider.rerankModel.key')}</span> |
| <Tooltip |
| popupContent={ |
| <div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div> |
| } |
| /> |
| </div> |
| </div> |
| <ModelSelector |
| triggerClassName={`${!value.reranking_enable && '!opacity-60 !cursor-not-allowed'}`} |
| defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }} |
| modelList={rerankModelList} |
| readonly={!value.reranking_enable} |
| onSelect={(v) => { |
| onChange({ |
| ...value, |
| reranking_model: { |
| reranking_provider_name: v.provider, |
| reranking_model_name: v.model, |
| }, |
| }) |
| }} |
| /> |
| </div> |
| )} |
| { |
| !isHybridSearch && ( |
| <div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-6')}> |
| <TopKItem |
| className='grow' |
| value={value.top_k} |
| onChange={(_key, v) => { |
| onChange({ |
| ...value, |
| top_k: v, |
| }) |
| }} |
| enable={true} |
| /> |
| {(!isEconomical && !(value.search_method === RETRIEVE_METHOD.fullText && !value.reranking_enable)) && ( |
| <ScoreThresholdItem |
| className='grow' |
| value={value.score_threshold} |
| onChange={(_key, v) => { |
| onChange({ |
| ...value, |
| score_threshold: v, |
| }) |
| }} |
| enable={value.score_threshold_enabled} |
| hasSwitch={true} |
| onSwitchChange={(_key, v) => { |
| onChange({ |
| ...value, |
| score_threshold_enabled: v, |
| }) |
| }} |
| /> |
| )} |
| </div> |
| ) |
| } |
| { |
| isHybridSearch && ( |
| <> |
| <div className='flex items-center justify-between'> |
| { |
| rerankingModeOptions.map(option => ( |
| <div |
| key={option.value} |
| className={cn( |
| 'flex items-center justify-center mb-4 w-[calc((100%-8px)/2)] h-8 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg cursor-pointer system-sm-medium text-text-secondary', |
| value.reranking_mode === RerankingModeEnum.WeightedScore && option.value === RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary', |
| value.reranking_mode !== RerankingModeEnum.WeightedScore && option.value !== RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary', |
| )} |
| onClick={() => handleChangeRerankMode(option.value)} |
| > |
| <div className='truncate'>{option.label}</div> |
| <Tooltip |
| popupContent={<div className='w-[200px]'>{option.tips}</div>} |
| triggerClassName='ml-0.5 w-3.5 h-3.5' |
| /> |
| </div> |
| )) |
| } |
| </div> |
| { |
| value.reranking_mode === RerankingModeEnum.WeightedScore && ( |
| <WeightedScore |
| value={{ |
| value: [ |
| value.weights!.vector_setting.vector_weight, |
| value.weights!.keyword_setting.keyword_weight, |
| ], |
| }} |
| onChange={(v) => { |
| 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 && ( |
| <ModelSelector |
| triggerClassName={`${!value.reranking_enable && '!opacity-60 !cursor-not-allowed'}`} |
| defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }} |
| modelList={rerankModelList} |
| readonly={!value.reranking_enable} |
| onSelect={(v) => { |
| onChange({ |
| ...value, |
| reranking_model: { |
| reranking_provider_name: v.provider, |
| reranking_model_name: v.model, |
| }, |
| }) |
| }} |
| /> |
| ) |
| } |
| <div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-6')}> |
| <TopKItem |
| className='grow' |
| value={value.top_k} |
| onChange={(_key, v) => { |
| onChange({ |
| ...value, |
| top_k: v, |
| }) |
| }} |
| enable={true} |
| /> |
| <ScoreThresholdItem |
| className='grow' |
| value={value.score_threshold} |
| onChange={(_key, v) => { |
| onChange({ |
| ...value, |
| score_threshold: v, |
| }) |
| }} |
| enable={value.score_threshold_enabled} |
| hasSwitch={true} |
| onSwitchChange={(_key, v) => { |
| onChange({ |
| ...value, |
| score_threshold_enabled: v, |
| }) |
| }} |
| /> |
| </div> |
| </> |
| ) |
| } |
| </div> |
| ) |
| } |
| export default React.memo(RetrievalParamConfig) |
|
|