perf: chunk read (#4109)

* package

* perf: chunk read
This commit is contained in:
Archer
2025-03-11 21:58:24 +08:00
committed by archer
parent e061e80235
commit d4df77e637
29 changed files with 416 additions and 431 deletions

View File

@@ -9,7 +9,7 @@ interface Props extends BoxProps {
const SideBar = (e?: Props) => {
const {
w = ['100%', '0 0 250px', '0 0 270px', '0 0 290px', '0 0 310px'],
w = ['100%', '0 0 250px', '0 0 250px', '0 0 270px', '0 0 290px'],
children,
externalTrigger,
...props

View File

@@ -79,10 +79,10 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
zIndex={3}
position={['fixed', 'absolute']}
top={[0, '2%']}
right={quoteData ? 600 : 0}
right={0}
h={['100%', '96%']}
w={'100%'}
maxW={['100%', '600px']}
maxW={quoteData ? ['100%', '1080px'] : ['100%', '600px']}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
@@ -151,46 +151,49 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
)}
{/* Chat container */}
<Box pt={2} flex={'1 0 0'} h={0}>
{isPlugin ? (
<Box h={'100%'} overflow={'auto'}>
<Flex pt={2} flex={'1 0 0'} h={0}>
<Box flex={'1 0 0'} h={'100%'} overflow={'auto'}>
{isPlugin ? (
<Box px={5} py={2}>
<PluginRunBox appId={appId} chatId={chatId} />
</Box>
) : (
<ChatBox
isReady
appId={appId}
chatId={chatId}
feedbackType={'admin'}
showMarkIcon
showVoiceIcon={false}
chatType="log"
/>
)}
</Box>
{quoteData && (
<Box
flex={'1 0 0'}
w={0}
mr={4}
maxW={'460px'}
h={'98%'}
bg={'white'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10)'
}
borderRadius={'md'}
>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</Box>
) : (
<ChatBox
isReady
appId={appId}
chatId={chatId}
feedbackType={'admin'}
showMarkIcon
showVoiceIcon={false}
chatType="log"
/>
)}
</Box>
</Flex>
</MyBox>
{quoteData && (
<Box
w={['full', '588px']}
zIndex={300}
position={'absolute'}
top={5}
right={0}
h={'95%'}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</Box>
)}
<Box zIndex={2} position={'fixed'} top={0} left={0} bottom={0} right={0} onClick={onClose} />
</>
);

View File

@@ -51,12 +51,13 @@ const ChatTest = ({ appForm, setRenderEdit }: Props) => {
return (
<Flex h={'full'} gap={2}>
<MyBox
flex={'1 0 0'}
w={0}
isLoading={loading}
display={'flex'}
position={'relative'}
flexDirection={'column'}
h={'full'}
w={quoteData ? '' : 'full'}
py={4}
{...cardStyles}
boxShadow={'3'}
@@ -85,7 +86,7 @@ const ChatTest = ({ appForm, setRenderEdit }: Props) => {
</Box>
</MyBox>
{quoteData && (
<Box w={['full', '588px']} {...cardStyles} boxShadow={'3'}>
<Box flex={'1 0 0'} w={0} maxW={'560px'} {...cardStyles} boxShadow={'3'}>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}

View File

@@ -69,9 +69,9 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
flexDirection={'column'}
position={'absolute'}
top={5}
right={quoteData ? 600 : 0}
right={0}
h={isOpen ? '95%' : '0'}
w={isOpen ? ['100%', '460px'] : '0'}
w={isOpen ? (quoteData ? ['100%', '960px'] : ['100%', '460px']) : '0'}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
@@ -144,30 +144,34 @@ const ChatTest = ({ isOpen, nodes = [], edges = [], onClose }: Props) => {
</Flex>
)}
<Box flex={'1 0 0'} overflow={'auto'}>
<ChatContainer />
</Box>
<Flex flex={'1 0 0'} alignItems={'end'}>
<Box flex={'1 0 0'} h={'100%'} overflow={'auto'}>
<ChatContainer />
</Box>
{quoteData && (
<Box
flex={'1 0 0'}
w={0}
mr={4}
maxW={'440px'}
h={'98%'}
bg={'white'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10)'
}
borderRadius={'md'}
>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</Box>
)}
</Flex>
</MyBox>
{quoteData && (
<Box
w={['full', '588px']}
zIndex={300}
position={'absolute'}
top={5}
right={0}
h={'95%'}
bg={'white'}
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
borderRadius={'md'}
>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</Box>
)}
</Flex>
);
};

View File

@@ -1,4 +1,4 @@
import { Box, Button, Flex } from '@chakra-ui/react';
import { Box, Button, Flex, HStack } from '@chakra-ui/react';
import { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -21,6 +21,10 @@ import { DatasetDataListItemType } from '@/global/core/dataset/type';
import { metadataType } from '@/web/core/chat/context/chatItemContext';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getCollectionQuote } from '@/web/core/chat/api';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { getCollectionSourceAndOpen } from '@/web/core/dataset/hooks/readCollectionSource';
const CollectionReader = ({
rawSearch,
@@ -105,10 +109,10 @@ const CollectionReader = ({
setDatasetDataList([]);
}, [collectionId, setDatasetDataList]);
const { runAsync: handleDownload, loading: downloadLoading } = useRequest2(async () => {
const { runAsync: handleDownload } = useRequest2(async () => {
await downloadFetch({
url: '/api/core/dataset/collection/export',
filename: 'parsed_content.md',
filename: 'data.csv',
body: {
collectionId: collectionId,
chatTime: chatTime,
@@ -117,27 +121,11 @@ const CollectionReader = ({
});
});
const { runAsync: handleRead, loading: readLoading } = useRequest2(
async () => await getCollectionSource({ ...metadata, appId, chatId }),
{
onSuccess: (res) => {
if (!res.value) {
throw new Error('No file found');
}
if (res.value.startsWith('/')) {
window.open(`${location.origin}${res.value}`, '_blank');
} else {
window.open(res.value, '_blank');
}
},
onError: (err) => {
toast({
title: t(getErrText(err, t('common:error.fileNotFound'))),
status: 'error'
});
}
}
);
const handleRead = getCollectionSourceAndOpen({
appId,
chatId,
...metadata
});
const handleNavigate = useCallback(
async (targetIndex: number) => {
@@ -164,77 +152,61 @@ const CollectionReader = ({
);
return (
<Flex flexDirection={'column'} h={'full'}>
<MyBox display={'flex'} flexDirection={'column'} h={'full'}>
{/* title */}
<Flex
w={'full'}
alignItems={'center'}
px={5}
borderBottom={'1px solid'}
borderColor={'myGray.150'}
>
<Box flex={1} py={4}>
<Flex mb={1} alignItems={['flex-start', 'center']} flexDirection={['column', 'row']}>
<Flex gap={2} mr={2}>
<MyIcon
name={getSourceNameIcon({ sourceId, sourceName }) as any}
w={['1rem', '1.25rem']}
color={'primary.600'}
/>
<Box
maxW={['200px', '300px']}
className={'textEllipsis'}
wordBreak={'break-all'}
color={'myGray.900'}
fontWeight={'medium'}
>
{sourceName || t('common:common.UnKnow Source')}
</Box>
</Flex>
<Flex gap={3} mt={[2, 0]} alignItems={'center'}>
{!!userInfo && permissionData?.permission?.hasReadPer && (
<Button
variant={'primaryGhost'}
size={'xs'}
fontSize={'mini'}
border={'none'}
_hover={{
bg: 'primary.100'
}}
<Box borderBottom={'1px solid'} borderBottomColor={'myGray.150'} px={3} py={2}>
{/* name */}
<HStack>
<Flex alignItems={'center'} flex={'1 0 0'} w={0}>
<MyIcon
name={getSourceNameIcon({ sourceId, sourceName }) as any}
w={['1rem', '1.25rem']}
color={'primary.600'}
/>
<Box
ml={1}
maxW={['200px', '220px']}
className={'textEllipsis'}
wordBreak={'break-all'}
fontSize={'sm'}
color={'myGray.900'}
fontWeight={'medium'}
>
{sourceName || t('common:common.UnKnow Source')}
</Box>
{!!userInfo && permissionData?.permission?.hasReadPer && (
<MyTooltip label={t('chat:to_dataset')}>
<MyIconButton
ml={3}
icon="core/dataset/datasetLight"
size="1rem"
onClick={() => {
router.push(
`/dataset/detail?datasetId=${datasetId}&currentTab=dataCard&collectionId=${collectionId}`
);
}}
>
{t('common:core.dataset.Go Dataset')}
<MyIcon name="common/upperRight" w={4} ml={1} />
</Button>
)}
/>
</MyTooltip>
)}
<Box ml={1}>
<DownloadButton
canAccessRawData={true}
onDownload={handleDownload}
onRead={handleRead}
isLoading={downloadLoading || readLoading}
/>
</Flex>
</Box>
</Flex>
<Box fontSize={'mini'} color={'myGray.500'}>
{t('common:core.chat.quote.Quote Tip')}
</Box>
<MyIconButton
icon={'common/closeLight'}
size={'1.25rem'}
color={'myGray.900'}
onClick={onClose}
/>
</HStack>
<Box fontSize={'mini'} color={'myGray.500'}>
{t('common:core.chat.quote.Quote Tip')}
</Box>
<Box
cursor={'pointer'}
borderRadius={'sm'}
p={1}
_hover={{
bg: 'myGray.100'
}}
onClick={onClose}
>
<MyIcon name="common/closeLight" color={'myGray.900'} w={6} />
</Box>
</Flex>
</Box>
{/* header control */}
{datasetDataList.length > 0 && (
@@ -299,7 +271,7 @@ const CollectionReader = ({
{/* quote list */}
{loading || datasetDataList.length > 0 ? (
<ScrollData flex={'1 0 0'} mt={2} px={5} py={1} isLoading={loading}>
<Flex flexDir={'column'} gap={3}>
<Flex flexDir={'column'}>
{formatedDataList.map((item, index) => (
<CollectionQuoteItem
key={item._id}
@@ -338,7 +310,7 @@ const CollectionReader = ({
</Box>
</Flex>
)}
</Flex>
</MyBox>
);
};

View File

@@ -1,18 +1,15 @@
import { Button } from '@chakra-ui/react';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useTranslation } from 'react-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
const DownloadButton = ({
canAccessRawData,
onDownload,
onRead,
isLoading
onRead
}: {
canAccessRawData: boolean;
onDownload: () => void;
onRead: () => void;
isLoading: boolean;
}) => {
const { t } = useTranslation();
@@ -20,27 +17,17 @@ const DownloadButton = ({
return (
<MyMenu
size={'xs'}
Button={
<Button
variant={'whitePrimary'}
size={'xs'}
fontSize={'mini'}
leftIcon={<MyIcon name={'common/download'} w={'4'} />}
isLoading={isLoading}
>
{t('common:Download')}
</Button>
}
Button={<MyIconButton icon="common/download" size={'1rem'} />}
menuList={[
{
children: [
{
label: t('common:core.dataset.Download the parsed content'),
label: t('chat:download_chunks'),
type: 'grayBg',
onClick: onDownload
},
{
label: t('common:core.dataset.Get the raw data'),
label: t('chat:read_raw_source'),
type: 'grayBg',
onClick: onRead
}
@@ -51,18 +38,7 @@ const DownloadButton = ({
);
}
return (
<Button
variant={'whitePrimary'}
size={'xs'}
fontSize={'mini'}
leftIcon={<MyIcon name={'common/download'} w={'4'} />}
onClick={onDownload}
isLoading={isLoading}
>
{t('common:Download')}
</Button>
);
return <MyIconButton icon="common/download" size={'1rem'} onClick={onDownload} />;
};
export default DownloadButton;

View File

@@ -13,9 +13,9 @@ const ScoreTag = (score: { primaryScore?: ScoreItemType; secondaryScore: ScoreIt
<MyTooltip
label={
score.secondaryScore.length ? (
<Box>
<Flex flexDir={'column'} gap={4}>
{score.secondaryScore.map((item, i) => (
<Box fontSize={'xs'} key={i}>
<Box fontSize={'sm'} key={i}>
<Flex alignItems={'flex-start'} lineHeight={1.2} mb={1}>
<Box
px={'5px'}
@@ -47,7 +47,7 @@ const ScoreTag = (score: { primaryScore?: ScoreItemType; secondaryScore: ScoreIt
</Box>
</Box>
))}
</Box>
</Flex>
) : (
t(SearchScoreTypeMap[score.primaryScore.type]?.desc as any)
)

View File

@@ -6,6 +6,8 @@ import { ApiRequestProps } from '@fastgpt/service/type/next';
import { LinkedListResponse, LinkedPaginationProps } from '@fastgpt/web/common/fetch/type';
import { FilterQuery, Types } from 'mongoose';
import { dataFieldSelector, processChatTimeFilter } from './getQuote';
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
export type GetCollectionQuoteProps = LinkedPaginationProps & {
chatTime: Date;
@@ -36,8 +38,8 @@ async function handler(
nextId,
nextIndex,
chatTime,
isInitialLoad,
collectionId,
chatItemId,
appId,
@@ -48,21 +50,32 @@ async function handler(
teamToken,
pageSize = 15
} = req.body;
const limitedPageSize = Math.min(pageSize, 30);
await Promise.all([
authChatCrud({
try {
await authDatasetCollection({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken
}),
authCollectionInChat({ appId, chatId, chatItemId, collectionId })
]);
authApiKey: true,
collectionId: req.body.collectionId,
per: ReadPermissionVal
});
} catch (error) {
await Promise.all([
authChatCrud({
req,
authToken: true,
appId,
chatId,
shareId,
outLinkUid,
teamId,
teamToken
}),
authCollectionInChat({ appId, chatId, chatItemId, collectionId })
]);
}
const baseMatch: BaseMatchType = {
collectionId,

View File

@@ -71,9 +71,7 @@ async function handler(req: ApiRequestProps<GetQuoteDataProps>): Promise<GetQuot
export default NextAPI(handler);
export function processChatTimeFilter(list: DatasetDataSchemaType[], chatTime?: Date) {
if (!chatTime) return list;
export function processChatTimeFilter(list: DatasetDataSchemaType[], chatTime: Date) {
return list.map((item) => {
if (!item.history) return item;

View File

@@ -39,7 +39,7 @@ async function handler(req: ApiRequestProps<ExportCollectionBody, {}>, res: Next
};
res.setHeader('Content-Type', 'text/csv; charset=utf-8;');
res.setHeader('Content-Disposition', 'attachment; filename=usage.csv; ');
res.setHeader('Content-Disposition', 'attachment; filename=data.csv; ');
const cursor = MongoDatasetData.find(where, 'q a', {
...readFromSecondary,
@@ -54,10 +54,13 @@ async function handler(req: ApiRequestProps<ExportCollectionBody, {}>, res: Next
readStream: cursor
});
cursor.on('data', (doc) => {
const res = doc.a ? `\n${doc.q}\n${doc.a}` : `\n${doc.q}`;
write(`\uFEFFindex,content`);
write(res);
cursor.on('data', (doc) => {
const q = doc.q.replace(/"/g, '""') || '';
const a = doc.a.replace(/"/g, '""') || '';
write(`\n"${q}","${a}"`);
});
cursor.on('end', () => {

View File

@@ -168,66 +168,68 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
<NextHead title={chatBoxData.app.name} icon={chatBoxData.app.avatar}></NextHead>
{/* pc show myself apps */}
{isPc && (
<Box borderRight={theme.borders.base} w={'220px'} flexShrink={0}>
<Box borderRight={theme.borders.base} flex={'0 0 220px'}>
<SliderApps apps={myApps} activeAppId={appId} />
</Box>
)}
<PageContainer
isLoading={loading}
flex={'1 0 0'}
w={0}
p={[0, '16px']}
pr={quoteData ? '8px !important' : '16px'}
position={'relative'}
>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{/* pc always show history. */}
{RenderHistorySlider}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{(!quoteData || isPc) && (
<PageContainer
isLoading={loading}
flex={'1 0 0'}
w={0}
p={[0, '16px']}
position={'relative'}
>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{/* pc always show history. */}
{RenderHistorySlider}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={'1 0 0'} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={onStartChat}
/>
) : (
<ChatBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
showEmptyIntro
feedbackType={'user'}
onStartChat={onStartChat}
chatType={'chat'}
isReady={!loading}
/>
)}
</Box>
{/* chat box */}
<Box flex={'1 0 0'} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={onStartChat}
/>
) : (
<ChatBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
showEmptyIntro
feedbackType={'user'}
onStartChat={onStartChat}
chatType={'chat'}
isReady={!loading}
/>
)}
</Box>
</Flex>
</Flex>
</Flex>
</PageContainer>
</PageContainer>
)}
{quoteData && (
<PageContainer w={['full', '588px']} insertProps={{ bg: 'white' }}>
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'}>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}

View File

@@ -239,73 +239,80 @@ const OutLink = (props: Props) => {
}, [isOpenSlider, isPc, onCloseSlider, quoteData, showHistory, t]);
return (
<Box h={'full'} display={quoteData ? 'flex' : ''}>
<>
<NextHead
title={props.appName || data?.app?.name || 'AI'}
desc={props.appIntro || data?.app?.intro}
icon={props.appAvatar || data?.app?.avatar}
/>
<PageContainer
isLoading={loading}
{...(isEmbed
? { p: '0 !important', insertProps: { borderRadius: '0', boxShadow: 'none' } }
: { p: [0, 5] })}
>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
<Flex h={'full'}>
{(!quoteData || isPc) && (
<PageContainer
flex={'1 0 0'}
flexDirection={'column'}
w={0}
isLoading={loading}
{...(isEmbed
? { p: '0 !important', insertProps: { borderRadius: '0', boxShadow: 'none' } }
: { p: [0, 5] })}
>
{/* header */}
{showHead === '1' ? (
<ChatHeader
history={chatRecords}
totalRecordsCount={totalRecordsCount}
showHistory={showHistory === '1'}
/>
) : null}
{/* chat box */}
<Box flex={1} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="share"
/>
)}
</Box>
</Flex>
</Flex>
</PageContainer>
{quoteData && (
<PageContainer w={['full', '800px']} py={5}>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</PageContainer>
)}
</Box>
<Flex h={'100%'} flexDirection={['column', 'row']}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
{showHead === '1' ? (
<ChatHeader
history={chatRecords}
totalRecordsCount={totalRecordsCount}
showHistory={showHistory === '1'}
/>
) : null}
{/* chat box */}
<Box flex={1} bg={'white'}>
{isPlugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="share"
/>
)}
</Box>
</Flex>
</Flex>
</PageContainer>
)}
{quoteData && (
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'}>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}
metadata={quoteData.metadata}
onClose={() => setQuoteData(undefined)}
/>
</PageContainer>
)}
</Flex>
</>
);
};

View File

@@ -191,52 +191,59 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
</Box>
)}
<PageContainer isLoading={loading} flex={'1 0 0'} w={0} p={[0, '16px']} position={'relative'}>
<Flex h={'100%'} flexDirection={['column', 'row']} bg={'white'}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={1}>
{chatBoxData.app.type === AppTypeEnum.plugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="team"
/>
)}
</Box>
{(!quoteData || isPc) && (
<PageContainer
isLoading={loading}
flex={'1 0 0'}
w={0}
p={[0, '16px']}
position={'relative'}
>
<Flex h={'100%'} flexDirection={['column', 'row']} bg={'white'}>
{RenderHistoryList}
{/* chat container */}
<Flex
position={'relative'}
h={[0, '100%']}
w={['100%', 0]}
flex={'1 0 0'}
flexDirection={'column'}
>
{/* header */}
<ChatHeader
totalRecordsCount={totalRecordsCount}
apps={myApps}
history={chatRecords}
showHistory
/>
{/* chat box */}
<Box flex={1}>
{chatBoxData.app.type === AppTypeEnum.plugin ? (
<CustomPluginRunBox
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
onNewChat={() => onChangeChatId(getNanoid())}
onStartChat={startChat}
/>
) : (
<ChatBox
isReady={!loading}
appId={appId}
chatId={chatId}
outLinkAuthData={outLinkAuthData}
feedbackType={'user'}
onStartChat={startChat}
chatType="team"
/>
)}
</Box>
</Flex>
</Flex>
</Flex>
</PageContainer>
</PageContainer>
)}
{quoteData && (
<PageContainer w={['full', '800px']} py={5}>
<PageContainer flex={'1 0 0'} w={0} maxW={'560px'}>
<ChatQuoteList
chatTime={quoteData.chatTime}
rawSearch={quoteData.rawSearch}

View File

@@ -220,7 +220,11 @@ export async function updateData2Dataset({
}
}
// insert vector
// 4. Update mongo updateTime(便于脏数据检查器识别)
mongoData.updateTime = new Date();
await mongoData.save();
// 5. insert vector
const insertResult = await Promise.all(
patchResult
.filter((item) => item.type === 'create' || item.type === 'update')
@@ -245,15 +249,16 @@ export async function updateData2Dataset({
.filter((item) => item.type !== 'delete')
.map((item) => item.index) as DatasetDataIndexItemType[];
// 6. update mongo data
await mongoSessionRun(async (session) => {
// update mongo data
// Update history
mongoData.history =
q !== mongoData.q || a !== mongoData.a
? [
{
q: mongoData.q,
a: mongoData.a,
updateTime: mongoData.updateTime
updateTime: new Date()
},
...(mongoData.history?.slice(0, 9) || [])
]
@@ -283,10 +288,6 @@ export async function updateData2Dataset({
}
});
// Update mongo updateTime(便于脏数据检查器识别)
mongoData.updateTime = new Date();
await mongoData.save();
return {
tokens
};