feat: add retriever rank fe (#1557)
Co-authored-by: StyleZhang <jasonapring2015@outlook.com>
This commit is contained in:
parent
e017eff5e4
commit
888e8c6dac
80 changed files with 2757 additions and 467 deletions
|
|
@ -16,7 +16,7 @@ export type ICardItemProps = {
|
|||
onRemove: (id: string) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
// used in universal-chat
|
||||
const CardItem: FC<ICardItemProps> = ({
|
||||
className,
|
||||
config,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
.card {
|
||||
box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
|
||||
width: calc(50% - 4px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);
|
||||
}
|
||||
|
||||
.deleteBtn {
|
||||
.btnWrap {
|
||||
padding-left: 64px;
|
||||
visibility: hidden;
|
||||
background: linear-gradient(270deg, #FFF 49.99%, rgba(255, 255, 255, 0.00) 98.1%);
|
||||
}
|
||||
|
||||
.card:hover .deleteBtn {
|
||||
.card:hover .btnWrap {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.settingBtn:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
|
@ -105,7 +105,6 @@ const DatasetConfig: FC = () => {
|
|||
onChange={handleSelectContextVar}
|
||||
/>
|
||||
)}
|
||||
|
||||
</FeaturePanel>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,96 +4,23 @@ import { memo, useState } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import cn from 'classnames'
|
||||
import { HelpCircle, Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Tooltip from '@/app/components/base/tooltip-plus'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
|
||||
// TODO
|
||||
const PARAMS_KEY = [
|
||||
'top_k',
|
||||
'score_threshold',
|
||||
]
|
||||
const PARAMS = {
|
||||
top_k: {
|
||||
default: 2,
|
||||
step: 1,
|
||||
min: 1,
|
||||
max: 10,
|
||||
},
|
||||
score_threshold: {
|
||||
default: 0.7,
|
||||
step: 0.01,
|
||||
min: 0,
|
||||
max: 1,
|
||||
},
|
||||
} as any
|
||||
|
||||
export type IParamItemProps = {
|
||||
id: string
|
||||
name: string
|
||||
tip: string
|
||||
value: number
|
||||
enable: boolean
|
||||
step?: number
|
||||
min?: number
|
||||
max: number
|
||||
onChange: (key: string, value: number) => void
|
||||
onSwitchChange: (key: string, enable: boolean) => void
|
||||
}
|
||||
|
||||
const ParamItem: FC<IParamItemProps> = ({ id, name, tip, step = 0.1, min = 0, max, value, enable, onChange, onSwitchChange }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
{id === 'score_threshold' && (
|
||||
<Switch
|
||||
size='md'
|
||||
defaultValue={enable}
|
||||
onChange={async (val) => {
|
||||
onSwitchChange(id, val)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<span className="mx-1 text-gray-800 text-[13px] leading-[18px] font-medium">{name}</span>
|
||||
<Tooltip popupContent={<div className="w-[200px]">{tip}</div>}>
|
||||
<HelpCircle className='w-[14px] h-[14px] text-gray-400' />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="flex items-center"></div>
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-between">
|
||||
<div className="flex items-center h-7">
|
||||
<div className="w-[148px]">
|
||||
<Slider
|
||||
disabled={!enable}
|
||||
value={max < 5 ? value * 100 : value}
|
||||
min={min < 1 ? min * 100 : min}
|
||||
max={max < 5 ? max * 100 : max}
|
||||
onChange={value => onChange(id, value / (max < 5 ? 100 : 1))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<input disabled={!enable} type="number" min={min} max={max} step={step} className="block w-[48px] h-7 text-xs leading-[18px] rounded-lg border-0 pl-1 pl py-1.5 bg-gray-50 text-gray-900 placeholder:text-gray-400 focus:ring-1 focus:ring-inset focus:ring-primary-600 disabled:opacity-60" value={value} onChange={(e) => {
|
||||
const value = parseFloat(e.target.value)
|
||||
if (value < min || value > max)
|
||||
return
|
||||
|
||||
onChange(id, value)
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import TopKItem from '@/app/components/base/param-item/top-k-item'
|
||||
import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import RadioCard from '@/app/components/base/radio-card/simple'
|
||||
import { RETRIEVE_TYPE } from '@/types/app'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-page/model-selector'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { ModelType } from '@/app/components/header/account-setting/model-page/declarations'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { DATASET_DEFAULT } from '@/config'
|
||||
import {
|
||||
MultiPathRetrieval,
|
||||
NTo1Retrieval,
|
||||
} from '@/app/components/base/icons/src/public/common'
|
||||
|
||||
const ParamsConfig: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -102,24 +29,47 @@ const ParamsConfig: FC = () => {
|
|||
datasetConfigs,
|
||||
setDatasetConfigs,
|
||||
} = useContext(ConfigContext)
|
||||
const [tempDataSetConfigs, setTempDataSetConfigs] = useState(datasetConfigs)
|
||||
|
||||
const type = tempDataSetConfigs.retrieval_model
|
||||
const setType = (value: RETRIEVE_TYPE) => {
|
||||
setTempDataSetConfigs({
|
||||
...tempDataSetConfigs,
|
||||
retrieval_model: value,
|
||||
})
|
||||
}
|
||||
|
||||
const {
|
||||
rerankDefaultModel,
|
||||
isRerankDefaultModelVaild,
|
||||
} = useProviderContext()
|
||||
|
||||
const rerankModel = (() => {
|
||||
if (tempDataSetConfigs.reranking_model) {
|
||||
return {
|
||||
provider_name: tempDataSetConfigs.reranking_model.reranking_provider_name,
|
||||
model_name: tempDataSetConfigs.reranking_model.reranking_model_name,
|
||||
}
|
||||
}
|
||||
else if (rerankDefaultModel) {
|
||||
return {
|
||||
provider_name: rerankDefaultModel.model_provider.provider_name,
|
||||
model_name: rerankDefaultModel.model_name,
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
const handleParamChange = (key: string, value: number) => {
|
||||
let notOutRangeValue = parseFloat(value.toFixed(2))
|
||||
notOutRangeValue = Math.max(PARAMS[key].min, notOutRangeValue)
|
||||
notOutRangeValue = Math.min(PARAMS[key].max, notOutRangeValue)
|
||||
if (key === 'top_k') {
|
||||
setDatasetConfigs({
|
||||
...datasetConfigs,
|
||||
top_k: notOutRangeValue,
|
||||
setTempDataSetConfigs({
|
||||
...tempDataSetConfigs,
|
||||
top_k: value,
|
||||
})
|
||||
}
|
||||
else if (key === 'score_threshold') {
|
||||
setDatasetConfigs({
|
||||
...datasetConfigs,
|
||||
[key]: {
|
||||
enable: datasetConfigs.score_threshold.enable,
|
||||
value: notOutRangeValue,
|
||||
},
|
||||
setTempDataSetConfigs({
|
||||
...tempDataSetConfigs,
|
||||
score_threshold: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -128,54 +78,133 @@ const ParamsConfig: FC = () => {
|
|||
if (key === 'top_k')
|
||||
return
|
||||
|
||||
setDatasetConfigs({
|
||||
...datasetConfigs,
|
||||
[key]: {
|
||||
enable,
|
||||
value: (datasetConfigs as any)[key].value,
|
||||
},
|
||||
setTempDataSetConfigs({
|
||||
...tempDataSetConfigs,
|
||||
score_threshold_enabled: enable,
|
||||
})
|
||||
}
|
||||
const isValid = () => {
|
||||
let errMsg = ''
|
||||
if (tempDataSetConfigs.retrieval_model === RETRIEVE_TYPE.multiWay) {
|
||||
if (!tempDataSetConfigs.reranking_model?.reranking_model_name && (!rerankDefaultModel && isRerankDefaultModelVaild))
|
||||
errMsg = t('appDebug.datasetConfig.rerankModelRequired')
|
||||
}
|
||||
if (errMsg) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: errMsg,
|
||||
})
|
||||
}
|
||||
return !errMsg
|
||||
}
|
||||
const handleSave = () => {
|
||||
if (!isValid())
|
||||
return
|
||||
|
||||
const config = { ...tempDataSetConfigs }
|
||||
if (config.retrieval_model === RETRIEVE_TYPE.multiWay && !config.reranking_model) {
|
||||
config.reranking_model = {
|
||||
reranking_provider_name: rerankDefaultModel?.model_provider.provider_name,
|
||||
reranking_model_name: rerankDefaultModel?.model_name,
|
||||
} as any
|
||||
}
|
||||
setDatasetConfigs(config)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<div className={cn('flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200', open && 'bg-gray-200')}>
|
||||
<Settings04 className="w-[14px] h-[14px]" />
|
||||
<div className='text-xs font-medium'>
|
||||
{t('appDebug.datasetConfig.params')}
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={cn('flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200', open && 'bg-gray-200')}
|
||||
onClick={() => {
|
||||
setTempDataSetConfigs({
|
||||
...datasetConfigs,
|
||||
top_k: datasetConfigs.top_k || DATASET_DEFAULT.top_k,
|
||||
score_threshold: datasetConfigs.score_threshold || DATASET_DEFAULT.score_threshold,
|
||||
})
|
||||
setOpen(true)
|
||||
}}
|
||||
>
|
||||
<Settings04 className="w-[14px] h-[14px]" />
|
||||
<div className='text-xs font-medium'>
|
||||
{t('appDebug.datasetConfig.params')}
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
||||
<div className='w-[240px] p-4 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg space-y-3'>
|
||||
{PARAMS_KEY.map((key: string) => {
|
||||
const currentValue = key === 'top_k' ? datasetConfigs[key] : (datasetConfigs as any)[key]?.value
|
||||
const currentEnableState = key === 'top_k' ? true : (datasetConfigs as any)[key]?.enable
|
||||
return (
|
||||
<ParamItem
|
||||
key={key}
|
||||
id={key}
|
||||
name={t(`appDebug.datasetConfig.${key}`)}
|
||||
tip={t(`appDebug.datasetConfig.${key}Tip`)}
|
||||
{...PARAMS[key]}
|
||||
value={currentValue}
|
||||
enable={currentEnableState}
|
||||
onChange={handleParamChange}
|
||||
onSwitchChange={handleSwitch}
|
||||
</div>
|
||||
{
|
||||
open && (
|
||||
<Modal
|
||||
isShow={open}
|
||||
onClose={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
className='min-w-[528px]'
|
||||
wrapperClassName='z-50'
|
||||
title={t('appDebug.datasetConfig.settingTitle')}
|
||||
>
|
||||
<div className='mt-2 space-y-3'>
|
||||
<RadioCard
|
||||
icon={<NTo1Retrieval className='shrink-0 mr-3 w-9 h-9 rounded-lg' />}
|
||||
title={t('appDebug.datasetConfig.retrieveOneWay.title')}
|
||||
description={t('appDebug.datasetConfig.retrieveOneWay.description')}
|
||||
isChosen={type === RETRIEVE_TYPE.oneWay}
|
||||
onChosen={() => { setType(RETRIEVE_TYPE.oneWay) }}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
<RadioCard
|
||||
icon={<MultiPathRetrieval className='shrink-0 mr-3 w-9 h-9 rounded-lg' />}
|
||||
title={t('appDebug.datasetConfig.retrieveMultiWay.title')}
|
||||
description={t('appDebug.datasetConfig.retrieveMultiWay.description')}
|
||||
isChosen={type === RETRIEVE_TYPE.multiWay}
|
||||
onChosen={() => { setType(RETRIEVE_TYPE.multiWay) }}
|
||||
/>
|
||||
</div>
|
||||
{type === RETRIEVE_TYPE.multiWay && (
|
||||
<>
|
||||
<div className='mt-6'>
|
||||
<div className='leading-[32px] text-[13px] font-medium text-gray-900'>{t('common.modelProvider.rerankModel.key')}</div>
|
||||
<div>
|
||||
<ModelSelector
|
||||
popClassName='!max-w-[100%] !w-full'
|
||||
value={rerankModel && { providerName: rerankModel.provider_name, modelName: rerankModel.model_name } as any}
|
||||
modelType={ModelType.reranking}
|
||||
onChange={(v) => {
|
||||
setTempDataSetConfigs({
|
||||
...tempDataSetConfigs,
|
||||
reranking_model: {
|
||||
reranking_provider_name: v.model_provider.provider_name,
|
||||
reranking_model_name: v.model_name,
|
||||
},
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-4 space-y-4'>
|
||||
<TopKItem
|
||||
value={tempDataSetConfigs.top_k}
|
||||
onChange={handleParamChange}
|
||||
enable={true}
|
||||
/>
|
||||
<ScoreThresholdItem
|
||||
value={tempDataSetConfigs.score_threshold}
|
||||
onChange={handleParamChange}
|
||||
enable={tempDataSetConfigs.score_threshold_enabled}
|
||||
hasSwitch={true}
|
||||
onSwitchChange={handleSwitch}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className='mt-6 flex justify-end'>
|
||||
<Button className='mr-2 flex-shrink-0' onClick={() => {
|
||||
setOpen(false)
|
||||
}}>{t('common.operation.cancel')}</Button>
|
||||
<Button type='primary' className='flex-shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default memo(ParamsConfig)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useClickAway } from 'ahooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isEqual } from 'lodash-es'
|
||||
import cn from 'classnames'
|
||||
import { BookOpenIcon } from '@heroicons/react/24/outline'
|
||||
import IndexMethodRadio from '@/app/components/datasets/settings/index-method-radio'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-page/model-selector'
|
||||
import type { ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
|
||||
|
|
@ -11,12 +14,29 @@ import type { DataSet } from '@/models/datasets'
|
|||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { updateDatasetSetting } from '@/service/datasets'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import type { RetrievalConfig } from '@/types/app'
|
||||
import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
|
||||
import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { ensureRerankModelSelected, isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
|
||||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||
import PermissionsRadio from '@/app/components/datasets/settings/permissions-radio'
|
||||
|
||||
type SettingsModalProps = {
|
||||
currentDataset: DataSet
|
||||
onCancel: () => void
|
||||
onSave: (newDataset: DataSet) => void
|
||||
}
|
||||
|
||||
const rowClass = `
|
||||
flex justify-between py-4
|
||||
`
|
||||
|
||||
const labelClass = `
|
||||
flex w-[168px] shrink-0
|
||||
`
|
||||
|
||||
const SettingsModal: FC<SettingsModalProps> = ({
|
||||
currentDataset,
|
||||
onCancel,
|
||||
|
|
@ -24,13 +44,28 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
|||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const ref = useRef(null)
|
||||
useClickAway(() => {
|
||||
if (ref)
|
||||
onCancel()
|
||||
}, ref)
|
||||
|
||||
const { setShowAccountSettingModal } = useModalContext()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [localeCurrentDataset, setLocaleCurrentDataset] = useState({ ...currentDataset })
|
||||
const [indexMethod, setIndexMethod] = useState(currentDataset.indexing_technique)
|
||||
const [retrievalConfig, setRetrievalConfig] = useState(localeCurrentDataset?.retrieval_model_dict as RetrievalConfig)
|
||||
|
||||
const {
|
||||
rerankDefaultModel,
|
||||
isRerankDefaultModelVaild,
|
||||
} = useProviderContext()
|
||||
|
||||
const handleValueChange = (type: string, value: string) => {
|
||||
setLocaleCurrentDataset({ ...localeCurrentDataset, [type]: value })
|
||||
}
|
||||
const [isHideChangedTip, setIsHideChangedTip] = useState(false)
|
||||
const isRetrievalChanged = !isEqual(retrievalConfig, localeCurrentDataset?.retrieval_model_dict) || indexMethod !== localeCurrentDataset?.indexing_technique
|
||||
|
||||
const handleSave = async () => {
|
||||
if (loading)
|
||||
|
|
@ -39,19 +74,41 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
|||
notify({ type: 'error', message: t('datasetSettings.form.nameError') })
|
||||
return
|
||||
}
|
||||
if (
|
||||
!isReRankModelSelected({
|
||||
rerankDefaultModel,
|
||||
isRerankDefaultModelVaild,
|
||||
retrievalConfig,
|
||||
indexMethod,
|
||||
})
|
||||
) {
|
||||
notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
|
||||
return
|
||||
}
|
||||
const postRetrievalConfig = ensureRerankModelSelected({
|
||||
rerankDefaultModel: rerankDefaultModel!,
|
||||
retrievalConfig,
|
||||
indexMethod,
|
||||
})
|
||||
try {
|
||||
setLoading(true)
|
||||
const { id, name, description, indexing_technique } = localeCurrentDataset
|
||||
const { id, name, description, permission } = localeCurrentDataset
|
||||
await updateDatasetSetting({
|
||||
datasetId: id,
|
||||
body: {
|
||||
name,
|
||||
description,
|
||||
indexing_technique,
|
||||
permission,
|
||||
indexing_technique: indexMethod,
|
||||
retrieval_model: postRetrievalConfig,
|
||||
},
|
||||
})
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
onSave(localeCurrentDataset)
|
||||
onSave({
|
||||
...localeCurrentDataset,
|
||||
indexing_technique: indexMethod,
|
||||
retrieval_model_dict: postRetrievalConfig,
|
||||
})
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
|
||||
|
|
@ -62,74 +119,162 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={() => {}}
|
||||
className='!p-8 !pb-6 !max-w-none !w-[640px]'
|
||||
<div
|
||||
className='fixed top-16 right-2 flex flex-col bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10'
|
||||
style={{
|
||||
zIndex: 11,
|
||||
width: 700,
|
||||
height: 'calc(100vh - 72px)',
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
<div className='mb-2 text-xl font-semibold text-gray-900'>
|
||||
{t('datasetSettings.title')}
|
||||
<div className='shrink-0 flex justify-between items-center pl-6 pr-5 h-14 border-b border-b-gray-100'>
|
||||
<div className='flex flex-col text-base font-semibold text-gray-900'>
|
||||
<div className='leading-6'>{t('datasetSettings.title')}</div>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<div
|
||||
onClick={onCancel}
|
||||
className='flex justify-center items-center w-6 h-6 cursor-pointer'
|
||||
>
|
||||
<XClose className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.name')}
|
||||
</div>
|
||||
<input
|
||||
value={localeCurrentDataset.name}
|
||||
onChange={e => handleValueChange('name', e.target.value)}
|
||||
className='block px-3 w-full h-9 bg-gray-100 rounded-lg text-sm text-gray-900 outline-none appearance-none'
|
||||
placeholder={t('datasetSettings.form.namePlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='flex justify-between items-center mb-1 h-5 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.desc')}
|
||||
</div>
|
||||
<div className='mb-2 text-xs text-gray-500'>
|
||||
{t('datasetSettings.form.descInfo')}<a href='/' className='text-primary-600'>{t('common.operation.learnMore')}</a>
|
||||
</div>
|
||||
<textarea
|
||||
value={localeCurrentDataset.description || ''}
|
||||
onChange={e => handleValueChange('description', e.target.value)}
|
||||
className='block px-3 py-2 w-full h-[88px] rounded-lg bg-gray-100 text-sm outline-none appearance-none resize-none'
|
||||
placeholder={t('datasetSettings.form.descPlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.indexMethod')}
|
||||
</div>
|
||||
<div>
|
||||
<IndexMethodRadio
|
||||
disable={!localeCurrentDataset?.embedding_available}
|
||||
value={localeCurrentDataset.indexing_technique}
|
||||
onChange={v => handleValueChange('indexing_technique', v!)}
|
||||
itemClassName='!w-[282px]'
|
||||
{/* Body */}
|
||||
<div className='p-6 pt-5 border-b overflow-y-auto pb-[68px]' style={{
|
||||
borderBottom: 'rgba(0, 0, 0, 0.05)',
|
||||
}}>
|
||||
<div className={cn(rowClass, 'items-center')}>
|
||||
<div className={labelClass}>
|
||||
{t('datasetSettings.form.name')}
|
||||
</div>
|
||||
<input
|
||||
value={localeCurrentDataset.name}
|
||||
onChange={e => handleValueChange('name', e.target.value)}
|
||||
className='block px-3 w-full h-9 bg-gray-100 rounded-lg text-sm text-gray-900 outline-none appearance-none'
|
||||
placeholder={t('datasetSettings.form.namePlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.embeddingModel')}
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
{t('datasetSettings.form.desc')}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<textarea
|
||||
value={localeCurrentDataset.description || ''}
|
||||
onChange={e => handleValueChange('description', e.target.value)}
|
||||
className='block px-3 py-2 w-full h-[88px] rounded-lg bg-gray-100 text-sm outline-none appearance-none resize-none'
|
||||
placeholder={t('datasetSettings.form.descPlaceholder') || ''}
|
||||
/>
|
||||
<a className='mt-2 flex items-center h-[18px] px-3 text-xs text-gray-500' href="https://docs.dify.ai/advanced/datasets#how-to-write-a-good-dataset-description" target='_blank'>
|
||||
<BookOpenIcon className='w-3 h-[18px] mr-1' />
|
||||
{t('datasetSettings.form.descWrite')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full h-9 rounded-lg bg-gray-100 opacity-60'>
|
||||
<ModelSelector
|
||||
readonly
|
||||
value={{
|
||||
providerName: localeCurrentDataset.embedding_model_provider as ProviderEnum,
|
||||
modelName: localeCurrentDataset.embedding_model,
|
||||
}}
|
||||
modelType={ModelType.embeddings}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div>{t('datasetSettings.form.permissions')}</div>
|
||||
</div>
|
||||
<div className='w-[480px]'>
|
||||
<PermissionsRadio
|
||||
disable={!localeCurrentDataset?.embedding_available}
|
||||
value={localeCurrentDataset.permission}
|
||||
onChange={v => handleValueChange('permission', v!)}
|
||||
itemClassName='!w-[227px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-2 w-full text-xs leading-6 text-gray-500'>
|
||||
{t('datasetSettings.form.embeddingModelTip')}
|
||||
<span className='text-[#155eef] cursor-pointer' onClick={() => setShowAccountSettingModal({ payload: 'provider' })}>{t('datasetSettings.form.embeddingModelTipLink')}</span>
|
||||
<div className="w-full h-0 border-b-[0.5px] border-b-gray-200 my-2"></div>
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
{t('datasetSettings.form.indexMethod')}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<IndexMethodRadio
|
||||
disable={!localeCurrentDataset?.embedding_available}
|
||||
value={indexMethod}
|
||||
onChange={v => setIndexMethod(v!)}
|
||||
itemClassName='!w-[227px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{indexMethod === 'high_quality' && (
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
{t('datasetSettings.form.embeddingModel')}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<div className='w-full h-9 rounded-lg bg-gray-100 opacity-60'>
|
||||
<ModelSelector
|
||||
readonly
|
||||
value={{
|
||||
providerName: localeCurrentDataset.embedding_model_provider as ProviderEnum,
|
||||
modelName: localeCurrentDataset.embedding_model,
|
||||
}}
|
||||
modelType={ModelType.embeddings}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-2 w-full text-xs leading-6 text-gray-500'>
|
||||
{t('datasetSettings.form.embeddingModelTip')}
|
||||
<span className='text-[#155eef] cursor-pointer' onClick={() => setShowAccountSettingModal({ payload: 'provider' })}>{t('datasetSettings.form.embeddingModelTipLink')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Retrieval Method Config */}
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div>
|
||||
<div>{t('datasetSettings.form.retrievalSetting.title')}</div>
|
||||
<div className='leading-[18px] text-xs font-normal text-gray-500'>
|
||||
<a target='_blank' href='https://docs.dify.ai/v/zh-hans/advanced/retrieval-augment' className='text-[#155eef]'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
|
||||
{t('datasetSettings.form.retrievalSetting.description')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-[480px]'>
|
||||
{indexMethod === 'high_quality'
|
||||
? (
|
||||
<RetrievalMethodConfig
|
||||
value={retrievalConfig}
|
||||
onChange={setRetrievalConfig}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<EconomicalRetrievalMethodConfig
|
||||
value={retrievalConfig}
|
||||
onChange={setRetrievalConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<div className='flex items-center justify-end mt-6'>
|
||||
{isRetrievalChanged && !isHideChangedTip && (
|
||||
<div className='absolute z-10 left-[30px] right-[30px] bottom-[76px] flex h-10 items-center px-3 rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] shadow-lg justify-between'>
|
||||
<div className='flex items-center'>
|
||||
<AlertTriangle className='mr-1 w-3 h-3 text-[#F79009]' />
|
||||
<div className='leading-[18px] text-xs font-medium text-gray-700'>{t('appDebug.datasetConfig.retrieveChangeTip')}</div>
|
||||
</div>
|
||||
<div className='p-1 cursor-pointer' onClick={(e) => {
|
||||
setIsHideChangedTip(true)
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
}}>
|
||||
<XClose className='w-4 h-4 text-gray-500 ' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className='absolute z-10 bottom-0 w-full flex justify-end py-4 px-6 border-t bg-white '
|
||||
style={{
|
||||
borderColor: 'rgba(0, 0, 0, 0.05)',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
className='mr-2 text-sm font-medium'
|
||||
|
|
@ -145,7 +290,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
|||
{t('common.operation.save')}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import { fetchAppDetail, updateAppModelConfig } from '@/service/apps'
|
|||
import { promptVariablesToUserInputsForm, userInputsFormToPromptVariables } from '@/utils/model-config'
|
||||
import { fetchDatasets } from '@/service/datasets'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { AppType, ModelModeType, Resolution, TransferMethod } from '@/types/app'
|
||||
import { AppType, ModelModeType, RETRIEVE_TYPE, Resolution, TransferMethod } from '@/types/app'
|
||||
import { FlipBackward } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { PromptMode } from '@/models/debug'
|
||||
import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
|
||||
|
|
@ -127,11 +127,14 @@ const Configuration: FC = () => {
|
|||
})
|
||||
|
||||
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>({
|
||||
top_k: 2,
|
||||
score_threshold: {
|
||||
enable: false,
|
||||
value: 0.7,
|
||||
retrieval_model: RETRIEVE_TYPE.oneWay,
|
||||
reranking_model: {
|
||||
reranking_provider_name: '',
|
||||
reranking_model_name: '',
|
||||
},
|
||||
top_k: 2,
|
||||
score_threshold_enabled: false,
|
||||
score_threshold: 0.7,
|
||||
})
|
||||
|
||||
const setModelConfig = (newModelConfig: ModelConfig) => {
|
||||
|
|
@ -391,7 +394,10 @@ const Configuration: FC = () => {
|
|||
|
||||
syncToPublishedConfig(config)
|
||||
setPublishedConfig(config)
|
||||
setDatasetConfigs(modelConfig.dataset_configs)
|
||||
setDatasetConfigs({
|
||||
retrieval_model: RETRIEVE_TYPE.oneWay,
|
||||
...modelConfig.dataset_configs,
|
||||
})
|
||||
setHasFetchedDetail(true)
|
||||
})
|
||||
}, [appId])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue