4.7-production (#1053)
* 4.7-alpha3 (#62) * doc * Optimize possible null Pointers and parts of Ux * fix: mulity index training error * feat: doc and rename question guide * fix ios speech input (#59) * fix: prompt editor variables nowrap (#61) * change openapi import in http module with curl import (#60) * chore(ui): dataset import modal ui (#58) * chore(ui): dataset import modal ui * use component * fix height * 4.7 (#63) * fix: claude3 image type verification failed (#1038) (#1040) * perf: curl import modal * doc img * perf: adapt cohere rerank * perf: code * perf: input style * doc --------- Co-authored-by: xiaotian <dimsky@163.com> * fix: ts * docker deploy * perf: prompt call * doc * ts * finish ui * perf: outlink detail ux * perf: user schema * fix: plugin update * feat: get current time plugin * fix: ts * perf: fetch anamation * perf: mark ux * doc * perf: select app ux * fix: split text custom string conflict * peref: inform readed * doc * memo flow component * perf: version * faq * feat: flow max runtimes * feat: similarity tip * feat: auto detect file encoding * Supports asymmetric vector model * fix: ts * perf: max w * move code * perf: hide whisper * fix: ts * feat: system msg modal * perf: catch error * perf: inform tip * fix: inform --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com> Co-authored-by: xiaotian <dimsky@163.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { ModalBody, Textarea, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { updateChatUserFeedback } from '@/web/core/chat/api';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { ChatFileTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { addDays } from 'date-fns';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||
import { ChatBoxInputFormType, ChatBoxInputType, UserInputFileItemType } from './type';
|
||||
@@ -61,7 +61,7 @@ const MessageInput = ({
|
||||
renderAudioGraph,
|
||||
stream
|
||||
} = useSpeech({ shareId, outLinkUid, teamId, teamToken });
|
||||
const { isPc } = useSystemStore();
|
||||
const { isPc, whisperModel } = useSystemStore();
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -369,7 +369,7 @@ const MessageInput = ({
|
||||
bottom={['10px', '12px']}
|
||||
>
|
||||
{/* voice-input */}
|
||||
{!shareId && !havInput && !isChatting && (
|
||||
{!shareId && !havInput && !isChatting && !!whisperModel && (
|
||||
<>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
@@ -402,7 +402,7 @@ const MessageInput = ({
|
||||
name={isSpeaking ? 'core/chat/stopSpeechFill' : 'core/chat/recordFill'}
|
||||
width={['20px', '22px']}
|
||||
height={['20px', '22px']}
|
||||
color={'primary.500'}
|
||||
color={isSpeaking ? 'primary.500' : 'myGray.600'}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
@@ -410,7 +410,7 @@ const MessageInput = ({
|
||||
)}
|
||||
{/* send and stop icon */}
|
||||
{isSpeaking ? (
|
||||
<Box color={'#5A646E'} w={'36px'} textAlign={'right'}>
|
||||
<Box color={'#5A646E'} w={'36px'} textAlign={'right'} whiteSpace={'nowrap'}>
|
||||
{speakingTimeString}
|
||||
</Box>
|
||||
) : (
|
||||
|
||||
@@ -32,8 +32,6 @@ const SelectMarkCollection = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const [selectedDatasetId, setSelectedDatasetId] = useState<string>();
|
||||
const [selectedDatasetCollectionIds, setSelectedDatasetCollectionIds] = useState<string[]>([]);
|
||||
const { paths, setParentId, datasets, isFetching } = useDatasetSelect();
|
||||
|
||||
return (
|
||||
@@ -45,17 +43,18 @@ const SelectMarkCollection = ({
|
||||
paths={paths}
|
||||
onClose={onClose}
|
||||
setParentId={setParentId}
|
||||
isLoading={isFetching}
|
||||
tips={t('core.chat.Select dataset Desc')}
|
||||
>
|
||||
<ModalBody flex={'1 0 0'} overflowY={'auto'}>
|
||||
<Grid
|
||||
display={'grid'}
|
||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
|
||||
gridGap={3}
|
||||
userSelect={'none'}
|
||||
>
|
||||
{datasets.map((item) =>
|
||||
(() => {
|
||||
const selected = selectedDatasetId === item._id;
|
||||
return (
|
||||
<Card
|
||||
key={item._id}
|
||||
@@ -67,16 +66,11 @@ const SelectMarkCollection = ({
|
||||
_hover={{
|
||||
boxShadow: 'md'
|
||||
}}
|
||||
{...(selected
|
||||
? {
|
||||
bg: 'primary.200'
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
if (item.type === DatasetTypeEnum.folder) {
|
||||
setParentId(item._id);
|
||||
} else {
|
||||
setSelectedDatasetId(item._id);
|
||||
setAdminMarkData({ ...adminMarkData, datasetId: item._id });
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -104,29 +98,21 @@ const SelectMarkCollection = ({
|
||||
</Flex>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
isLoading={isFetching}
|
||||
isDisabled={!selectedDatasetId}
|
||||
onClick={() => {
|
||||
setAdminMarkData({ ...adminMarkData, datasetId: selectedDatasetId });
|
||||
}}
|
||||
>
|
||||
{t('common.Next Step')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</DatasetSelectModal>
|
||||
)}
|
||||
|
||||
{/* select collection */}
|
||||
{adminMarkData.datasetId && !adminMarkData.collectionId && (
|
||||
{adminMarkData.datasetId && (
|
||||
<SelectCollections
|
||||
datasetId={adminMarkData.datasetId}
|
||||
type={'collection'}
|
||||
title={t('dataset.collections.Select One Collection To Store')}
|
||||
onClose={onClose}
|
||||
onChange={({ collectionIds }) => {
|
||||
setSelectedDatasetCollectionIds(collectionIds);
|
||||
setAdminMarkData({
|
||||
...adminMarkData,
|
||||
collectionId: collectionIds[0]
|
||||
});
|
||||
}}
|
||||
CustomFooter={
|
||||
<ModalFooter>
|
||||
@@ -142,17 +128,6 @@ const SelectMarkCollection = ({
|
||||
>
|
||||
{t('common.Last Step')}
|
||||
</Button>
|
||||
<Button
|
||||
isDisabled={selectedDatasetCollectionIds.length === 0}
|
||||
onClick={() => {
|
||||
setAdminMarkData({
|
||||
...adminMarkData,
|
||||
collectionId: selectedDatasetCollectionIds[0]
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t('common.Next Step')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
}
|
||||
/>
|
||||
@@ -161,7 +136,12 @@ const SelectMarkCollection = ({
|
||||
{/* input data */}
|
||||
{adminMarkData.datasetId && adminMarkData.collectionId && (
|
||||
<InputDataModal
|
||||
onClose={onClose}
|
||||
onClose={() => {
|
||||
setAdminMarkData({
|
||||
...adminMarkData,
|
||||
collectionId: undefined
|
||||
});
|
||||
}}
|
||||
collectionId={adminMarkData.collectionId}
|
||||
dataId={adminMarkData.dataId}
|
||||
defaultValue={{
|
||||
|
||||
@@ -90,13 +90,14 @@ const ChatItem = ({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/* AI */
|
||||
return (
|
||||
<Flex flexDirection={'column'} gap={2}>
|
||||
{chat.value.map((value, i) => {
|
||||
const key = `${chat.dataId}-ai-${i}`;
|
||||
if (value.text) {
|
||||
let source = value.text?.content || '';
|
||||
let source = (value.text?.content || '').trim();
|
||||
|
||||
if (!source && chat.value.length > 1) return <></>;
|
||||
|
||||
@@ -137,6 +138,7 @@ ${JSON.stringify(questionGuides)}`;
|
||||
return tool.response;
|
||||
}
|
||||
})();
|
||||
|
||||
return (
|
||||
<Box key={tool.id}>
|
||||
<Accordion allowToggle>
|
||||
@@ -169,7 +171,7 @@ ${JSON.stringify(questionGuides)}`;
|
||||
maxH={'500px'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{toolParams && (
|
||||
{toolParams && toolParams !== '{}' && (
|
||||
<Markdown
|
||||
source={`~~~json#Input
|
||||
${toolParams}`}
|
||||
|
||||
@@ -652,7 +652,7 @@ const ChatBox = (
|
||||
} catch (error) {}
|
||||
};
|
||||
},
|
||||
[appId, chatId, feedbackType, outLinkUid, shareId]
|
||||
[appId, chatId, feedbackType, outLinkUid, shareId, teamId, teamToken]
|
||||
);
|
||||
const onCloseUserLike = useCallback(
|
||||
(chat: ChatSiteItemType) => {
|
||||
@@ -676,7 +676,7 @@ const ChatBox = (
|
||||
});
|
||||
};
|
||||
},
|
||||
[appId, chatId, feedbackType]
|
||||
[appId, chatId, feedbackType, teamId, teamToken]
|
||||
);
|
||||
const onADdUserDislike = useCallback(
|
||||
(chat: ChatSiteItemType) => {
|
||||
@@ -713,7 +713,7 @@ const ChatBox = (
|
||||
return () => setFeedbackId(chat.dataId);
|
||||
}
|
||||
},
|
||||
[appId, chatId, feedbackType, outLinkUid, shareId]
|
||||
[appId, chatId, feedbackType, outLinkUid, shareId, teamId, teamToken]
|
||||
);
|
||||
const onReadUserDislike = useCallback(
|
||||
(chat: ChatSiteItemType) => {
|
||||
@@ -938,7 +938,7 @@ const ChatBox = (
|
||||
icon="core/app/markLight"
|
||||
text={t('core.chat.Admin Mark Content')}
|
||||
/>
|
||||
<Box whiteSpace={'pre'}>
|
||||
<Box whiteSpace={'pre-wrap'}>
|
||||
<Box color={'black'}>{item.adminFeedback.q}</Box>
|
||||
<Box color={'myGray.600'}>{item.adminFeedback.a}</Box>
|
||||
</Box>
|
||||
|
||||
@@ -14,6 +14,8 @@ import Navbar from './navbar';
|
||||
import NavbarPhone from './navbarPhone';
|
||||
const UpdateInviteModal = dynamic(() => import('@/components/support/user/team/UpdateInviteModal'));
|
||||
const NotSufficientModal = dynamic(() => import('@/components/support/wallet/NotSufficientModal'));
|
||||
const SystemMsgModal = dynamic(() => import('@/components/support/user/inform/SystemMsgModal'));
|
||||
const ImportantInform = dynamic(() => import('@/components/support/user/inform/ImportantInform'));
|
||||
|
||||
const pcUnShowLayoutRoute: Record<string, boolean> = {
|
||||
'/': true,
|
||||
@@ -70,10 +72,12 @@ const Layout = ({ children }: { children: JSX.Element }) => {
|
||||
};
|
||||
}, [setScreenWidth]);
|
||||
|
||||
const { data: unread = 0 } = useQuery(['getUnreadCount'], getUnreadCount, {
|
||||
const { data, refetch: refetchUnRead } = useQuery(['getUnreadCount'], getUnreadCount, {
|
||||
enabled: !!userInfo && !!feConfigs.isPlus,
|
||||
refetchInterval: 10000
|
||||
});
|
||||
const unread = data?.unReadCount || 0;
|
||||
const importantInforms = data?.importantInforms || [];
|
||||
|
||||
const isHideNavbar = !!pcUnShowLayoutRoute[router.pathname];
|
||||
|
||||
@@ -117,6 +121,10 @@ const Layout = ({ children }: { children: JSX.Element }) => {
|
||||
|
||||
{!!userInfo && <UpdateInviteModal />}
|
||||
{isNotSufficientModal && !isHideNavbar && <NotSufficientModal />}
|
||||
{!!userInfo && <SystemMsgModal />}
|
||||
{!!userInfo && importantInforms.length > 0 && (
|
||||
<ImportantInform informs={importantInforms} refetch={refetchUnRead} />
|
||||
)}
|
||||
</Box>
|
||||
<Loading loading={loading} zIndex={999999} />
|
||||
</>
|
||||
|
||||
@@ -24,7 +24,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
|
||||
|
||||
return questionGuides.length > 0 ? (
|
||||
<Box mt={2}>
|
||||
<ChatBoxDivider icon="core/chat/QGFill" text={t('core.chat.Question Guide Tips')} />
|
||||
<ChatBoxDivider icon="core/chat/QGFill" text={t('core.chat.Question Guide')} />
|
||||
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
|
||||
{questionGuides.map((text) => (
|
||||
<Flex
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Menu, MenuList, MenuItem, Box, useOutsideClick, MenuButton } from '@chakra-ui/react';
|
||||
import {
|
||||
Menu,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Box,
|
||||
useOutsideClick,
|
||||
MenuButton,
|
||||
MenuItemProps
|
||||
} from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
type MenuItemType = 'primary' | 'danger';
|
||||
|
||||
interface Props {
|
||||
width?: number | string;
|
||||
offset?: [number, number];
|
||||
@@ -11,6 +21,7 @@ interface Props {
|
||||
isActive?: boolean;
|
||||
label: string | React.ReactNode;
|
||||
icon?: string;
|
||||
type?: MenuItemType;
|
||||
onClick: () => any;
|
||||
}[];
|
||||
}
|
||||
@@ -22,15 +33,25 @@ const MyMenu = ({
|
||||
Button,
|
||||
menuList
|
||||
}: Props) => {
|
||||
const menuItemStyles = {
|
||||
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
|
||||
primary: {
|
||||
_hover: {
|
||||
backgroundColor: 'primary.50',
|
||||
color: 'primary.600'
|
||||
}
|
||||
},
|
||||
danger: {
|
||||
_hover: {
|
||||
color: 'red.600',
|
||||
background: 'red.1'
|
||||
}
|
||||
}
|
||||
};
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 3,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.05',
|
||||
color: 'primary.600'
|
||||
}
|
||||
alignItems: 'center'
|
||||
};
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const closeTimer = useRef<any>();
|
||||
@@ -92,6 +113,7 @@ const MyMenu = ({
|
||||
<MenuItem
|
||||
key={i}
|
||||
{...menuItemStyles}
|
||||
{...typeMapStyle[item.type || 'primary']}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsOpen(false);
|
||||
|
||||
@@ -42,16 +42,17 @@ const SideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) =>
|
||||
borderRadius={'md'}
|
||||
px={3}
|
||||
mb={2}
|
||||
fontWeight={'medium'}
|
||||
alignItems={'center'}
|
||||
{...(activeId === item.id
|
||||
? {
|
||||
bg: ' primary.100 !important',
|
||||
fontWeight: 'bold',
|
||||
color: 'primary.600 ',
|
||||
cursor: 'default'
|
||||
}
|
||||
: {
|
||||
cursor: 'pointer'
|
||||
cursor: 'pointer',
|
||||
color: 'myGray.600'
|
||||
})}
|
||||
_hover={{
|
||||
bg: 'myGray.05'
|
||||
@@ -61,7 +62,7 @@ const SideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) =>
|
||||
onChange(item.id);
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={item.icon as IconNameType} w={'16px'} />
|
||||
<MyIcon mr={2} name={item.icon as IconNameType} w={'20px'} />
|
||||
{item.label}
|
||||
</Flex>
|
||||
))}
|
||||
|
||||
@@ -2,14 +2,22 @@ import React from 'react';
|
||||
import { Box, Flex, useTheme, Grid, type GridProps, theme, Image } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
list: { icon?: string; title: string | React.ReactNode; desc?: string; value: any }[];
|
||||
list: {
|
||||
icon?: string;
|
||||
title: string | React.ReactNode;
|
||||
desc?: string;
|
||||
value: any;
|
||||
forbidTip?: string; // If this value is exists, it will be prompted to disable when clicked
|
||||
}[];
|
||||
iconSize?: string;
|
||||
align?: 'top' | 'center';
|
||||
value: any;
|
||||
hiddenCircle?: boolean;
|
||||
|
||||
onChange: (e: any) => void;
|
||||
}
|
||||
|
||||
@@ -25,6 +33,8 @@ const MyRadio = ({
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
|
||||
return (
|
||||
<Grid gridGap={[3, 5]} fontSize={['sm', 'md']} {...props}>
|
||||
{list.map((item) => (
|
||||
@@ -73,7 +83,16 @@ const MyRadio = ({
|
||||
borderColor: 'myGray.200'
|
||||
})
|
||||
}}
|
||||
onClick={() => onChange(item.value)}
|
||||
onClick={() => {
|
||||
if (item.forbidTip) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: item.forbidTip
|
||||
});
|
||||
} else {
|
||||
onChange(item.value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!!item.icon && (
|
||||
<>
|
||||
|
||||
@@ -30,7 +30,8 @@ const RawSourceBox = ({ sourceId, sourceName = '', canView = true, ...props }: P
|
||||
shouldWrapChildren={false}
|
||||
>
|
||||
<Box
|
||||
color={'myGray.600'}
|
||||
color={'myGray.900'}
|
||||
fontWeight={'medium'}
|
||||
display={'inline-flex'}
|
||||
whiteSpace={'nowrap'}
|
||||
{...(canPreview
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, { Dispatch, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import ParentPaths from '@/components/common/ParentPaths';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
|
||||
type PathItemType = {
|
||||
parentId: string;
|
||||
@@ -17,6 +18,7 @@ const DatasetSelectContainer = ({
|
||||
paths,
|
||||
onClose,
|
||||
tips,
|
||||
isLoading,
|
||||
children
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
@@ -24,6 +26,7 @@ const DatasetSelectContainer = ({
|
||||
paths: PathItemType[];
|
||||
onClose: () => void;
|
||||
tips?: string | null;
|
||||
isLoading?: boolean;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -57,7 +60,9 @@ const DatasetSelectContainer = ({
|
||||
maxW={['90vw', '900px']}
|
||||
isCentered
|
||||
>
|
||||
{children}
|
||||
<MyBox isLoading={isLoading} h={'100%'}>
|
||||
{children}
|
||||
</MyBox>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -81,6 +81,8 @@ const DatasetParamsModal = ({
|
||||
const datasetSearchUsingCfrForm = watch('datasetSearchUsingExtensionQuery');
|
||||
const queryExtensionModel = watch('datasetSearchExtensionModel');
|
||||
const cfbBgDesc = watch('datasetSearchExtensionBg');
|
||||
const usingReRankWatch = watch('usingReRank');
|
||||
const searchModeWatch = watch('searchMode');
|
||||
|
||||
const chatModelSelectList = (() =>
|
||||
llmModelList
|
||||
@@ -97,16 +99,10 @@ const DatasetParamsModal = ({
|
||||
|
||||
const showSimilarity = useMemo(() => {
|
||||
if (similarity === undefined) return false;
|
||||
if (
|
||||
getValues('searchMode') === DatasetSearchModeEnum.fullTextRecall &&
|
||||
!getValues('usingReRank')
|
||||
)
|
||||
return false;
|
||||
if (getValues('searchMode') === DatasetSearchModeEnum.mixedRecall && !getValues('usingReRank'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}, [getValues, similarity]);
|
||||
if (usingReRankWatch) return true;
|
||||
if (searchModeWatch === DatasetSearchModeEnum.embedding) return true;
|
||||
return false;
|
||||
}, [searchModeWatch, similarity, usingReRankWatch]);
|
||||
|
||||
const showReRank = useMemo(() => {
|
||||
return usingReRank !== undefined && reRankModelList.length > 0;
|
||||
@@ -155,64 +151,57 @@ const DatasetParamsModal = ({
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
{showReRank && (
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
if (
|
||||
teamPlanStatus?.standardConstants &&
|
||||
!teamPlanStatus?.standardConstants?.permissionReRank
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('support.team.limit.No permission rerank')
|
||||
});
|
||||
<>
|
||||
<Divider my={4} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
py={3}
|
||||
pl={'14px'}
|
||||
pr={'16px'}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
position={'relative'}
|
||||
{...(getValues('usingReRank')
|
||||
? {
|
||||
borderColor: 'primary.400'
|
||||
}
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
: {})}
|
||||
onClick={(e) => {
|
||||
if (!showReRank) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('core.ai.Not deploy rerank model')
|
||||
});
|
||||
}
|
||||
if (
|
||||
teamPlanStatus?.standardConstants &&
|
||||
!teamPlanStatus?.standardConstants?.permissionReRank
|
||||
) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
title: t('support.team.limit.No permission rerank')
|
||||
});
|
||||
}
|
||||
setValue('usingReRank', !getValues('usingReRank'));
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
>
|
||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||
<Box>{t('core.dataset.search.ReRank')}</Box>
|
||||
<Box fontSize={['xs', 'sm']} color={'myGray.500'}>
|
||||
{t('core.dataset.search.ReRank desc')}
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox
|
||||
colorScheme="primary"
|
||||
isChecked={getValues('usingReRank')}
|
||||
size="lg"
|
||||
/>
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
left={0}
|
||||
zIndex={1}
|
||||
></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||
<Checkbox colorScheme="primary" isChecked={getValues('usingReRank')} size="lg" />
|
||||
<Box position={'absolute'} top={0} right={0} bottom={0} left={0} zIndex={1}></Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
{currentTabType === SearchSettingTabEnum.limit && (
|
||||
@@ -243,15 +232,15 @@ const DatasetParamsModal = ({
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{showSimilarity && (
|
||||
<Box display={['block', 'flex']} mt={10}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
<Box display={['block', 'flex']} mt={10}>
|
||||
<Box flex={'0 0 120px'} mb={[8, 0]}>
|
||||
{t('core.dataset.search.Min Similarity')}
|
||||
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Box flex={1} mx={4}>
|
||||
{showSimilarity ? (
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '0', value: 0 },
|
||||
@@ -266,9 +255,11 @@ const DatasetParamsModal = ({
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Box color={'myGray.500'}>{t('core.dataset.search.No support similarity')}</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
||||
|
||||
@@ -20,7 +20,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { moduleTemplatesList } from '@fastgpt/global/core/module/template/constants';
|
||||
import RowTabs from '@fastgpt/web/components/common/Tabs/RowTabs';
|
||||
import { useWorkflowStore } from '@/web/core/workflow/store/workflow';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import ParentPaths from '@/components/common/ParentPaths';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -70,7 +70,7 @@ const ModuleTemplateList = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
searchKey ? item.pluginType !== PluginTypeEnum.folder : true
|
||||
)
|
||||
};
|
||||
return map[templateType];
|
||||
return JSON.stringify(map[templateType]);
|
||||
}, [basicNodeTemplates, searchKey, systemNodeTemplates, teamPluginNodeTemplates, templateType]);
|
||||
|
||||
const { mutate: onChangeTab } = useRequest({
|
||||
@@ -96,120 +96,125 @@ const ModuleTemplateList = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
zIndex={2}
|
||||
display={isOpen ? 'block' : 'none'}
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
w={`${sliderWidth}px`}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<Flex
|
||||
zIndex={3}
|
||||
flexDirection={'column'}
|
||||
position={'absolute'}
|
||||
top={'10px'}
|
||||
left={0}
|
||||
pt={'20px'}
|
||||
pb={4}
|
||||
h={isOpen ? 'calc(100% - 20px)' : '0'}
|
||||
w={isOpen ? ['100%', `${sliderWidth}px`] : '0'}
|
||||
bg={'white'}
|
||||
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
|
||||
borderRadius={'0 20px 20px 0'}
|
||||
transition={'.2s ease'}
|
||||
userSelect={'none'}
|
||||
overflow={isOpen ? 'none' : 'hidden'}
|
||||
>
|
||||
<Box mb={2} pl={'20px'} pr={'10px'} whiteSpace={'nowrap'} overflow={'hidden'}>
|
||||
<Flex flex={'1 0 0'} alignItems={'center'} gap={3}>
|
||||
<RowTabs
|
||||
list={[
|
||||
{
|
||||
icon: 'core/modules/basicNode',
|
||||
label: t('core.module.template.Basic Node'),
|
||||
value: TemplateTypeEnum.basic
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/systemPlugin',
|
||||
label: t('core.module.template.System Plugin'),
|
||||
value: TemplateTypeEnum.systemPlugin
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/teamPlugin',
|
||||
label: t('core.module.template.Team Plugin'),
|
||||
value: TemplateTypeEnum.teamPlugin
|
||||
}
|
||||
]}
|
||||
py={'5px'}
|
||||
value={templateType}
|
||||
onChange={onChangeTab}
|
||||
/>
|
||||
{/* close icon */}
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'common/backFill'} w={'14px'} color={'myGray.700'} />}
|
||||
w={'26px'}
|
||||
h={'26px'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'grayBase'}
|
||||
aria-label={''}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</Flex>
|
||||
{templateType === TemplateTypeEnum.teamPlugin && (
|
||||
<Flex mt={2} alignItems={'center'} h={10}>
|
||||
<InputGroup mr={4} h={'full'}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon name={'common/searchLight'} w={'16px'} color={'myGray.500'} ml={3} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
h={'full'}
|
||||
bg={'myGray.50'}
|
||||
placeholder={t('plugin.Search plugin')}
|
||||
onChange={debounce((e) => setSearchKey(e.target.value), 200)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Box flex={1} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.600'
|
||||
}}
|
||||
onClick={() => router.push('/plugin/list')}
|
||||
>
|
||||
<Box>去创建</Box>
|
||||
<MyIcon name={'common/rightArrowLight'} w={'14px'} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{templateType === TemplateTypeEnum.teamPlugin && !searchKey && currentParent && (
|
||||
<Flex alignItems={'center'} mt={2}>
|
||||
<ParentPaths
|
||||
paths={[currentParent]}
|
||||
FirstPathDom={null}
|
||||
onClick={() => {
|
||||
setCurrentParent(undefined);
|
||||
}}
|
||||
fontSize="md"
|
||||
const Render = useMemo(() => {
|
||||
const parseTemplates = JSON.parse(templates) as FlowNodeTemplateType[];
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
zIndex={2}
|
||||
display={isOpen ? 'block' : 'none'}
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
w={`${sliderWidth}px`}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<Flex
|
||||
zIndex={3}
|
||||
flexDirection={'column'}
|
||||
position={'absolute'}
|
||||
top={'10px'}
|
||||
left={0}
|
||||
pt={'20px'}
|
||||
pb={4}
|
||||
h={isOpen ? 'calc(100% - 20px)' : '0'}
|
||||
w={isOpen ? ['100%', `${sliderWidth}px`] : '0'}
|
||||
bg={'white'}
|
||||
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
|
||||
borderRadius={'0 20px 20px 0'}
|
||||
transition={'.2s ease'}
|
||||
userSelect={'none'}
|
||||
overflow={isOpen ? 'none' : 'hidden'}
|
||||
>
|
||||
<Box mb={2} pl={'20px'} pr={'10px'} whiteSpace={'nowrap'} overflow={'hidden'}>
|
||||
<Flex flex={'1 0 0'} alignItems={'center'} gap={3}>
|
||||
<RowTabs
|
||||
list={[
|
||||
{
|
||||
icon: 'core/modules/basicNode',
|
||||
label: t('core.module.template.Basic Node'),
|
||||
value: TemplateTypeEnum.basic
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/systemPlugin',
|
||||
label: t('core.module.template.System Plugin'),
|
||||
value: TemplateTypeEnum.systemPlugin
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/teamPlugin',
|
||||
label: t('core.module.template.Team Plugin'),
|
||||
value: TemplateTypeEnum.teamPlugin
|
||||
}
|
||||
]}
|
||||
py={'5px'}
|
||||
value={templateType}
|
||||
onChange={onChangeTab}
|
||||
/>
|
||||
{/* close icon */}
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'common/backFill'} w={'14px'} color={'myGray.700'} />}
|
||||
w={'26px'}
|
||||
h={'26px'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'grayBase'}
|
||||
aria-label={''}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
<RenderList
|
||||
templates={templates}
|
||||
onClose={onClose}
|
||||
currentParent={currentParent}
|
||||
setCurrentParent={setCurrentParent}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
{templateType === TemplateTypeEnum.teamPlugin && (
|
||||
<Flex mt={2} alignItems={'center'} h={10}>
|
||||
<InputGroup mr={4} h={'full'}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon name={'common/searchLight'} w={'16px'} color={'myGray.500'} ml={3} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
h={'full'}
|
||||
bg={'myGray.50'}
|
||||
placeholder={t('plugin.Search plugin')}
|
||||
onChange={debounce((e) => setSearchKey(e.target.value), 200)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Box flex={1} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.600'
|
||||
}}
|
||||
onClick={() => router.push('/plugin/list')}
|
||||
>
|
||||
<Box>去创建</Box>
|
||||
<MyIcon name={'common/rightArrowLight'} w={'14px'} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{templateType === TemplateTypeEnum.teamPlugin && !searchKey && currentParent && (
|
||||
<Flex alignItems={'center'} mt={2}>
|
||||
<ParentPaths
|
||||
paths={[currentParent]}
|
||||
FirstPathDom={null}
|
||||
onClick={() => {
|
||||
setCurrentParent(undefined);
|
||||
}}
|
||||
fontSize="md"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
<RenderList
|
||||
templates={parseTemplates}
|
||||
onClose={onClose}
|
||||
currentParent={currentParent}
|
||||
setCurrentParent={setCurrentParent}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
}, [currentParent, isOpen, onChangeTab, onClose, router, searchKey, t, templateType, templates]);
|
||||
|
||||
return Render;
|
||||
};
|
||||
|
||||
export default React.memo(ModuleTemplateList);
|
||||
|
||||
@@ -40,11 +40,10 @@ const SelectAppModal = ({
|
||||
title={`选择应用${max > 1 ? `(${selectedApps.length}/${max})` : ''}`}
|
||||
iconSrc="/imgs/module/ai.svg"
|
||||
onClose={onClose}
|
||||
minW={'700px'}
|
||||
position={'relative'}
|
||||
w={'600px'}
|
||||
>
|
||||
<ModalBody
|
||||
minH={'300px'}
|
||||
display={'grid'}
|
||||
gridTemplateColumns={['1fr', 'repeat(3, minmax(0, 1fr))']}
|
||||
gridGap={4}
|
||||
|
||||
@@ -5,12 +5,13 @@ import { Box, Flex, Switch, type SwitchProps } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
// question generator switch
|
||||
const QGSwitch = (props: SwitchProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={'core/app/questionGuide'} mr={2} w={'20px'} />
|
||||
<Box>{t('core.app.Next Step Guide')}</Box>
|
||||
<MyIcon name={'core/chat/QGFill'} mr={2} w={'20px'} />
|
||||
<Box>{t('core.app.Question Guide')}</Box>
|
||||
<MyTooltip label={t('core.app.Question Guide Tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
|
||||
@@ -124,12 +124,12 @@ const VariableEdit = ({
|
||||
<TableContainer>
|
||||
<Table bg={'white'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th w={'18px !important'} p={0} bg={'myGray.50'} />
|
||||
<Th bg={'myGray.50'}>{t('core.module.variable.variable name')}</Th>
|
||||
<Th bg={'myGray.50'}>{t('core.module.variable.key')}</Th>
|
||||
<Th bg={'myGray.50'}>{t('common.Require Input')}</Th>
|
||||
<Th bg={'myGray.50'}></Th>
|
||||
<Tr bg={'myGray.50'}>
|
||||
<Th w={'18px !important'} p={0} />
|
||||
<Th>{t('core.module.variable.variable name')}</Th>
|
||||
<Th>{t('core.module.variable.key')}</Th>
|
||||
<Th>{t('common.Require Input')}</Th>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box, Button, Flex, Textarea } from '@chakra-ui/react';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
@@ -16,93 +16,69 @@ import { useTranslation } from 'next-i18next';
|
||||
import SourceHandle from '../render/SourceHandle';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { onChangeNode } from '../../FlowProvider';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
|
||||
const NodeCQNode = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { moduleId, inputs } = data;
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
<Divider text={t('common.Input')} />
|
||||
<Container>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
[ModuleInputKeyEnum.agents]: ({ key: agentKey, value = [], ...props }) => {
|
||||
const agents = value as ClassifyQuestionAgentItemType[];
|
||||
return (
|
||||
<Box>
|
||||
{agents.map((item, i) => (
|
||||
<Box key={item.key} mb={4}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyTooltip label={t('common.Delete')}>
|
||||
<MyIcon
|
||||
mt={1}
|
||||
mr={2}
|
||||
name={'minus'}
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
color={'myGray.600'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
onClick={() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: agents.filter((input) => input.key !== item.key)
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delOutput',
|
||||
key: item.key
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<Box flex={1}>分类{i + 1}</Box>
|
||||
</Flex>
|
||||
<Box position={'relative'}>
|
||||
<Textarea
|
||||
rows={2}
|
||||
mt={1}
|
||||
defaultValue={item.value}
|
||||
onChange={(e) => {
|
||||
const newVal = agents.map((val) =>
|
||||
val.key === item.key
|
||||
? {
|
||||
...val,
|
||||
value: e.target.value
|
||||
}
|
||||
: val
|
||||
);
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: newVal
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SourceHandle
|
||||
handleKey={item.key}
|
||||
valueType={ModuleIOValueTypeEnum.boolean}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
<Button
|
||||
onClick={() => {
|
||||
const key = nanoid();
|
||||
|
||||
const CustomComponent = useMemo(
|
||||
() => ({
|
||||
[ModuleInputKeyEnum.agents]: ({
|
||||
key: agentKey,
|
||||
value = [],
|
||||
...props
|
||||
}: FlowNodeInputItemType) => {
|
||||
const agents = value as ClassifyQuestionAgentItemType[];
|
||||
return (
|
||||
<Box>
|
||||
{agents.map((item, i) => (
|
||||
<Box key={item.key} mb={4}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyTooltip label={t('common.Delete')}>
|
||||
<MyIcon
|
||||
mt={1}
|
||||
mr={2}
|
||||
name={'minus'}
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
color={'myGray.600'}
|
||||
_hover={{ color: 'red.600' }}
|
||||
onClick={() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: agents.filter((input) => input.key !== item.key)
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delOutput',
|
||||
key: item.key
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<Box flex={1}>分类{i + 1}</Box>
|
||||
</Flex>
|
||||
<Box position={'relative'}>
|
||||
<Textarea
|
||||
rows={2}
|
||||
mt={1}
|
||||
defaultValue={item.value}
|
||||
onChange={(e) => {
|
||||
const newVal = agents.map((val) =>
|
||||
val.key === item.key
|
||||
? {
|
||||
...val,
|
||||
value: e.target.value
|
||||
}
|
||||
: val
|
||||
);
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
@@ -110,29 +86,56 @@ const NodeCQNode = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: agents.concat({ value: '', key })
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'addOutput',
|
||||
value: {
|
||||
key,
|
||||
label: '',
|
||||
type: FlowNodeOutputTypeEnum.hidden,
|
||||
targets: []
|
||||
value: newVal
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t('core.module.Add question type')}
|
||||
</Button>
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={ModuleIOValueTypeEnum.boolean} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
<Button
|
||||
onClick={() => {
|
||||
const key = nanoid();
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: agentKey,
|
||||
value: {
|
||||
...props,
|
||||
key: agentKey,
|
||||
value: agents.concat({ value: '', key })
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'addOutput',
|
||||
value: {
|
||||
key,
|
||||
label: '',
|
||||
type: FlowNodeOutputTypeEnum.hidden,
|
||||
targets: []
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t('core.module.Add question type')}
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}),
|
||||
[moduleId, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
<Divider text={t('common.Input')} />
|
||||
<Container>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} CustomComponent={CustomComponent} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ import SourceHandle from '../render/SourceHandle';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
|
||||
const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -27,7 +28,10 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowModuleItemType>) =>
|
||||
const { nodes } = useFlowProviderStore();
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
const quotes = inputs.filter((item) => item.valueType === ModuleIOValueTypeEnum.datasetQuote);
|
||||
const quotes = useMemo(
|
||||
() => inputs.filter((item) => item.valueType === ModuleIOValueTypeEnum.datasetQuote),
|
||||
[inputs]
|
||||
);
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
let maxTokens = 3000;
|
||||
@@ -46,8 +50,8 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowModuleItemType>) =>
|
||||
return maxTokens;
|
||||
}, [llmModelList, nodes]);
|
||||
|
||||
const RenderQuoteList = useMemo(
|
||||
() => (
|
||||
const RenderQuoteList = useMemo(() => {
|
||||
return (
|
||||
<Box>
|
||||
<Box>
|
||||
{quotes.map((quote, i) => (
|
||||
@@ -88,45 +92,45 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowModuleItemType>) =>
|
||||
{t('core.module.Dataset quote.Add quote')}
|
||||
</Button>
|
||||
</Box>
|
||||
),
|
||||
[moduleId, quotes, t]
|
||||
);
|
||||
);
|
||||
}, [moduleId, quotes, t]);
|
||||
|
||||
const CustomComponent = useMemo(() => {
|
||||
console.log(111);
|
||||
return {
|
||||
[ModuleInputKeyEnum.datasetMaxTokens]: (item: FlowNodeInputItemType) => (
|
||||
<Box px={2}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: tokenLimit, value: tokenLimit }
|
||||
]}
|
||||
width={'100%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
};
|
||||
}, [moduleId, tokenLimit]);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} selected={selected} {...data}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'} position={'relative'}>
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
flowInputList={inputs}
|
||||
CustomComponent={{
|
||||
[ModuleInputKeyEnum.datasetMaxTokens]: (item) => (
|
||||
<Box px={2}>
|
||||
<MySlider
|
||||
markList={[
|
||||
{ label: '100', value: 100 },
|
||||
{ label: tokenLimit, value: tokenLimit }
|
||||
]}
|
||||
width={'100%'}
|
||||
min={100}
|
||||
max={tokenLimit}
|
||||
step={50}
|
||||
value={item.value}
|
||||
onChange={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} CustomComponent={CustomComponent} />
|
||||
{/* render dataset select */}
|
||||
{RenderQuoteList}
|
||||
<Flex position={'absolute'} right={4} top={'60%'}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -28,6 +28,7 @@ import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constan
|
||||
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../FlowProvider';
|
||||
import RenderToolInput from '../../render/RenderToolInput';
|
||||
import { FlowNodeInputItemType } from '../../../../../../../../../../packages/global/core/module/node/type';
|
||||
|
||||
const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { inputs, outputs, moduleId } = data;
|
||||
@@ -36,6 +37,99 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
||||
|
||||
const CustomComponent = useMemo(
|
||||
() => ({
|
||||
[ModuleInputKeyEnum.extractKeys]: ({
|
||||
value: extractKeys = [],
|
||||
...props
|
||||
}: Omit<FlowNodeInputItemType, 'value'> & {
|
||||
value?: ContextExtractAgentItemType[];
|
||||
}) => (
|
||||
<Box>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'1 0 0'}>{t('core.module.extract.Target field')}</Box>
|
||||
<Button
|
||||
size={'sm'}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<AddIcon fontSize={'10px'} />}
|
||||
onClick={() => setEditExtractField(defaultField)}
|
||||
>
|
||||
{t('core.module.extract.Add field')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Box
|
||||
mt={2}
|
||||
borderRadius={'md'}
|
||||
overflow={'hidden'}
|
||||
borderWidth={'1px'}
|
||||
borderBottom="none"
|
||||
>
|
||||
<TableContainer>
|
||||
<Table bg={'white'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th bg={'myGray.50'}>字段 key</Th>
|
||||
<Th bg={'myGray.50'}>字段描述</Th>
|
||||
<Th bg={'myGray.50'}>必须</Th>
|
||||
<Th bg={'myGray.50'}></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{extractKeys.map((item, index) => (
|
||||
<Tr
|
||||
key={index}
|
||||
position={'relative'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-all'}
|
||||
>
|
||||
<Td>{item.key}</Td>
|
||||
<Td>{item.desc}</Td>
|
||||
<Td>{item.required ? '✔' : ''}</Td>
|
||||
<Td whiteSpace={'nowrap'}>
|
||||
<MyIcon
|
||||
mr={3}
|
||||
name={'common/settingLight'}
|
||||
w={'16px'}
|
||||
cursor={'pointer'}
|
||||
onClick={() => {
|
||||
setEditExtractField(item);
|
||||
}}
|
||||
/>
|
||||
<MyIcon
|
||||
name={'delete'}
|
||||
w={'16px'}
|
||||
cursor={'pointer'}
|
||||
onClick={() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.extractKeys,
|
||||
value: {
|
||||
...props,
|
||||
value: extractKeys.filter((extract) => item.key !== extract.key)
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delOutput',
|
||||
key: item.key
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}),
|
||||
[moduleId, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} {...data}>
|
||||
{toolInputs.length > 0 && (
|
||||
@@ -52,97 +146,7 @@ const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
<RenderInput
|
||||
moduleId={moduleId}
|
||||
flowInputList={commonInputs}
|
||||
CustomComponent={{
|
||||
[ModuleInputKeyEnum.extractKeys]: ({
|
||||
value: extractKeys = [],
|
||||
...props
|
||||
}: {
|
||||
value?: ContextExtractAgentItemType[];
|
||||
}) => (
|
||||
<Box>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'1 0 0'}>{t('core.module.extract.Target field')}</Box>
|
||||
<Button
|
||||
size={'sm'}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<AddIcon fontSize={'10px'} />}
|
||||
onClick={() => setEditExtractField(defaultField)}
|
||||
>
|
||||
{t('core.module.extract.Add field')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Box
|
||||
mt={2}
|
||||
borderRadius={'md'}
|
||||
overflow={'hidden'}
|
||||
borderWidth={'1px'}
|
||||
borderBottom="none"
|
||||
>
|
||||
<TableContainer>
|
||||
<Table bg={'white'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th bg={'myGray.50'}>字段 key</Th>
|
||||
<Th bg={'myGray.50'}>字段描述</Th>
|
||||
<Th bg={'myGray.50'}>必须</Th>
|
||||
<Th bg={'myGray.50'}></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{extractKeys.map((item, index) => (
|
||||
<Tr
|
||||
key={index}
|
||||
position={'relative'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-all'}
|
||||
>
|
||||
<Td>{item.key}</Td>
|
||||
<Td>{item.desc}</Td>
|
||||
<Td>{item.required ? '✔' : ''}</Td>
|
||||
<Td whiteSpace={'nowrap'}>
|
||||
<MyIcon
|
||||
mr={3}
|
||||
name={'common/settingLight'}
|
||||
w={'16px'}
|
||||
cursor={'pointer'}
|
||||
onClick={() => {
|
||||
setEditExtractField(item);
|
||||
}}
|
||||
/>
|
||||
<MyIcon
|
||||
name={'delete'}
|
||||
w={'16px'}
|
||||
cursor={'pointer'}
|
||||
onClick={() => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.extractKeys,
|
||||
value: {
|
||||
...props,
|
||||
value: extractKeys.filter(
|
||||
(extract) => item.key !== extract.key
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'delOutput',
|
||||
key: item.key
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}}
|
||||
CustomComponent={CustomComponent}
|
||||
/>
|
||||
</Container>
|
||||
</>
|
||||
|
||||
@@ -6,8 +6,8 @@ import { onChangeNode } from '../../../FlowProvider';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import yaml from 'js-yaml';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import parse from '@bany/curl-to-json';
|
||||
|
||||
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
||||
const methodMap: { [K in RequestMethod]: string } = {
|
||||
@@ -18,20 +18,19 @@ const methodMap: { [K in RequestMethod]: string } = {
|
||||
patch: 'PATCH'
|
||||
};
|
||||
|
||||
const OpenApiImportModal = ({
|
||||
children,
|
||||
const CurlImportModal = ({
|
||||
moduleId,
|
||||
inputs
|
||||
inputs,
|
||||
onClose
|
||||
}: {
|
||||
children: React.ReactElement;
|
||||
moduleId: string;
|
||||
inputs: FlowNodeInputItemType[];
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { t } = useTranslation();
|
||||
const { register, handleSubmit } = useForm({
|
||||
defaultValues: {
|
||||
openapiContent: ''
|
||||
curlContent: ''
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,60 +38,36 @@ const OpenApiImportModal = ({
|
||||
|
||||
const handleFileProcessing = async (content: string) => {
|
||||
try {
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(content);
|
||||
} catch (jsonError) {
|
||||
try {
|
||||
data = yaml.load(content, { schema: yaml.FAILSAFE_SCHEMA });
|
||||
} catch (yamlError) {
|
||||
console.error(yamlError);
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
const firstPathName = Object.keys(data.paths)[0];
|
||||
const firstPathData = data.paths[firstPathName];
|
||||
const firstRequestMethod = Object.keys(firstPathData)[0];
|
||||
const firstRequestMethodData = firstPathData[firstRequestMethod];
|
||||
const firstRequestParameters = firstRequestMethodData.parameters || [];
|
||||
|
||||
const pathParams = [];
|
||||
const headerParams = [];
|
||||
for (const parameter of firstRequestParameters) {
|
||||
if (parameter.in === 'path') {
|
||||
pathParams.push({
|
||||
key: parameter.name,
|
||||
type: parameter.schema.type
|
||||
});
|
||||
} else {
|
||||
headerParams.push({
|
||||
key: parameter.name,
|
||||
type: parameter.schema.type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const requestBodySchema =
|
||||
firstRequestMethodData.requestBody?.content?.['application/json']?.schema;
|
||||
let requestBodyValue = '';
|
||||
if (requestBodySchema) {
|
||||
requestBodyValue = JSON.stringify(requestBodySchema, null, 2);
|
||||
}
|
||||
|
||||
const requestUrl = inputs.find((item) => item.key === ModuleInputKeyEnum.httpReqUrl);
|
||||
const requestMethod = inputs.find((item) => item.key === ModuleInputKeyEnum.httpMethod);
|
||||
const params = inputs.find((item) => item.key === ModuleInputKeyEnum.httpParams);
|
||||
const headers = inputs.find((item) => item.key === ModuleInputKeyEnum.httpHeaders);
|
||||
const jsonBody = inputs.find((item) => item.key === ModuleInputKeyEnum.httpJsonBody);
|
||||
|
||||
const parsed = parse(content);
|
||||
if (!parsed.url) {
|
||||
throw new Error('url not found');
|
||||
}
|
||||
|
||||
const newParams = Object.keys(parsed.params || {}).map((key) => ({
|
||||
key,
|
||||
value: parsed.params?.[key],
|
||||
type: 'string'
|
||||
}));
|
||||
const newHeaders = Object.keys(parsed.header || {}).map((key) => ({
|
||||
key,
|
||||
value: parsed.header?.[key],
|
||||
type: 'string'
|
||||
}));
|
||||
const newBody = JSON.stringify(parsed.data, null, 2);
|
||||
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: ModuleInputKeyEnum.httpReqUrl,
|
||||
value: {
|
||||
...requestUrl,
|
||||
value: firstPathName
|
||||
value: parsed.url
|
||||
}
|
||||
});
|
||||
|
||||
@@ -102,7 +77,7 @@ const OpenApiImportModal = ({
|
||||
key: ModuleInputKeyEnum.httpMethod,
|
||||
value: {
|
||||
...requestMethod,
|
||||
value: methodMap[firstRequestMethod.toLowerCase() as RequestMethod] || 'GET'
|
||||
value: methodMap[parsed.method?.toLowerCase() as RequestMethod] || 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -112,7 +87,7 @@ const OpenApiImportModal = ({
|
||||
key: ModuleInputKeyEnum.httpParams,
|
||||
value: {
|
||||
...params,
|
||||
value: pathParams
|
||||
value: newParams
|
||||
}
|
||||
});
|
||||
|
||||
@@ -122,7 +97,7 @@ const OpenApiImportModal = ({
|
||||
key: ModuleInputKeyEnum.httpHeaders,
|
||||
value: {
|
||||
...headers,
|
||||
value: headerParams
|
||||
value: newHeaders
|
||||
}
|
||||
});
|
||||
|
||||
@@ -132,7 +107,7 @@ const OpenApiImportModal = ({
|
||||
key: ModuleInputKeyEnum.httpJsonBody,
|
||||
value: {
|
||||
...jsonBody,
|
||||
value: requestBodyValue
|
||||
value: newBody
|
||||
}
|
||||
});
|
||||
|
||||
@@ -153,33 +128,28 @@ const OpenApiImportModal = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{children && <Box onClick={onOpen}>{children}</Box>}
|
||||
<MyModal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
iconSrc="modal/edit"
|
||||
title={t('common.Import')}
|
||||
m={'auto'}
|
||||
w={500}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
height={400}
|
||||
maxH={500}
|
||||
mt={2}
|
||||
{...register('openapiContent')}
|
||||
placeholder={t('core.module.http.OpenAPI import placeholder')}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={handleSubmit((data) => handleFileProcessing(data.openapiContent))}>
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
</>
|
||||
<MyModal
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
iconSrc="modal/edit"
|
||||
title={t('core.module.http.curl import')}
|
||||
w={600}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
rows={20}
|
||||
mt={2}
|
||||
{...register('curlContent')}
|
||||
placeholder={t('core.module.http.curl import placeholder')}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={handleSubmit((data) => handleFileProcessing(data.curlContent))}>
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(OpenApiImportModal);
|
||||
export default React.memo(CurlImportModal);
|
||||
@@ -17,7 +17,8 @@ import {
|
||||
Th,
|
||||
Td,
|
||||
TableContainer,
|
||||
Button
|
||||
Button,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../FlowProvider';
|
||||
@@ -39,7 +40,7 @@ import HttpInput from '@fastgpt/web/components/common/Input/HttpInput';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import RenderToolInput from '../../render/RenderToolInput';
|
||||
const OpenApiImportModal = dynamic(() => import('./OpenApiImportModal'));
|
||||
const CurlImportModal = dynamic(() => import('./CurlImportModal'));
|
||||
|
||||
export const HttpHeaders = [
|
||||
{ key: 'A-IM', label: 'A-IM' },
|
||||
@@ -104,6 +105,8 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
const { toast } = useToast();
|
||||
const [_, startSts] = useTransition();
|
||||
|
||||
const { isOpen: isOpenCurl, onOpen: onOpenCurl, onClose: onCloseCurl } = useDisclosure();
|
||||
|
||||
const requestMethods = inputs.find((item) => item.key === ModuleInputKeyEnum.httpMethod);
|
||||
const requestUrl = inputs.find((item) => item.key === ModuleInputKeyEnum.httpReqUrl);
|
||||
|
||||
@@ -180,11 +183,9 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
<Box>
|
||||
<Box mb={2} display={'flex'} justifyContent={'space-between'}>
|
||||
<Box>{t('core.module.Http request settings')}</Box>
|
||||
<Box>
|
||||
<OpenApiImportModal moduleId={moduleId} inputs={inputs}>
|
||||
<Button variant={'link'}>{t('core.module.http.OpenAPI import')}</Button>
|
||||
</OpenApiImportModal>
|
||||
</Box>
|
||||
<Button variant={'link'} onClick={onOpenCurl}>
|
||||
{t('core.module.http.curl import')}
|
||||
</Button>
|
||||
</Box>
|
||||
<Flex alignItems={'center'} className="nodrag">
|
||||
<MySelect
|
||||
@@ -228,16 +229,18 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
flex={'1 0 0'}
|
||||
ml={2}
|
||||
h={'34px'}
|
||||
value={requestUrl?.value}
|
||||
placeholder={t('core.module.input.label.Http Request Url')}
|
||||
fontSize={'xs'}
|
||||
w={'350px'}
|
||||
onChange={onChangeUrl}
|
||||
onBlur={onBlurUrl}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
{isOpenCurl && <CurlImportModal moduleId={moduleId} inputs={inputs} onClose={onCloseCurl} />}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const NodeRunAPP = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
return (
|
||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
<Divider text={t('common.Output')} />
|
||||
<Container>
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
export default React.memo(NodeRunAPP);
|
||||
@@ -9,6 +9,7 @@ import RenderOutput from '../render/RenderOutput';
|
||||
import RenderToolInput from '../render/RenderToolInput';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../../FlowProvider';
|
||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
|
||||
const NodeSimple = ({
|
||||
data,
|
||||
@@ -44,7 +45,7 @@ const NodeSimple = ({
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
{outputs.length > 0 && (
|
||||
{outputs.filter((output) => output.type !== FlowNodeOutputTypeEnum.hidden).length > 0 && (
|
||||
<>
|
||||
<Divider text={t('common.Output')} />
|
||||
<Container>
|
||||
|
||||
@@ -21,10 +21,6 @@ const NodeTools = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
|
||||
<Divider text={t('common.Output')} />
|
||||
<Container>
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
<Box position={'relative'}>
|
||||
<Box borderBottomLeftRadius={'md'} borderBottomRadius={'md'} overflow={'hidden'}>
|
||||
<Divider showBorderBottom={false} text={t('core.module.template.Tool module')} />
|
||||
|
||||
@@ -22,7 +22,7 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<>
|
||||
<NodeCard minW={'300px'} selected={selected} {...data}>
|
||||
<NodeCard minW={'300px'} selected={selected} forbidMenu {...data}>
|
||||
<Container className="nodrag" borderTop={'2px solid'} borderTopColor={'myGray.200'}>
|
||||
<WelcomeText data={data} />
|
||||
<Box pt={4} pb={2}>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { getPreviewPluginModule } from '@/web/core/plugin/api';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { ToolTargetHandle } from './ToolHandle';
|
||||
import { useEditTextarea } from '@fastgpt/web/hooks/useEditTextarea';
|
||||
|
||||
@@ -13,6 +13,10 @@ const RenderList: {
|
||||
types: `${FlowNodeInputTypeEnum}`[];
|
||||
Component: React.ComponentType<RenderInputProps>;
|
||||
}[] = [
|
||||
{
|
||||
types: [FlowNodeInputTypeEnum.triggerAndFinish],
|
||||
Component: dynamic(() => import('./templates/TriggerAndFinish'))
|
||||
},
|
||||
{
|
||||
types: [FlowNodeInputTypeEnum.input],
|
||||
Component: dynamic(() => import('./templates/TextInput'))
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { getFlowStore, onChangeNode, useFlowProviderStoreType } from '../../../../FlowProvider';
|
||||
import { onChangeNode, useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/module/type';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import SelectAppModal from '../../../../SelectAppModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const SelectAppRender = ({ item, moduleId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const [filterAppIds, setFilterAppIds] = useState<useFlowProviderStoreType['filterAppIds']>([]);
|
||||
const { filterAppIds } = useFlowProviderStore();
|
||||
|
||||
const {
|
||||
isOpen: isOpenSelectApp,
|
||||
@@ -18,50 +20,65 @@ const SelectAppRender = ({ item, moduleId }: RenderInputProps) => {
|
||||
|
||||
const value = item.value as SelectAppItemType | undefined;
|
||||
|
||||
useEffect(() => {
|
||||
async () => {
|
||||
const { filterAppIds } = await getFlowStore();
|
||||
setFilterAppIds(filterAppIds);
|
||||
};
|
||||
}, []);
|
||||
const filterAppString = useMemo(() => filterAppIds.join(','), [filterAppIds]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box onClick={onOpenSelectApp}>
|
||||
{!value ? (
|
||||
<Button variant={'whitePrimary'} w={'100%'}>
|
||||
选择应用
|
||||
</Button>
|
||||
) : (
|
||||
<Flex alignItems={'center'} border={theme.borders.base} borderRadius={'md'} px={3} py={2}>
|
||||
<Avatar src={value?.logo} />
|
||||
<Box fontWeight={'bold'} ml={1}>
|
||||
{value?.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
<Box onClick={onOpenSelectApp}>
|
||||
{!value ? (
|
||||
<Button variant={'whitePrimary'} w={'100%'}>
|
||||
{t('core.module.Select app')}
|
||||
</Button>
|
||||
) : (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
border={theme.borders.base}
|
||||
borderRadius={'md'}
|
||||
px={3}
|
||||
py={2}
|
||||
>
|
||||
<Avatar src={value?.logo} />
|
||||
<Box fontWeight={'bold'} ml={1}>
|
||||
{value?.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{isOpenSelectApp && (
|
||||
<SelectAppModal
|
||||
defaultApps={item.value?.id ? [item.value.id] : []}
|
||||
filterAppIds={filterAppString.split(',')}
|
||||
onClose={onCloseSelectApp}
|
||||
onSuccess={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: 'app',
|
||||
value: {
|
||||
...item,
|
||||
value: e[0]
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
filterAppString,
|
||||
isOpenSelectApp,
|
||||
item,
|
||||
moduleId,
|
||||
onCloseSelectApp,
|
||||
onOpenSelectApp,
|
||||
t,
|
||||
theme.borders.base,
|
||||
value
|
||||
]);
|
||||
|
||||
{isOpenSelectApp && (
|
||||
<SelectAppModal
|
||||
defaultApps={item.value?.id ? [item.value.id] : []}
|
||||
filterAppIds={filterAppIds}
|
||||
onClose={onCloseSelectApp}
|
||||
onSuccess={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'updateInput',
|
||||
key: 'app',
|
||||
value: {
|
||||
...item,
|
||||
value: e[0]
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return Render;
|
||||
};
|
||||
|
||||
export default React.memo(SelectAppRender);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import React, { useMemo } 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';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
|
||||
const TriggerAndFinish = ({ moduleId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodes } = useFlowProviderStore();
|
||||
|
||||
const outputs = useMemo(
|
||||
() => nodes.find((node) => node.data.moduleId === moduleId)?.data?.outputs || [],
|
||||
[moduleId, nodes]
|
||||
);
|
||||
const hasFinishOutput = useMemo(
|
||||
() => outputs.some((output) => output.key === ModuleOutputKeyEnum.finish),
|
||||
[outputs]
|
||||
);
|
||||
|
||||
const Render = useMemo(
|
||||
() => (
|
||||
<Flex
|
||||
className="nodrag"
|
||||
cursor={'default'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'space-between'}
|
||||
position={'relative'}
|
||||
>
|
||||
<Box position={'relative'}>
|
||||
<TargetHandle handleKey={ModuleInputKeyEnum.switch} valueType={'any'} />
|
||||
{t('core.module.input.label.switch')}
|
||||
</Box>
|
||||
{hasFinishOutput && (
|
||||
<Box position={'relative'}>
|
||||
{t('core.module.output.label.running done')}
|
||||
<SourceHandle handleKey={ModuleOutputKeyEnum.finish} valueType={'boolean'} />
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
),
|
||||
[hasFinishOutput, t]
|
||||
);
|
||||
|
||||
return Render;
|
||||
};
|
||||
|
||||
export default React.memo(TriggerAndFinish);
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { defaultEditFormData } from './constants';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { onChangeNode } from '../../../FlowProvider';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
|
||||
|
||||
@@ -14,39 +14,40 @@ import { useCallback } from 'react';
|
||||
type ToolHandleProps = BoxProps & {
|
||||
moduleId: string;
|
||||
};
|
||||
export const ToolTargetHandle = ({ moduleId, ...props }: ToolHandleProps) => {
|
||||
export const ToolTargetHandle = ({ moduleId }: ToolHandleProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const valueTypeMap = FlowValueTypeMap[ModuleIOValueTypeEnum.tools];
|
||||
|
||||
return (
|
||||
<Box position={'absolute'} left={'50%'} transform={'translate(-17px,-10px)'} {...props}>
|
||||
<MyTooltip
|
||||
label={t('app.module.type', {
|
||||
type: t(valueTypeMap?.label),
|
||||
description: valueTypeMap?.description
|
||||
})}
|
||||
<MyTooltip
|
||||
label={t('app.module.type', {
|
||||
type: t(valueTypeMap?.label),
|
||||
description: valueTypeMap?.description
|
||||
})}
|
||||
shouldWrapChildren={false}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
borderRadius: '0',
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
type="target"
|
||||
id={ModuleOutputKeyEnum.selectedTools}
|
||||
position={Position.Top}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
width: '14px',
|
||||
height: '14px',
|
||||
border: '4px solid #5E8FFF',
|
||||
borderRadius: '0',
|
||||
backgroundColor: 'transparent',
|
||||
transformOrigin: 'center',
|
||||
transform: 'rotate(45deg)'
|
||||
}}
|
||||
type="target"
|
||||
id={ModuleOutputKeyEnum.selectedTools}
|
||||
position={Position.Top}
|
||||
<Box
|
||||
w={'14px'}
|
||||
h={'14px'}
|
||||
border={'4px solid #5E8FFF'}
|
||||
transform={'translate(-40%,-30%) rotate(45deg)'}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
</Handle>
|
||||
</MyTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export const ToolSourceHandle = ({ moduleId, ...props }: ToolHandleProps) => {
|
||||
export const ToolSourceHandle = ({ moduleId }: ToolHandleProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { setEdges, nodes } = useFlowProviderStore();
|
||||
|
||||
@@ -75,29 +76,30 @@ export const ToolSourceHandle = ({ moduleId, ...props }: ToolHandleProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Box position={'absolute'} left={'50%'} transform={'translate(-16px,-14px)'} {...props}>
|
||||
<MyTooltip
|
||||
label={t('app.module.type', {
|
||||
type: t(valueTypeMap?.label),
|
||||
description: valueTypeMap?.description
|
||||
})}
|
||||
<MyTooltip
|
||||
label={t('app.module.type', {
|
||||
type: t(valueTypeMap?.label),
|
||||
description: valueTypeMap?.description
|
||||
})}
|
||||
shouldWrapChildren={false}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
borderRadius: '0',
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
type="source"
|
||||
id={ModuleOutputKeyEnum.selectedTools}
|
||||
position={Position.Bottom}
|
||||
onConnect={onConnect}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
width: '14px',
|
||||
height: '14px',
|
||||
border: '4px solid #5E8FFF',
|
||||
borderRadius: '0',
|
||||
backgroundColor: 'transparent',
|
||||
transformOrigin: 'center',
|
||||
transform: 'rotate(45deg)'
|
||||
}}
|
||||
type="source"
|
||||
id={ModuleOutputKeyEnum.selectedTools}
|
||||
position={Position.Bottom}
|
||||
onConnect={onConnect}
|
||||
<Box
|
||||
w={'14px'}
|
||||
h={'14px'}
|
||||
border={'4px solid #5E8FFF'}
|
||||
transform={'translate(-40%,-30%) rotate(45deg)'}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
</Handle>
|
||||
</MyTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,7 +18,8 @@ import {
|
||||
MenuList,
|
||||
MenuItem,
|
||||
MenuButton,
|
||||
Menu
|
||||
Menu,
|
||||
IconButton
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
getOpenApiKeys,
|
||||
@@ -37,10 +38,11 @@ import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import MyMenu from '@/components/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
|
||||
type EditProps = EditApiKeyProps & { _id?: string };
|
||||
const defaultEditData: EditProps = {
|
||||
@@ -59,6 +61,10 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
const [baseUrl, setBaseUrl] = useState('https://fastgpt.in/api');
|
||||
const [editData, setEditData] = useState<EditProps>();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
type: 'delete',
|
||||
content: '确认删除该API密钥?删除后该密钥立即失效,对应的对话日志不会删除,请确认!'
|
||||
});
|
||||
|
||||
const { mutate: onclickRemove, isLoading: isDeleting } = useMutation({
|
||||
mutationFn: async (id: string) => delOpenApiById(id),
|
||||
@@ -181,13 +187,12 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
<MyMenu
|
||||
offset={[-50, 5]}
|
||||
Button={
|
||||
<MyIcon
|
||||
<IconButton
|
||||
icon={<MyIcon name={'more'} w={'14px'} />}
|
||||
name={'more'}
|
||||
w={'14px'}
|
||||
p={2}
|
||||
_hover={{ bg: 'myWhite.600 ' }}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
variant={'whitePrimary'}
|
||||
size={'sm'}
|
||||
aria-label={''}
|
||||
/>
|
||||
}
|
||||
menuList={[
|
||||
@@ -205,7 +210,8 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
{
|
||||
label: t('common.Delete'),
|
||||
icon: 'delete',
|
||||
onClick: () => onclickRemove(_id)
|
||||
type: 'danger',
|
||||
onClick: openConfirm(() => onclickRemove(_id))
|
||||
}
|
||||
]}
|
||||
/>
|
||||
@@ -216,6 +222,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
</Table>
|
||||
<Loading loading={isGetting || isDeleting} fixed={false} />
|
||||
</TableContainer>
|
||||
|
||||
{!!editData && (
|
||||
<EditKeyModal
|
||||
defaultData={editData}
|
||||
@@ -231,6 +238,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<ConfirmModal />
|
||||
<MyModal
|
||||
isOpen={!!apiKey}
|
||||
w={['400px', '600px']}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import React from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import { readInform } from '@/web/support/user/inform/api';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
const ImportantInform = ({
|
||||
informs,
|
||||
refetch
|
||||
}: {
|
||||
informs: UserInformSchema[];
|
||||
refetch: () => void;
|
||||
}) => {
|
||||
const { mutate: onClickClose } = useRequest({
|
||||
mutationFn: async (id: string) => {
|
||||
await readInform(id);
|
||||
},
|
||||
onSuccess: () => {
|
||||
refetch();
|
||||
},
|
||||
errorToast: 'Failed to read the inform'
|
||||
});
|
||||
|
||||
return (
|
||||
<Box position={'fixed'} top={'3%'} left={'50%'} transform={'translateX(-50%)'} zIndex={99999}>
|
||||
{informs.map((inform) => (
|
||||
<Flex
|
||||
key={inform._id}
|
||||
bg={'primary.015'}
|
||||
py={3}
|
||||
px={5}
|
||||
fontSize={'md'}
|
||||
borderRadius={'lg'}
|
||||
boxShadow={'4'}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'borderColor.base'}
|
||||
minW={['200px', '400px']}
|
||||
alignItems={'flex-start'}
|
||||
mb={3}
|
||||
backdropFilter={'blur(30px)'}
|
||||
>
|
||||
<MyIcon name={'support/user/informLight'} w={'16px'} mr={2} />
|
||||
<Box flex={'1 0 0'}>
|
||||
<Box fontWeight={'bold'}>{inform.title}</Box>
|
||||
<Box fontSize={'sm'}>{inform.content}</Box>
|
||||
</Box>
|
||||
<CloseIcon
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.700'
|
||||
}}
|
||||
w={'12px'}
|
||||
onClick={() => onClickClose(inform._id)}
|
||||
/>
|
||||
</Flex>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImportantInform;
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button, ModalBody, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { getSystemMsgModalData } from '@/web/support/user/inform/api';
|
||||
import Markdown from '@/components/Markdown';
|
||||
|
||||
const SystemMsgModal = ({}: {}) => {
|
||||
const { t } = useTranslation();
|
||||
const { systemMsgReadId, setSysMsgReadId } = useUserStore();
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const { data } = useQuery(['initSystemMsgModal', systemMsgReadId], getSystemMsgModalData, {
|
||||
onSuccess(res) {
|
||||
if (res?.content && (!systemMsgReadId || res.id !== systemMsgReadId)) {
|
||||
onOpen();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const onclickRead = useCallback(() => {
|
||||
if (!data) return;
|
||||
setSysMsgReadId(data.id);
|
||||
onClose();
|
||||
}, [data, onClose, setSysMsgReadId]);
|
||||
|
||||
return (
|
||||
<MyModal isOpen={isOpen} iconSrc={LOGO_ICON} title={t('support.user.inform.System message')}>
|
||||
<ModalBody overflow={'auto'}>
|
||||
<Markdown source={data?.content} />
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={onclickRead}>{t('support.inform.Read')}</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SystemMsgModal);
|
||||
@@ -5,7 +5,7 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { Box, Button, Flex, Input, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useTranslation } from 'next-i18next';
|
||||
import { ModalCloseButton, ModalBody, Box, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import TagTextarea from '@/components/common/Textarea/TagTextarea';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { postInviteTeamMember } from '@/web/support/user/team/api';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import type { InviteMemberResponse } from '@fastgpt/global/support/user/team/controller.d';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@ import {
|
||||
TeamMemberStatusMap
|
||||
} from '@fastgpt/global/support/user/team/constant';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { setToken } from '@/web/support/user/auth';
|
||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||
import { FormDataType, defaultForm } from './EditModal';
|
||||
import MyMenu from '@/components/MyMenu';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import type { TeamTagItemType } from '@fastgpt/global/support/user/team/type';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { RepeatIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
|
||||
@@ -14,9 +14,9 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { getTeamList, updateInviteResult } from '@/web/support/user/team/api';
|
||||
import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
const UpdateInviteModal = () => {
|
||||
|
||||
@@ -29,7 +29,11 @@ function Error() {
|
||||
{`出现未捕获的异常。
|
||||
1. 私有部署用户,90%由于配置文件不正确导致。
|
||||
2. 部分系统不兼容相关API。大部分是苹果的safari 浏览器导致,可以尝试更换 chrome。
|
||||
3. 请关闭浏览器翻译功能,部分翻译导致页面崩溃。`}
|
||||
3. 请关闭浏览器翻译功能,部分翻译导致页面崩溃。
|
||||
|
||||
排除3后,打开控制台的 console 查看具体报错信息。
|
||||
如果提示 xxx undefined 的话,就是配置文件有错误。
|
||||
`}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from '@fastgpt/global/support/wallet/bill/constants';
|
||||
// import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { standardSubLevelMap, subModeMap } from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
|
||||
@@ -403,7 +403,7 @@ const PlanUsage = () => {
|
||||
</Flex>
|
||||
{isFreeTeam && (
|
||||
<Box mt="2" color={'#485264'} fontSize="sm">
|
||||
免费版用户15天无任何使用记录时,系统会自动清理账号知识库。
|
||||
免费版用户30天无任何使用记录时,系统会自动清理账号知识库。
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
@@ -504,9 +504,9 @@ const PlanUsage = () => {
|
||||
const Other = () => {
|
||||
const theme = useTheme();
|
||||
const { toast } = useToast();
|
||||
const { feConfigs, systemVersion } = useSystemStore();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, updateUserInfo, initUserInfo, teamPlanStatus } = useUserStore();
|
||||
const { userInfo, updateUserInfo } = useUserStore();
|
||||
const { reset } = useForm<UserUpdateParams>({
|
||||
defaultValues: userInfo as UserType
|
||||
});
|
||||
@@ -552,10 +552,6 @@ const Other = () => {
|
||||
<Box ml={2} flex={1}>
|
||||
{t('system.Help Document')}
|
||||
</Box>
|
||||
<Box w={'8px'} h={'8px'} borderRadius={'50%'} bg={'#67c13b'} />
|
||||
<Box fontSize={'md'} ml={2}>
|
||||
V{systemVersion}
|
||||
</Box>
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Box, Flex, useTheme } from '@chakra-ui/react';
|
||||
import { Box, Button, Flex, useTheme } from '@chakra-ui/react';
|
||||
import { getInforms, readInform } from '@/web/support/user/inform/api';
|
||||
import type { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import { formatTimeToChatTime } from '@/utils/tools';
|
||||
@@ -7,8 +7,10 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { usePagination } from '@fastgpt/web/hooks/usePagination';
|
||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const InformTable = () => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { Loading } = useLoading();
|
||||
const { isPc } = useSystemStore();
|
||||
@@ -22,7 +24,7 @@ const InformTable = () => {
|
||||
pageNum
|
||||
} = usePagination<UserInformSchema>({
|
||||
api: getInforms,
|
||||
pageSize: isPc ? 20 : 10
|
||||
pageSize: 20
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -35,35 +37,44 @@ const InformTable = () => {
|
||||
py={2}
|
||||
px={4}
|
||||
borderRadius={'md'}
|
||||
cursor={item.read ? 'default' : 'pointer'}
|
||||
position={'relative'}
|
||||
_notLast={{ mb: 3 }}
|
||||
onClick={async () => {
|
||||
if (!item.read) {
|
||||
await readInform(item._id);
|
||||
getData(pageNum);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box fontWeight={'bold'}>{item.title}</Box>
|
||||
<Box ml={2} color={'myGray.500'}>
|
||||
{formatTimeToChatTime(item.time)}
|
||||
<Box ml={2} color={'myGray.500'} flex={'1 0 0'}>
|
||||
({formatTimeToChatTime(item.time)})
|
||||
</Box>
|
||||
{!item.read && (
|
||||
<Button
|
||||
variant={'whitePrimary'}
|
||||
size={'xs'}
|
||||
onClick={async () => {
|
||||
if (!item.read) {
|
||||
await readInform(item._id);
|
||||
getData(pageNum);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('support.inform.Read')}
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
<Box fontSize={'sm'} color={'myGray.600'} whiteSpace={'pre-wrap'}>
|
||||
<Box mt={2} fontSize={'sm'} color={'myGray.600'} whiteSpace={'pre-wrap'}>
|
||||
{item.content}
|
||||
</Box>
|
||||
{!item.read && (
|
||||
<Box
|
||||
w={'5px'}
|
||||
h={'5px'}
|
||||
borderRadius={'10px'}
|
||||
bg={'red.600'}
|
||||
position={'absolute'}
|
||||
bottom={'8px'}
|
||||
right={'8px'}
|
||||
></Box>
|
||||
<>
|
||||
<Box
|
||||
w={'5px'}
|
||||
h={'5px'}
|
||||
borderRadius={'10px'}
|
||||
bg={'red.600'}
|
||||
position={'absolute'}
|
||||
top={'8px'}
|
||||
left={'8px'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/rea
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import type { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
|
||||
const OpenAIAccountModal = ({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/rea
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { updatePasswordByOld } from '@/web/support/user/api';
|
||||
|
||||
type FormType = {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRouter } from 'next/router';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import SideTabs from '@/components/SideTabs';
|
||||
import Tabs from '@/components/Tabs';
|
||||
@@ -34,7 +34,7 @@ enum TabEnum {
|
||||
const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, setUserInfo } = useUserStore();
|
||||
const { feConfigs, isPc } = useSystemStore();
|
||||
const { feConfigs, isPc, systemVersion } = useSystemStore();
|
||||
|
||||
const tabList = [
|
||||
{
|
||||
@@ -148,6 +148,12 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
activeId={currentTab}
|
||||
onChange={setCurrentTab}
|
||||
/>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box w={'8px'} h={'8px'} borderRadius={'50%'} bg={'#67c13b'} />
|
||||
<Box fontSize={'md'} ml={2}>
|
||||
V{systemVersion}
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
) : (
|
||||
<Box mb={3}>
|
||||
|
||||
@@ -2,9 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authFileToken } from '@fastgpt/service/support/permission/controller';
|
||||
import { detect } from 'jschardet';
|
||||
import { getDownloadStream, getFileById } from '@fastgpt/service/common/file/gridfs/controller';
|
||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -37,7 +37,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
}
|
||||
}
|
||||
|
||||
const encoding = detect(buffers)?.encoding || 'utf-8';
|
||||
const encoding = detectFileEncoding(buffers);
|
||||
|
||||
res.setHeader('Content-Type', `${file.contentType}; charset=${encoding}`);
|
||||
res.setHeader('Cache-Control', 'public, max-age=3600');
|
||||
|
||||
@@ -25,8 +25,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
reRankModels:
|
||||
global.reRankModels?.map((item) => ({
|
||||
...item,
|
||||
requestUrl: undefined,
|
||||
requestAuth: undefined
|
||||
requestUrl: '',
|
||||
requestAuth: ''
|
||||
})) || [],
|
||||
whisperModel: global.whisperModel,
|
||||
audioSpeechModels: global.audioSpeechModels,
|
||||
@@ -42,7 +42,7 @@ const defaultFeConfigs: FastGPTFeConfigsType = {
|
||||
openAPIDocUrl: 'https://doc.fastgpt.in/docs/development/openapi',
|
||||
systemTitle: 'FastGPT',
|
||||
concatMd:
|
||||
'* 项目开源地址: [FastGPT GitHub](https://github.com/labring/FastGPT)\n* 交流群: ',
|
||||
'项目开源地址: [FastGPT GitHub](https://github.com/labring/FastGPT)\n交流群: ',
|
||||
limit: {
|
||||
exportDatasetLimitMinutes: 0,
|
||||
websiteSyncLimitMinuted: 0
|
||||
@@ -150,7 +150,7 @@ function getSystemPlugin() {
|
||||
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||
|
||||
// read json file
|
||||
const fileTemplates: PluginTemplateType[] = filterFiles.map((filename) => {
|
||||
const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => {
|
||||
const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
|
||||
return {
|
||||
...JSON.parse(content),
|
||||
@@ -159,5 +159,7 @@ function getSystemPlugin() {
|
||||
};
|
||||
});
|
||||
|
||||
fileTemplates.sort((a, b) => b.weight - a.weight);
|
||||
|
||||
global.communityPlugins = fileTemplates;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
userChatInput: text
|
||||
},
|
||||
stream: true,
|
||||
detail: true
|
||||
detail: true,
|
||||
maxRunTimes: 200
|
||||
});
|
||||
|
||||
responseWrite({
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import * as SwaggerParser from '@apidevtools/swagger-parser';
|
||||
import SwaggerParser from '@apidevtools/swagger-parser';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
const apiURL = req.body.url as string;
|
||||
|
||||
const api = await (SwaggerParser as any).validate(apiURL);
|
||||
const api = await SwaggerParser.validate(apiURL);
|
||||
|
||||
return jsonRes(res, {
|
||||
data: api
|
||||
|
||||
@@ -17,6 +17,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
|
||||
const { teamId, tmbId } = await authPluginCrud({ req, authToken: true, id, per: 'owner' });
|
||||
|
||||
const updateData = {
|
||||
name: props.name,
|
||||
intro: props.intro,
|
||||
avatar: props.avatar,
|
||||
parentId: props.parentId,
|
||||
...(props.modules &&
|
||||
props.modules.length > 0 && {
|
||||
modules: props.modules
|
||||
}),
|
||||
metadata: props.metadata
|
||||
};
|
||||
|
||||
if (props.metadata?.apiSchemaStr) {
|
||||
await mongoSessionRun(async (session) => {
|
||||
// update children
|
||||
@@ -26,13 +38,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
parent: body,
|
||||
session
|
||||
});
|
||||
await MongoPlugin.findByIdAndUpdate(id, props, { session });
|
||||
await MongoPlugin.findByIdAndUpdate(id, updateData, { session });
|
||||
});
|
||||
|
||||
jsonRes(res, {});
|
||||
} else {
|
||||
jsonRes(res, {
|
||||
data: await MongoPlugin.findByIdAndUpdate(id, props)
|
||||
data: await MongoPlugin.findByIdAndUpdate(id, updateData)
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { readMongoImg } from '@fastgpt/service/common/file/image/controller';
|
||||
import { guessImageTypeFromBase64 } from '@fastgpt/service/common/file/utils';
|
||||
import { guessBase64ImageType } from '@fastgpt/service/common/file/utils';
|
||||
|
||||
// get the models available to the system
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -11,8 +11,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const { id } = req.query as { id: string };
|
||||
|
||||
const binary = await readMongoImg({ id });
|
||||
const imageType = guessImageTypeFromBase64(binary.toString('base64'));
|
||||
res.setHeader('Content-Type', imageType);
|
||||
|
||||
res.setHeader('Content-Type', guessBase64ImageType(binary.toString('base64')));
|
||||
res.send(binary);
|
||||
} catch (error) {
|
||||
jsonRes(res, {
|
||||
|
||||
@@ -184,7 +184,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
userChatInput: text
|
||||
},
|
||||
stream,
|
||||
detail
|
||||
detail,
|
||||
maxRunTimes: 200
|
||||
});
|
||||
|
||||
// save chat
|
||||
|
||||
@@ -9,17 +9,19 @@ import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
||||
import { getUsageSourceByAuthType } from '@fastgpt/global/support/wallet/usage/tools';
|
||||
import { getVectorModel } from '@fastgpt/service/core/ai/model';
|
||||
import { checkTeamAIPoints } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import { EmbeddingTypeEnm } from '@fastgpt/global/core/ai/constants';
|
||||
|
||||
type Props = {
|
||||
input: string | string[];
|
||||
model: string;
|
||||
dimensions?: number;
|
||||
billId?: string;
|
||||
type: `${EmbeddingTypeEnm}`;
|
||||
};
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
let { input, model, billId } = req.body as Props;
|
||||
let { input, model, billId, type } = req.body as Props;
|
||||
await connectToDatabase();
|
||||
|
||||
if (!Array.isArray(input) && typeof input !== 'string') {
|
||||
@@ -38,7 +40,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
|
||||
const { tokens, vectors } = await getVectorsByText({
|
||||
input: query,
|
||||
model: getVectorModel(model)
|
||||
model: getVectorModel(model),
|
||||
type
|
||||
});
|
||||
|
||||
res.json({
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback, useRef, useState } from 'react';
|
||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
||||
import { SmallCloseIcon } from '@chakra-ui/icons';
|
||||
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
@@ -16,7 +16,7 @@ import { useFlowProviderStore } from '@/components/core/module/Flow/FlowProvider
|
||||
import { flowNode2Modules, filterExportModules } from '@/components/core/module/utils';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
|
||||
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
|
||||
@@ -102,7 +102,10 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
|
||||
data-open-icon="${getValues('scriptOpenIcon')}"
|
||||
data-close-icon="${getValues('scriptCloseIcon')}"
|
||||
defer
|
||||
/>`
|
||||
/>
|
||||
<script>
|
||||
console.log("Chat box loaded")
|
||||
</script>`
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
ModalBody,
|
||||
Input,
|
||||
Switch,
|
||||
Link
|
||||
Link,
|
||||
IconButton
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -31,7 +32,7 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { defaultOutLinkForm } from '@/constants/app';
|
||||
import type { OutLinkEditType, OutLinkSchema } from '@fastgpt/global/support/outLink/type.d';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
@@ -42,6 +43,7 @@ import dayjs from 'dayjs';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyMenu from '@/components/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
|
||||
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
|
||||
|
||||
@@ -53,6 +55,10 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
const [editLinkData, setEditLinkData] = useState<OutLinkEditType>();
|
||||
const [selectedLinkData, setSelectedLinkData] = useState<OutLinkSchema>();
|
||||
const { toast } = useToast();
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
content: t('support.outlink.Delete link tip'),
|
||||
type: 'delete'
|
||||
});
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
@@ -130,25 +136,25 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
)}
|
||||
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : t('common.Un used')}</Td>
|
||||
<Td display={'flex'} alignItems={'center'}>
|
||||
<Button
|
||||
onClick={() => setSelectedLinkData(item)}
|
||||
size={'sm'}
|
||||
mr={3}
|
||||
variant={'whitePrimary'}
|
||||
>
|
||||
{t('core.app.outLink.Select Mode')}
|
||||
</Button>
|
||||
<MyMenu
|
||||
Button={
|
||||
<MyIcon
|
||||
<IconButton
|
||||
icon={<MyIcon name={'more'} w={'14px'} />}
|
||||
name={'more'}
|
||||
_hover={{ bg: 'myGray.100 ' }}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
w={'14px'}
|
||||
p={2}
|
||||
variant={'whiteBase'}
|
||||
size={'sm'}
|
||||
aria-label={''}
|
||||
/>
|
||||
}
|
||||
menuList={[
|
||||
{
|
||||
label: t('core.app.outLink.Select Mode'),
|
||||
icon: 'copy',
|
||||
onClick: () => {
|
||||
setSelectedLinkData(item);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('common.Edit'),
|
||||
icon: 'edit',
|
||||
@@ -163,7 +169,8 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
{
|
||||
label: t('common.Delete'),
|
||||
icon: 'delete',
|
||||
onClick: async () => {
|
||||
type: 'danger',
|
||||
onClick: openConfirm(async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await delShareChatById(item._id);
|
||||
@@ -172,7 +179,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
console.log(error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
]}
|
||||
/>
|
||||
@@ -219,6 +226,7 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
onClose={() => setSelectedLinkData(undefined)}
|
||||
/>
|
||||
)}
|
||||
<ConfirmModal />
|
||||
<Loading loading={isFetching} fixed={false} />
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Flex, Button, IconButton } from '@chakra-ui/react';
|
||||
import { DragHandleIcon } from '@chakra-ui/icons';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||
|
||||
@@ -7,8 +7,8 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { appModules2Form, getDefaultAppForm } from '@fastgpt/global/core/app/utils';
|
||||
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
|
||||
import { chatNodeSystemPromptTip, welcomeTextTip } from '@fastgpt/global/core/module/template/tip';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { getTeamsTags } from '@/web/support/user/team/api';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import RowTabs from '@fastgpt/web/components/common/Tabs/RowTabs';
|
||||
import { useWorkflowStore } from '@/web/core/workflow/store/workflow';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import EmptyTip from '@/components/EmptyTip';
|
||||
import { FlowNodeTemplateType } from '@fastgpt/global/core/module/type';
|
||||
|
||||
@@ -23,7 +23,7 @@ import { postCreateApp } from '@/web/core/app/api';
|
||||
import { useRouter } from 'next/router';
|
||||
import { appTemplates } from '@/web/core/app/templates';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { delModelById } from '@/web/core/app/api';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
@@ -17,7 +17,7 @@ import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { AppListItemType } from '@fastgpt/global/core/app/type';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useMemo, useRef, useState } from 'react';
|
||||
import { ModalFooter, ModalBody, Input, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
const EditFolderModal = ({
|
||||
onClose,
|
||||
|
||||
@@ -26,12 +26,12 @@ import {
|
||||
} from '@/web/core/dataset/api';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { debounce } from 'lodash';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import dayjs from 'dayjs';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
@@ -707,6 +707,7 @@ const CollectionCard = () => {
|
||||
<Box>{t('common.Delete')}</Box>
|
||||
</Flex>
|
||||
),
|
||||
type: 'danger',
|
||||
onClick: () =>
|
||||
openDeleteConfirm(
|
||||
() => {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { debounce } from 'lodash';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -302,7 +302,10 @@ const DataCard = () => {
|
||||
>
|
||||
<Flex zIndex={1} alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Box
|
||||
border={theme.borders.base}
|
||||
borderWidth={'1px'}
|
||||
borderColor={'primary.200'}
|
||||
bg={'primary.50'}
|
||||
color={'primary.600'}
|
||||
px={2}
|
||||
fontSize={'sm'}
|
||||
mr={1}
|
||||
@@ -310,7 +313,7 @@ const DataCard = () => {
|
||||
>
|
||||
# {item.chunkIndex ?? '-'}
|
||||
</Box>
|
||||
<Box className={'textEllipsis'} color={'myGray.500'} fontSize={'xs'}>
|
||||
<Box className={'textEllipsis'} fontSize={'xs'}>
|
||||
ID:{item._id}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Box, Button, Input, Link, ModalBody, ModalFooter } from '@chakra-ui/rea
|
||||
import { strIsLink } from '@fastgpt/global/common/string/tools';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const PreviewData = ({
|
||||
const { sources, setSources } = useImportStore();
|
||||
|
||||
return (
|
||||
<Flex flexDirection={'column'} h={'100%'} maxW={'1080px'}>
|
||||
<Flex flexDirection={'column'} h={'100%'}>
|
||||
<Box flex={'1 0 0 '}>
|
||||
<Preview showPreviewChunks={showPreviewChunks} sources={sources} />
|
||||
</Box>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
import { useImportStore, type FormType } from '../Provider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { postCreateTrainingUsage } from '@/web/support/wallet/usage/api';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { chunksUpload, fileCollectionCreate } from '@/web/core/dataset/utils';
|
||||
|
||||
@@ -8,7 +8,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { formatFileSize } from '@fastgpt/global/common/file/tools';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { readFileRawContent } from '@fastgpt/web/common/file/read';
|
||||
import { getUploadBase64ImgController } from '@/web/common/file/controller';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
|
||||
@@ -8,7 +8,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { formatFileSize } from '@fastgpt/global/common/file/tools';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useImportStore } from '../Provider';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { DeleteIcon } from '@chakra-ui/icons';
|
||||
import { delDatasetById } from '@/web/core/dataset/api';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
|
||||
@@ -14,7 +14,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import PermissionRadio from '@/components/support/permission/Radio';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import AIModelSelector from '@/components/Select/AIModelSelector';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Box, Flex, Button, Textarea, useTheme, Grid } from '@chakra-ui/react';
|
||||
import { Box, Flex, Button, Textarea, useTheme, Grid, HStack } from '@chakra-ui/react';
|
||||
import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form';
|
||||
import {
|
||||
postInsertData2Dataset,
|
||||
@@ -12,12 +12,11 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils';
|
||||
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import SideTabs from '@/components/SideTabs';
|
||||
@@ -27,8 +26,8 @@ import { getDocPath } from '@/web/common/system/doc';
|
||||
import RawSourceBox from '@/components/core/dataset/RawSourceBox';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import RowTabs from '@fastgpt/web/components/common/Tabs/RowTabs';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
|
||||
export type InputDataType = {
|
||||
q: string;
|
||||
@@ -232,9 +231,9 @@ const InputDataModal = ({
|
||||
return (
|
||||
<MyModal isOpen={true} isCentered w={'90vw'} maxW={'1440px'} h={'90vh'}>
|
||||
<MyBox isLoading={isLoading} display={'flex'} h={'100%'}>
|
||||
<Box p={5} borderRight={theme.borders.base}>
|
||||
<Box p={5} bg={'myGray.50'} borderLeftRadius={'md'} borderRight={theme.borders.base}>
|
||||
<RawSourceBox
|
||||
w={'200px'}
|
||||
w={'210px'}
|
||||
className="textEllipsis3"
|
||||
whiteSpace={'pre-wrap'}
|
||||
sourceName={collection.sourceName}
|
||||
@@ -256,32 +255,40 @@ const InputDataModal = ({
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Flex flexDirection={'column'} py={3} flex={1} h={'100%'}>
|
||||
<Box fontSize={'lg'} px={5} fontWeight={'bold'} mb={4}>
|
||||
<Flex flexDirection={'column'} pb={8} flex={1} h={'100%'}>
|
||||
<Box fontSize={'lg'} px={5} py={3} fontWeight={'medium'}>
|
||||
{currentTab === TabEnum.content && (
|
||||
<>{dataId ? t('dataset.data.Update Data') : t('dataset.data.Input Data')}</>
|
||||
)}
|
||||
{currentTab === TabEnum.index && <> {t('dataset.data.Index Edit')}</>}
|
||||
</Box>
|
||||
<Box flex={1} px={5} overflow={'auto'}>
|
||||
<Box flex={1} px={9} overflow={'auto'}>
|
||||
{currentTab === TabEnum.content && <InputTab maxToken={maxToken} register={register} />}
|
||||
{currentTab === TabEnum.index && (
|
||||
<Grid gridTemplateColumns={['1fr', '1fr 1fr']} gridGap={4}>
|
||||
<Grid mt={3} gridTemplateColumns={['1fr', '1fr 1fr']} gridGap={4}>
|
||||
{indexes?.map((index, i) => (
|
||||
<Box
|
||||
key={index.dataId || i}
|
||||
p={3}
|
||||
p={4}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
bg={i % 2 !== 0 ? 'myWhite.400' : ''}
|
||||
border={
|
||||
index.defaultIndex
|
||||
? '1.5px solid var(--light-fastgpt-primary-opacity-01, rgba(51, 112, 255, 0.10))'
|
||||
: '1.5px solid var(--Gray-Modern-200, #E8EBF0)'
|
||||
}
|
||||
bg={index.defaultIndex ? 'primary.50' : 'myGray.25'}
|
||||
_hover={{
|
||||
'& .delete': {
|
||||
display: index.defaultIndex ? 'none' : 'block'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex mb={1}>
|
||||
<Box flex={1}>
|
||||
<Flex mb={2}>
|
||||
<Box
|
||||
flex={1}
|
||||
fontWeight={'medium'}
|
||||
color={index.defaultIndex ? 'primary.700' : 'myGray.900'}
|
||||
>
|
||||
{index.defaultIndex
|
||||
? t('dataset.data.Default Index')
|
||||
: t('dataset.data.Custom Index Number', { number: i })}
|
||||
@@ -296,16 +303,23 @@ const InputDataModal = ({
|
||||
/>
|
||||
</Flex>
|
||||
{index.defaultIndex ? (
|
||||
<Box>{t('core.dataset.data.Default Index Tip')}</Box>
|
||||
<Box fontSize={'sm'} fontWeight={'medium'} color={'myGray.600'}>
|
||||
{t('core.dataset.data.Default Index Tip')}
|
||||
</Box>
|
||||
) : (
|
||||
<Textarea
|
||||
maxLength={maxToken}
|
||||
fontSize={'sm'}
|
||||
rows={10}
|
||||
borderColor={'transparent'}
|
||||
px={0}
|
||||
pt={0}
|
||||
_focus={{
|
||||
borderColor: 'primary.400',
|
||||
px: 3
|
||||
px: 3,
|
||||
py: 2,
|
||||
borderColor: 'primary.500',
|
||||
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)',
|
||||
bg: 'white'
|
||||
}}
|
||||
placeholder={t('dataset.data.Index Placeholder')}
|
||||
{...register(`indexes.${i}.text`, {
|
||||
@@ -316,14 +330,19 @@ const InputDataModal = ({
|
||||
</Box>
|
||||
))}
|
||||
<Flex
|
||||
flexDirection={'column'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
color={'myGray.600'}
|
||||
fontWeight={'medium'}
|
||||
border={'1.5px solid var(--Gray-Modern-200, #E8EBF0)'}
|
||||
bg={'myGray.25'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
bg: 'primary.50'
|
||||
bg: 'primary.50',
|
||||
color: 'primary.600',
|
||||
border:
|
||||
'1.5px solid var(--light-fastgpt-primary-opacity-01, rgba(51, 112, 255, 0.10))'
|
||||
}}
|
||||
minH={'100px'}
|
||||
onClick={() =>
|
||||
@@ -334,14 +353,14 @@ const InputDataModal = ({
|
||||
})
|
||||
}
|
||||
>
|
||||
<MyIcon name={'common/addCircleLight'} w={'16px'} />
|
||||
<MyIcon name={'common/addLight'} w={'18px'} mr={1.5} />
|
||||
<Box>{t('dataset.data.Add Index')}</Box>
|
||||
</Flex>
|
||||
</Grid>
|
||||
)}
|
||||
</Box>
|
||||
{/* footer */}
|
||||
<Flex justifyContent={'flex-end'} px={5} mt={4}>
|
||||
<Flex justifyContent={'flex-end'} px={9} mt={6}>
|
||||
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
|
||||
{t('common.Close')}
|
||||
</Button>
|
||||
@@ -364,10 +383,6 @@ const InputDataModal = ({
|
||||
|
||||
export default React.memo(InputDataModal);
|
||||
|
||||
enum InputTypeEnum {
|
||||
q = 'q',
|
||||
a = 'a'
|
||||
}
|
||||
const InputTab = ({
|
||||
maxToken,
|
||||
register
|
||||
@@ -376,70 +391,46 @@ const InputTab = ({
|
||||
register: UseFormRegister<InputDataType>;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystemStore();
|
||||
const [inputType, setInputType] = useState(InputTypeEnum.q);
|
||||
|
||||
return (
|
||||
<Flex flexDirection={'column'} h={'100%'}>
|
||||
<Box>
|
||||
<RowTabs
|
||||
list={[
|
||||
{
|
||||
label: (
|
||||
<Flex alignItems={'center'}>
|
||||
<Box as="span" color={'red.600'}>
|
||||
*
|
||||
</Box>
|
||||
{t('core.dataset.data.Main Content')}
|
||||
<MyTooltip label={t('core.dataset.data.Data Content Tip')}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
),
|
||||
value: InputTypeEnum.q
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Flex alignItems={'center'}>
|
||||
{t('core.dataset.data.Auxiliary Data')}
|
||||
<MyTooltip label={t('core.dataset.data.Auxiliary Data Tip')}>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
),
|
||||
value: InputTypeEnum.a
|
||||
}
|
||||
]}
|
||||
value={inputType}
|
||||
onChange={(e) => setInputType(e as InputTypeEnum)}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box mt={3} flex={'1 0 0'}>
|
||||
{inputType === InputTypeEnum.q && (
|
||||
<HStack h={'100%'} spacing={6}>
|
||||
<Flex flexDirection={'column'} w={'50%'} h={'100%'}>
|
||||
<Flex pt={3} pb={2} fontWeight={'medium'} fontSize={'md'} alignItems={'center'}>
|
||||
<Box color={'red.600'}>*</Box>
|
||||
<Box color={'myGray.900'}>{t('core.dataset.data.Main Content')}</Box>
|
||||
<QuestionTip label={t('core.dataset.data.Data Content Tip')} ml={1} />
|
||||
</Flex>
|
||||
<Box flex={'1 0 0'}>
|
||||
<Textarea
|
||||
placeholder={t('core.dataset.data.Data Content Placeholder', { maxToken })}
|
||||
maxLength={maxToken}
|
||||
h={'100%'}
|
||||
bg={'myWhite.400'}
|
||||
tabIndex={1}
|
||||
bg={'myGray.50'}
|
||||
h={'full'}
|
||||
{...register(`q`, {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{inputType === InputTypeEnum.a && (
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex flexDirection={'column'} w={'50%'} h={'100%'}>
|
||||
<Flex pt={3} pb={2} fontWeight={'medium'} fontSize={'md'} alignItems={'center'}>
|
||||
<Box color={'myGray.900'}>{t('core.dataset.data.Auxiliary Data')}</Box>
|
||||
<QuestionTip label={t('core.dataset.data.Auxiliary Data Tip')} ml={1} />
|
||||
</Flex>
|
||||
<Box flex={'1 0 0'}>
|
||||
<Textarea
|
||||
placeholder={t('core.dataset.data.Auxiliary Data Placeholder', {
|
||||
maxToken: maxToken * 1.5
|
||||
})}
|
||||
h={'100%'}
|
||||
bg={'myWhite.400'}
|
||||
rows={isPc ? 24 : 12}
|
||||
tabIndex={1}
|
||||
bg={'myGray.50'}
|
||||
maxLength={maxToken * 1.5}
|
||||
{...register('a')}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useSearchTestStore, SearchTestStoreItemType } from '@/web/core/dataset/store/searchTest';
|
||||
import { postSearchText } from '@/web/core/dataset/api';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { formatTimeToChatTime } from '@/utils/tools';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
|
||||
@@ -15,7 +15,6 @@ import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getTrainingQueueLen } from '@/web/core/dataset/api';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import Script from 'next/script';
|
||||
import CollectionCard from './components/CollectionCard';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
@@ -24,8 +23,8 @@ import {
|
||||
DatasetTypeEnum,
|
||||
DatasetTypeMap
|
||||
} from '@fastgpt/global/core/dataset/constants';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
|
||||
import Head from 'next/head';
|
||||
import MyBox from '@/components/common/MyBox';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
|
||||
@@ -18,7 +18,7 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getDatasets, putDatasetById, getDatasetPaths } from '@/web/core/dataset/api';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
const MoveModal = ({
|
||||
onClose,
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Grid,
|
||||
useTheme,
|
||||
useDisclosure,
|
||||
Card,
|
||||
MenuButton,
|
||||
Image,
|
||||
Button
|
||||
} from '@chakra-ui/react';
|
||||
import { Box, Flex, Grid, useDisclosure, Image, Button } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
@@ -31,7 +21,7 @@ import dynamic from 'next/dynamic';
|
||||
import { DatasetTypeEnum, DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
|
||||
import { FolderImgUrl, FolderIcon } from '@fastgpt/global/common/file/image/constants';
|
||||
import MyMenu from '@/components/MyMenu';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import EditFolderModal, { useEditFolder } from '../component/EditFolderModal';
|
||||
@@ -389,6 +379,7 @@ const Kb = () => {
|
||||
{t('common.Delete')}
|
||||
</Flex>
|
||||
),
|
||||
type: 'danger',
|
||||
onClick: () => {
|
||||
openConfirm(
|
||||
() => onclickDelDataset(dataset._id),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Box, Flex, IconButton, useTheme, useDisclosure } from '@chakra-ui/react';
|
||||
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
@@ -81,7 +81,7 @@ const Render = ({ pluginId }: Props) => {
|
||||
|
||||
export default function FlowEdit(props: any) {
|
||||
return (
|
||||
<FlowProvider mode={'plugin'} filterAppIds={[]}>
|
||||
<FlowProvider mode={'plugin'}>
|
||||
<Render {...props} />
|
||||
</FlowProvider>
|
||||
);
|
||||
|
||||
@@ -7,13 +7,13 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { delOnePlugin, postCreatePlugin, putUpdatePlugin } from '@/web/core/plugin/api';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { compressImgFileAndUpload } from '@/web/common/file/controller';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
} from '@/web/core/plugin/api';
|
||||
import { str2OpenApiSchema } from '@fastgpt/global/core/plugin/httpPlugin/utils';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { EditFormType } from './type';
|
||||
@@ -100,12 +100,6 @@ const HttpPluginEditModal = ({
|
||||
}
|
||||
}, [apiSchemaStr, t, toast]);
|
||||
|
||||
const {
|
||||
isOpen: isOpenUrlImport,
|
||||
onOpen: onOpenUrlImport,
|
||||
onClose: onCloseUrlImport
|
||||
} = useDisclosure();
|
||||
|
||||
const { mutate: onCreate, isLoading: isCreating } = useRequest({
|
||||
mutationFn: async (data: CreateOnePluginParams) => {
|
||||
return postCreatePlugin(data);
|
||||
@@ -194,8 +188,6 @@ const HttpPluginEditModal = ({
|
||||
|
||||
const schema = await getApiSchemaByUrl(schemaUrl);
|
||||
setValue('metadata.apiSchemaStr', JSON.stringify(schema, null, 2));
|
||||
|
||||
onCloseUrlImport();
|
||||
},
|
||||
errorToast: t('plugin.Invalid Schema')
|
||||
});
|
||||
@@ -251,7 +243,13 @@ const HttpPluginEditModal = ({
|
||||
<Box color={'myGray.800'} fontWeight={'bold'} mt={3}>
|
||||
{t('plugin.Intro')}
|
||||
</Box>
|
||||
<Textarea {...register('intro')} bg={'myWhite.600'} rows={3} mt={3} />
|
||||
<Textarea
|
||||
{...register('intro')}
|
||||
bg={'myWhite.600'}
|
||||
rows={3}
|
||||
mt={3}
|
||||
placeholder={t('core.plugin.Http plugin intro placeholder')}
|
||||
/>
|
||||
</>
|
||||
<Box mt={4}>
|
||||
<Box
|
||||
@@ -263,32 +261,24 @@ const HttpPluginEditModal = ({
|
||||
<Box my={'auto'}>{'OpenAPI Schema'}</Box>
|
||||
|
||||
<Box>
|
||||
{isOpenUrlImport ? (
|
||||
<Flex alignItems={'center'}>
|
||||
<Input
|
||||
mr={2}
|
||||
placeholder={'https://...'}
|
||||
h={'30px'}
|
||||
onBlur={(e) => setSchemaUrl(e.target.value)}
|
||||
/>
|
||||
<Button size={'sm'} isLoading={isLoadingUrlApi} onClick={onClickUrlLoadApi}>
|
||||
{t('common.Confirm')}
|
||||
</Button>
|
||||
<Button ml={2} variant={'whiteBase'} size={'sm'} onClick={onCloseUrlImport}>
|
||||
{t('common.Cancel')}
|
||||
</Button>
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex alignItems={'center'}>
|
||||
<Input
|
||||
mr={2}
|
||||
placeholder={t('plugin.Import from URL')}
|
||||
h={'30px'}
|
||||
w={['150px', '250px']}
|
||||
fontSize={'sm'}
|
||||
onBlur={(e) => setSchemaUrl(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
size={'sm'}
|
||||
fontSize={'xs'}
|
||||
leftIcon={<AddIcon fontSize={'xs'} />}
|
||||
onClick={onOpenUrlImport}
|
||||
variant={'whitePrimary'}
|
||||
isLoading={isLoadingUrlApi}
|
||||
onClick={onClickUrlLoadApi}
|
||||
>
|
||||
{t('plugin.Import from URL')}
|
||||
{t('common.Import')}
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Box>
|
||||
<Textarea
|
||||
@@ -466,34 +456,42 @@ const HttpPluginEditModal = ({
|
||||
<Box color={'myGray.800'} fontWeight={'bold'} mt={3}>
|
||||
{t('plugin.Plugin List')}
|
||||
</Box>
|
||||
<TableContainer maxH={400} overflowY={'auto'} mt={3}>
|
||||
<Table border={'1px solid'} borderColor={'myGray.200'}>
|
||||
<Thead>
|
||||
<Th>{t('Name')}</Th>
|
||||
<Th>{t('plugin.Description')}</Th>
|
||||
<Th>{t('plugin.Method')}</Th>
|
||||
<Th>{t('plugin.Path')}</Th>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{apiData?.pathData?.map((item, index) => (
|
||||
<Tr key={index}>
|
||||
<Td>{item.name}</Td>
|
||||
<Td
|
||||
fontSize={'sm'}
|
||||
textColor={'gray.600'}
|
||||
w={'auto'}
|
||||
maxW={80}
|
||||
whiteSpace={'pre-wrap'}
|
||||
>
|
||||
{item.description}
|
||||
</Td>
|
||||
<Td>{item.method}</Td>
|
||||
<Td>{item.path}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Box
|
||||
mt={3}
|
||||
borderRadius={'md'}
|
||||
overflow={'hidden'}
|
||||
borderWidth={'1px'}
|
||||
borderBottom="none"
|
||||
>
|
||||
<TableContainer maxH={400} overflowY={'auto'}>
|
||||
<Table bg={'white'}>
|
||||
<Thead bg={'myGray.50'}>
|
||||
<Th>{t('Name')}</Th>
|
||||
<Th>{t('plugin.Description')}</Th>
|
||||
<Th>{t('plugin.Method')}</Th>
|
||||
<Th>{t('plugin.Path')}</Th>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{apiData?.pathData?.map((item, index) => (
|
||||
<Tr key={index}>
|
||||
<Td>{item.name}</Td>
|
||||
<Td
|
||||
fontSize={'sm'}
|
||||
textColor={'gray.600'}
|
||||
w={'auto'}
|
||||
maxW={80}
|
||||
whiteSpace={'pre-wrap'}
|
||||
>
|
||||
{item.description}
|
||||
</Td>
|
||||
<Td>{item.method}</Td>
|
||||
<Td>{item.path}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</>
|
||||
</ModalBody>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ const FAQ = () => {
|
||||
},
|
||||
{
|
||||
title: '免费版数据会清除么?',
|
||||
desc: '免费版用户(免费版且未购买额外套餐)15天无使用记录后,系统会自动清除账号下所有知识库内容。'
|
||||
desc: '免费版用户(免费版且未购买额外套餐)30天无使用记录后,系统会自动清除账号下所有知识库内容。'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { postCheckStandardSub, postUpdateStandardSub } from '@/web/support/walle
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
|
||||
import { StandardSubPlanParams } from '@fastgpt/global/support/wallet/sub/api';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { StandardSubPlanUpdateResponse } from '@fastgpt/global/support/wallet/sub/api.d';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
|
||||
import { checkTeamAIPoints } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import { sendOneInform } from '../support/user/inform/api';
|
||||
import { lockTrainingDataByTeamId } from '@fastgpt/service/core/dataset/training/controller';
|
||||
import { InformLevelEnum } from '@fastgpt/global/support/user/inform/constants';
|
||||
|
||||
export const checkTeamAiPointsAndLock = async (teamId: string, tmbId: string) => {
|
||||
try {
|
||||
@@ -12,7 +13,7 @@ export const checkTeamAiPointsAndLock = async (teamId: string, tmbId: string) =>
|
||||
// send inform and lock data
|
||||
try {
|
||||
sendOneInform({
|
||||
type: 'system',
|
||||
level: InformLevelEnum.important,
|
||||
title: '文本训练任务中止',
|
||||
content:
|
||||
'该团队账号AI积分不足,文本训练任务中止,重新充值后将会继续。暂停的任务将在 7 天后被删除。',
|
||||
|
||||
@@ -23,7 +23,7 @@ export function connectToDatabase(): Promise<void> {
|
||||
afterHook: async () => {
|
||||
// init system config
|
||||
getInitConfig();
|
||||
// init vector database, init root user
|
||||
//init vector database, init root user
|
||||
await Promise.all([initVectorStore(), initRootUser()]);
|
||||
|
||||
startMongoWatch();
|
||||
@@ -36,7 +36,7 @@ export function connectToDatabase(): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
async function initRootUser() {
|
||||
async function initRootUser(retry = 3): Promise<any> {
|
||||
try {
|
||||
const rootUser = await MongoUser.findOne({
|
||||
username: 'root'
|
||||
@@ -48,12 +48,9 @@ async function initRootUser() {
|
||||
await mongoSessionRun(async (session) => {
|
||||
// init root user
|
||||
if (rootUser) {
|
||||
await MongoUser.findOneAndUpdate(
|
||||
{ username: 'root' },
|
||||
{
|
||||
password: hashStr(psw)
|
||||
}
|
||||
);
|
||||
await rootUser.updateOne({
|
||||
password: hashStr(psw)
|
||||
});
|
||||
} else {
|
||||
const [{ _id }] = await MongoUser.create(
|
||||
[
|
||||
@@ -75,7 +72,12 @@ async function initRootUser() {
|
||||
password: psw
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('init root user error', error);
|
||||
exit(1);
|
||||
if (retry > 0) {
|
||||
console.log('retry init root user');
|
||||
return initRootUser(retry - 1);
|
||||
} else {
|
||||
console.error('init root user error', error);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { SendInformProps } from '@fastgpt/global/support/user/inform/type';
|
||||
import { SendInform2UserProps } from '@fastgpt/global/support/user/inform/type';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
|
||||
export function sendOneInform(data: SendInformProps) {
|
||||
export function sendOneInform(data: SendInform2UserProps) {
|
||||
if (!FastGPTProUrl) return;
|
||||
return POST('/support/user/inform/create', data);
|
||||
}
|
||||
|
||||
@@ -181,12 +181,12 @@ export const pushQuestionGuideUsage = ({
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: 'core.app.Next Step Guide',
|
||||
appName: 'core.app.Question Guide',
|
||||
totalPoints,
|
||||
source: UsageSourceEnum.fastgpt,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'core.app.Next Step Guide',
|
||||
moduleName: 'core.app.Question Guide',
|
||||
amount: totalPoints,
|
||||
model: modelName,
|
||||
tokens
|
||||
|
||||
@@ -83,8 +83,7 @@ export const streamFetch = ({
|
||||
}
|
||||
|
||||
if (responseQueue.length > 0) {
|
||||
const fetchCount = Math.max(1, Math.round(responseQueue.length / 10));
|
||||
|
||||
const fetchCount = Math.max(1, Math.round(responseQueue.length / 30));
|
||||
for (let i = 0; i < fetchCount; i++) {
|
||||
const item = responseQueue[i];
|
||||
onMessage(item);
|
||||
@@ -167,7 +166,15 @@ export const streamFetch = ({
|
||||
}
|
||||
})();
|
||||
// console.log(parseJson, event);
|
||||
if (event === SseResponseEventEnum.answer || event === SseResponseEventEnum.fastAnswer) {
|
||||
if (event === SseResponseEventEnum.answer) {
|
||||
const text = parseJson.choices?.[0]?.delta?.content || '';
|
||||
for (const item of text) {
|
||||
responseQueue.push({
|
||||
event,
|
||||
text: item
|
||||
});
|
||||
}
|
||||
} else if (event === SseResponseEventEnum.fastAnswer) {
|
||||
const text = parseJson.choices?.[0]?.delta?.content || '';
|
||||
responseQueue.push({
|
||||
event,
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useDisclosure, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
|
||||
export const useConfirm = (props?: {
|
||||
title?: string;
|
||||
iconSrc?: string | '';
|
||||
content?: string;
|
||||
showCancel?: boolean;
|
||||
type?: 'common' | 'delete';
|
||||
hideFooter?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const map = useMemo(() => {
|
||||
const map = {
|
||||
common: {
|
||||
title: t('common.confirm.Common Tip'),
|
||||
bg: undefined,
|
||||
iconSrc: 'common/confirm/commonTip'
|
||||
},
|
||||
delete: {
|
||||
title: t('common.Delete Warning'),
|
||||
bg: 'red.600',
|
||||
iconSrc: 'common/confirm/deleteTip'
|
||||
}
|
||||
};
|
||||
if (props?.type && map[props.type]) return map[props.type];
|
||||
return map.common;
|
||||
}, [props?.type, t]);
|
||||
|
||||
const {
|
||||
title = map?.title || t('Warning'),
|
||||
iconSrc = map?.iconSrc,
|
||||
content,
|
||||
showCancel = true,
|
||||
hideFooter = false
|
||||
} = props || {};
|
||||
const [customContent, setCustomContent] = useState<string | React.ReactNode>(content);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const confirmCb = useRef<any>();
|
||||
const cancelCb = useRef<any>();
|
||||
|
||||
return {
|
||||
openConfirm: useCallback(
|
||||
(confirm?: any, cancel?: any, customContent?: string | React.ReactNode) => {
|
||||
confirmCb.current = confirm;
|
||||
cancelCb.current = cancel;
|
||||
|
||||
customContent && setCustomContent(customContent);
|
||||
|
||||
return onOpen;
|
||||
},
|
||||
[onOpen]
|
||||
),
|
||||
onClose,
|
||||
ConfirmModal: useCallback(
|
||||
({
|
||||
closeText = t('common.Close'),
|
||||
confirmText = t('common.Confirm'),
|
||||
isLoading,
|
||||
bg,
|
||||
countDown = 0
|
||||
}: {
|
||||
closeText?: string;
|
||||
confirmText?: string;
|
||||
isLoading?: boolean;
|
||||
bg?: string;
|
||||
countDown?: number;
|
||||
}) => {
|
||||
const timer = useRef<any>();
|
||||
const [countDownAmount, setCountDownAmount] = useState(countDown);
|
||||
|
||||
useEffect(() => {
|
||||
timer.current = setInterval(() => {
|
||||
setCountDownAmount((val) => {
|
||||
if (val <= 0) {
|
||||
clearInterval(timer.current);
|
||||
}
|
||||
return val - 1;
|
||||
});
|
||||
}, 1000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
iconSrc={iconSrc}
|
||||
title={title}
|
||||
maxW={['90vw', '500px']}
|
||||
>
|
||||
<ModalBody pt={5}>{customContent}</ModalBody>
|
||||
{!hideFooter && (
|
||||
<ModalFooter>
|
||||
{showCancel && (
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
typeof cancelCb.current === 'function' && cancelCb.current();
|
||||
}}
|
||||
>
|
||||
{closeText}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
bg={bg ? bg : map.bg}
|
||||
isDisabled={countDownAmount > 0}
|
||||
ml={4}
|
||||
isLoading={isLoading}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
typeof confirmCb.current === 'function' && confirmCb.current();
|
||||
}}
|
||||
>
|
||||
{countDownAmount > 0 ? `${countDownAmount}s` : confirmText}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
)}
|
||||
</MyModal>
|
||||
);
|
||||
},
|
||||
[customContent, hideFooter, iconSrc, isOpen, map.bg, onClose, showCancel, t, title]
|
||||
)
|
||||
};
|
||||
};
|
||||
@@ -8,7 +8,6 @@ import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||
export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
const { t } = useTranslation();
|
||||
const mediaRecorder = useRef<MediaRecorder>();
|
||||
// const mediaStream = useRef<MediaStream>();
|
||||
const [mediaStream, setMediaStream] = useState<MediaStream>();
|
||||
const { toast } = useToast();
|
||||
const [isSpeaking, setIsSpeaking] = useState(false);
|
||||
@@ -54,6 +53,7 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
setMediaStream(stream);
|
||||
|
||||
mediaRecorder.current = new MediaRecorder(stream);
|
||||
const chunks: Blob[] = [];
|
||||
setIsSpeaking(true);
|
||||
@@ -74,11 +74,18 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
|
||||
mediaRecorder.current.onstop = async () => {
|
||||
const formData = new FormData();
|
||||
const blob = new Blob(chunks, { type: 'audio/webm' });
|
||||
|
||||
let options = {};
|
||||
if (MediaRecorder.isTypeSupported('audio/webm')) {
|
||||
options = { type: 'audio/webm' };
|
||||
} else if (MediaRecorder.isTypeSupported('video/mp4')) {
|
||||
options = { type: 'video/mp4' };
|
||||
} else {
|
||||
console.error('no suitable mimetype found for this device');
|
||||
}
|
||||
const blob = new Blob(chunks, options);
|
||||
const duration = Math.round((Date.now() - startTimestamp.current) / 1000);
|
||||
|
||||
formData.append('file', blob, 'recording.webm');
|
||||
formData.append('file', blob, 'recording.mp4');
|
||||
formData.append(
|
||||
'data',
|
||||
JSON.stringify({
|
||||
@@ -112,7 +119,13 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
};
|
||||
|
||||
mediaRecorder.current.start();
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: getErrText(error, 'Whisper error')
|
||||
});
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const stopSpeak = () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AppItemType } from '@/types/app';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { Dataset_SEARCH_DESC } from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
|
||||
// template
|
||||
export const appTemplates: (AppItemType & {
|
||||
@@ -876,7 +877,7 @@ export const appTemplates: (AppItemType & {
|
||||
{
|
||||
moduleId: '0voh5n',
|
||||
name: '知识库搜索',
|
||||
intro: '调用知识库搜索能力,查找“有可能”与问题相关的内容',
|
||||
intro: Dataset_SEARCH_DESC,
|
||||
avatar: '/imgs/module/db.png',
|
||||
flowType: 'datasetSearchNode',
|
||||
showStatus: true,
|
||||
|
||||
@@ -4,7 +4,10 @@ import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/mo
|
||||
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { UserInputModule } from '@fastgpt/global/core/module/template/system/userInput';
|
||||
import { ToolModule } from '@fastgpt/global/core/module/template/system/tools';
|
||||
import { DatasetSearchModule } from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
import {
|
||||
DatasetSearchModule,
|
||||
Dataset_SEARCH_DESC
|
||||
} from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
@@ -489,7 +492,7 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
{
|
||||
moduleId: '0voh5n',
|
||||
name: '知识库搜索',
|
||||
intro: '调用知识库搜索能力,查找“有可能”与问题相关的内容',
|
||||
intro: Dataset_SEARCH_DESC,
|
||||
avatar: '/imgs/module/db.png',
|
||||
flowType: 'datasetSearchNode',
|
||||
showStatus: true,
|
||||
@@ -640,14 +643,6 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
key: 'quoteQA'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'finish',
|
||||
label: 'core.module.output.label.running done',
|
||||
description: 'core.module.output.description.running done',
|
||||
valueType: 'boolean',
|
||||
type: 'source',
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -800,14 +795,6 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
type: 'source',
|
||||
valueType: 'datasetQuote',
|
||||
targets: []
|
||||
},
|
||||
{
|
||||
key: 'finish',
|
||||
label: 'core.module.output.label.running done',
|
||||
description: 'core.module.output.description.running done',
|
||||
valueType: 'boolean',
|
||||
type: 'source',
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import ParentPaths from '@/components/common/ParentPaths';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { getDatasetCollectionPathById, getDatasetCollections } from '@/web/core/dataset/api';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { Box, Flex, ModalFooter, Button, useTheme, Grid, Card, ModalBody } from '@chakra-ui/react';
|
||||
|
||||
@@ -17,7 +17,13 @@ export const getPluginPaths = (parentId?: string) =>
|
||||
|
||||
// http plugin
|
||||
export const getApiSchemaByUrl = (url: string) =>
|
||||
POST<Object>('/core/plugin/httpPlugin/getApiSchemaByUrl', { url });
|
||||
POST<Object>(
|
||||
'/core/plugin/httpPlugin/getApiSchemaByUrl',
|
||||
{ url },
|
||||
{
|
||||
timeout: 30000
|
||||
}
|
||||
);
|
||||
|
||||
/* work flow */
|
||||
export const getPlugTemplates = () => GET<FlowNodeTemplateType[]>('/core/plugin/templates');
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { GET, POST, PUT } from '@/web/common/api/request';
|
||||
import type { PagingData, RequestPaging } from '@/types';
|
||||
import type { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import { SystemMsgModalValueType } from '@fastgpt/service/support/user/inform/type';
|
||||
|
||||
export const getInforms = (data: RequestPaging) =>
|
||||
POST<PagingData<UserInformSchema>>(`/proApi/support/user/inform/list`, data);
|
||||
|
||||
export const getUnreadCount = () => GET<number>(`/proApi/support/user/inform/countUnread`);
|
||||
export const getUnreadCount = () =>
|
||||
GET<{
|
||||
unReadCount: number;
|
||||
importantInforms: UserInformSchema[];
|
||||
}>(`/proApi/support/user/inform/countUnread`);
|
||||
export const readInform = (id: string) => GET(`/proApi/support/user/inform/read`, { id });
|
||||
|
||||
export const getSystemMsgModalData = () =>
|
||||
GET<SystemMsgModalValueType>(`/proApi/support/user/inform/getSystemMsgModal`);
|
||||
|
||||
@@ -6,9 +6,11 @@ import type { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
import { getTokenLogin, putUserInfo } from '@/web/support/user/api';
|
||||
import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
|
||||
import { getTeamPlanStatus } from './team/api';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
type State = {
|
||||
systemMsgReadId: string;
|
||||
setSysMsgReadId: (id: string) => void;
|
||||
|
||||
userInfo: UserType | null;
|
||||
initUserInfo: () => Promise<UserType>;
|
||||
setUserInfo: (user: UserType | null) => void;
|
||||
@@ -21,6 +23,13 @@ export const useUserStore = create<State>()(
|
||||
devtools(
|
||||
persist(
|
||||
immer((set, get) => ({
|
||||
systemMsgReadId: '',
|
||||
setSysMsgReadId(id: string) {
|
||||
set((state) => {
|
||||
state.systemMsgReadId = id;
|
||||
});
|
||||
},
|
||||
|
||||
userInfo: null,
|
||||
async initUserInfo() {
|
||||
get().initTeamPlanStatus();
|
||||
@@ -71,7 +80,9 @@ export const useUserStore = create<State>()(
|
||||
})),
|
||||
{
|
||||
name: 'userStore',
|
||||
partialize: (state) => ({})
|
||||
partialize: (state) => ({
|
||||
systemMsgReadId: state.systemMsgReadId
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user