Spaces:
Build error
Build error
import React, { useState } from 'react' | |
import { useTranslation } from 'react-i18next' | |
import { | |
RiEqualizer2Line, | |
} from '@remixicon/react' | |
import Button from '../../base/button' | |
import Tag from '../../base/tag' | |
import { getIcon } from '../common/retrieval-method-info' | |
import s from './style.module.css' | |
import ModifyExternalRetrievalModal from './modify-external-retrieval-modal' | |
import Tooltip from '@/app/components/base/tooltip' | |
import cn from '@/utils/classnames' | |
import type { ExternalKnowledgeBaseHitTestingResponse, HitTestingResponse } from '@/models/datasets' | |
import { externalKnowledgeBaseHitTesting, hitTesting } from '@/service/datasets' | |
import { asyncRunSafe } from '@/utils' | |
import { RETRIEVE_METHOD, type RetrievalConfig } from '@/types/app' | |
type TextAreaWithButtonIProps = { | |
datasetId: string | |
onUpdateList: () => void | |
setHitResult: (res: HitTestingResponse) => void | |
setExternalHitResult: (res: ExternalKnowledgeBaseHitTestingResponse) => void | |
loading: boolean | |
setLoading: (v: boolean) => void | |
text: string | |
setText: (v: string) => void | |
isExternal?: boolean | |
onClickRetrievalMethod: () => void | |
retrievalConfig: RetrievalConfig | |
isEconomy: boolean | |
onSubmit?: () => void | |
} | |
const TextAreaWithButton = ({ | |
datasetId, | |
onUpdateList, | |
setHitResult, | |
setExternalHitResult, | |
setLoading, | |
loading, | |
text, | |
setText, | |
isExternal = false, | |
onClickRetrievalMethod, | |
retrievalConfig, | |
isEconomy, | |
onSubmit: _onSubmit, | |
}: TextAreaWithButtonIProps) => { | |
const { t } = useTranslation() | |
const [isSettingsOpen, setIsSettingsOpen] = useState(false) | |
const [externalRetrievalSettings, setExternalRetrievalSettings] = useState({ | |
top_k: 2, | |
score_threshold: 0.5, | |
score_threshold_enabled: false, | |
}) | |
const handleSaveExternalRetrievalSettings = (data: { top_k: number; score_threshold: number; score_threshold_enabled: boolean }) => { | |
setExternalRetrievalSettings(data) | |
setIsSettingsOpen(false) | |
} | |
function handleTextChange(event: any) { | |
setText(event.target.value) | |
} | |
const onSubmit = async () => { | |
setLoading(true) | |
const [e, res] = await asyncRunSafe<HitTestingResponse>( | |
hitTesting({ | |
datasetId, | |
queryText: text, | |
retrieval_model: { | |
...retrievalConfig, | |
search_method: isEconomy ? RETRIEVE_METHOD.keywordSearch : retrievalConfig.search_method, | |
}, | |
}) as Promise<HitTestingResponse>, | |
) | |
if (!e) { | |
setHitResult(res) | |
onUpdateList?.() | |
} | |
setLoading(false) | |
_onSubmit && _onSubmit() | |
} | |
const externalRetrievalTestingOnSubmit = async () => { | |
const [e, res] = await asyncRunSafe<ExternalKnowledgeBaseHitTestingResponse>( | |
externalKnowledgeBaseHitTesting({ | |
datasetId, | |
query: text, | |
external_retrieval_model: { | |
top_k: externalRetrievalSettings.top_k, | |
score_threshold: externalRetrievalSettings.score_threshold, | |
score_threshold_enabled: externalRetrievalSettings.score_threshold_enabled, | |
}, | |
}) as Promise<ExternalKnowledgeBaseHitTestingResponse>, | |
) | |
if (!e) { | |
setExternalHitResult(res) | |
onUpdateList?.() | |
} | |
setLoading(false) | |
} | |
const retrievalMethod = isEconomy ? RETRIEVE_METHOD.invertedIndex : retrievalConfig.search_method | |
const Icon = getIcon(retrievalMethod) | |
return ( | |
<> | |
<div className={s.wrapper}> | |
<div className='relative pt-2 rounded-tl-xl rounded-tr-xl bg-[#EEF4FF]'> | |
<div className="px-4 pb-2 flex justify-between h-8 items-center"> | |
<span className="text-gray-800 font-semibold text-sm"> | |
{t('datasetHitTesting.input.title')} | |
</span> | |
{isExternal | |
? <Button | |
variant='secondary' | |
size='small' | |
onClick={() => setIsSettingsOpen(!isSettingsOpen)} | |
> | |
<RiEqualizer2Line className='text-components-button-secondary-text w-3.5 h-3.5' /> | |
<div className='flex px-[3px] justify-center items-center gap-1'> | |
<span className='text-components-button-secondary-text system-xs-medium'>{t('datasetHitTesting.settingTitle')}</span> | |
</div> | |
</Button> | |
: <Tooltip | |
popupContent={t('dataset.retrieval.changeRetrievalMethod')} | |
> | |
<div | |
onClick={onClickRetrievalMethod} | |
className='flex px-2 h-7 items-center space-x-1 bg-white hover:bg-[#ECE9FE] rounded-md shadow-sm cursor-pointer text-[#6927DA]' | |
> | |
<Icon className='w-3.5 h-3.5'></Icon> | |
<div className='text-xs font-medium'>{t(`dataset.retrieval.${retrievalMethod}.title`)}</div> | |
</div> | |
</Tooltip> | |
} | |
</div> | |
{ | |
isSettingsOpen && ( | |
<ModifyExternalRetrievalModal | |
onClose={() => setIsSettingsOpen(false)} | |
onSave={handleSaveExternalRetrievalSettings} | |
initialTopK={externalRetrievalSettings.top_k} | |
initialScoreThreshold={externalRetrievalSettings.score_threshold} | |
initialScoreThresholdEnabled={externalRetrievalSettings.score_threshold_enabled} | |
/> | |
) | |
} | |
<div className='h-2 rounded-tl-xl rounded-tr-xl bg-white'></div> | |
</div> | |
<div className='px-4 pb-11'> | |
<textarea | |
className='h-[220px] border-none resize-none font-normal caret-primary-600 text-gray-700 text-sm w-full focus-visible:outline-none placeholder:text-gray-300 placeholder:text-sm placeholder:font-normal' | |
value={text} | |
onChange={handleTextChange} | |
placeholder={t('datasetHitTesting.input.placeholder') as string} | |
/> | |
<div className="absolute inset-x-0 bottom-0 flex items-center justify-between mx-4 mt-2 mb-2"> | |
{text?.length > 200 | |
? ( | |
<Tooltip | |
popupContent={t('datasetHitTesting.input.countWarning')} | |
> | |
<div> | |
<Tag color="red" className="!text-red-600"> | |
{text?.length} | |
<span className="text-red-300 mx-0.5">/</span> | |
200 | |
</Tag> | |
</div> | |
</Tooltip> | |
) | |
: ( | |
<Tag | |
color="gray" | |
className={cn('!text-gray-500', text?.length ? '' : 'opacity-50')} | |
> | |
{text?.length} | |
<span className="text-gray-300 mx-0.5">/</span> | |
200 | |
</Tag> | |
)} | |
<div> | |
<Button | |
onClick={isExternal ? externalRetrievalTestingOnSubmit : onSubmit} | |
variant="primary" | |
loading={loading} | |
disabled={(!text?.length || text?.length > 200)} | |
> | |
{t('datasetHitTesting.input.testing')} | |
</Button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</> | |
) | |
} | |
export default TextAreaWithButton | |