import React, { useMemo, useState } from 'react'; import { Box, Flex, Button, Textarea, useTheme, Grid, HStack } from '@chakra-ui/react'; import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form'; import { postInsertData2Dataset, putDatasetDataById, delOneDatasetDataById, 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 '@/components/MyTooltip'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useRequest } from '@fastgpt/web/hooks/useRequest'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils'; import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type'; import SideTabs from '@/components/SideTabs'; import DeleteIcon from '@fastgpt/web/components/common/Icon/delete'; import { defaultCollectionDetail } from '@/constants/dataset'; import { getDocPath } from '@/web/common/system/doc'; import RawSourceBox from '@/components/core/dataset/RawSourceBox'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; export type InputDataType = { q: string; a: string; indexes: (Omit & { dataId?: string; // pg data id })[]; }; enum TabEnum { content = 'content', index = 'index', delete = 'delete', doc = 'doc' } const InputDataModal = ({ collectionId, dataId, defaultValue, onClose, onSuccess, onDelete }: { collectionId: string; dataId?: string; defaultValue?: { q: string; a?: string }; onClose: () => void; onSuccess: (data: InputDataType & { dataId: string }) => void; onDelete?: () => void; }) => { const { t } = useTranslation(); const theme = useTheme(); const { toast } = useToast(); const [currentTab, setCurrentTab] = useState(TabEnum.content); const { vectorModelList } = useSystemStore(); const { register, handleSubmit, reset, control } = useForm(); const { fields: indexes, append: appendIndexes, remove: removeIndexes } = useFieldArray({ control, name: 'indexes' }); const tabList = [ { label: t('dataset.data.edit.Content'), id: TabEnum.content, icon: 'common/overviewLight' }, { label: t('dataset.data.edit.Index', { amount: indexes.length }), id: TabEnum.index, icon: 'kbTest' }, ...(dataId ? [{ label: t('dataset.data.edit.Delete'), id: TabEnum.delete, icon: 'delete' }] : []), { label: t('dataset.data.edit.Course'), id: TabEnum.doc, icon: 'common/courseLight' } ]; const { ConfirmModal, openConfirm } = useConfirm({ content: t('dataset.data.Delete Tip'), type: 'delete' }); const { data: collection = defaultCollectionDetail } = useQuery( ['loadCollectionId', collectionId], () => { return getDatasetCollectionById(collectionId); } ); const { isFetching: isFetchingData } = useQuery( ['getDatasetDataItemById', dataId], () => { if (dataId) return getDatasetDataItemById(dataId); return null; }, { onSuccess(res) { if (res) { reset({ q: res.q, a: res.a, indexes: res.indexes }); } else if (defaultValue) { reset({ q: defaultValue.q, a: defaultValue.a }); } }, onError(err) { toast({ status: 'error', title: t(getErrText(err)) }); onClose(); } } ); const maxToken = useMemo(() => { const vectorModel = vectorModelList.find((item) => item.model === collection.datasetId.vectorModel) || vectorModelList[0]; return vectorModel?.maxToken || 3000; }, [collection.datasetId.vectorModel, vectorModelList]); // import new data const { mutate: sureImportData, isLoading: isImporting } = useRequest({ mutationFn: async (e: InputDataType) => { if (!e.q) { setCurrentTab(TabEnum.content); return Promise.reject(t('dataset.data.input is empty')); } const totalLength = e.q.length + (e.a?.length || 0); if (totalLength >= maxToken * 1.4) { return Promise.reject(t('core.dataset.data.Too Long')); } const data = { ...e }; const dataId = await postInsertData2Dataset({ collectionId: collection._id, q: e.q, a: e.a, // remove dataId indexes: e.indexes?.map((index) => ({ ...index, dataId: undefined })) || [] }); return { ...data, dataId }; }, successToast: t('dataset.data.Input Success Tip'), onSuccess(e) { reset({ ...e, q: '', a: '', indexes: [] }); onSuccess(e); }, errorToast: t('common.error.unKnow') }); // update const { mutate: onUpdateData, isLoading: isUpdating } = useRequest({ mutationFn: async (e: InputDataType) => { if (!dataId) return e; // not exactly same await putDatasetDataById({ id: dataId, ...e, indexes: e.indexes?.map((index) => index.defaultIndex ? getDefaultIndex({ q: e.q, a: e.a, dataId: index.dataId }) : index ) || [] }); return { dataId, ...e }; }, successToast: t('dataset.data.Update Success Tip'), errorToast: t('common.error.unKnow'), onSuccess(data) { onSuccess(data); onClose(); } }); // delete const { mutate: onDeleteData, isLoading: isDeleting } = useRequest({ mutationFn: () => { if (!onDelete || !dataId) return Promise.resolve(null); return delOneDatasetDataById(dataId); }, onSuccess() { if (!onDelete) return; onDelete(); onClose(); }, successToast: t('common.Delete Success'), errorToast: t('common.error.unKnow') }); const isLoading = useMemo( () => isImporting || isUpdating || isFetchingData || isDeleting, [isImporting, isUpdating, isFetchingData, isDeleting] ); return ( { if (e === TabEnum.delete) { return openConfirm(onDeleteData)(); } if (e === TabEnum.doc) { return window.open(getDocPath('/docs/course/dataset_engine'), '_blank'); } setCurrentTab(e); }} /> {currentTab === TabEnum.content && ( <>{dataId ? t('dataset.data.Update Data') : t('dataset.data.Input Data')} )} {currentTab === TabEnum.index && <> {t('dataset.data.Index Edit')}} {currentTab === TabEnum.content && } {currentTab === TabEnum.index && ( {indexes?.map((index, i) => ( {index.defaultIndex ? t('dataset.data.Default Index') : t('dataset.data.Custom Index Number', { number: i })} { if (indexes.length <= 1) { appendIndexes(getDefaultIndex({ dataId: `${Date.now()}` })); } removeIndexes(i); }} /> {index.defaultIndex ? ( {t('core.dataset.data.Default Index Tip')} ) : (