feat: quote change

This commit is contained in:
archer
2023-05-23 18:35:45 +08:00
parent 944e876aaa
commit b8f08eb33e
21 changed files with 439 additions and 215 deletions

View File

@@ -0,0 +1,175 @@
import React, { useCallback, useState } from 'react';
import {
Modal,
ModalOverlay,
ModalContent,
ModalBody,
ModalCloseButton,
ModalHeader,
Box,
useTheme
} from '@chakra-ui/react';
import { QuoteItemType } from '@/pages/api/openapi/kb/appKbSearch';
import MyIcon from '@/components/Icon';
import InputDataModal from '@/pages/kb/components/InputDataModal';
import { getKbDataItemById } from '@/api/plugins/kb';
import { useLoading } from '@/hooks/useLoading';
import { useQuery } from '@tanstack/react-query';
import { getHistoryQuote, updateHistoryQuote } from '@/api/chat';
import { useToast } from '@/hooks/useToast';
import { getErrText } from '@/utils/tools';
const QuoteModal = ({
historyId,
chatId,
onClose
}: {
historyId: string;
chatId: string;
onClose: () => void;
}) => {
const theme = useTheme();
const { toast } = useToast();
const { setIsLoading, Loading } = useLoading();
const [editDataItem, setEditDataItem] = useState<{
dataId: string;
a: string;
q: string;
}>();
const {
data: quote = [],
refetch,
isLoading
} = useQuery(['getHistoryQuote'], () => getHistoryQuote({ historyId, chatId }));
/**
* click edit, get new kbDataItem
*/
const onclickEdit = useCallback(
async (item: QuoteItemType) => {
try {
setIsLoading(true);
const data = (await getKbDataItemById(item.id)) as QuoteItemType;
if (!data) {
throw new Error('该数据已被删除');
}
setEditDataItem({
dataId: data.id,
q: data.q,
a: data.a
});
} catch (err) {
toast({
status: 'warning',
title: getErrText(err)
});
}
setIsLoading(false);
},
[setIsLoading, toast]
);
/**
* update kbData, update mongo status and reload quotes
*/
const updateQuoteStatus = useCallback(
async (quoteId: string) => {
setIsLoading(true);
try {
await updateHistoryQuote({
chatId,
historyId,
quoteId
});
// reload quote
refetch();
} catch (err) {
toast({
status: 'warning',
title: getErrText(err)
});
}
setIsLoading(false);
},
[chatId, historyId, refetch, setIsLoading, toast]
);
return (
<>
<Modal isOpen={true} onClose={onClose}>
<ModalOverlay />
<ModalContent
position={'relative'}
maxW={'min(90vw, 700px)'}
h={'80vh'}
overflow={'overlay'}
>
<ModalHeader>
({quote.length})
<Box fontSize={'sm'} fontWeight={'normal'}>
注意: 修改知识库内容成功后
</Box>
</ModalHeader>
<ModalCloseButton />
<ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}>
{quote.map((item) => (
<Box
key={item.id}
flex={'1 0 0'}
p={2}
borderRadius={'sm'}
border={theme.borders.base}
_notLast={{ mb: 2 }}
position={'relative'}
_hover={{ '& .edit': { display: 'flex' } }}
>
{item.isEdit && <Box color={'myGray.600'}>()</Box>}
<Box>{item.q}</Box>
<Box>{item.a}</Box>
<Box
className="edit"
display={'none'}
position={'absolute'}
right={0}
top={0}
bottom={0}
w={'40px'}
bg={'rgba(255,255,255,0.9)'}
alignItems={'center'}
justifyContent={'center'}
boxShadow={'-10px 0 10px rgba(255,255,255,1)'}
>
<MyIcon
name={'edit'}
w={'18px'}
h={'18px'}
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'myBlue.700'
}}
onClick={() => onclickEdit(item)}
/>
</Box>
</Box>
))}
</ModalBody>
<Loading loading={isLoading} fixed={false} />
</ModalContent>
</Modal>
{editDataItem && (
<InputDataModal
onClose={() => setEditDataItem(undefined)}
onSuccess={() => updateQuoteStatus(editDataItem.dataId)}
kbId=""
defaultValues={editDataItem}
/>
)}
</>
);
};
export default QuoteModal;

