feat: select dataset

This commit is contained in:
archer 2023-09-10 14:30:32 +08:00
parent ce47c96b9f
commit b40561ad37
No known key found for this signature in database
GPG Key ID: 569A5660D2379E28
18 changed files with 347 additions and 198 deletions

View File

@ -23,6 +23,7 @@ import { QuoteItemType } from '@/types/chat';
/* knowledge base */ /* knowledge base */
export const getKbList = (parentId?: string) => export const getKbList = (parentId?: string) =>
GET<KbListItemType[]>(`/plugins/kb/list`, { parentId }); GET<KbListItemType[]>(`/plugins/kb/list`, { parentId });
export const getAllDataset = () => GET<KbListItemType[]>(`/plugins/kb/allDataset`);
export const getKbPaths = (parentId?: string) => export const getKbPaths = (parentId?: string) =>
GET<KbPathItemType[]>('/plugins/kb/paths', { parentId }); GET<KbPathItemType[]>('/plugins/kb/paths', { parentId });

View File

@ -12,7 +12,7 @@ import {
import MyModal from '../MyModal'; import MyModal from '../MyModal';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import Avatar from '../Avatar'; import Avatar from '../Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
@ -29,7 +29,7 @@ const SelectDataset = ({
const theme = useTheme(); const theme = useTheme();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const { toast } = useToast(); const { toast } = useToast();
const { myKbList, loadKbList } = useUserStore(); const { myKbList, loadKbList } = useDatasetStore();
const [selectedId, setSelectedId] = useState<string>(); const [selectedId, setSelectedId] = useState<string>();
useQuery(['loadKbList'], () => loadKbList()); useQuery(['loadKbList'], () => loadKbList());

View File

@ -0,0 +1,34 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response';
import { connectToDatabase, KB } from '@/service/mongo';
import { authUser } from '@/service/utils/auth';
import { getVectorModel } from '@/service/utils/data';
import { KbListItemType } from '@/types/plugin';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
// 凭证校验
const { userId } = await authUser({ req, authToken: true });
await connectToDatabase();
const kbList = await KB.find({
userId,
type: 'dataset'
});
const data = kbList.map((item) => ({
...item.toJSON(),
vectorModel: getVectorModel(item.vectorModel)
}));
jsonRes<KbListItemType[]>(res, {
data
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import { FlowModuleItemType } from '@/types/flow'; import { FlowModuleItemType } from '@/types/flow';
import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react'; import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import NodeCard from '../modules/NodeCard'; import NodeCard from '../modules/NodeCard';
import Divider from '../modules/Divider'; import Divider from '../modules/Divider';
@ -21,7 +21,7 @@ const KBSelect = ({
onChange: (e: SelectedKbType) => void; onChange: (e: SelectedKbType) => void;
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const { myKbList, loadKbList } = useUserStore(); const { datasets, loadAllDatasets } = useDatasetStore();
const { const {
isOpen: isOpenKbSelect, isOpen: isOpenKbSelect,
onOpen: onOpenKbSelect, onOpen: onOpenKbSelect,
@ -29,11 +29,11 @@ const KBSelect = ({
} = useDisclosure(); } = useDisclosure();
const showKbList = useMemo( const showKbList = useMemo(
() => myKbList.filter((item) => activeKbs.find((kb) => kb.kbId === item._id)), () => datasets.filter((item) => activeKbs.find((kb) => kb.kbId === item._id)),
[myKbList, activeKbs] [datasets, activeKbs]
); );
useQuery(['initkb'], () => loadKbList()); useQuery(['loadAllDatasets'], loadAllDatasets);
return ( return (
<> <>
@ -58,12 +58,7 @@ const KBSelect = ({
))} ))}
</Grid> </Grid>
{isOpenKbSelect && ( {isOpenKbSelect && (
<KBSelectModal <KBSelectModal activeKbs={activeKbs} onChange={onChange} onClose={onCloseKbSelect} />
kbList={myKbList}
activeKbs={activeKbs}
onChange={onChange}
onClose={onCloseKbSelect}
/>
)} )}
</> </>
); );

View File

@ -56,18 +56,21 @@ import MyIcon from '@/components/Icon';
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox'; import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
import { addVariable } from '../VariableEditModal'; import { addVariable } from '../VariableEditModal';
import { KBSelectModal, KbParamsModal } from '../KBSelectModal'; import { KbParamsModal } from '../KBSelectModal';
import { AppTypeEnum } from '@/constants/app'; import { AppTypeEnum } from '@/constants/app';
import { useDatasetStore } from '@/store/dataset';
const VariableEditModal = dynamic(() => import('../VariableEditModal')); const VariableEditModal = dynamic(() => import('../VariableEditModal'));
const InfoModal = dynamic(() => import('../InfoModal')); const InfoModal = dynamic(() => import('../InfoModal'));
const KBSelectModal = dynamic(() => import('../KBSelectModal'));
const Settings = ({ appId }: { appId: string }) => { const Settings = ({ appId }: { appId: string }) => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const { appDetail, updateAppDetail, loadKbList, myKbList } = useUserStore(); const { appDetail, updateAppDetail } = useUserStore();
const { loadAllDatasets, datasets } = useDatasetStore();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const [editVariable, setEditVariable] = useState<VariableItemType>(); const [editVariable, setEditVariable] = useState<VariableItemType>();
@ -122,8 +125,8 @@ const Settings = ({ appId }: { appId: string }) => {
); );
}, [getValues, refresh]); }, [getValues, refresh]);
const selectedKbList = useMemo( const selectedKbList = useMemo(
() => myKbList.filter((item) => kbList.find((kb) => kb.kbId === item._id)), () => datasets.filter((item) => kbList.find((kb) => kb.kbId === item._id)),
[myKbList, kbList] [datasets, kbList]
); );
/* 点击删除 */ /* 点击删除 */
@ -167,7 +170,7 @@ const Settings = ({ appId }: { appId: string }) => {
appModule2Form(); appModule2Form();
}, [appModule2Form]); }, [appModule2Form]);
useQuery(['initkb', appId], () => loadKbList()); useQuery(['loadAllDatasets'], loadAllDatasets);
const BoxStyles: BoxProps = { const BoxStyles: BoxProps = {
bg: 'myWhite.200', bg: 'myWhite.200',
@ -304,6 +307,23 @@ const Settings = ({ appId }: { appId: string }) => {
</Button> </Button>
</Flex> </Flex>
{/* welcome */}
<Box mt={5} {...BoxStyles}>
<Flex alignItems={'center'}>
<Avatar src={'/imgs/module/userGuide.png'} w={'18px'} />
<Box mx={2}></Box>
<MyTooltip label={welcomeTextTip} forceShow>
<QuestionOutlineIcon />
</MyTooltip>
</Flex>
<Textarea
mt={2}
rows={5}
placeholder={welcomeTextTip}
borderColor={'myGray.100'}
{...register('guide.welcome.text')}
/>
</Box>
{/* variable */} {/* variable */}
<Box mt={2} {...BoxStyles}> <Box mt={2} {...BoxStyles}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
@ -498,24 +518,6 @@ const Settings = ({ appId }: { appId: string }) => {
</Grid> </Grid>
</Box> </Box>
{/* welcome */}
<Box mt={5} {...BoxStyles}>
<Flex alignItems={'center'}>
<Avatar src={'/imgs/module/userGuide.png'} w={'18px'} />
<Box mx={2}></Box>
<MyTooltip label={welcomeTextTip} forceShow>
<QuestionOutlineIcon />
</MyTooltip>
</Flex>
<Textarea
mt={2}
rows={5}
placeholder={welcomeTextTip}
borderColor={'myGray.100'}
{...register('guide.welcome.text')}
/>
</Box>
<ConfirmSaveModal /> <ConfirmSaveModal />
<ConfirmDelModal /> <ConfirmDelModal />
{settingAppInfo && ( {settingAppInfo && (
@ -548,7 +550,6 @@ const Settings = ({ appId }: { appId: string }) => {
)} )}
{isOpenKbSelect && ( {isOpenKbSelect && (
<KBSelectModal <KBSelectModal
kbList={myKbList}
activeKbs={selectedKbList.map((item) => ({ activeKbs={selectedKbList.map((item) => ({
kbId: item._id, kbId: item._id,
vectorModel: item.vectorModel vectorModel: item.vectorModel

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useMemo, useState } from 'react';
import { import {
Card, Card,
Flex, Flex,
@ -8,18 +8,25 @@ import {
ModalHeader, ModalHeader,
ModalFooter, ModalFooter,
useTheme, useTheme,
Textarea Textarea,
Grid,
Divider
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { getKbPaths } from '@/api/plugins/kb';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import type { KbListItemType, SelectedKbType } from '@/types/plugin'; import type { SelectedKbType } from '@/types/plugin';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import MySlider from '@/components/Slider'; import MySlider from '@/components/Slider';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { KbTypeEnum } from '@/constants/kb';
import { useTranslation } from 'react-i18next';
import { useQuery } from '@tanstack/react-query';
import { useDatasetStore } from '@/store/dataset';
export type KbParamsType = { export type KbParamsType = {
searchSimilarity: number; searchSimilarity: number;
@ -28,20 +35,42 @@ export type KbParamsType = {
}; };
export const KBSelectModal = ({ export const KBSelectModal = ({
kbList,
activeKbs = [], activeKbs = [],
onChange, onChange,
onClose onClose
}: { }: {
kbList: KbListItemType[];
activeKbs: SelectedKbType; activeKbs: SelectedKbType;
onChange: (e: SelectedKbType) => void; onChange: (e: SelectedKbType) => void;
onClose: () => void; onClose: () => void;
}) => { }) => {
const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
const [selectedKbList, setSelectedKbList] = useState<SelectedKbType>(activeKbs); const [selectedKbList, setSelectedKbList] = useState<SelectedKbType>(activeKbs);
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const { toast } = useToast(); const { toast } = useToast();
const [parentId, setParentId] = useState<string>();
const { myKbList, loadKbList, datasets, loadAllDatasets } = useDatasetStore();
const { data } = useQuery(['loadKbList', parentId], () => {
return Promise.all([loadKbList(parentId), getKbPaths(parentId)]);
});
useQuery(['loadAllDatasets'], loadAllDatasets);
const paths = useMemo(
() => [
{
parentId: '',
parentName: t('kb.My Dataset')
},
...(data?.[1] || [])
],
[data, t]
);
const filterKbList = useMemo(() => {
return {
selected: datasets.filter((item) => selectedKbList.find((kb) => kb.kbId === item._id)),
unSelected: myKbList.filter((item) => !selectedKbList.find((kb) => kb.kbId === item._id))
};
}, [myKbList, datasets, selectedKbList]);
return ( return (
<MyModal <MyModal
@ -53,10 +82,43 @@ export const KBSelectModal = ({
> >
<Flex flexDirection={'column'} h={['90vh', 'auto']}> <Flex flexDirection={'column'} h={['90vh', 'auto']}>
<ModalHeader> <ModalHeader>
<Box>({selectedKbList.length})</Box> {!!parentId ? (
<Box fontSize={'sm'} color={'myGray.500'} fontWeight={'normal'}> <Flex flex={1}>
{paths.map((item, i) => (
</Box> <Flex key={item.parentId} mr={2} alignItems={'center'}>
<Box
fontSize={'lg'}
borderRadius={'md'}
{...(i === paths.length - 1
? {
cursor: 'default'
}
: {
cursor: 'pointer',
_hover: {
color: 'myBlue.600'
},
onClick: () => {
setParentId(item.parentId);
}
})}
>
{item.parentName}
</Box>
{i !== paths.length - 1 && (
<MyIcon name={'rightArrowLight'} color={'myGray.500'} />
)}
</Flex>
))}
</Flex>
) : (
<Box>({selectedKbList.length})</Box>
)}
{isPc && (
<Box fontSize={'sm'} color={'myGray.500'} fontWeight={'normal'}>
</Box>
)}
</ModalHeader> </ModalHeader>
<ModalBody <ModalBody
@ -64,72 +126,119 @@ export const KBSelectModal = ({
maxH={'80vh'} maxH={'80vh'}
overflowY={'auto'} overflowY={'auto'}
display={'grid'} display={'grid'}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'} userSelect={'none'}
> >
{kbList.map((item) => <Grid
(() => { h={'auto'}
const selected = !!selectedKbList.find((kb) => kb.kbId === item._id); gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
const active = !!activeKbs.find((kb) => kb.kbId === item._id); gridGap={3}
return ( >
<Card {filterKbList.selected.map((item) =>
key={item._id} (() => {
p={3} return (
border={theme.borders.base} <Card
boxShadow={'sm'} key={item._id}
h={'80px'} p={3}
cursor={'pointer'} border={theme.borders.base}
order={active ? 0 : 1} boxShadow={'sm'}
_hover={{ bg={'myBlue.300'}
boxShadow: 'md' >
}} <Flex alignItems={'center'} h={'38px'}>
{...(selected <Avatar src={item.avatar} w={['24px', '28px']}></Avatar>
? { <Box flex={'1 0 0'} mx={3}>
bg: 'myBlue.300' {item.name}
} </Box>
: {})} <MyIcon
onClick={() => { name={'delete'}
if (selected) { w={'14px'}
setSelectedKbList((state) => state.filter((kb) => kb.kbId !== item._id)); cursor={'pointer'}
} else { _hover={{ color: 'red.500' }}
const vectorModel = selectedKbList[0]?.vectorModel?.model; onClick={() => {
setSelectedKbList((state) => state.filter((kb) => kb.kbId !== item._id));
}}
/>
</Flex>
</Card>
);
})()
)}
</Grid>
if (vectorModel && vectorModel !== item.vectorModel.model) { {filterKbList.selected.length > 0 && <Divider my={3} />}
return toast({
status: 'warning', <Grid
title: '仅能选择同一个索引模型的知识库' gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
}); gridGap={3}
>
{filterKbList.unSelected.map((item) =>
(() => {
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
h={'80px'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
onClick={() => {
if (item.type === KbTypeEnum.folder) {
setParentId(item._id);
} else if (item.type === KbTypeEnum.dataset) {
const vectorModel = selectedKbList[0]?.vectorModel?.model;
if (vectorModel && vectorModel !== item.vectorModel.model) {
return toast({
status: 'warning',
title: '仅能选择同一个索引模型的知识库'
});
}
setSelectedKbList((state) => [
...state,
{ kbId: item._id, vectorModel: item.vectorModel }
]);
} }
setSelectedKbList((state) => [ }}
...state, >
{ kbId: item._id, vectorModel: item.vectorModel } <Flex alignItems={'center'} h={'38px'}>
]); <Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar>
} <Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
}} {item.name}
> </Box>
<Flex alignItems={'center'} h={'38px'}> </Flex>
<Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar> <Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}> {item.type === KbTypeEnum.folder ? (
{item.name} <Box color={'myGray.500'}>{t('Folder')}</Box>
</Box> ) : (
</Flex> <>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}> <MyIcon mr={1} name="kbTest" w={'12px'} />
<MyIcon mr={1} name="kbTest" w={'12px'} /> <Box color={'myGray.500'}>{item.vectorModel.name}</Box>
<Box color={'myGray.500'}>{item.vectorModel.name}</Box> </>
</Flex> )}
</Card> </Flex>
); </Card>
})() );
})()
)}
</Grid>
{filterKbList.unSelected.length === 0 && (
<Flex mt={5} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
西~
</Box>
</Flex>
)} )}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
onClick={() => { onClick={() => {
// filter out the kb that is not in the kbList // filter out the kb that is not in the kList
const filterKbList = selectedKbList.filter((kb) => { const filterKbList = selectedKbList.filter((kb) => {
return kbList.find((item) => item._id === kb.kbId); return datasets.find((item) => item._id === kb.kbId);
}); });
onClose(); onClose();

View File

@ -26,12 +26,12 @@ import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { TrainingModeEnum } from '@/constants/plugin'; import { TrainingModeEnum } from '@/constants/plugin';
import FileSelect, { type FileItemType } from './FileSelect'; import FileSelect, { type FileItemType } from './FileSelect';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
const fileExtension = '.txt, .doc, .docx, .pdf, .md'; const fileExtension = '.txt, .doc, .docx, .pdf, .md';
const ChunkImport = ({ kbId }: { kbId: string }) => { const ChunkImport = ({ kbId }: { kbId: string }) => {
const { kbDetail } = useUserStore(); const { kbDetail } = useDatasetStore();
const vectorModel = kbDetail.vectorModel; const vectorModel = kbDetail.vectorModel;
const unitPrice = vectorModel?.price || 0.2; const unitPrice = vectorModel?.price || 0.2;

View File

@ -10,12 +10,12 @@ import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
import { TrainingModeEnum } from '@/constants/plugin'; import { TrainingModeEnum } from '@/constants/plugin';
import FileSelect, { type FileItemType } from './FileSelect'; import FileSelect, { type FileItemType } from './FileSelect';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
const fileExtension = '.csv'; const fileExtension = '.csv';
const CsvImport = ({ kbId }: { kbId: string }) => { const CsvImport = ({ kbId }: { kbId: string }) => {
const { kbDetail } = useUserStore(); const { kbDetail } = useDatasetStore();
const maxToken = kbDetail.vectorModel?.maxToken || 2000; const maxToken = kbDetail.vectorModel?.maxToken || 2000;
const theme = useTheme(); const theme = useTheme();

View File

@ -19,7 +19,7 @@ import dynamic from 'next/dynamic';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { FetchResultItem, DatasetItemType } from '@/types/plugin'; import { FetchResultItem, DatasetItemType } from '@/types/plugin';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
const UrlFetchModal = dynamic(() => import('./UrlFetchModal')); const UrlFetchModal = dynamic(() => import('./UrlFetchModal'));
const CreateFileModal = dynamic(() => import('./CreateFileModal')); const CreateFileModal = dynamic(() => import('./CreateFileModal'));
@ -55,7 +55,7 @@ const FileSelect = ({
showCreateFile = true, showCreateFile = true,
...props ...props
}: Props) => { }: Props) => {
const { kbDetail } = useUserStore(); const { kbDetail } = useDatasetStore();
const { Loading: FileSelectLoading } = useLoading(); const { Loading: FileSelectLoading } = useLoading();
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -6,14 +6,14 @@ import { useRequest } from '@/hooks/useRequest';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { postKbDataFromList } from '@/api/plugins/kb'; import { postKbDataFromList } from '@/api/plugins/kb';
import { TrainingModeEnum } from '@/constants/plugin'; import { TrainingModeEnum } from '@/constants/plugin';
import { useUserStore } from '@/store/user';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useDatasetStore } from '@/store/dataset';
type ManualFormType = { q: string; a: string }; type ManualFormType = { q: string; a: string };
const ManualImport = ({ kbId }: { kbId: string }) => { const ManualImport = ({ kbId }: { kbId: string }) => {
const { kbDetail } = useUserStore(); const { kbDetail } = useDatasetStore();
const maxToken = kbDetail.vectorModel?.maxToken || 2000; const maxToken = kbDetail.vectorModel?.maxToken || 2000;
const { register, handleSubmit, reset } = useForm({ const { register, handleSubmit, reset } = useForm({

View File

@ -12,7 +12,7 @@ import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons';
import { delKbById, putKbById } from '@/api/plugins/kb'; import { delKbById, putKbById } from '@/api/plugins/kb';
import { useSelectFile } from '@/hooks/useSelectFile'; import { useSelectFile } from '@/hooks/useSelectFile';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
import { useConfirm } from '@/hooks/useConfirm'; import { useConfirm } from '@/hooks/useConfirm';
import { UseFormReturn } from 'react-hook-form'; import { UseFormReturn } from 'react-hook-form';
import { compressImg } from '@/utils/file'; import { compressImg } from '@/utils/file';
@ -47,7 +47,7 @@ const Info = (
multiple: false multiple: false
}); });
const { kbDetail, getKbDetail, loadKbList, myKbList } = useUserStore(); const { kbDetail, getKbDetail, loadKbList } = useDatasetStore();
/* 点击删除 */ /* 点击删除 */
const onclickDelKb = useCallback(async () => { const onclickDelKb = useCallback(async () => {

View File

@ -9,10 +9,10 @@ import MyIcon from '@/components/Icon';
import MyModal from '@/components/MyModal'; import MyModal from '@/components/MyModal';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useUserStore } from '@/store/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { DatasetItemType } from '@/types/plugin'; import { DatasetItemType } from '@/types/plugin';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDatasetStore } from '@/store/dataset';
export type FormData = { dataId?: string } & DatasetItemType; export type FormData = { dataId?: string } & DatasetItemType;
@ -36,7 +36,7 @@ const InputDataModal = ({
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
const { kbDetail, getKbDetail } = useUserStore(); const { kbDetail, getKbDetail } = useDatasetStore();
const { getValues, register, handleSubmit, reset } = useForm<FormData>({ const { getValues, register, handleSubmit, reset } = useForm<FormData>({
defaultValues defaultValues

View File

@ -1,6 +1,6 @@
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react'; import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react';
import { useKbStore } from '@/store/kb'; import { useDatasetStore } from '@/store/dataset';
import type { KbTestItemType } from '@/types/plugin'; import type { KbTestItemType } from '@/types/plugin';
import { searchText, getKbDataItemById } from '@/api/plugins/kb'; import { searchText, getKbDataItemById } from '@/api/plugins/kb';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
@ -13,16 +13,14 @@ import { useToast } from '@/hooks/useToast';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons'; import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useUserStore } from '@/store/user';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
const Test = ({ kbId }: { kbId: string }) => { const Test = ({ kbId }: { kbId: string }) => {
const { kbDetail } = useUserStore();
const theme = useTheme(); const theme = useTheme();
const { toast } = useToast(); const { toast } = useToast();
const { setLoading } = useGlobalStore(); const { setLoading } = useGlobalStore();
const { kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } = useKbStore(); const { kbDetail, kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } =
useDatasetStore();
const [inputText, setInputText] = useState(''); const [inputText, setInputText] = useState('');
const [kbTestItem, setKbTestItem] = useState<KbTestItemType>(); const [kbTestItem, setKbTestItem] = useState<KbTestItemType>();
const [editData, setEditData] = useState<FormData>(); const [editData, setEditData] = useState<FormData>();

View File

@ -4,7 +4,6 @@ import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/store/user';
import { KbItemType } from '@/types/plugin'; import { KbItemType } from '@/types/plugin';
import { getErrText } from '@/utils/tools'; import { getErrText } from '@/utils/tools';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
@ -24,6 +23,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { feConfigs } from '@/store/static'; import { feConfigs } from '@/store/static';
import Script from 'next/script'; import Script from 'next/script';
import FileCard from './components/FileCard'; import FileCard from './components/FileCard';
import { useDatasetStore } from '@/store/dataset';
const DataCard = dynamic(() => import('./components/DataCard'), { const DataCard = dynamic(() => import('./components/DataCard'), {
ssr: false ssr: false
@ -50,7 +50,7 @@ const Detail = ({ kbId, currentTab }: { kbId: string; currentTab: `${TabEnum}` }
const { toast } = useToast(); const { toast } = useToast();
const router = useRouter(); const router = useRouter();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const { kbDetail, getKbDetail } = useUserStore(); const { kbDetail, getKbDetail } = useDatasetStore();
const tabList = useRef([ const tabList = useRef([
{ label: '数据集', id: TabEnum.dataset, icon: 'overviewLight' }, { label: '数据集', id: TabEnum.dataset, icon: 'overviewLight' },

View File

@ -11,7 +11,7 @@ import {
Image Image
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/store/user'; import { useDatasetStore } from '@/store/dataset';
import PageContainer from '@/components/PageContainer'; import PageContainer from '@/components/PageContainer';
import { useConfirm } from '@/hooks/useConfirm'; import { useConfirm } from '@/hooks/useConfirm';
import { AddIcon } from '@chakra-ui/icons'; import { AddIcon } from '@chakra-ui/icons';
@ -49,7 +49,7 @@ const Kb = () => {
title: t('common.Delete Warning'), title: t('common.Delete Warning'),
content: '' content: ''
}); });
const { myKbList, loadKbList, setKbList } = useUserStore(); const { myKbList, loadKbList, setKbList } = useDatasetStore();
const { const {
isOpen: isOpenCreateModal, isOpen: isOpenCreateModal,

View File

@ -0,0 +1,86 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { type KbTestItemType } from '@/types/plugin';
import type { KbItemType, KbListItemType } from '@/types/plugin';
import { getKbList, getKbById, getAllDataset } from '@/api/plugins/kb';
import { defaultKbDetail } from '@/constants/kb';
type State = {
datasets: KbListItemType[];
loadAllDatasets: () => Promise<KbListItemType[]>;
myKbList: KbListItemType[];
loadKbList: (parentId?: string) => Promise<any>;
setKbList(val: KbListItemType[]): void;
kbDetail: KbItemType;
getKbDetail: (id: string, init?: boolean) => Promise<KbItemType>;
kbTestList: KbTestItemType[];
pushKbTestItem: (data: KbTestItemType) => void;
delKbTestItemById: (id: string) => void;
updateKbItemById: (data: KbTestItemType) => void;
};
export const useDatasetStore = create<State>()(
devtools(
persist(
immer((set, get) => ({
datasets: [],
async loadAllDatasets() {
const res = await getAllDataset();
set((state) => {
state.datasets = res;
});
return res;
},
myKbList: [],
async loadKbList(parentId) {
const res = await getKbList(parentId);
set((state) => {
state.myKbList = res;
});
return res;
},
setKbList(val) {
set((state) => {
state.myKbList = val;
});
},
kbDetail: defaultKbDetail,
async getKbDetail(id: string, init = false) {
if (id === get().kbDetail._id && !init) return get().kbDetail;
const data = await getKbById(id);
set((state) => {
state.kbDetail = data;
});
return data;
},
kbTestList: [],
pushKbTestItem(data) {
set((state) => {
state.kbTestList = [data, ...state.kbTestList].slice(0, 500);
});
},
delKbTestItemById(id) {
set((state) => {
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
});
},
updateKbItemById(data: KbTestItemType) {
set((state) => {
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
});
}
})),
{
name: 'kbStore',
partialize: (state) => ({
kbTestList: state.kbTestList
})
}
)
)
);

View File

@ -1,42 +0,0 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { type KbTestItemType } from '@/types/plugin';
type State = {
kbTestList: KbTestItemType[];
pushKbTestItem: (data: KbTestItemType) => void;
delKbTestItemById: (id: string) => void;
updateKbItemById: (data: KbTestItemType) => void;
};
export const useKbStore = create<State>()(
devtools(
persist(
immer((set, get) => ({
kbTestList: [],
pushKbTestItem(data) {
set((state) => {
state.kbTestList = [data, ...state.kbTestList].slice(0, 500);
});
},
delKbTestItemById(id) {
set((state) => {
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
});
},
updateKbItemById(data: KbTestItemType) {
set((state) => {
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
});
}
})),
{
name: 'kbStore',
partialize: (state) => ({
kbTestList: state.kbTestList
})
}
)
)
);

View File

@ -7,9 +7,7 @@ import { formatPrice } from '@/utils/user';
import { getTokenLogin, putUserInfo } from '@/api/user'; import { getTokenLogin, putUserInfo } from '@/api/user';
import { defaultApp } from '@/constants/model'; import { defaultApp } from '@/constants/model';
import { AppListItemType, AppUpdateParams } from '@/types/app'; import { AppListItemType, AppUpdateParams } from '@/types/app';
import type { KbItemType, KbListItemType } from '@/types/plugin';
import { getKbList, getKbById, putKbById } from '@/api/plugins/kb';
import { defaultKbDetail } from '@/constants/kb';
import type { AppSchema } from '@/types/mongoSchema'; import type { AppSchema } from '@/types/mongoSchema';
type State = { type State = {
@ -24,12 +22,6 @@ type State = {
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>; loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>; updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>;
clearAppModules(): void; clearAppModules(): void;
// kb
myKbList: KbListItemType[];
loadKbList: (parentId?: string) => Promise<any>;
setKbList(val: KbListItemType[]): void;
kbDetail: KbItemType;
getKbDetail: (id: string, init?: boolean) => Promise<KbItemType>;
}; };
export const useUserStore = create<State>()( export const useUserStore = create<State>()(
@ -106,31 +98,6 @@ export const useUserStore = create<State>()(
modules: [] modules: []
}; };
}); });
},
myKbList: [],
async loadKbList(parentId) {
const res = await getKbList(parentId);
set((state) => {
state.myKbList = res;
});
return res;
},
setKbList(val) {
set((state) => {
state.myKbList = val;
});
},
kbDetail: defaultKbDetail,
async getKbDetail(id: string, init = false) {
if (id === get().kbDetail._id && !init) return get().kbDetail;
const data = await getKbById(id);
set((state) => {
state.kbDetail = data;
});
return data;
} }
})), })),
{ {