v4.6.6-search test adapt diff search mode (#685)

This commit is contained in:
Archer
2024-01-03 15:40:03 +08:00
committed by GitHub
parent c766a0ed8a
commit 13b10720ac
57 changed files with 1101 additions and 612 deletions

View File

@@ -32,7 +32,7 @@ const ContextModal = ({
<Box
key={i}
p={2}
borderRadius={'lg'}
borderRadius={'md'}
border={theme.borders.base}
_notLast={{ mb: 2 }}
position={'relative'}

View File

@@ -9,12 +9,16 @@ const FeedbackModal = ({
appId,
chatId,
chatItemId,
shareId,
outLinkUid,
onSuccess,
onClose
}: {
appId: string;
chatId: string;
chatItemId: string;
shareId?: string;
outLinkUid?: string;
onSuccess: (e: string) => void;
onClose: () => void;
}) => {
@@ -28,6 +32,8 @@ const FeedbackModal = ({
appId,
chatId,
chatItemId,
shareId,
outLinkUid,
userBadFeedback: val
});
},

View File

@@ -1,31 +1,38 @@
import React, { useCallback, useState } from 'react';
import { ModalBody, Box, useTheme, Flex, Progress, Link } from '@chakra-ui/react';
import { getDatasetDataItemById } from '@/web/core/dataset/api';
import { useLoading } from '@/web/common/hooks/useLoading';
import { useToast } from '@/web/common/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyIcon from '@/components/Icon';
import InputDataModal, {
RawSourceText,
type InputDataType
} from '@/pages/dataset/detail/components/InputDataModal';
import React, { useMemo, useState } from 'react';
import { ModalBody, Box, useTheme } from '@chakra-ui/react';
import MyModal from '../MyModal';
import { useTranslation } from 'next-i18next';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import MyTooltip from '../MyTooltip';
import NextLink from 'next/link';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import QuoteItem from '../core/dataset/QuoteItem';
import { RawSourceText } from '@/pages/dataset/detail/components/InputDataModal';
const QuoteModal = ({
rawSearch = [],
onClose,
isShare
isShare,
metadata
}: {
rawSearch: SearchDataResponseItemType[];
onClose: () => void;
isShare: boolean;
metadata?: {
collectionId: string;
sourceId?: string;
sourceName: string;
};
}) => {
const { t } = useTranslation();
const filterResults = useMemo(
() =>
metadata
? rawSearch.filter(
(item) =>
item.collectionId === metadata.collectionId && item.sourceId === metadata.sourceId
)
: rawSearch,
[metadata, rawSearch]
);
return (
<>
@@ -35,18 +42,22 @@ const QuoteModal = ({
h={['90vh', '80vh']}
isCentered
minW={['90vw', '600px']}
iconSrc="/imgs/modal/quote.svg"
iconSrc={!!metadata ? undefined : '/imgs/modal/quote.svg'}
title={
<Box>
{t('core.chat.Quote Amount', { amount: rawSearch.length })}
<Box fontSize={'sm'} color={'myGray.500'} fontWeight={'normal'}>
{metadata ? (
<RawSourceText {...metadata} canView={false} />
) : (
<>{t('core.chat.Quote Amount', { amount: rawSearch.length })}</>
)}
<Box fontSize={'xs'} color={'myGray.500'} fontWeight={'normal'}>
{t('core.chat.quote.Quote Tip')}
</Box>
</Box>
}
>
<ModalBody whiteSpace={'pre-wrap'} textAlign={'justify'} wordBreak={'break-all'}>
<QuoteList rawSearch={rawSearch} isShare={isShare} />
<ModalBody>
<QuoteList rawSearch={filterResults} isShare={isShare} />
</ModalBody>
</MyModal>
</>
@@ -62,38 +73,7 @@ export const QuoteList = React.memo(function QuoteList({
rawSearch: SearchDataResponseItemType[];
isShare: boolean;
}) {
const { t } = useTranslation();
const { isPc } = useSystemStore();
const theme = useTheme();
const { toast } = useToast();
const { setIsLoading, Loading } = useLoading();
const [editInputData, setEditInputData] = useState<InputDataType & { collectionId: string }>();
/**
* click edit, get new DataItem
*/
const onclickEdit = useCallback(
async (item: InputDataType) => {
if (!item.id) return;
try {
setIsLoading(true);
const data = await getDatasetDataItemById(item.id);
if (!data) {
throw new Error('该数据已被删除');
}
setEditInputData(data);
} catch (err) {
toast({
status: 'warning',
title: getErrText(err)
});
}
setIsLoading(false);
},
[setIsLoading, toast]
);
return (
<>
@@ -102,113 +82,15 @@ export const QuoteList = React.memo(function QuoteList({
key={i}
flex={'1 0 0'}
p={2}
borderRadius={'lg'}
borderRadius={'sm'}
border={theme.borders.base}
_notLast={{ mb: 2 }}
position={'relative'}
overflow={'hidden'}
_hover={{ '& .hover-data': { display: 'flex' } }}
bg={i % 2 === 0 ? 'white' : 'myWhite.500'}
>
<Flex alignItems={'flex-end'} mb={3} fontSize={'sm'}>
<RawSourceText
fontWeight={'bold'}
color={'black'}
sourceName={item.sourceName}
sourceId={item.sourceId}
canView={!isShare}
/>
<Box flex={1} />
{!isShare && (
<Link
as={NextLink}
className="hover-data"
display={'none'}
alignItems={'center'}
color={'primary.500'}
href={`/dataset/detail?datasetId=${item.datasetId}&currentTab=dataCard&collectionId=${item.collectionId}`}
>
{t('core.dataset.Go Dataset')}
<MyIcon name={'common/rightArrowLight'} w={'10px'} />
</Link>
)}
</Flex>
<Box color={'black'}>{item.q}</Box>
<Box color={'myGray.600'}>{item.a}</Box>
{!isShare && (
<Flex alignItems={'center'} fontSize={'sm'} mt={3} gap={4} color={'myGray.500'}>
{isPc && (
<MyTooltip label={t('core.dataset.data.id')}>
<Flex border={theme.borders.base} py={'1px'} px={3} borderRadius={'3px'}>
# {item.id}
</Flex>
</MyTooltip>
)}
<MyTooltip label={t('core.dataset.Quote Length')}>
<Flex alignItems={'center'}>
<MyIcon name="common/text/t" w={'14px'} mr={1} color={'myGray.500'} />
{item.q.length + (item.a?.length || 0)}
</Flex>
</MyTooltip>
{/* {!isShare && item.score && (
<MyTooltip label={t('core.dataset.Similarity')}>
<Flex alignItems={'center'}>
<MyIcon name={'kbTest'} w={'12px'} />
<Progress
mx={2}
w={['60px', '90px']}
value={item.score * 100}
size="sm"
borderRadius={'20px'}
colorScheme="myGray"
border={theme.borders.base}
/>
<Box>{item.score.toFixed(4)}</Box>
</Flex>
</MyTooltip>
)} */}
<Box flex={1} />
{item.id && (
<MyTooltip label={t('core.dataset.data.Edit')}>
<Box
bg={'rgba(255,255,255,0.9)'}
alignItems={'center'}
justifyContent={'center'}
boxShadow={'-10px 0 10px rgba(255,255,255,1)'}
>
<MyIcon
name={'edit'}
w={['16px', '18px']}
h={['16px', '18px']}
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'primary.600'
}}
onClick={() => onclickEdit(item)}
/>
</Box>
</MyTooltip>
)}
</Flex>
)}
<QuoteItem quoteItem={item} canViewSource={!isShare} linkToDataset={!isShare} />
</Box>
))}
{editInputData && editInputData.id && (
<InputDataModal
onClose={() => setEditInputData(undefined)}
onSuccess={() => {
console.log('更新引用成功');
}}
onDelete={() => {
console.log('删除引用成功');
}}
defaultValue={editInputData}
collectionId={editInputData.collectionId}
/>
)}
<Loading fixed={false} />
</>
);
});

View File

@@ -11,8 +11,6 @@ import MyTooltip from '../MyTooltip';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
import ChatBoxDivider from '@/components/core/chat/Divider';
import MyIcon from '../Icon';
import { getFileAndOpen } from '@/web/core/dataset/utils';
import { strIsLink } from '@fastgpt/global/common/string/tools';
const QuoteModal = dynamic(() => import('./QuoteModal'), { ssr: false });
@@ -29,7 +27,14 @@ const ResponseTags = ({
const theme = useTheme();
const { isPc } = useSystemStore();
const { t } = useTranslation();
const [quoteModalData, setQuoteModalData] = useState<SearchDataResponseItemType[]>();
const [quoteModalData, setQuoteModalData] = useState<{
rawSearch: SearchDataResponseItemType[];
metadata?: {
collectionId: string;
sourceId?: string;
sourceName: string;
};
}>();
const [contextModalData, setContextModalData] = useState<ChatItemType[]>();
const {
isOpen: isOpenWholeModal,
@@ -52,8 +57,8 @@ const ResponseTags = ({
.filter(Boolean) as SearchDataResponseItemType[];
const sourceList = quoteList.reduce(
(acc: Record<string, SearchDataResponseItemType[]>, cur) => {
if (!acc[cur.sourceName]) {
acc[cur.sourceName] = [cur];
if (!acc[cur.collectionId]) {
acc[cur.collectionId] = [cur];
}
return acc;
},
@@ -70,7 +75,8 @@ const ResponseTags = ({
sourceName: item.sourceName,
sourceId: item.sourceId,
icon: getSourceNameIcon({ sourceId: item.sourceId, sourceName: item.sourceName }),
canReadQuote: !isShare || strIsLink(item.sourceId)
canReadQuote: !isShare || strIsLink(item.sourceId),
collectionId: item.collectionId
})),
historyPreview: chatData?.historyPreview,
runningTime: +responseData.reduce((sum, item) => sum + (item.runningTime || 0), 0).toFixed(2)
@@ -89,88 +95,52 @@ const ResponseTags = ({
<ChatBoxDivider icon="core/chat/quoteFill" text={t('chat.Quote')} />
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
{sourceList.map((item) => (
<Flex
key={item.sourceName}
alignItems={'center'}
flexWrap={'wrap'}
fontSize={'sm'}
border={theme.borders.sm}
py={1}
px={2}
borderRadius={'md'}
_hover={{
'.controller': {
display: 'flex'
}
}}
overflow={'hidden'}
position={'relative'}
>
<Image src={item.icon} alt={''} mr={1} w={'12px'} />
<Box className="textEllipsis" flex={'1 0 0'}>
{item.sourceName}
</Box>
<Box
className="controller"
display={'none'}
pr={2}
position={'absolute'}
right={0}
left={0}
justifyContent={'flex-end'}
<MyTooltip key={item.sourceName} label={t('core.chat.quote.Read Quote')}>
<Flex
alignItems={'center'}
h={'100%'}
lineHeight={0}
bg={`linear-gradient(to left, white,white ${
item.sourceId ? '60px' : '30px'
}, rgba(255,255,255,0) 80%)`}
fontSize={'sm'}
border={theme.borders.sm}
py={1}
px={2}
borderRadius={'sm'}
_hover={{
'.controller': {
display: 'flex'
}
}}
overflow={'hidden'}
position={'relative'}
cursor={'pointer'}
onClick={(e) => {
e.stopPropagation();
setQuoteModalData({
rawSearch: quoteList,
metadata: {
collectionId: item.collectionId,
sourceId: item.sourceId,
sourceName: item.sourceName
}
});
}}
>
<MyTooltip label={t('core.chat.quote.Read Quote')}>
<MyIcon
name="common/viewLight"
w={'14px'}
cursor={'pointer'}
_hover={{
color: 'green.600'
}}
onClick={(e) => {
e.stopPropagation();
setQuoteModalData(quoteList);
}}
/>
</MyTooltip>
{item.sourceId && item.canReadQuote && (
<MyTooltip label={t('core.chat.quote.Read Source')}>
<MyIcon
ml={4}
name="common/routePushLight"
w={'14px'}
cursor={'pointer'}
_hover={{ color: 'primary.500' }}
onClick={async (e) => {
e.stopPropagation();
if (!item.sourceId) return;
await getFileAndOpen(item.sourceId);
}}
/>
</MyTooltip>
)}
</Box>
</Flex>
<Image src={item.icon} alt={''} mr={1} flexShrink={0} w={'12px'} />
<Box className="textEllipsis3" wordBreak={'break-all'} flex={'1 0 0'}>
{item.sourceName}
</Box>
</Flex>
</MyTooltip>
))}
</Flex>
</>
)}
<Flex alignItems={'center'} mt={2} flexWrap={'wrap'}>
<Flex alignItems={'center'} mt={3} flexWrap={'wrap'}>
{quoteList.length > 0 && (
<MyTooltip label="查看引用">
<Tag
colorSchema="blue"
cursor={'pointer'}
{...TagStyles}
onClick={() => setQuoteModalData(quoteList)}
onClick={() => setQuoteModalData({ rawSearch: quoteList })}
>
{quoteList.length}
</Tag>
@@ -213,7 +183,7 @@ const ResponseTags = ({
{!!quoteModalData && (
<QuoteModal
rawSearch={quoteModalData}
{...quoteModalData}
isShare={isShare}
onClose={() => setQuoteModalData(undefined)}
/>

View File

@@ -632,14 +632,13 @@ const ChatBox = (
leftIcon={<MyIcon name={'chatFill'} w={'16px'} />}
size={'sm'}
maxW={'100px'}
borderRadius={'lg'}
onClick={handleSubmit((data) => {
onUpdateVariable?.(data);
setVariables(data);
setVariableInputFinish(true);
})}
>
{'开始对话'}
{t('core.chat.Start Chat')}
</Button>
)}
</Card>
@@ -952,6 +951,8 @@ const ChatBox = (
appId={appId}
chatId={chatId}
chatItemId={feedbackId}
shareId={shareId}
outLinkUid={outLinkUid}
onClose={() => setFeedbackId(undefined)}
onSuccess={(content: string) => {
setChatHistory((state) =>
@@ -1142,7 +1143,7 @@ function ChatAvatar({ src, type }: { src?: string; type: 'Human' | 'AI' }) {
w={['28px', '34px']}
h={['28px', '34px']}
p={'2px'}
borderRadius={'lg'}
borderRadius={'sm'}
border={theme.borders.base}
boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
bg={type === 'Human' ? 'white' : 'primary.50'}
@@ -1208,7 +1209,7 @@ function ChatController({
cursor: 'pointer',
p: 1,
bg: 'white',
borderRadius: 'lg',
borderRadius: 'md',
boxShadow: '0 0 5px rgba(0,0,0,0.1)',
border: theme.borders.base,
mr: 3