import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Box, Flex, Button, Textarea, ModalFooter, HStack, VStack } from '@chakra-ui/react'; import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form'; import { postInsertData2Dataset, putDatasetDataById, getDatasetCollectionById, getDatasetDataItemById } from '@/web/core/dataset/api'; import { useToast } from '@fastgpt/web/hooks/useToast'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyModal from '@fastgpt/web/components/common/MyModal'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils'; import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type'; import DeleteIcon from '@fastgpt/web/components/common/Icon/delete'; import { defaultCollectionDetail } from '@/web/core/dataset/constants'; import { getDocPath } from '@/web/common/system/doc'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import styles from './styles.module.scss'; import { DatasetDataIndexTypeEnum, getDatasetIndexMapData } from '@fastgpt/global/core/dataset/data/constants'; import FillRowTabs from '@fastgpt/web/components/common/Tabs/FillRowTabs'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import MyIconButton from '@fastgpt/web/components/common/Icon/button'; export type InputDataType = { q: string; a: string; indexes: (Omit & { dataId?: string; // pg data id fold: boolean; })[]; }; enum TabEnum { chunk = 'chunk', qa = 'qa' } const InputDataModal = ({ collectionId, dataId, defaultValue, onClose, onSuccess }: { collectionId: string; dataId?: string; defaultValue?: { q: string; a?: string }; onClose: () => void; onSuccess: (data: InputDataType & { dataId: string }) => void; }) => { const { t } = useTranslation(); const { toast } = useToast(); const { embeddingModelList, defaultModels } = useSystemStore(); const [currentTab, setCurrentTab] = useState(TabEnum.chunk); const { register, handleSubmit, reset, control } = useForm(); const { fields: indexes, prepend: prependIndexes, remove: removeIndexes, update: updateIndexes } = useFieldArray({ control, name: 'indexes' }); const { data: collection = defaultCollectionDetail } = useRequest2( () => { return getDatasetCollectionById(collectionId); }, { manual: false, refreshDeps: [collectionId] } ); const { loading: isFetchingData } = useRequest2( async () => { if (dataId) return getDatasetDataItemById(dataId); return null; }, { manual: false, refreshDeps: [dataId], onSuccess(res) { if (res) { reset({ q: res.q, a: res.a, indexes: res.indexes.map((item) => ({ ...item, fold: true })) }); } else if (defaultValue) { reset({ q: defaultValue.q, a: defaultValue.a }); } if (res?.a || defaultValue?.a) { setCurrentTab(TabEnum.qa); } }, onError(err) { toast({ status: 'error', title: t(getErrText(err) as any) }); onClose(); } } ); const maxToken = useMemo(() => { const vectorModel = embeddingModelList.find((item) => item.model === collection.dataset.vectorModel) || defaultModels.embedding; return vectorModel?.maxToken || 3000; }, [collection.dataset.vectorModel, defaultModels.embedding, embeddingModelList]); // import new data const { runAsync: sureImportData, loading: isImporting } = useRequest2( async (e: InputDataType) => { if (!e.q) { return Promise.reject(t('common:dataset.data.input is empty')); } const totalLength = e.q.length + (e.a?.length || 0); if (totalLength >= maxToken * 1.4) { return Promise.reject(t('common:core.dataset.data.Too Long')); } const data = { ...e }; const dataId = await postInsertData2Dataset({ collectionId: collection._id, q: e.q, a: currentTab === TabEnum.qa ? e.a : '', // Contains no default index indexes: e.indexes.filter((item) => !!item.text?.trim()) }); return { ...data, dataId }; }, { refreshDeps: [currentTab], successToast: t('common:dataset.data.Input Success Tip'), onSuccess(e) { reset({ ...e, q: '', a: '', indexes: [] }); onSuccess(e); }, errorToast: t('common:common.error.unKnow') } ); // update const { runAsync: onUpdateData, loading: isUpdating } = useRequest2( async (e: InputDataType) => { if (!dataId) return Promise.reject(t('common:common.error.unKnow')); await putDatasetDataById({ dataId, q: e.q, a: currentTab === TabEnum.qa ? e.a : '', indexes: e.indexes.filter((item) => !!item.text?.trim()) }); return { dataId, ...e }; }, { refreshDeps: [currentTab], successToast: t('common:dataset.data.Update Success Tip'), onSuccess(data) { onSuccess(data); onClose(); } } ); const isLoading = isFetchingData; const icon = useMemo( () => getSourceNameIcon({ sourceName: collection.sourceName, sourceId: collection.sourceId }), [collection] ); return ( onClose()} closeOnOverlayClick={false} maxW={'1440px'} h={'46.25rem'} title={ {collection.sourceName || t('common:common.UnKnow Source')} } > {/* Tab */} { setCurrentTab(e); }} /> {/* Data */} {currentTab === TabEnum.chunk ? t('common:dataset_data_input_chunk_content') : t('common:dataset_data_input_q')}