View File

@@ -1,11 +1,6 @@
import React, { useCallback, useState, useRef, useMemo, useEffect, MouseEvent } from 'react';
import { useRouter } from 'next/router';
import {
getInitChatSiteInfo,
delChatRecordByIndex,
getChatResult,
delChatHistoryById
} from '@/api/chat';
import { getInitChatSiteInfo, delChatRecordByIndex, delChatHistoryById } from '@/api/chat';
import type { ChatItemType, ChatSiteItemType, ExportChatType } from '@/types/chat';
import {
Textarea,
@@ -22,6 +17,7 @@ import {
ModalContent,
ModalBody,
ModalCloseButton,
ModalHeader,
useDisclosure,
Drawer,
DrawerOverlay,
@@ -29,8 +25,7 @@ import {
Card,
Tooltip,
useOutsideClick,
useTheme,
ModalHeader
useTheme
} from '@chakra-ui/react';
import { useToast } from '@/hooks/useToast';
import { useGlobalStore } from '@/store/global';
@@ -48,12 +43,12 @@ import { useLoading } from '@/hooks/useLoading';
import { fileDownload } from '@/utils/file';
import { htmlTemplate } from '@/constants/common';
import { useUserStore } from '@/store/user';
import type { QuoteItemType } from '@/pages/api/openapi/kb/appKbSearch';
import Loading from '@/components/Loading';
import Markdown from '@/components/Markdown';
import SideBar from '@/components/SideBar';
import Avatar from '@/components/Avatar';
import Empty from './components/Empty';
import QuoteModal from './components/QuoteModal';
const PhoneSliderBar = dynamic(() => import('./components/PhoneSliderBar'), {
ssr: false
@@ -80,7 +75,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
const controller = useRef(new AbortController());
const isLeavePage = useRef(false);
const [showQuote, setShowQuote] = useState<QuoteItemType[]>([]);
const [showHistoryQuote, setShowHistoryQuote] = useState<string>();
const [messageContextMenuData, setMessageContextMenuData] = useState<{
// message messageContextMenuData
left: number;
@@ -182,7 +177,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
}));
// 流请求,获取数据
const { newChatId } = await streamFetch({
const { newChatId, quoteLen } = await streamFetch({
url: '/api/chat/chat',
data: {
prompt,
@@ -217,9 +212,6 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
abortSignal.signal.aborted && (await delay(600));
// get chat result
const { quote } = await getChatResult(chatId || newChatId);
// 设置聊天内容为完成状态
setChatData((state) => ({
...state,
@@ -229,7 +221,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
return {
...item,
status: 'finish',
quote
quoteLen
};
})
}));
@@ -735,7 +727,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
isChatting={isChatting && index === chatData.history.length - 1}
formatLink
/>
{item.quote && item.quote.length > 0 && (
{!!item.quoteLen && (
<Button
size={'xs'}
mt={2}
@@ -743,9 +735,9 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
colorScheme={'gray'}
variant={'outline'}
w={'90px'}
onClick={() => setShowQuote(item.quote || [])}
onClick={() => setShowHistoryQuote(item._id)}
>
{item.quoteLen}
</Button>
)}
</Card>
@@ -876,30 +868,14 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
</DrawerContent>
</Drawer>
)}
{/* system prompt show modal */}
{
<Modal isOpen={showQuote.length > 0} onClose={() => setShowQuote([])}>
<ModalOverlay />
<ModalContent maxW={'min(90vw, 700px)'} h={'80vh'} overflow={'overlay'}>
<ModalHeader>({showQuote.length})</ModalHeader>
<ModalCloseButton />
<ModalBody whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'sm'}>
{showQuote.map((item) => (
<Box
key={item.id}
p={2}
borderRadius={'sm'}
border={theme.borders.base}
_notLast={{ mb: 2 }}
>
<Box>{item.q}</Box>
<Box>{item.a}</Box>
</Box>
))}
</ModalBody>
</ModalContent>
</Modal>
}
{/* quote modal*/}
{showHistoryQuote && chatId && (
<QuoteModal
historyId={showHistoryQuote}
chatId={chatId}
onClose={() => setShowHistoryQuote(undefined)}
/>
)}
{/* context menu */}
{messageContextMenuData && (
<Box