227 lines
6.6 KiB
TypeScript
227 lines
6.6 KiB
TypeScript
import React, { useCallback, useEffect, useRef } from 'react';
|
|
import { useRouter } from 'next/router';
|
|
import { initShareChatInfo } from '@/api/chat';
|
|
import { Box, Flex, useDisclosure, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
|
|
import { useToast } from '@/hooks/useToast';
|
|
import { useGlobalStore } from '@/store/global';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { streamFetch } from '@/api/fetch';
|
|
import { useShareChatStore, defaultHistory } from '@/store/shareChat';
|
|
import SideBar from '@/components/SideBar';
|
|
import { gptMessage2ChatType } from '@/utils/adapt';
|
|
import { getErrText } from '@/utils/tools';
|
|
|
|
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
|
import PageContainer from '@/components/PageContainer';
|
|
import ChatHistorySlider from './components/ChatHistorySlider';
|
|
import ChatHeader from './components/ChatHeader';
|
|
|
|
const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string }) => {
|
|
const router = useRouter();
|
|
const { toast } = useToast();
|
|
const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure();
|
|
const { isPc } = useGlobalStore();
|
|
|
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
|
|
|
const {
|
|
shareChatData,
|
|
setShareChatData,
|
|
shareChatHistory,
|
|
saveChatResponse,
|
|
delShareChatHistoryItemById,
|
|
delOneShareHistoryByHistoryId,
|
|
delManyShareChatHistoryByShareId
|
|
} = useShareChatStore();
|
|
|
|
const startChat = useCallback(
|
|
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
|
|
const prompts = messages.slice(-shareChatData.maxContext - 2);
|
|
const { responseText } = await streamFetch({
|
|
data: {
|
|
history,
|
|
messages: prompts,
|
|
variables,
|
|
shareId
|
|
},
|
|
onMessage: generatingMessage,
|
|
abortSignal: controller
|
|
});
|
|
|
|
const result = {
|
|
question: messages[messages.length - 2].content || '',
|
|
answer: responseText
|
|
};
|
|
|
|
prompts[prompts.length - 1].content = responseText;
|
|
|
|
/* save chat */
|
|
const { newChatId } = saveChatResponse({
|
|
historyId,
|
|
prompts: gptMessage2ChatType(prompts).map((item) => ({
|
|
...item,
|
|
status: 'finish'
|
|
})),
|
|
variables,
|
|
shareId
|
|
});
|
|
|
|
if (newChatId) {
|
|
router.replace({
|
|
query: {
|
|
shareId,
|
|
historyId: newChatId
|
|
}
|
|
});
|
|
}
|
|
|
|
window.top?.postMessage(
|
|
{
|
|
type: 'shareChatFinish',
|
|
data: result
|
|
},
|
|
'*'
|
|
);
|
|
|
|
return { responseText };
|
|
},
|
|
[historyId, router, saveChatResponse, shareChatData.maxContext, shareId]
|
|
);
|
|
|
|
const loadAppInfo = useCallback(
|
|
async (shareId: string, historyId: string) => {
|
|
console.log(shareId, historyId);
|
|
|
|
if (!shareId) return null;
|
|
const history = shareChatHistory.find((item) => item._id === historyId) || defaultHistory;
|
|
|
|
ChatBoxRef.current?.resetHistory(history.chats);
|
|
ChatBoxRef.current?.resetVariables(history.variables);
|
|
|
|
try {
|
|
const chatData = await (async () => {
|
|
if (shareChatData.app.name === '') {
|
|
return initShareChatInfo({
|
|
shareId
|
|
});
|
|
}
|
|
return shareChatData;
|
|
})();
|
|
|
|
setShareChatData({
|
|
...chatData,
|
|
history
|
|
});
|
|
} catch (e: any) {
|
|
toast({
|
|
status: 'error',
|
|
title: getErrText(e, '获取应用失败')
|
|
});
|
|
if (e?.code === 501) {
|
|
delManyShareChatHistoryByShareId(shareId);
|
|
}
|
|
}
|
|
|
|
if (history.chats.length > 0) {
|
|
ChatBoxRef.current?.scrollToBottom('auto');
|
|
}
|
|
|
|
return history;
|
|
},
|
|
[delManyShareChatHistoryByShareId, setShareChatData, shareChatData, shareChatHistory, toast]
|
|
);
|
|
|
|
useQuery(['init', shareId, historyId], () => {
|
|
return loadAppInfo(shareId, historyId);
|
|
});
|
|
|
|
return (
|
|
<PageContainer>
|
|
<Flex h={'100%'} flexDirection={['column', 'row']}>
|
|
{((children: React.ReactNode) => {
|
|
return isPc ? (
|
|
<SideBar>{children}</SideBar>
|
|
) : (
|
|
<Drawer isOpen={isOpenSlider} placement="left" size={'xs'} onClose={onCloseSlider}>
|
|
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
|
|
<DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}>
|
|
{children}
|
|
</DrawerContent>
|
|
</Drawer>
|
|
);
|
|
})(
|
|
<ChatHistorySlider
|
|
appName={shareChatData.app.name}
|
|
appAvatar={shareChatData.app.avatar}
|
|
activeHistoryId={historyId}
|
|
history={shareChatHistory.map((item) => ({
|
|
id: item._id,
|
|
title: item.title
|
|
}))}
|
|
onChangeChat={(historyId) => {
|
|
router.push({
|
|
query: {
|
|
historyId: historyId || '',
|
|
shareId
|
|
}
|
|
});
|
|
if (!isPc) {
|
|
onCloseSlider();
|
|
}
|
|
}}
|
|
onDelHistory={delOneShareHistoryByHistoryId}
|
|
/>
|
|
)}
|
|
|
|
{/* chat container */}
|
|
<Flex
|
|
position={'relative'}
|
|
h={[0, '100%']}
|
|
w={['100%', 0]}
|
|
flex={'1 0 0'}
|
|
flexDirection={'column'}
|
|
>
|
|
{/* header */}
|
|
<ChatHeader
|
|
appAvatar={shareChatData.app.avatar}
|
|
title={shareChatData.history.title}
|
|
history={shareChatData.history.chats}
|
|
onOpenSlider={onOpenSlider}
|
|
/>
|
|
{/* chat box */}
|
|
<Box flex={1}>
|
|
<ChatBox
|
|
ref={ChatBoxRef}
|
|
appAvatar={shareChatData.app.avatar}
|
|
variableModules={shareChatData.app.variableModules}
|
|
welcomeText={shareChatData.app.welcomeText}
|
|
onUpdateVariable={(e) => {
|
|
setShareChatData((state) => ({
|
|
...state,
|
|
history: {
|
|
...state.history,
|
|
variables: e
|
|
}
|
|
}));
|
|
}}
|
|
onStartChat={startChat}
|
|
onDelMessage={({ index }) => delShareChatHistoryItemById({ historyId, index })}
|
|
/>
|
|
</Box>
|
|
</Flex>
|
|
</Flex>
|
|
</PageContainer>
|
|
);
|
|
};
|
|
|
|
export async function getServerSideProps(context: any) {
|
|
const shareId = context?.query?.shareId || '';
|
|
const historyId = context?.query?.historyId || '';
|
|
|
|
return {
|
|
props: { shareId, historyId }
|
|
};
|
|
}
|
|
|
|
export default ShareChat;
|