mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 18:48:55 +00:00
v4.6.6-search test adapt diff search mode (#685)
This commit is contained in:
@@ -32,7 +32,7 @@ const ContextModal = ({
|
||||
<Box
|
||||
key={i}
|
||||
p={2}
|
||||
borderRadius={'lg'}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
_notLast={{ mb: 2 }}
|
||||
position={'relative'}
|
||||
|
@@ -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
|
||||
});
|
||||
},
|
||||
|
@@ -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}¤tTab=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} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@@ -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)}
|
||||
/>
|
||||
|
@@ -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
|
||||
|
@@ -9,7 +9,6 @@ import {
|
||||
Skeleton,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
|
||||
const MdImage = ({ src }: { src?: string }) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -34,6 +33,7 @@ const MdImage = ({ src }: { src?: string }) => {
|
||||
cursor={succeed ? 'pointer' : 'default'}
|
||||
loading="eager"
|
||||
objectFit={'contain'}
|
||||
referrerPolicy="no-referrer"
|
||||
onLoad={() => {
|
||||
setIsLoading(false);
|
||||
setSucceed(true);
|
||||
@@ -53,6 +53,7 @@ const MdImage = ({ src }: { src?: string }) => {
|
||||
alt={''}
|
||||
w={'100%'}
|
||||
maxH={'80vh'}
|
||||
referrerPolicy="no-referrer"
|
||||
fallbackSrc={'/imgs/errImg.png'}
|
||||
fallbackStrategy={'onError'}
|
||||
objectFit={'contain'}
|
||||
|
@@ -39,7 +39,7 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
|
||||
px={2}
|
||||
lineHeight={1}
|
||||
py={1}
|
||||
borderRadius={'md'}
|
||||
borderRadius={'sm'}
|
||||
fontSize={'xs'}
|
||||
alignItems={'center'}
|
||||
{...theme}
|
||||
|
@@ -77,7 +77,7 @@ const Editor = React.memo(function Editor({
|
||||
|
||||
return (
|
||||
<Box h={'100%'} w={'100%'} position={'relative'}>
|
||||
<Textarea ref={textareaRef} textAlign={'justify'} maxW={'100%'} {...props} />
|
||||
<Textarea ref={textareaRef} maxW={'100%'} {...props} />
|
||||
{onOpenModal && (
|
||||
<Box
|
||||
zIndex={1}
|
||||
|
223
projects/app/src/components/core/dataset/QuoteItem.tsx
Normal file
223
projects/app/src/components/core/dataset/QuoteItem.tsx
Normal file
@@ -0,0 +1,223 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Box, Flex, Link, Progress, useTheme } from '@chakra-ui/react';
|
||||
import {
|
||||
type InputDataType,
|
||||
RawSourceText
|
||||
} from '@/pages/dataset/detail/components/InputDataModal';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
import NextLink from 'next/link';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
import { getDatasetDataItemById } from '@/web/core/dataset/api';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { DatasetDataItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import { SearchScoreTypeEnum, SearchScoreTypeMap } from '@fastgpt/global/core/dataset/constant';
|
||||
|
||||
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
|
||||
|
||||
const QuoteItem = ({
|
||||
quoteItem,
|
||||
canViewSource,
|
||||
linkToDataset
|
||||
}: {
|
||||
quoteItem: SearchDataResponseItemType;
|
||||
canViewSource?: boolean;
|
||||
linkToDataset?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystemStore();
|
||||
const theme = useTheme();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType & { collectionId: string }>();
|
||||
|
||||
const { mutate: onclickEdit, isLoading } = useRequest({
|
||||
mutationFn: async (id: string) => {
|
||||
return getDatasetDataItemById(id);
|
||||
},
|
||||
onSuccess(data: DatasetDataItemType) {
|
||||
setEditInputData(data);
|
||||
},
|
||||
errorToast: t('core.dataset.data.get data error')
|
||||
});
|
||||
|
||||
const rank = useMemo(() => {
|
||||
if (quoteItem.score.length === 1) {
|
||||
return quoteItem.score[0].index;
|
||||
}
|
||||
const rrf = quoteItem.score?.find((item) => item.type === SearchScoreTypeEnum.rrf);
|
||||
if (rrf) return rrf.index;
|
||||
|
||||
return 0;
|
||||
}, [quoteItem.score]);
|
||||
|
||||
const score = useMemo(() => {
|
||||
let searchScore: number | undefined = undefined;
|
||||
let text = '';
|
||||
|
||||
const reRankScore = quoteItem.score?.find((item) => item.type === SearchScoreTypeEnum.reRank);
|
||||
if (reRankScore) {
|
||||
searchScore = reRankScore.value;
|
||||
text = t('core.dataset.search.Rerank score');
|
||||
}
|
||||
|
||||
const embScore = quoteItem.score?.find((item) => item.type === SearchScoreTypeEnum.embedding);
|
||||
if (embScore && quoteItem.score.length === 1) {
|
||||
searchScore = embScore.value;
|
||||
text = t('core.dataset.search.Embedding score');
|
||||
}
|
||||
|
||||
const detailScore = (() => {
|
||||
if (Array.isArray(quoteItem.score)) {
|
||||
return quoteItem.score
|
||||
.map(
|
||||
(item) =>
|
||||
`${t('core.dataset.search.Search type')}: ${t(SearchScoreTypeMap[item.type]?.label)}
|
||||
${t('core.dataset.search.Rank')}: ${item.index + 1}
|
||||
${t('core.dataset.search.Score')}: ${item.value.toFixed(4)}`
|
||||
)
|
||||
.join('\n----\n');
|
||||
}
|
||||
return 'null';
|
||||
})();
|
||||
|
||||
return {
|
||||
value: searchScore,
|
||||
tip: t('core.dataset.Search score tip', {
|
||||
scoreText: text ? `${text}。\n` : text,
|
||||
detailScore
|
||||
})
|
||||
};
|
||||
}, [quoteItem.score, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MyBox
|
||||
isLoading={isLoading}
|
||||
position={'relative'}
|
||||
overflow={'hidden'}
|
||||
fontSize={'sm'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
_hover={{ '& .hover-data': { display: 'flex' } }}
|
||||
>
|
||||
<Flex alignItems={'flex-end'} mb={3}>
|
||||
{rank !== undefined && (
|
||||
<MyTooltip label={t('core.dataset.search.Rank Tip')}>
|
||||
<Box px={2} py={'3px'} mr={3} bg={'myGray.200'} borderRadius={'md'}>
|
||||
# {rank + 1}
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
)}
|
||||
|
||||
<RawSourceText
|
||||
fontWeight={'bold'}
|
||||
color={'black'}
|
||||
sourceName={quoteItem.sourceName}
|
||||
sourceId={quoteItem.sourceId}
|
||||
canView={canViewSource}
|
||||
/>
|
||||
<Box flex={1} />
|
||||
{linkToDataset && (
|
||||
<Link
|
||||
as={NextLink}
|
||||
className="hover-data"
|
||||
display={'none'}
|
||||
alignItems={'center'}
|
||||
color={'primary.500'}
|
||||
href={`/dataset/detail?datasetId=${quoteItem.datasetId}¤tTab=dataCard&collectionId=${quoteItem.collectionId}`}
|
||||
>
|
||||
{t('core.dataset.Go Dataset')}
|
||||
<MyIcon name={'common/rightArrowLight'} w={'10px'} />
|
||||
</Link>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Box color={'black'}>{quoteItem.q}</Box>
|
||||
<Box color={'myGray.600'}>{quoteItem.a}</Box>
|
||||
{canViewSource && (
|
||||
<Flex alignItems={'center'} mt={3} gap={4} color={'myGray.500'} fontSize={'xs'}>
|
||||
{isPc && (
|
||||
<Flex border={theme.borders.base} px={3} borderRadius={'xs'} lineHeight={'16px'}>
|
||||
ID: {quoteItem.id}
|
||||
</Flex>
|
||||
)}
|
||||
<MyTooltip label={t('core.dataset.Quote Length')}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name="common/text/t" w={'14px'} mr={1} color={'myGray.500'} />
|
||||
{quoteItem.q.length + (quoteItem.a?.length || 0)}
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
{canViewSource && score && (
|
||||
<MyTooltip label={score.tip}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'kbTest'} w={'12px'} />
|
||||
{score.value ? (
|
||||
<>
|
||||
<Progress
|
||||
mx={2}
|
||||
w={['60px', '90px']}
|
||||
value={score?.value * 100}
|
||||
size="sm"
|
||||
borderRadius={'20px'}
|
||||
colorScheme="myGray"
|
||||
border={theme.borders.base}
|
||||
/>
|
||||
<Box>{score?.value.toFixed(4)}</Box>
|
||||
</>
|
||||
) : (
|
||||
<Box ml={1} cursor={'pointer'}>
|
||||
{t('core.dataset.search.Read score')}
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
)}
|
||||
<Box flex={1} />
|
||||
{quoteItem.id && (
|
||||
<MyTooltip label={t('core.dataset.data.Edit')}>
|
||||
<Box
|
||||
className="hover-data"
|
||||
display={['flex', 'none']}
|
||||
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(quoteItem.id)}
|
||||
/>
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
</MyBox>
|
||||
|
||||
{editInputData && editInputData.id && (
|
||||
<InputDataModal
|
||||
onClose={() => setEditInputData(undefined)}
|
||||
onSuccess={() => {
|
||||
console.log('更新引用成功');
|
||||
}}
|
||||
onDelete={() => {
|
||||
console.log('删除引用成功');
|
||||
}}
|
||||
defaultValue={editInputData}
|
||||
collectionId={editInputData.collectionId}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(QuoteItem);
|
@@ -128,7 +128,7 @@ const VariableEdit = ({
|
||||
</Flex>
|
||||
</Flex>
|
||||
{formatVariables.length > 0 && (
|
||||
<Box mt={2} borderRadius={'lg'} overflow={'hidden'} borderWidth={'1px'} borderBottom="none">
|
||||
<Box mt={2} borderRadius={'md'} overflow={'hidden'} borderWidth={'1px'} borderBottom="none">
|
||||
<TableContainer>
|
||||
<Table bg={'white'}>
|
||||
<Thead>
|
||||
@@ -266,7 +266,7 @@ const VariableEdit = ({
|
||||
w={'16px'}
|
||||
cursor={'pointer'}
|
||||
p={2}
|
||||
borderRadius={'lg'}
|
||||
borderRadius={'md'}
|
||||
_hover={{ bg: 'red.100' }}
|
||||
onClick={() => removeEnums(i)}
|
||||
/>
|
||||
|
@@ -7,6 +7,7 @@ import dynamic from 'next/dynamic';
|
||||
import InputLabel from './Label';
|
||||
import type { RenderInputProps } from './type.d';
|
||||
import { getFlowStore, type useFlowProviderStoreType } from '../../../FlowProvider';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
|
||||
const RenderList: {
|
||||
types: `${FlowNodeInputTypeEnum}`[];
|
||||
@@ -65,6 +66,7 @@ const RenderList: {
|
||||
Component: dynamic(() => import('./templates/AddInputParam'))
|
||||
}
|
||||
];
|
||||
const UserChatInput = dynamic(() => import('./templates/UserChatInput'));
|
||||
|
||||
type Props = {
|
||||
flowInputList: FlowNodeInputItemType[];
|
||||
@@ -124,18 +126,23 @@ const RenderInput = ({ flowInputList, moduleId, CustomComponent = {} }: Props) =
|
||||
})();
|
||||
|
||||
return (
|
||||
input.type !== FlowNodeInputTypeEnum.hidden && (
|
||||
<Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||
{!!input.label && (
|
||||
<InputLabel moduleId={moduleId} inputKey={input.key} mode={mode} {...input} />
|
||||
)}
|
||||
{!!RenderComponent && (
|
||||
<Box mt={2} className={'nodrag'}>
|
||||
{RenderComponent}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
<Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}>
|
||||
{input.key === ModuleInputKeyEnum.userChatInput && (
|
||||
<UserChatInput inputs={filterInputs} item={input} moduleId={moduleId} />
|
||||
)}
|
||||
{input.type !== FlowNodeInputTypeEnum.hidden && (
|
||||
<>
|
||||
{!!input.label && (
|
||||
<InputLabel moduleId={moduleId} inputKey={input.key} mode={mode} {...input} />
|
||||
)}
|
||||
{!!RenderComponent && (
|
||||
<Box mt={2} className={'nodrag'}>
|
||||
{RenderComponent}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
|
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import TargetHandle from '../../TargetHandle';
|
||||
import SourceHandle from '../../SourceHandle';
|
||||
import { ModuleInputKeyEnum, ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
|
||||
const UserChatInput = ({ item }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Flex
|
||||
className="nodrag"
|
||||
cursor={'default'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'space-between'}
|
||||
position={'relative'}
|
||||
>
|
||||
<Box position={'relative'}>
|
||||
<TargetHandle handleKey={ModuleInputKeyEnum.userChatInput} valueType={item.valueType} />
|
||||
{t('core.module.input.label.user question')}
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={'-2px'}
|
||||
right={'-8px'}
|
||||
color={'red.500'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
*
|
||||
</Box>
|
||||
</Box>
|
||||
<Box position={'relative'}>
|
||||
{t('core.module.input.label.user question')}
|
||||
<SourceHandle handleKey={ModuleOutputKeyEnum.userChatInput} valueType={item.valueType} />
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(UserChatInput);
|
Reference in New Issue
Block a user