mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
whole response modal
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
"Output Field Settings": "Output Field Settings"
|
"Output Field Settings": "Output Field Settings"
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
|
"Complete Response": "Complete Response",
|
||||||
"Confirm to clear history": "Confirm to clear history?",
|
"Confirm to clear history": "Confirm to clear history?",
|
||||||
"Exit Chat": "Exit",
|
"Exit Chat": "Exit",
|
||||||
"History": "History",
|
"History": "History",
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
"Output Field Settings": "输出字段编辑"
|
"Output Field Settings": "输出字段编辑"
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
|
"Complete Response": "完整响应",
|
||||||
"Confirm to clear history": "确认清空该应用的聊天记录?",
|
"Confirm to clear history": "确认清空该应用的聊天记录?",
|
||||||
"Exit Chat": "退出聊天",
|
"Exit Chat": "退出聊天",
|
||||||
"History": "记录",
|
"History": "记录",
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { ChatModuleEnum } from '@/constants/chat';
|
import { ChatModuleEnum } from '@/constants/chat';
|
||||||
import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat';
|
import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat';
|
||||||
import { Flex, BoxProps } from '@chakra-ui/react';
|
import { Flex, BoxProps, useDisclosure } from '@chakra-ui/react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useGlobalStore } from '@/store/global';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import Tag from '../Tag';
|
import Tag from '../Tag';
|
||||||
import MyTooltip from '../MyTooltip';
|
import MyTooltip from '../MyTooltip';
|
||||||
const QuoteModal = dynamic(() => import('./QuoteModal'), { ssr: false });
|
const QuoteModal = dynamic(() => import('./QuoteModal'), { ssr: false });
|
||||||
const ContextModal = dynamic(() => import('./ContextModal'), { ssr: false });
|
const ContextModal = dynamic(() => import('./ContextModal'), { ssr: false });
|
||||||
|
const WholeResponseModal = dynamic(() => import('./WholeResponseModal'), { ssr: false });
|
||||||
|
|
||||||
const ResponseDetailModal = ({
|
const ResponseTags = ({
|
||||||
chatId,
|
chatId,
|
||||||
contentId,
|
contentId,
|
||||||
responseData = []
|
responseData = []
|
||||||
@@ -17,28 +20,30 @@ const ResponseDetailModal = ({
|
|||||||
contentId?: string;
|
contentId?: string;
|
||||||
responseData?: ChatHistoryItemResType[];
|
responseData?: ChatHistoryItemResType[];
|
||||||
}) => {
|
}) => {
|
||||||
|
const { isPc } = useGlobalStore();
|
||||||
|
const { t } = useTranslation();
|
||||||
const [quoteModalData, setQuoteModalData] = useState<QuoteItemType[]>();
|
const [quoteModalData, setQuoteModalData] = useState<QuoteItemType[]>();
|
||||||
const [contextModalData, setContextModalData] = useState<ChatItemType[]>();
|
const [contextModalData, setContextModalData] = useState<ChatItemType[]>();
|
||||||
|
const {
|
||||||
|
isOpen: isOpenWholeModal,
|
||||||
|
onOpen: onOpenWholeModal,
|
||||||
|
onClose: onCloseWholeModal
|
||||||
|
} = useDisclosure();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
tokens = 0,
|
|
||||||
quoteList = [],
|
quoteList = [],
|
||||||
completeMessages = []
|
completeMessages = [],
|
||||||
|
tokens = 0
|
||||||
} = useMemo(() => {
|
} = useMemo(() => {
|
||||||
const chatData = responseData.find((item) => item.moduleName === ChatModuleEnum.AIChat);
|
const chatData = responseData.find((item) => item.moduleName === ChatModuleEnum.AIChat);
|
||||||
if (!chatData) return {};
|
if (!chatData) return {};
|
||||||
return {
|
return {
|
||||||
tokens: chatData.tokens,
|
|
||||||
quoteList: chatData.quoteList,
|
quoteList: chatData.quoteList,
|
||||||
completeMessages: chatData.completeMessages
|
completeMessages: chatData.completeMessages,
|
||||||
|
tokens: responseData.reduce((sum, item) => sum + (item.tokens || 0), 0)
|
||||||
};
|
};
|
||||||
}, [responseData]);
|
}, [responseData]);
|
||||||
|
|
||||||
const isEmpty = useMemo(
|
|
||||||
() => quoteList.length === 0 && completeMessages.length === 0 && tokens === 0,
|
|
||||||
[completeMessages.length, quoteList.length, tokens]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateQuote = useCallback(async (quoteId: string, sourceText: string) => {}, []);
|
const updateQuote = useCallback(async (quoteId: string, sourceText: string) => {}, []);
|
||||||
|
|
||||||
const TagStyles: BoxProps = {
|
const TagStyles: BoxProps = {
|
||||||
@@ -46,7 +51,7 @@ const ResponseDetailModal = ({
|
|||||||
bg: 'transparent'
|
bg: 'transparent'
|
||||||
};
|
};
|
||||||
|
|
||||||
return isEmpty ? null : (
|
return (
|
||||||
<Flex alignItems={'center'} mt={2} flexWrap={'wrap'}>
|
<Flex alignItems={'center'} mt={2} flexWrap={'wrap'}>
|
||||||
{quoteList.length > 0 && (
|
{quoteList.length > 0 && (
|
||||||
<MyTooltip label="查看引用">
|
<MyTooltip label="查看引用">
|
||||||
@@ -72,11 +77,17 @@ const ResponseDetailModal = ({
|
|||||||
</Tag>
|
</Tag>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
)}
|
)}
|
||||||
{tokens > 0 && (
|
{isPc && tokens > 0 && (
|
||||||
<Tag colorSchema="gray" cursor={'default'} {...TagStyles}>
|
<Tag colorSchema="purple" cursor={'default'} {...TagStyles}>
|
||||||
{tokens}tokens
|
{tokens}Tokens
|
||||||
</Tag>
|
</Tag>
|
||||||
)}
|
)}
|
||||||
|
<MyTooltip label={'点击查看完整响应值'}>
|
||||||
|
<Tag colorSchema="gray" cursor={'pointer'} {...TagStyles} onClick={onOpenWholeModal}>
|
||||||
|
{t('chat.Complete Response')}
|
||||||
|
</Tag>
|
||||||
|
</MyTooltip>
|
||||||
|
|
||||||
{!!quoteModalData && (
|
{!!quoteModalData && (
|
||||||
<QuoteModal
|
<QuoteModal
|
||||||
rawSearch={quoteModalData}
|
rawSearch={quoteModalData}
|
||||||
@@ -87,8 +98,11 @@ const ResponseDetailModal = ({
|
|||||||
{!!contextModalData && (
|
{!!contextModalData && (
|
||||||
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />
|
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />
|
||||||
)}
|
)}
|
||||||
|
{isOpenWholeModal && (
|
||||||
|
<WholeResponseModal response={responseData} onClose={onCloseWholeModal} />
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ResponseDetailModal;
|
export default ResponseTags;
|
71
client/src/components/ChatBox/WholeResponseModal.tsx
Normal file
71
client/src/components/ChatBox/WholeResponseModal.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { Box, ModalBody, useTheme, ModalHeader, Flex } from '@chakra-ui/react';
|
||||||
|
import type { ChatHistoryItemResType } from '@/types/chat';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import MyModal from '../MyModal';
|
||||||
|
import MyTooltip from '../MyTooltip';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
|
||||||
|
const ResponseModal = ({
|
||||||
|
response,
|
||||||
|
onClose
|
||||||
|
}: {
|
||||||
|
response: ChatHistoryItemResType[];
|
||||||
|
onClose: () => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const formatResponse = useMemo(
|
||||||
|
() =>
|
||||||
|
response.map((item) => {
|
||||||
|
const copy = { ...item };
|
||||||
|
delete copy.completeMessages;
|
||||||
|
delete copy.quoteList;
|
||||||
|
return copy;
|
||||||
|
}),
|
||||||
|
[response]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyModal
|
||||||
|
isOpen={true}
|
||||||
|
onClose={onClose}
|
||||||
|
h={['90vh', '80vh']}
|
||||||
|
minW={['90vw', '600px']}
|
||||||
|
title={
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
{t('chat.Complete Response')}
|
||||||
|
<MyTooltip
|
||||||
|
label={
|
||||||
|
'moduleName: 模型名\nprice: 价格,倍率:100000\nmodel?: 模型名\ntokens?: token 消耗\n\nanswer?: 回答内容\nquestion?: 问题\ntemperature?: 温度\nmaxToken?: 最大 tokens\n\nsimilarity?: 相似度\nlimit?: 单次搜索结果\n\ncqList?: 问题分类列表\ncqResult?: 分类结果\n\nextractDescription?: 内容提取描述\nextractResult?: 提取结果'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<QuestionOutlineIcon ml={2} />
|
||||||
|
</MyTooltip>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
isCentered
|
||||||
|
>
|
||||||
|
<ModalBody>
|
||||||
|
{formatResponse.map((item, i) => (
|
||||||
|
<Box
|
||||||
|
key={i}
|
||||||
|
p={2}
|
||||||
|
pt={[0, 2]}
|
||||||
|
borderRadius={'lg'}
|
||||||
|
border={theme.borders.base}
|
||||||
|
_notLast={{ mb: 2 }}
|
||||||
|
position={'relative'}
|
||||||
|
whiteSpace={'pre-wrap'}
|
||||||
|
>
|
||||||
|
{JSON.stringify(item, null, 2)}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</ModalBody>
|
||||||
|
</MyModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResponseModal;
|
@@ -47,7 +47,7 @@ import Markdown from '@/components/Markdown';
|
|||||||
import MySelect from '@/components/Select';
|
import MySelect from '@/components/Select';
|
||||||
import MyTooltip from '../MyTooltip';
|
import MyTooltip from '../MyTooltip';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
const ResponseDetailModal = dynamic(() => import('./ResponseDetailModal'));
|
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ const ChatBox = (
|
|||||||
source={item.value}
|
source={item.value}
|
||||||
isChatting={index === chatHistory.length - 1 && isChatting}
|
isChatting={index === chatHistory.length - 1 && isChatting}
|
||||||
/>
|
/>
|
||||||
<ResponseDetailModal
|
<ResponseTags
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
contentId={item._id}
|
contentId={item._id}
|
||||||
responseData={item.responseData}
|
responseData={item.responseData}
|
||||||
|
@@ -3,7 +3,7 @@ import { Flex, type FlexProps } from '@chakra-ui/react';
|
|||||||
|
|
||||||
interface Props extends FlexProps {
|
interface Props extends FlexProps {
|
||||||
children: React.ReactNode | React.ReactNode[];
|
children: React.ReactNode | React.ReactNode[];
|
||||||
colorSchema?: 'blue' | 'green' | 'gray';
|
colorSchema?: 'blue' | 'green' | 'gray' | 'purple';
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
|
const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
|
||||||
@@ -19,6 +19,11 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
|
|||||||
bg: '#f8fff8',
|
bg: '#f8fff8',
|
||||||
color: '#67c13b'
|
color: '#67c13b'
|
||||||
},
|
},
|
||||||
|
purple: {
|
||||||
|
borderColor: '#A558C9',
|
||||||
|
bg: '#F6EEFA',
|
||||||
|
color: '#A558C9'
|
||||||
|
},
|
||||||
gray: {
|
gray: {
|
||||||
borderColor: '#979797',
|
borderColor: '#979797',
|
||||||
bg: '#F7F7F7',
|
bg: '#F7F7F7',
|
||||||
|
Reference in New Issue
Block a user