fix: save chat

This commit is contained in:
archer
2023-07-11 23:39:58 +08:00
parent b2e2f60e0d
commit eb68b35ddf
5 changed files with 112 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ const Avatar = ({ w = '30px', ...props }: ImageProps) => {
return (
<Image
fallbackSrc={LOGO_ICON}
fallbackStrategy={'onError'}
borderRadius={'50%'}
objectFit={'cover'}
alt=""

View File

@@ -8,7 +8,7 @@ import React, {
ForwardedRef
} from 'react';
import { throttle } from 'lodash';
import { ChatSiteItemType } from '@/types/chat';
import { ChatItemType, ChatSiteItemType, ExportChatType } from '@/types/chat';
import { useToast } from '@/hooks/useToast';
import { useCopyData, voiceBroadcast, hasVoiceApi } from '@/utils/tools';
import { Box, Card, Flex, Input, Textarea, Button, useTheme } from '@chakra-ui/react';
@@ -28,6 +28,8 @@ import MySelect from '@/components/Select';
import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions';
import styles from './index.module.scss';
import MyTooltip from '../MyTooltip';
import { fileDownload } from '@/utils/file';
import { htmlTemplate } from '@/constants/common';
const textareaMinH = '22px';
export type StartChatFnProps = {
@@ -607,3 +609,76 @@ const ChatBox = (
};
export default React.memo(forwardRef(ChatBox));
export const useChatBox = () => {
const onExportChat = useCallback(
({ type, history }: { type: ExportChatType; history: ChatItemType[] }) => {
const getHistoryHtml = () => {
const historyDom = document.getElementById('history');
if (!historyDom) return;
const dom = Array.from(historyDom.children).map((child, i) => {
const avatar = `<img src="${
child.querySelector<HTMLImageElement>('.avatar')?.src
}" alt="" />`;
const chatContent = child.querySelector<HTMLDivElement>('.markdown');
if (!chatContent) {
return '';
}
const chatContentClone = chatContent.cloneNode(true) as HTMLDivElement;
const codeHeader = chatContentClone.querySelectorAll('.code-header');
codeHeader.forEach((childElement: any) => {
childElement.remove();
});
return `<div class="chat-item">
${avatar}
${chatContentClone.outerHTML}
</div>`;
});
const html = htmlTemplate.replace('{{CHAT_CONTENT}}', dom.join('\n'));
return html;
};
const map: Record<ExportChatType, () => void> = {
md: () => {
fileDownload({
text: history.map((item) => item.value).join('\n\n'),
type: 'text/markdown',
filename: 'chat.md'
});
},
html: () => {
const html = getHistoryHtml();
html &&
fileDownload({
text: html,
type: 'text/html',
filename: '聊天记录.html'
});
},
pdf: () => {
const html = getHistoryHtml();
html &&
// @ts-ignore
html2pdf(html, {
margin: 0,
filename: `聊天记录.pdf`
});
}
};
map[type]();
},
[]
);
return {
onExportChat
};
};

View File

@@ -124,6 +124,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
historyId,
newHistoryId,
appId,
variables,
prompts: [
prompt,
{

View File

@@ -0,0 +1,30 @@
import React from 'react';
import { useChatBox } from '@/components/ChatBox';
import { ChatItemType } from '@/types/chat';
import { Menu, MenuButton, MenuList, MenuItem } from '@chakra-ui/react';
import MyIcon from '@/components/Icon';
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
const { onExportChat } = useChatBox();
return (
<Menu autoSelect={false} isLazy>
<MenuButton
_hover={{ bg: 'myWhite.600 ' }}
cursor={'pointer'}
borderRadius={'md'}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
<MenuList color={'myGray.700'} minW={`90px !important`}>
<MenuItem onClick={() => onExportChat({ type: 'html', history })}>HTML格式</MenuItem>
<MenuItem onClick={() => onExportChat({ type: 'pdf', history })}>PDF格式</MenuItem>
<MenuItem onClick={() => onExportChat({ type: 'md', history })}>Markdown格式</MenuItem>
</MenuList>
</Menu>
);
};
export default ToolMenu;

View File

@@ -32,12 +32,13 @@ import { useChatStore } from '@/store/chat';
import { useLoading } from '@/hooks/useLoading';
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
import { ChatHistoryItemType } from '@/types/chat';
import PageContainer from '@/components/PageContainer';
import SideBar from '@/components/SideBar';
import ChatHistorySlider from './components/ChatHistorySlider';
import SliderApps from './components/SliderApps';
import Tag from '@/components/Tag';
import { ChatHistoryItemType } from '@/types/chat';
import ToolMenu from './components/ToolMenu';
const Chat = () => {
const router = useRouter();
@@ -316,6 +317,8 @@ const Chat = () => {
/>
</>
)}
<Box flex={1} />
<ToolMenu history={chatData.history} />
</Flex>
{/* chat box */}
<Box flex={1}>