mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-03 13:38:00 +00:00
v4.6 -1 (#459)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { ModalBody, Box, useTheme } from '@chakra-ui/react';
|
||||
import { ChatItemType } from '@/types/chat';
|
||||
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import MyModal from '../MyModal';
|
||||
|
||||
const ContextModal = ({
|
||||
|
@@ -16,6 +16,7 @@ import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/ty
|
||||
import MyTooltip from '../MyTooltip';
|
||||
import NextLink from 'next/link';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
|
||||
const QuoteModal = ({
|
||||
rawSearch = [],
|
||||
@@ -28,14 +29,15 @@ const QuoteModal = ({
|
||||
const { isPc } = useSystemStore();
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { userInfo } = useUserStore();
|
||||
const { toast } = useToast();
|
||||
const { setIsLoading, Loading } = useLoading();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType>();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType & { datasetId: string }>();
|
||||
|
||||
const isShare = useMemo(() => router.pathname === '/chat/share', [router.pathname]);
|
||||
|
||||
/**
|
||||
* click edit, get new kbDataItem
|
||||
* click edit, get new DataItem
|
||||
*/
|
||||
const onclickEdit = useCallback(
|
||||
async (item: InputDataType) => {
|
||||
@@ -181,6 +183,7 @@ const QuoteModal = ({
|
||||
</MyModal>
|
||||
{editInputData && editInputData.id && (
|
||||
<InputDataModal
|
||||
canWrite={userInfo?.team?.canWrite || false}
|
||||
onClose={() => setEditInputData(undefined)}
|
||||
onSuccess={() => {
|
||||
console.log('更新引用成功');
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { Flex, BoxProps, useDisclosure, Image, useTheme } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
@@ -6,7 +6,7 @@ import MyIcon from '@/components/Icon';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import DatasetSelectModal, { useDatasetSelect } from '@/components/core/dataset/SelectModal';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { MarkDataType } from '@/global/core/dataset/type';
|
||||
import { AdminFbkType } from '@fastgpt/global/core/chat/type.d';
|
||||
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
|
||||
|
||||
const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal'));
|
||||
@@ -28,7 +28,7 @@ const SelectMarkCollection = ({
|
||||
adminMarkData: AdminMarkType;
|
||||
setAdminMarkData: (e: AdminMarkType) => void;
|
||||
onClose: () => void;
|
||||
onSuccess: (adminFeedback: MarkDataType) => void;
|
||||
onSuccess: (adminFeedback: AdminFbkType) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
@@ -166,12 +166,12 @@ const SelectMarkCollection = ({
|
||||
datasetId={adminMarkData.datasetId}
|
||||
defaultValues={{
|
||||
id: adminMarkData.dataId,
|
||||
datasetId: adminMarkData.datasetId,
|
||||
collectionId: adminMarkData.collectionId,
|
||||
sourceName: '手动标注',
|
||||
q: adminMarkData.q,
|
||||
a: adminMarkData.a
|
||||
}}
|
||||
canWrite
|
||||
onSuccess={(data) => {
|
||||
if (!data.q || !adminMarkData.datasetId || !adminMarkData.collectionId || !data.id) {
|
||||
return onClose();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Box, useTheme, Flex, Image } from '@chakra-ui/react';
|
||||
import type { ChatHistoryItemResType } from '@/types/chat';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ModuleTemplatesFlat } from '@/constants/flow/ModuleTemplate';
|
||||
import Tabs from '../Tabs';
|
||||
@@ -8,7 +8,7 @@ import Tabs from '../Tabs';
|
||||
import MyModal from '../MyModal';
|
||||
import MyTooltip from '../MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { formatPrice } from '@fastgpt/global/common/bill/tools';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
|
||||
function Row({ label, value }: { label: string; value?: string | number | React.ReactNode }) {
|
||||
const theme = useTheme();
|
||||
|
@@ -10,12 +10,9 @@ import React, {
|
||||
} from 'react';
|
||||
import Script from 'next/script';
|
||||
import { throttle } from 'lodash';
|
||||
import {
|
||||
ChatHistoryItemResType,
|
||||
ChatItemType,
|
||||
ChatSiteItemType,
|
||||
ExportChatType
|
||||
} from '@/types/chat';
|
||||
import type { ExportChatType } from '@/types/chat.d';
|
||||
import type { ChatItemType, ChatSiteItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/api.d';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useAudioPlay } from '@/web/common/utils/voice';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
@@ -38,12 +35,12 @@ import { useMarkdown } from '@/web/common/hooks/useMarkdown';
|
||||
import { ModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import { VariableInputEnum } from '@/constants/app';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { MessageItemType } from '@/types/core/chat/type';
|
||||
import type { ChatMessageItemType } from '@fastgpt/global/core/ai/type.d';
|
||||
import { fileDownload } from '@/web/common/file/utils';
|
||||
import { htmlTemplate } from '@/constants/common';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
import { TaskResponseKeyEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { adminUpdateChatFeedback, userUpdateChatFeedback } from '@/web/core/chat/api';
|
||||
@@ -64,6 +61,7 @@ const SelectMarkCollection = dynamic(() => import('./SelectMarkCollection'));
|
||||
import styles from './index.module.scss';
|
||||
import { postQuestionGuide } from '@/web/core/ai/api';
|
||||
import { splitGuideModule } from '@/global/core/app/modules/utils';
|
||||
import { AppTTSConfigType } from '@/types/app';
|
||||
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
||||
|
||||
@@ -73,7 +71,7 @@ type generatingMessageProps = { text?: string; name?: string; status?: 'running'
|
||||
|
||||
export type StartChatFnProps = {
|
||||
chatList: ChatSiteItemType[];
|
||||
messages: MessageItemType[];
|
||||
messages: ChatMessageItemType[];
|
||||
controller: AbortController;
|
||||
variables: Record<string, any>;
|
||||
generatingMessage: (e: generatingMessageProps) => void;
|
||||
@@ -158,7 +156,7 @@ const ChatBox = (
|
||||
[chatHistory]
|
||||
);
|
||||
|
||||
const { welcomeText, variableModules, questionGuide } = useMemo(
|
||||
const { welcomeText, variableModules, questionGuide, ttsConfig } = useMemo(
|
||||
() => splitGuideModule(userGuideModule),
|
||||
[userGuideModule]
|
||||
);
|
||||
@@ -206,32 +204,28 @@ const ChatBox = (
|
||||
[]
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const generatingMessage = useCallback(
|
||||
// concat text to end of message
|
||||
({ text = '', status, name }: generatingMessageProps) => {
|
||||
setChatHistory((state) =>
|
||||
state.map((item, index) => {
|
||||
if (index !== state.length - 1) return item;
|
||||
return {
|
||||
...item,
|
||||
...(text
|
||||
? {
|
||||
value: item.value + text
|
||||
}
|
||||
: {}),
|
||||
...(status && name
|
||||
? {
|
||||
status,
|
||||
moduleName: name
|
||||
}
|
||||
: {})
|
||||
};
|
||||
})
|
||||
);
|
||||
generatingScroll();
|
||||
},
|
||||
[generatingScroll, setChatHistory]
|
||||
);
|
||||
const generatingMessage = ({ text = '', status, name }: generatingMessageProps) => {
|
||||
setChatHistory((state) =>
|
||||
state.map((item, index) => {
|
||||
if (index !== state.length - 1) return item;
|
||||
return {
|
||||
...item,
|
||||
...(text
|
||||
? {
|
||||
value: item.value + text
|
||||
}
|
||||
: {}),
|
||||
...(status && name
|
||||
? {
|
||||
status,
|
||||
moduleName: name
|
||||
}
|
||||
: {})
|
||||
};
|
||||
})
|
||||
);
|
||||
generatingScroll();
|
||||
};
|
||||
|
||||
// 重置输入内容
|
||||
const resetInputVal = useCallback((val: string) => {
|
||||
@@ -489,7 +483,7 @@ const ChatBox = (
|
||||
|
||||
return {
|
||||
bg: colorMap[chatContent.status] || colorMap.loading,
|
||||
name: t(chatContent.moduleName || 'common.Loading')
|
||||
name: chatContent.moduleName || t('common.Loading')
|
||||
};
|
||||
}, [chatHistory, isChatting, t]);
|
||||
/* style end */
|
||||
@@ -654,8 +648,10 @@ const ChatBox = (
|
||||
<ChatController
|
||||
ml={2}
|
||||
chat={item}
|
||||
setChatHistory={setChatHistory}
|
||||
display={index === chatHistory.length - 1 && isChatting ? 'none' : 'flex'}
|
||||
showVoiceIcon={showVoiceIcon}
|
||||
ttsConfig={ttsConfig}
|
||||
onDelete={
|
||||
onDelMessage
|
||||
? () => {
|
||||
@@ -801,13 +797,20 @@ const ChatBox = (
|
||||
</Box>
|
||||
{/* message input */}
|
||||
{onStartChat && variableIsFinish && active ? (
|
||||
<Box m={['0 auto', '10px auto']} w={'100%'} maxW={['auto', 'min(750px, 100%)']} px={[0, 5]}>
|
||||
<Box m={['0 auto', '10px auto']} w={'100%'} maxW={['auto', 'min(800px, 100%)']} px={[0, 5]}>
|
||||
<Box
|
||||
py={'18px'}
|
||||
position={'relative'}
|
||||
boxShadow={`0 0 10px rgba(0,0,0,0.2)`}
|
||||
borderTop={['1px solid', 0]}
|
||||
borderTopColor={'myGray.200'}
|
||||
{...(isPc
|
||||
? {
|
||||
border: '1px solid',
|
||||
borderColor: 'rgba(0,0,0,0.12)'
|
||||
}
|
||||
: {
|
||||
borderTop: '1px solid',
|
||||
borderTopColor: 'rgba(0,0,0,0.15)'
|
||||
})}
|
||||
borderRadius={['none', 'md']}
|
||||
backgroundColor={'white'}
|
||||
>
|
||||
@@ -836,6 +839,7 @@ const ChatBox = (
|
||||
const textarea = e.target;
|
||||
textarea.style.height = textareaMinH;
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
// enter send.(pc or iframe && enter and unPress shift)
|
||||
@@ -852,11 +856,14 @@ const ChatBox = (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
h={'25px'}
|
||||
w={'25px'}
|
||||
h={['26px', '32px']}
|
||||
w={['26px', '32px']}
|
||||
position={'absolute'}
|
||||
right={['12px', '20px']}
|
||||
bottom={'15px'}
|
||||
right={['12px', '14px']}
|
||||
bottom={['15px', '13px']}
|
||||
borderRadius={'md'}
|
||||
bg={TextareaDom.current?.value ? 'myBlue.600' : ''}
|
||||
lineHeight={1}
|
||||
>
|
||||
{isChatting ? (
|
||||
<MyIcon
|
||||
@@ -869,16 +876,18 @@ const ChatBox = (
|
||||
onClick={() => chatController.current?.abort('stop')}
|
||||
/>
|
||||
) : (
|
||||
<MyIcon
|
||||
name={'chatSend'}
|
||||
width={['18px', '20px']}
|
||||
height={['18px', '20px']}
|
||||
cursor={'pointer'}
|
||||
color={'gray.500'}
|
||||
onClick={() => {
|
||||
handleSubmit((data) => sendPrompt(data, TextareaDom.current?.value))();
|
||||
}}
|
||||
/>
|
||||
<MyTooltip label={t('core.chat.Send Message')}>
|
||||
<MyIcon
|
||||
name={'core/chat/sendFill'}
|
||||
width={'16px'}
|
||||
height={'16px'}
|
||||
cursor={'pointer'}
|
||||
color={TextareaDom.current?.value ? 'white' : 'myBlue.600'}
|
||||
onClick={() => {
|
||||
handleSubmit((data) => sendPrompt(data, TextareaDom.current?.value))();
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
@@ -1106,8 +1115,10 @@ function Empty() {
|
||||
|
||||
function ChatController({
|
||||
chat,
|
||||
setChatHistory,
|
||||
display,
|
||||
showVoiceIcon,
|
||||
ttsConfig,
|
||||
onReadFeedback,
|
||||
onMark,
|
||||
onRetry,
|
||||
@@ -1117,7 +1128,9 @@ function ChatController({
|
||||
mr
|
||||
}: {
|
||||
chat: ChatSiteItemType;
|
||||
setChatHistory?: React.Dispatch<React.SetStateAction<ChatSiteItemType[]>>;
|
||||
showVoiceIcon?: boolean;
|
||||
ttsConfig?: AppTTSConfigType;
|
||||
onRetry?: () => void;
|
||||
onDelete?: () => void;
|
||||
onMark?: () => void;
|
||||
@@ -1127,7 +1140,9 @@ function ChatController({
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
const { audioLoading, audioPlaying, hasAudio, playAudio, cancelAudio } = useAudioPlay({});
|
||||
const { audioLoading, audioPlaying, hasAudio, playAudio, cancelAudio } = useAudioPlay({
|
||||
ttsConfig
|
||||
});
|
||||
const controlIconStyle = {
|
||||
w: '14px',
|
||||
cursor: 'pointer',
|
||||
@@ -1198,7 +1213,24 @@ function ChatController({
|
||||
{...controlIconStyle}
|
||||
name={'voice'}
|
||||
_hover={{ color: '#E74694' }}
|
||||
onClick={() => playAudio(chat.value)}
|
||||
onClick={async () => {
|
||||
const buffer = await playAudio({
|
||||
buffer: chat.ttsBuffer,
|
||||
chatItemId: chat.dataId,
|
||||
text: chat.value
|
||||
});
|
||||
if (!setChatHistory) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((item) =>
|
||||
item.dataId === chat.dataId
|
||||
? {
|
||||
...item,
|
||||
ttsBuffer: buffer
|
||||
}
|
||||
: item
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
))}
|
||||
|
Reference in New Issue
Block a user