4.6.7 first pr (#726)

This commit is contained in:
Archer
2024-01-10 23:35:04 +08:00
committed by GitHub
parent 414b693303
commit 006ad17c6a
186 changed files with 2996 additions and 1838 deletions

View File

@@ -1,44 +1,38 @@
import React, { useMemo, useState } from 'react';
import { Box, Flex, Button, Textarea, BoxProps, Image, useTheme, Grid } from '@chakra-ui/react';
import { Box, Flex, Button, Textarea, useTheme, Grid } from '@chakra-ui/react';
import { useFieldArray, useForm } from 'react-hook-form';
import {
postInsertData2Dataset,
putDatasetDataById,
delOneDatasetDataById,
getDatasetCollectionById
getDatasetCollectionById,
getDatasetDataItemById
} from '@/web/core/dataset/api';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@/components/MyModal';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'next-i18next';
import { getFileAndOpen } from '@/web/core/dataset/utils';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRequest } from '@/web/common/hooks/useRequest';
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { getDefaultIndex, getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import { feConfigs, vectorModelList } from '@/web/common/system/staticData';
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
import { vectorModelList } from '@/web/common/system/staticData';
import { DatasetDataIndexTypeEnum } from '@fastgpt/global/core/dataset/constant';
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
import SideTabs from '@/components/SideTabs';
import { useLoading } from '@/web/common/hooks/useLoading';
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 '@/components/common/MyBox';
import { getErrText } from '@fastgpt/global/common/error/utils';
export type RawSourceTextProps = BoxProps & {
sourceName?: string;
sourceId?: string;
canView?: boolean;
};
export type InputDataType = {
id?: string;
q: string;
a?: string;
a: string;
indexes: (Omit<DatasetDataIndexItemType, 'dataId'> & {
dataId?: string; // pg data id
})[];
@@ -53,26 +47,25 @@ enum TabEnum {
const InputDataModal = ({
collectionId,
dataId,
defaultValue,
onClose,
onSuccess,
onDelete
}: {
collectionId: string;
defaultValue: InputDataType;
dataId?: string;
defaultValue?: { q: string; a?: string };
onClose: () => void;
onSuccess: (data: InputDataType) => void;
onSuccess: (data: InputDataType & { dataId: string }) => void;
onDelete?: () => void;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const { toast } = useToast();
const { Loading } = useLoading();
const [currentTab, setCurrentTab] = useState(TabEnum.content);
const { register, handleSubmit, reset, control } = useForm<InputDataType>({
defaultValues: defaultValue
});
const { register, handleSubmit, reset, control } = useForm<InputDataType>();
const {
fields: indexes,
append: appendIndexes,
@@ -89,14 +82,15 @@ const InputDataModal = ({
id: TabEnum.index,
icon: 'kbTest'
},
...(defaultValue.id
...(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')
content: t('dataset.data.Delete Tip'),
type: 'delete'
});
const { data: collection = defaultCollectionDetail } = useQuery(
@@ -105,6 +99,37 @@ const InputDataModal = ({
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,
indexes: [getDefaultIndex({ dataId: `${Date.now()}` })]
});
}
},
onError(err) {
toast({
status: 'error',
title: getErrText(err)
});
onClose();
}
}
);
const maxToken = useMemo(() => {
const vectorModel =
@@ -130,7 +155,7 @@ const InputDataModal = ({
const data = { ...e };
data.id = await postInsertData2Dataset({
const dataId = await postInsertData2Dataset({
collectionId: collection._id,
q: e.q,
a: e.a,
@@ -140,7 +165,10 @@ const InputDataModal = ({
)
});
return data;
return {
...data,
dataId
};
},
successToast: t('dataset.data.Input Success Tip'),
onSuccess(e) {
@@ -158,17 +186,18 @@ const InputDataModal = ({
// update
const { mutate: onUpdateData, isLoading: isUpdating } = useRequest({
mutationFn: async (e: InputDataType) => {
if (!e.id) return e;
if (!dataId) return e;
// not exactly same
await putDatasetDataById({
id: e.id,
q: e.q,
a: e.a,
indexes: e.indexes
id: dataId,
...e
});
return e;
return {
dataId,
...e
};
},
successToast: t('dataset.data.Update Success Tip'),
errorToast: t('common.error.unKnow'),
@@ -180,8 +209,8 @@ const InputDataModal = ({
// delete
const { mutate: onDeleteData, isLoading: isDeleting } = useRequest({
mutationFn: () => {
if (!onDelete || !defaultValue.id) return Promise.resolve(null);
return delOneDatasetDataById(defaultValue.id);
if (!onDelete || !dataId) return Promise.resolve(null);
return delOneDatasetDataById(dataId);
},
onSuccess() {
if (!onDelete) return;
@@ -192,13 +221,16 @@ const InputDataModal = ({
errorToast: t('common.error.unKnow')
});
const loading = useMemo(() => isImporting || isUpdating, [isImporting, isUpdating]);
const isLoading = useMemo(
() => isImporting || isUpdating || isFetchingData || isDeleting,
[isImporting, isUpdating, isFetchingData, isDeleting]
);
return (
<MyModal isOpen={true} isCentered w={'90vw'} maxW={'1440px'} h={'90vh'}>
<Flex h={'100%'}>
<MyBox isLoading={isLoading} display={'flex'} h={'100%'}>
<Box p={5} borderRight={theme.borders.base}>
<RawSourceText
<RawSourceBox
w={'200px'}
className="textEllipsis3"
whiteSpace={'pre-wrap'}
@@ -224,7 +256,7 @@ const InputDataModal = ({
<Flex flexDirection={'column'} py={3} flex={1} h={'100%'}>
<Box fontSize={'lg'} px={5} fontWeight={'bold'} mb={4}>
{currentTab === TabEnum.content && (
<>{defaultValue.id ? t('dataset.data.Update Data') : t('dataset.data.Input Data')}</>
<>{dataId ? t('dataset.data.Update Data') : t('dataset.data.Input Data')}</>
)}
{currentTab === TabEnum.index && <> {t('dataset.data.Index Edit')}</>}
</Box>
@@ -351,82 +383,24 @@ const InputDataModal = ({
)}
</Box>
<Flex justifyContent={'flex-end'} px={5} mt={4}>
<Button variant={'whitePrimary'} mr={3} isLoading={loading} onClick={onClose}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common.Close')}
</Button>
<MyTooltip label={collection.canWrite ? '' : t('dataset.data.Can not edit')}>
<Button
isDisabled={!collection.canWrite}
isLoading={loading}
// @ts-ignore
onClick={handleSubmit(defaultValue.id ? onUpdateData : sureImportData)}
onClick={handleSubmit(dataId ? onUpdateData : sureImportData)}
>
{defaultValue.id ? t('common.Confirm Update') : t('common.Confirm Import')}
{dataId ? t('common.Confirm Update') : t('common.Confirm Import')}
</Button>
</MyTooltip>
</Flex>
</Flex>
</Flex>
</MyBox>
<ConfirmModal />
<Loading fixed={false} loading={isDeleting} />
</MyModal>
);
};
export default InputDataModal;
export function RawSourceText({
sourceId,
sourceName = '',
canView = true,
...props
}: RawSourceTextProps) {
const { t } = useTranslation();
const { toast } = useToast();
const { setLoading } = useSystemStore();
const canPreview = useMemo(() => !!sourceId && canView, [canView, sourceId]);
const icon = useMemo(() => getSourceNameIcon({ sourceId, sourceName }), [sourceId, sourceName]);
return (
<MyTooltip
label={canPreview ? t('file.Click to view file') || '' : ''}
shouldWrapChildren={false}
>
<Box
color={'myGray.600'}
display={'inline-flex'}
whiteSpace={'nowrap'}
{...(canPreview
? {
cursor: 'pointer',
textDecoration: 'underline',
onClick: async () => {
setLoading(true);
try {
await getFileAndOpen(sourceId as string);
} catch (error) {
toast({
title: t(getErrText(error, 'error.fileNotFound')),
status: 'error'
});
}
setLoading(false);
}
}
: {})}
{...props}
>
<Image src={icon} alt="" w={['14px', '16px']} mr={2} />
<Box
maxW={['200px', '300px']}
className={props.className ?? 'textEllipsis'}
wordBreak={'break-all'}
>
{sourceName || t('common.UnKnow Source')}
</Box>
</Box>
</MyTooltip>
);
}
export default React.memo(InputDataModal);