4.6.8-alpha (#804)

* perf: redirect request and err log replace

perf: dataset openapi

feat: session

fix: retry input error

feat: 468 doc

sub page

feat: standard sub

perf: rerank tip

perf: rerank tip

perf: api sdk

perf: openapi

sub plan

perf: sub ui

fix: ts

* perf: init log

* fix: variable select

* sub page

* icon

* perf: llm model config

* perf: menu ux

* perf: system store

* perf: publish app name

* fix: init data

* perf: flow edit ux

* fix: value type format and ux

* fix prompt editor default value (#13)

* fix prompt editor default value

* fix prompt editor update when not focus

* add key with variable

---------

Co-authored-by: Archer <545436317@qq.com>

* fix: value type

* doc

* i18n

* import path

* home page

* perf: mongo session running

* fix: ts

* perf: use toast

* perf: flow edit

* perf: sse response

* slider ui

* fetch error

* fix prompt editor rerender when not focus by key defaultvalue (#14)

* perf: prompt editor

* feat: dataset search concat

* perf: doc

* fix:ts

* perf: doc

* fix json editor onblur value (#15)

* faq

* vector model default config

* ipv6

---------

Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
Archer
2024-02-01 21:57:41 +08:00
committed by GitHub
parent fc19c4cf09
commit 34602b25df
285 changed files with 10345 additions and 11223 deletions

View File

@@ -13,7 +13,7 @@ import { throttle } from 'lodash';
import type { ExportChatType } from '@/types/chat.d';
import type { ChatItemType, ChatSiteItemType } from '@fastgpt/global/core/chat/type.d';
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useAudioPlay } from '@/web/common/utils/voice';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useCopyData } from '@/web/common/hooks/useCopyData';
@@ -30,7 +30,6 @@ import {
Textarea,
Checkbox
} from '@chakra-ui/react';
import { feConfigs } from '@/web/common/system/staticData';
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
import { adaptChat2GptMessages } from '@fastgpt/global/core/chat/adapt';
import { useMarkdown } from '@/web/common/hooks/useMarkdown';
@@ -159,7 +158,7 @@ const ChatBox = (
const router = useRouter();
const { t } = useTranslation();
const { toast } = useToast();
const { isPc, setLoading } = useSystemStore();
const { isPc, setLoading, feConfigs } = useSystemStore();
const TextareaDom = useRef<HTMLTextAreaElement>(null);
const chatController = useRef(new AbortController());
const questionGuideController = useRef(new AbortController());
@@ -519,7 +518,13 @@ const ChatBox = (
chatHistory.length === 0 &&
!variableModules?.length &&
!welcomeText,
[chatHistory.length, showEmptyIntro, variableModules, welcomeText]
[
chatHistory.length,
feConfigs?.show_emptyChat,
showEmptyIntro,
variableModules?.length,
welcomeText
]
);
const statusBoxData = useMemo(() => {
const colorMap = {
@@ -954,7 +959,6 @@ const ChatBox = (
setAdminMarkData={(e) => setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })}
onClose={() => setAdminMarkData(undefined)}
onSuccess={(adminFeedback) => {
console.log(adminMarkData);
if (!appId || !chatId || !adminMarkData.chatItemId) return;
updateChatAdminFeedback({
appId,
@@ -1108,6 +1112,7 @@ const VariableInput = React.memo(function VariableInput({
}>;
}) {
const { t } = useTranslation();
const [refresh, setRefresh] = useState(false);
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
const variables = watch('variables');
@@ -1168,6 +1173,7 @@ const VariableInput = React.memo(function VariableInput({
value={variables[item.key]}
onchange={(e) => {
setValue(`variables.${item.key}`, e);
setRefresh((state) => !state);
}}
/>
)}

View File

@@ -3,10 +3,12 @@ import { Button, ModalFooter, ModalBody } from '@chakra-ui/react';
import MyModal from '../MyModal';
import { useTranslation } from 'next-i18next';
import Markdown from '../Markdown';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const CommunityModal = ({ onClose }: { onClose: () => void }) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
return (
<MyModal
isOpen={true}

View File

@@ -1,7 +1,8 @@
import { useRouter } from 'next/router';
import { useToast } from '@chakra-ui/react';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'next-i18next';
import { useToast } from '@fastgpt/web/hooks/useToast';
const unAuthPage: { [key: string]: boolean } = {
'/': true,
@@ -10,16 +11,14 @@ const unAuthPage: { [key: string]: boolean } = {
'/login/fastlogin': true,
'/appStore': true,
'/chat/share': true,
'/tools/price': true
'/tools/price': true,
'/price': true
};
const Auth = ({ children }: { children: JSX.Element }) => {
const { t } = useTranslation();
const router = useRouter();
const toast = useToast({
title: '请先登录',
position: 'top',
status: 'warning'
});
const { toast } = useToast();
const { userInfo, initUserInfo } = useUserStore();
useQuery(
@@ -37,12 +36,15 @@ const Auth = ({ children }: { children: JSX.Element }) => {
router.replace(
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
);
toast();
toast({
status: 'warning',
title: t('support.user.Need to login')
});
}
}
);
return userInfo || unAuthPage[router.pathname] === true ? children : null;
return !!userInfo || unAuthPage[router.pathname] === true ? children : null;
};
export default Auth;

View File

@@ -7,7 +7,6 @@ import { throttle } from 'lodash';
import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getUnreadCount } from '@/web/support/user/inform/api';
import { feConfigs } from '@/web/common/system/staticData';
import dynamic from 'next/dynamic';
import Auth from './auth';
@@ -26,7 +25,8 @@ const pcUnShowLayoutRoute: Record<string, boolean> = {
'/chat/share': true,
'/app/edit': true,
'/chat': true,
'/tools/price': true
'/tools/price': true,
'/price': true
};
const phoneUnShowLayoutRoute: Record<string, boolean> = {
'/': true,
@@ -34,14 +34,15 @@ const phoneUnShowLayoutRoute: Record<string, boolean> = {
'/login/provider': true,
'/login/fastlogin': true,
'/chat/share': true,
'/tools/price': true
'/tools/price': true,
'/price': true
};
const Layout = ({ children }: { children: JSX.Element }) => {
const router = useRouter();
const { colorMode, setColorMode } = useColorMode();
const { Loading } = useLoading();
const { loading, setScreenWidth, isPc } = useSystemStore();
const { loading, setScreenWidth, isPc, feConfigs } = useSystemStore();
const { userInfo } = useUserStore();
const isChatPage = useMemo(
@@ -74,12 +75,14 @@ const Layout = ({ children }: { children: JSX.Element }) => {
refetchInterval: 10000
});
const isHideNavbar = !!pcUnShowLayoutRoute[router.pathname];
return (
<>
<Box h={'100%'} bg={'myGray.100'}>
{isPc === true && (
<>
{pcUnShowLayoutRoute[router.pathname] ? (
{isHideNavbar ? (
<Auth>{children}</Auth>
) : (
<>

View File

@@ -4,7 +4,6 @@ import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useChatStore } from '@/web/core/chat/storeChat';
import { HUMAN_ICON } from '@fastgpt/global/common/system/constants';
import { feConfigs } from '@/web/common/system/staticData';
import NextLink from 'next/link';
import Badge from '../Badge';
import Avatar from '../Avatar';
@@ -23,7 +22,7 @@ const Navbar = ({ unread }: { unread: number }) => {
const { t } = useTranslation();
const router = useRouter();
const { userInfo } = useUserStore();
const { gitStar } = useSystemStore();
const { gitStar, feConfigs } = useSystemStore();
const { lastChatAppId, lastChatId } = useChatStore();
const navbarList = useMemo(
() => [
@@ -159,7 +158,7 @@ const Navbar = ({ unread }: { unread: number }) => {
color={'myGray.500'}
>
<Badge count={unread}>
<MyIcon name={'inform'} width={'22px'} height={'22px'} />
<MyIcon name={'support/user/informLight'} width={'22px'} height={'22px'} />
</Badge>
</Link>
</Box>

View File

@@ -1,18 +1,27 @@
import React from 'react';
import { Menu, MenuList, MenuItem } from '@chakra-ui/react';
import React, { useRef, useState } from 'react';
import { Menu, MenuList, MenuItem, Box, useOutsideClick, MenuButton } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
interface Props {
width: number;
width?: number | string;
offset?: [number, number];
Button: React.ReactNode;
trigger?: 'hover' | 'click';
menuList: {
isActive?: boolean;
child: React.ReactNode;
label: string | React.ReactNode;
icon?: string;
onClick: () => any;
}[];
}
const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => {
const MyMenu = ({
width = 'auto',
trigger = 'hover',
offset = [0, 5],
Button,
menuList
}: Props) => {
const menuItemStyles = {
borderRadius: 'sm',
py: 3,
@@ -23,31 +32,80 @@ const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => {
color: 'primary.600'
}
};
const ref = useRef<HTMLDivElement>(null);
const closeTimer = useRef<any>();
const [isOpen, setIsOpen] = useState(false);
useOutsideClick({
ref: ref,
handler: () => {
setIsOpen(false);
}
});
return (
<Menu offset={offset} autoSelect={false} isLazy>
{Button}
<MenuList
minW={`${width}px !important`}
p={'6px'}
border={'1px solid #fff'}
boxShadow={'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'}
<Menu offset={offset} isOpen={isOpen} autoSelect={false} direction={'ltr'} isLazy>
<Box
ref={ref}
onMouseEnter={() => {
if (trigger === 'hover') {
setIsOpen(true);
}
clearTimeout(closeTimer.current);
}}
onMouseLeave={() => {
if (trigger === 'hover') {
closeTimer.current = setTimeout(() => {
setIsOpen(false);
}, 100);
}
}}
>
{menuList.map((item, i) => (
<MenuItem
key={i}
{...menuItemStyles}
onClick={(e) => {
e.stopPropagation();
item.onClick && item.onClick();
}}
color={item.isActive ? 'primary.700' : 'myGray.600'}
whiteSpace={'pre-wrap'}
>
{item.child}
</MenuItem>
))}
</MenuList>
<Box
position={'relative'}
onClickCapture={() => {
if (trigger === 'click') {
setIsOpen(!isOpen);
}
}}
>
<MenuButton
w={'100%'}
h={'100%'}
position={'absolute'}
top={0}
right={0}
bottom={0}
left={0}
/>
<Box position={'relative'}>{Button}</Box>
</Box>
<MenuList
minW={isOpen ? `${width}px !important` : 0}
p={'6px'}
border={'1px solid #fff'}
boxShadow={
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
}
>
{menuList.map((item, i) => (
<MenuItem
key={i}
{...menuItemStyles}
onClick={(e) => {
e.stopPropagation();
setIsOpen(false);
item.onClick && item.onClick();
}}
color={item.isActive ? 'primary.700' : 'myGray.600'}
whiteSpace={'pre-wrap'}
>
{!!item.icon && <MyIcon name={item.icon as any} w={'16px'} mr={2} />}
{item.label}
</MenuItem>
))}
</MenuList>
</Box>
</Menu>
);
};

View File

@@ -4,11 +4,13 @@ import MySelect, { type SelectProps } from './index';
import { useTranslation } from 'next-i18next';
import dynamic from 'next/dynamic';
import { useDisclosure } from '@chakra-ui/react';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const PriceBox = dynamic(() => import('@/components/support/wallet/Price'));
const SelectAiModel = ({ list, ...props }: SelectProps) => {
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const expandList = useMemo(() => {
return feConfigs.show_pay
? list.concat({
@@ -16,7 +18,7 @@ const SelectAiModel = ({ list, ...props }: SelectProps) => {
value: 'price'
})
: list;
}, [list, t]);
}, [feConfigs.show_pay, list, t]);
const {
isOpen: isOpenPriceBox,

View File

@@ -42,63 +42,76 @@ const MySlider = ({
};
return (
<Slider
max={max}
min={min}
step={step}
size={'lg'}
value={value}
width={width}
onChange={onChange}
>
{markList?.map((item, i) => (
<SliderMark
key={item.value}
value={item.value}
fontSize={'sm'}
mt={3}
whiteSpace={'nowrap'}
transform={'translateX(-50%)'}
color={'myGray.600'}
>
<Box px={3} cursor={'pointer'}>
{item.label}
</Box>
</SliderMark>
))}
<SliderMark
<Box pb={4} zIndex={10}>
<Slider
max={max}
min={min}
step={step}
size={'lg'}
value={value}
textAlign="center"
bg="primary.500"
color="white"
px={1}
minW={'18px'}
w={'auto'}
h={'18px'}
lineHeight={'18px'}
borderRadius={'18px'}
transform={'translate(-50%, -155%)'}
fontSize={'11px'}
>
<Box transform={'scale(0.9)'}>{value}</Box>
</SliderMark>
<SliderTrack
bg={'#EAEDF3'}
overflow={'visible'}
h={'4px'}
_before={{
...startEndPointStyle,
left: '-3px'
width={width}
onChange={onChange}
_hover={{
'& .marker': {
display: 'block'
}
}}
_after={{
...startEndPointStyle,
right: '-3px'
_active={{
'& .marker': {
display: 'block'
}
}}
>
<SliderFilledTrack bg={'primary.500'} />
</SliderTrack>
<SliderThumb border={'3px solid'} borderColor={'primary.500'}></SliderThumb>
</Slider>
{markList?.map((item, i) => (
<SliderMark
key={item.value}
value={item.value}
fontSize={'sm'}
mt={2}
whiteSpace={'nowrap'}
transform={'translateX(-50%)'}
color={'myGray.600'}
>
<Box px={3} cursor={'pointer'}>
{item.label}
</Box>
</SliderMark>
))}
<SliderMark
className="marker"
value={value}
textAlign="center"
bg="primary.500"
color="white"
px={1}
minW={'20px'}
w={'auto'}
py={'1px'}
borderRadius={'md'}
transform={'translate(-50%, -155%)'}
fontSize={'11px'}
display={'none'}
>
<Box transform={'scale(0.9)'}>{value}</Box>
</SliderMark>
<SliderTrack
bg={'#EAEDF3'}
overflow={'visible'}
h={'4px'}
_before={{
...startEndPointStyle,
left: '-3px'
}}
_after={{
...startEndPointStyle,
right: '-3px'
}}
>
<SliderFilledTrack bg={'primary.500'} />
</SliderTrack>
<SliderThumb border={'3px solid'} borderColor={'primary.500'}></SliderThumb>
</Slider>
</Box>
);
};

View File

@@ -9,7 +9,7 @@ import {
TagLabel,
useTheme
} from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useTranslation } from 'next-i18next';
type Props = BoxProps & { defaultValues: string[]; onUpdate: (e: string[]) => void };

View File

@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import { Box, BoxProps, Image } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import MyTooltip from '@/components/MyTooltip';
import { useTranslation } from 'next-i18next';

View File

@@ -7,17 +7,15 @@ import {
BoxProps,
Button,
Flex,
Image,
Link,
ModalBody,
ModalFooter,
Switch,
Textarea
Switch
} from '@chakra-ui/react';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { Prompt_QuotePromptList, Prompt_QuoteTemplateList } from '@/global/core/prompt/AIChat';
import { chatModelList, feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MySlider from '@/components/Slider';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import dynamic from 'next/dynamic';
@@ -27,7 +25,7 @@ import type { AppSimpleEditConfigTemplateType } from '@fastgpt/global/core/app/t
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
import { getDocPath } from '@/web/common/system/doc';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { PickerMenuItemType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
import { EditorVariablePickerType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
const PromptTemplate = dynamic(() => import('@/components/PromptTemplate'));
@@ -44,14 +42,17 @@ const AIChatSettingsModal = ({
onSuccess: (e: AIChatModuleProps) => void;
defaultData: AIChatModuleProps;
simpleModeTemplate?: AppSimpleEditConfigTemplateType;
pickerMenu?: PickerMenuItemType[];
pickerMenu?: EditorVariablePickerType[];
}) => {
const { t } = useTranslation();
const [refresh, setRefresh] = useState(false);
const { feConfigs, llmModelList } = useSystemStore();
const { register, handleSubmit, getValues, setValue } = useForm({
const { handleSubmit, getValues, setValue, watch } = useForm({
defaultValues: defaultData
});
const aiChatQuoteTemplate = watch(ModuleInputKeyEnum.aiChatQuoteTemplate);
const aiChatQuotePrompt = watch(ModuleInputKeyEnum.aiChatQuotePrompt);
const [selectTemplateData, setSelectTemplateData] = useState<{
title: string;
@@ -60,10 +61,10 @@ const AIChatSettingsModal = ({
const tokenLimit = useMemo(() => {
return (
chatModelList.find((item) => item.model === getValues(ModuleInputKeyEnum.aiModel))
llmModelList.find((item) => item.model === getValues(ModuleInputKeyEnum.aiModel))
?.maxResponse || 4000
);
}, [getValues]);
}, [getValues, llmModelList]);
const quoteTemplateVariables = (() => [
{
@@ -160,7 +161,7 @@ const AIChatSettingsModal = ({
</Flex>
)}
{simpleModeTemplate?.systemForm?.aiSettings?.temperature && (
<Flex alignItems={'center'} mb={10} mt={isAdEdit ? 8 : 5}>
<Flex mb={10} mt={isAdEdit ? 8 : 6}>
<Box {...LabelStyles} mr={2} w={'80px'}>
{t('core.app.Temperature')}
</Box>
@@ -183,7 +184,7 @@ const AIChatSettingsModal = ({
</Flex>
)}
{simpleModeTemplate?.systemForm?.aiSettings?.maxToken && (
<Flex alignItems={'center'} mt={12} mb={10}>
<Flex mt={5} mb={5}>
<Box {...LabelStyles} mr={2} w={'80px'}>
{t('core.app.Max tokens')}
</Box>
@@ -239,10 +240,10 @@ const AIChatSettingsModal = ({
placeholder={t('template.Quote Content Tip', {
default: Prompt_QuoteTemplateList[0].value
})}
defaultValue={getValues(ModuleInputKeyEnum.aiChatQuoteTemplate)}
value={aiChatQuoteTemplate}
onChange={(e) => {
setValue(ModuleInputKeyEnum.aiChatQuoteTemplate, e);
setRefresh(!refresh);
// setRefresh(!refresh);
}}
/>
</Box>
@@ -265,7 +266,7 @@ const AIChatSettingsModal = ({
placeholder={t('template.Quote Prompt Tip', {
default: Prompt_QuotePromptList[0].value
})}
defaultValue={getValues(ModuleInputKeyEnum.aiChatQuotePrompt)}
value={aiChatQuotePrompt}
onChange={(e) => {
setValue(ModuleInputKeyEnum.aiChatQuotePrompt, e);
}}

View File

@@ -17,7 +17,7 @@ import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
import { useTranslation } from 'next-i18next';
import { reRankModelList } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
@@ -45,6 +45,7 @@ const DatasetParamsModal = ({
}: DatasetParamsProps & { onClose: () => void; onSuccess: (e: DatasetParamsProps) => void }) => {
const { t } = useTranslation();
const theme = useTheme();
const { reRankModelList } = useSystemStore();
const [refresh, setRefresh] = useState(false);
const { register, setValue, getValues, handleSubmit } = useForm<DatasetParamsProps>({
defaultValues: {
@@ -72,7 +73,7 @@ const DatasetParamsModal = ({
return false;
return true;
}, [getValues, similarity, refresh]);
}, [getValues, similarity]);
return (
<MyModal
@@ -135,7 +136,7 @@ const DatasetParamsModal = ({
)}
{limit !== undefined && (
<Box display={['block', 'flex']} py={8} mt={3}>
<Box display={['block', 'flex']} mt={5}>
<Box flex={'0 0 120px'} mb={[8, 0]}>
{t('core.dataset.search.Max Tokens')}
<MyTooltip label={t('core.dataset.search.Max Tokens Tips')} forceShow>
@@ -151,9 +152,9 @@ const DatasetParamsModal = ({
min={100}
max={maxTokens}
step={50}
value={getValues(ModuleInputKeyEnum.datasetLimit) ?? 1000}
value={getValues(ModuleInputKeyEnum.datasetMaxTokens) ?? 1000}
onChange={(val) => {
setValue(ModuleInputKeyEnum.datasetLimit, val);
setValue(ModuleInputKeyEnum.datasetMaxTokens, val);
setRefresh(!refresh);
}}
/>
@@ -161,7 +162,7 @@ const DatasetParamsModal = ({
</Box>
)}
{showSimilarity && (
<Box display={['block', 'flex']} py={8}>
<Box display={['block', 'flex']} mt={5}>
<Box flex={'0 0 120px'} mb={[8, 0]}>
{t('core.dataset.search.Min Similarity')}
<MyTooltip label={t('core.dataset.search.Min Similarity Tips')} forceShow>

View File

@@ -12,7 +12,7 @@ import {
} from '@chakra-ui/react';
import Avatar from '@/components/Avatar';
import type { SelectedDatasetType } from '@fastgpt/global/core/module/api.d';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyTooltip from '@/components/MyTooltip';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';

View File

@@ -66,7 +66,7 @@ const ChatTest = (
appName: `调试-${app.name}`
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
return { responseText, responseData };

View File

@@ -24,7 +24,7 @@ import React, {
} from 'react';
import { customAlphabet } from 'nanoid';
import { appModule2FlowEdge, appModule2FlowNode } from '@/utils/adapt';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { EDGE_TYPE, FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { useTranslation } from 'next-i18next';

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
import MyModal from '@/components/MyModal';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useFlowProviderStore } from './FlowProvider';
type Props = {

View File

@@ -15,7 +15,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import EmptyTip from '@/components/EmptyTip';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { getPreviewPluginModule } from '@/web/core/plugin/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { moduleTemplatesList } from '@/web/core/modules/template/system';
@@ -100,6 +100,7 @@ const RenderList = React.memo(function RenderList({ templates, onClose }: Render
if (template.flowType === FlowNodeTypeEnum.pluginModule) {
setLoading(true);
const res = await getPreviewPluginModule(template.id);
setLoading(false);
return res;
}
@@ -107,7 +108,7 @@ const RenderList = React.memo(function RenderList({ templates, onClose }: Render
} catch (e) {
toast({
status: 'error',
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
title: getErrText(e, t('core.plugin.Get Plugin Module Detail Failed'))
});
setLoading(false);
return Promise.reject(e);

View File

@@ -1,10 +1,11 @@
import React, { useMemo } from 'react';
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
import { onDelConnect } from '../../FlowProvider';
import { onDelConnect, useFlowProviderStore } from '../../FlowProvider';
import { Flex } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
const ButtonEdge = (props: EdgeProps) => {
const { nodes } = useFlowProviderStore();
const {
id,
sourceX,
@@ -17,6 +18,13 @@ const ButtonEdge = (props: EdgeProps) => {
style = {}
} = props;
const active = (() => {
const connectNode = nodes.find((node) => {
return (node.id === props.source || node.id === props.target) && node.selected;
});
return !!(connectNode || selected);
})();
const [, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
@@ -41,8 +49,9 @@ const ButtonEdge = (props: EdgeProps) => {
borderRadius={'20px'}
color={'black'}
cursor={'pointer'}
border={'1px solid #fff'}
zIndex={selected ? 1000 : 0}
borderWidth={'1px'}
borderColor={'borderColor.low'}
zIndex={active ? 1000 : 0}
_hover={{
boxShadow: '0 0 6px 2px rgba(0, 0, 0, 0.08)'
}}
@@ -51,26 +60,43 @@ const ButtonEdge = (props: EdgeProps) => {
<MyIcon
name="closeSolid"
w={'100%'}
color={selected ? 'primary.700' : 'myGray.500'}
color={active ? 'primary.800' : 'myGray.400'}
></MyIcon>
</Flex>
<Flex
alignItems={'center'}
justifyContent={'center'}
position={'absolute'}
transform={`translate(-78%, -50%) translate(${targetX}px,${targetY}px)`}
pointerEvents={'all'}
w={'16px'}
h={'16px'}
bg={'white'}
zIndex={active ? 1000 : 0}
>
<MyIcon
name={'common/rightArrowLight'}
w={'100%'}
color={active ? 'primary.800' : 'myGray.400'}
></MyIcon>
</Flex>
</EdgeLabelRenderer>
);
}, [id, labelX, labelY, selected]);
}, [id, labelX, labelY, active, targetX, targetY]);
const memoBezierEdge = useMemo(() => {
const edgeStyle: React.CSSProperties = {
...style,
...(selected
...(active
? {
strokeWidth: 4,
strokeWidth: 5,
stroke: '#3370ff'
}
: { strokeWidth: 2, stroke: '#BDC1C5' })
: { strokeWidth: 2, zIndex: 2, stroke: 'myGray.300' })
};
return <BezierEdge {...props} style={edgeStyle} />;
}, [props, selected, style]);
}, [props, active, style]);
return (
<>

View File

@@ -2,19 +2,22 @@ import React from 'react';
import { Box, useTheme } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
const Divider = ({ text }: { text: 'Input' | 'Output' | string }) => {
const Divider = ({ text }: { text?: 'Input' | 'Output' | string }) => {
const theme = useTheme();
const { t } = useTranslation();
const isDivider = !text;
return (
<Box
textAlign={'center'}
bg={'#f8f8f8'}
py={2}
py={isDivider ? '0' : 2}
borderTop={theme.borders.base}
borderBottom={theme.borders.base}
fontSize={'lg'}
>
{t(`common.${text}`)}
{text ? t(`common.${text}`) : ''}
</Box>
);
};

View File

@@ -8,7 +8,7 @@ import MySelect from '@/components/Select';
import { TTSTypeEnum } from '@/constants/app';
import type { AppTTSConfigType } from '@fastgpt/global/core/module/type.d';
import { useAudioPlay } from '@/web/common/utils/voice';
import { audioSpeechModelList } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyModal from '@/components/MyModal';
import MySlider from '@/components/Slider';
@@ -20,6 +20,7 @@ const TTSSelect = ({
onChange: (e: AppTTSConfigType) => void;
}) => {
const { t } = useTranslation();
const { audioSpeechModelList } = useSystemStore();
const { isOpen, onOpen, onClose } = useDisclosure();
const list = useMemo(
@@ -28,7 +29,7 @@ const TTSSelect = ({
{ label: t('core.app.tts.Web'), value: TTSTypeEnum.web },
...audioSpeechModelList.map((item) => item?.voices || []).flat()
],
[t]
[audioSpeechModelList, t]
);
const formatValue = useMemo(() => {
@@ -106,7 +107,7 @@ const TTSSelect = ({
{t('core.app.tts.Speech model')}
<MySelect w={'220px'} value={formatValue} list={list} onchange={onclickChange} />
</Flex>
<Flex mt={8} justifyContent={'space-between'} alignItems={'center'}>
<Flex mt={8} justifyContent={'space-between'}>
{t('core.app.tts.Speech speed')}
<MySlider
markList={[

View File

@@ -36,9 +36,9 @@ import MyModal from '@/components/MyModal';
import MyTooltip from '@/components/MyTooltip';
import { variableTip } from '@fastgpt/global/core/module/template/tip';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyRadio from '@/components/common/MyRadio';
import { formatVariablesIcon } from '@fastgpt/global/core/module/utils';
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/module/utils';
const VariableEdit = ({
variables,
@@ -102,7 +102,14 @@ const VariableEdit = ({
};
const formatVariables = useMemo(() => {
return formatVariablesIcon(variables);
const results = formatEditorVariablePickerIcon(variables);
return results.map((item) => {
const variable = variables.find((variable) => variable.key === item.key);
return {
...variable,
icon: item.icon
};
});
}, [variables]);
return (
@@ -111,7 +118,7 @@ const VariableEdit = ({
<MyIcon name={'core/app/simpleMode/variable'} w={'20px'} />
<Box ml={2} flex={1}>
{t('core.module.Variable')}
<MyTooltip label={variableTip} forceShow>
<MyTooltip label={t(variableTip)} forceShow>
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
</MyTooltip>
</Box>

View File

@@ -6,17 +6,16 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput';
const NodeAnswer = React.memo(function NodeAnswer({ data }: { data: FlowModuleItemType }) {
const NodeAnswer = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data;
return (
<NodeCard minW={'400px'} {...data}>
<NodeCard minW={'400px'} selected={selected} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
<RenderInput moduleId={moduleId} flowInputList={inputs} />
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
</Container>
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeAnswer data={data} />;
}
};
export default React.memo(NodeAnswer);

View File

@@ -17,12 +17,12 @@ import SourceHandle from '../render/SourceHandle';
import MyTooltip from '@/components/MyTooltip';
import { onChangeNode } from '../../FlowProvider';
const NodeCQNode = React.memo(function NodeCQNode({ data }: { data: FlowModuleItemType }) {
const NodeCQNode = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { moduleId, inputs } = data;
return (
<NodeCard minW={'400px'} {...data}>
<NodeCard minW={'400px'} selected={selected} {...data}>
<Divider text="Input" />
<Container>
<RenderInput
@@ -136,7 +136,5 @@ const NodeCQNode = React.memo(function NodeCQNode({ data }: { data: FlowModuleIt
</Container>
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeCQNode data={data} />;
}
};
export default React.memo(NodeCQNode);

View File

@@ -0,0 +1,145 @@
import React, { useMemo } from 'react';
import { NodeProps } from 'reactflow';
import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
import Container from '../modules/Container';
import RenderInput from '../render/RenderInput';
import { Box, Button, Flex } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { AddIcon } from '@chakra-ui/icons';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum
} from '@fastgpt/global/core/module/constants';
import { getOneQuoteInputTemplate } from '@fastgpt/global/core/module/template/system/datasetConcat';
import { onChangeNode, useFlowProviderStore } from '../../FlowProvider';
import TargetHandle from '../render/TargetHandle';
import MyIcon from '@fastgpt/web/components/common/Icon';
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';
const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { llmModelList } = useSystemStore();
const { nodes } = useFlowProviderStore();
const { moduleId, inputs, outputs } = data;
const quotes = inputs.filter((item) => item.valueType === ModuleIOValueTypeEnum.datasetQuote);
const tokenLimit = useMemo(() => {
let maxTokens = 3000;
nodes.forEach((item) => {
if (item.type === FlowNodeTypeEnum.chatNode) {
const model =
item.data.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const quoteMaxToken =
llmModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
}
});
return maxTokens;
}, [llmModelList, nodes]);
const RenderQuoteList = useMemo(
() => (
<Box>
<Box>
{quotes.map((quote, i) => (
<Flex key={quote.key} position={'relative'} mb={4} alignItems={'center'}>
<TargetHandle handleKey={quote.key} valueType={quote.valueType} />
<Box>
{t('core.chat.Quote')}
{i + 1}
</Box>
<MyIcon
ml={2}
w={'14px'}
name={'delete'}
cursor={'pointer'}
_hover={{ color: 'red.600' }}
onClick={() => {
onChangeNode({
moduleId,
type: 'delInput',
key: quote.key
});
}}
/>
</Flex>
))}
</Box>
<Button
leftIcon={<AddIcon />}
variant={'whiteBase'}
onClick={() => {
onChangeNode({
moduleId,
type: 'addInput',
value: getOneQuoteInputTemplate()
});
}}
>
{t('core.module.Dataset quote.Add quote')}
</Button>
</Box>
),
[moduleId, quotes, t]
);
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>
)
}}
/>
{/* render dataset select */}
{RenderQuoteList}
<Flex position={'absolute'} right={4} top={'50%'} transform={'translate(0,-50%)'}>
<Box>{t('core.module.Dataset quote.Concat result')}</Box>
<SourceHandle
handleKey={ModuleOutputKeyEnum.datasetQuoteQA}
valueType={ModuleIOValueTypeEnum.datasetQuote}
// transform={'translate(-14px, -50%)'}
/>
</Flex>
{/* <RenderOutput moduleId={moduleId} flowOutputList={outputs} /> */}
</Container>
</NodeCard>
);
};
export default React.memo(NodeDatasetConcat);

View File

@@ -3,10 +3,8 @@ import { NodeProps } from 'reactflow';
import NodeCard from '../render/NodeCard';
import { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
const NodeAnswer = React.memo(function NodeAnswer({ data }: { data: FlowModuleItemType }) {
return <NodeCard {...data}></NodeCard>;
});
const NodeEmpty = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
return <NodeCard selected={selected} {...data}></NodeCard>;
};
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeAnswer data={data} />;
}
export default React.memo(NodeEmpty);

View File

@@ -17,7 +17,7 @@ import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/module/node/constan
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { onChangeNode } from '../../../FlowProvider';
const NodeExtract = React.memo(function NodeExtract({ data }: { data: FlowModuleItemType }) {
const NodeExtract = ({ data }: NodeProps<FlowModuleItemType>) => {
const { inputs, outputs, moduleId } = data;
const { t } = useTranslation();
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
@@ -183,8 +183,6 @@ const NodeExtract = React.memo(function NodeExtract({ data }: { data: FlowModule
)}
</NodeCard>
);
});
};
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeExtract data={data} />;
}
export default React.memo(NodeExtract);

View File

@@ -1,37 +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 { Box, Button } from '@chakra-ui/react';
import { SmallAddIcon } from '@chakra-ui/icons';
import RenderOutput from '../render/RenderOutput';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant';
import { ModuleIOValueTypeEnum } from '@fastgpt/global/core/module/constants';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
const NodeHttp = React.memo(function NodeHttp({ data }: { data: FlowModuleItemType }) {
const { moduleId, inputs, outputs } = data;
return (
<NodeCard minW={'350px'} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
<RenderInput moduleId={moduleId} flowInputList={inputs} />
</Container>
<Divider text="Output" />
<Container>
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
</Container>
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeHttp data={data} />;
}

View File

@@ -41,18 +41,14 @@ const createEditField = {
inputType: true
};
const NodePluginInput = React.memo(function NodePluginInput({
data
}: {
data: FlowModuleItemType;
}) {
const NodePluginInput = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { moduleId, inputs, outputs } = data;
const [createField, setCreateField] = useState<EditNodeFieldType>();
const [editField, setEditField] = useState<EditNodeFieldType>();
return (
<NodeCard minW={'300px'} {...data}>
<NodeCard minW={'300px'} selected={selected} forbidMenu {...data}>
<Container mt={1} borderTop={'2px solid'} borderTopColor={'myGray.300'}>
{inputs.map((item) => (
<Flex
@@ -257,7 +253,5 @@ const NodePluginInput = React.memo(function NodePluginInput({
)}
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodePluginInput data={data} />;
}
};
export default React.memo(NodePluginInput);

View File

@@ -14,7 +14,7 @@ import Container from '../modules/Container';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@/components/MyTooltip';
import TargetHandle from '../render/TargetHandle';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import {
EditNodeFieldType,
FlowNodeInputItemType,
@@ -42,18 +42,14 @@ const createEditField = {
inputType: false
};
const NodePluginOutput = React.memo(function NodePluginOutput({
data
}: {
data: FlowModuleItemType;
}) {
const NodePluginOutput = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { t } = useTranslation();
const { moduleId, inputs, outputs } = data;
const [createField, setCreateField] = useState<EditNodeFieldType>();
const [editField, setEditField] = useState<EditNodeFieldType>();
return (
<NodeCard minW={'300px'} {...data}>
<NodeCard minW={'300px'} selected={selected} forbidMenu {...data}>
<Container mt={1} borderTop={'2px solid'} borderTopColor={'myGray.300'}>
{inputs.map((item) => (
<Flex
@@ -237,8 +233,6 @@ const NodePluginOutput = React.memo(function NodePluginOutput({
)}
</NodeCard>
);
});
};
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodePluginOutput data={data} />;
}
export default React.memo(NodePluginOutput);

View File

@@ -6,22 +6,16 @@ import Container from '../modules/Container';
import RenderOutput from '../render/RenderOutput';
const QuestionInputNode = React.memo(function QuestionInputNode({
data
}: {
data: FlowModuleItemType;
}) {
const QuestionInputNode = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { moduleId, outputs } = data;
return (
<NodeCard minW={'240px'} {...data}>
<NodeCard minW={'240px'} selected={selected} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'} textAlign={'end'}>
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
</Container>
</NodeCard>
);
});
};
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <QuestionInputNode data={data} />;
}
export default React.memo(QuestionInputNode);

View File

@@ -7,11 +7,11 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput';
const NodeRunAPP = React.memo(function NodeRunAPP({ data }: { data: FlowModuleItemType }) {
const NodeRunAPP = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data;
return (
<NodeCard minW={'350px'} {...data}>
<NodeCard minW={'350px'} selected={selected} {...data}>
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
<RenderInput moduleId={moduleId} flowInputList={inputs} />
</Container>
@@ -21,7 +21,5 @@ const NodeRunAPP = React.memo(function NodeRunAPP({ data }: { data: FlowModuleIt
</Container>
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeRunAPP data={data} />;
}
};
export default React.memo(NodeRunAPP);

View File

@@ -7,11 +7,11 @@ import Container from '../modules/Container';
import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput';
const NodeSimple = React.memo(function NodeSimple({ data }: { data: FlowModuleItemType }) {
const NodeSimple = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const { moduleId, inputs, outputs } = data;
return (
<NodeCard minW={'350px'} {...data}>
<NodeCard minW={'350px'} selected={selected} {...data}>
{inputs.length > 0 && (
<>
<Divider text="Input" />
@@ -30,7 +30,5 @@ const NodeSimple = React.memo(function NodeSimple({ data }: { data: FlowModuleIt
)}
</NodeCard>
);
});
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeSimple data={data} />;
}
};
export default React.memo(NodeSimple);

View File

@@ -18,11 +18,11 @@ import TTSSelect from '@/components/core/module/Flow/components/modules/TTSSelec
import { splitGuideModule } from '@fastgpt/global/core/module/utils';
import { useTranslation } from 'next-i18next';
const NodeUserGuide = React.memo(function NodeUserGuide({ data }: { data: FlowModuleItemType }) {
const NodeUserGuide = ({ data, selected }: NodeProps<FlowModuleItemType>) => {
const theme = useTheme();
return (
<>
<NodeCard minW={'300px'} {...data}>
<NodeCard minW={'300px'} selected={selected} {...data}>
<Container className="nodrag" borderTop={'2px solid'} borderTopColor={'myGray.200'}>
<WelcomeText data={data} />
<Box pt={4} pb={2}>
@@ -38,12 +38,11 @@ const NodeUserGuide = React.memo(function NodeUserGuide({ data }: { data: FlowMo
</NodeCard>
</>
);
});
};
export default function Node({ data }: NodeProps<FlowModuleItemType>) {
return <NodeUserGuide data={data} />;
}
export function WelcomeText({ data }: { data: FlowModuleItemType }) {
export default React.memo(NodeUserGuide);
function WelcomeText({ data }: { data: FlowModuleItemType }) {
const { t } = useTranslation();
const { inputs, moduleId } = data;
const [, startTst] = useTransition();

View File

@@ -20,7 +20,7 @@ import {
FlowNodeOutputTypeEnum
} from '@fastgpt/global/core/module/node/constant';
import { EditInputFieldMap, EditNodeFieldType } from '@fastgpt/global/core/module/node/type.d';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
const FieldEditModal = ({
editField = {

View File

@@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import { Box, Flex, useTheme, Menu, MenuButton, MenuList, MenuItem } from '@chakra-ui/react';
import { Box, Flex, useTheme, MenuButton } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import Avatar from '@/components/Avatar';
import type { FlowModuleItemType } from '@fastgpt/global/core/module/type.d';
@@ -7,7 +7,7 @@ import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useTranslation } from 'next-i18next';
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { onChangeNode, onCopyNode, onResetNode, onDelNode } from '../../FlowProvider';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
@@ -16,11 +16,13 @@ import { getPreviewPluginModule } from '@/web/core/plugin/api';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
import MyMenu from '@/components/MyMenu';
type Props = FlowModuleItemType & {
children?: React.ReactNode | React.ReactNode[] | string;
minW?: string | number;
isPreview?: boolean;
forbidMenu?: boolean;
selected?: boolean;
};
const NodeCard = (props: Props) => {
@@ -34,7 +36,8 @@ const NodeCard = (props: Props) => {
moduleId,
flowType,
inputs,
isPreview
selected,
forbidMenu
} = props;
const theme = useTheme();
@@ -113,12 +116,6 @@ const NodeCard = (props: Props) => {
icon: 'delete',
label: t('common.Delete'),
onClick: () => onDelNode(moduleId)
},
{
icon: 'common/backLight',
label: t('common.Back'),
onClick: () => {}
}
],
[flowType, inputs, moduleId, name, onOpenModal, openConfirm, setLoading, t, toast]
@@ -129,13 +126,16 @@ const NodeCard = (props: Props) => {
minW={minW}
maxW={'500px'}
bg={'white'}
border={theme.borders.md}
borderWidth={'1px'}
borderColor={selected ? 'primary.600' : 'borderColor.base'}
borderRadius={'md'}
boxShadow={'sm'}
className={isPreview ? 'nodrag' : ''}
boxShadow={'1'}
_hover={{
boxShadow: '4'
}}
>
<Flex className="custom-drag-handle" px={4} py={3} alignItems={'center'}>
<Avatar src={avatar} borderRadius={'md'} objectFit={'contain'} w={'30px'} h={'30px'} />
<Avatar src={avatar} borderRadius={'0'} objectFit={'contain'} w={'30px'} h={'30px'} />
<Box ml={3} fontSize={'lg'} color={'myGray.600'}>
{t(name)}
</Box>
@@ -145,28 +145,25 @@ const NodeCard = (props: Props) => {
</MyTooltip>
)}
<Box flex={1} />
{!isPreview && (
<Menu autoSelect={false} isLazy>
<MenuButton
className={'nodrag'}
_hover={{ bg: 'myWhite.600' }}
cursor={'pointer'}
borderRadius={'md'}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
<MenuList color={'myGray.700'} minW={`120px !important`} zIndex={10}>
{menuList.map((item) => (
<MenuItem key={item.label} onClick={item.onClick} py={[2, 3]}>
<MyIcon name={item.icon as any} w={['14px', '16px']} />
<Box ml={[1, 2]}>{item.label}</Box>
</MenuItem>
))}
</MenuList>
</Menu>
{!forbidMenu && (
<MyMenu
offset={[-60, 5]}
width={120}
Button={
<MenuButton
className={'nodrag'}
_hover={{ bg: 'myWhite.600' }}
cursor={'pointer'}
borderRadius={'md'}
onClick={(e) => {
e.stopPropagation();
}}
>
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
}
menuList={menuList}
/>
)}
</Flex>
{children}

View File

@@ -123,25 +123,21 @@ const RenderInput = ({ flowInputList, moduleId, CustomComponent }: Props) => {
return <Component inputs={filterInputs} item={input} moduleId={moduleId} />;
})();
return (
return input.type !== FlowNodeInputTypeEnum.hidden ? (
<Box key={input.key} _notLast={{ mb: 7 }} position={'relative'}>
{input.key === ModuleInputKeyEnum.userChatInput && (
<UserChatInput inputs={filterInputs} item={input} moduleId={moduleId} />
)}
{input.type !== FlowNodeInputTypeEnum.hidden && (
<>
{!!input.label && (
<InputLabel moduleId={moduleId} inputKey={input.key} mode={mode} {...input} />
)}
{!!RenderComponent && (
<Box mt={2} className={'nodrag'}>
{RenderComponent}
</Box>
)}
</>
{!!input.label && (
<InputLabel moduleId={moduleId} inputKey={input.key} mode={mode} {...input} />
)}
{!!RenderComponent && (
<Box mt={2} className={'nodrag'}>
{RenderComponent}
</Box>
)}
</Box>
);
) : null;
});
}, [memoCustomComponent, filterInputs, mode, moduleId]);

View File

@@ -2,17 +2,11 @@ import React, { useCallback, useEffect } from 'react';
import type { RenderInputProps } from '../type';
import { onChangeNode } from '../../../../FlowProvider';
import SelectAiModel from '@/components/Select/SelectAiModel';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { chatModelList, cqModelList, extractModelList } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const SelectAiModelRender = ({ item, inputs = [], moduleId }: RenderInputProps) => {
const modelList = (() => {
if (item.type === FlowNodeInputTypeEnum.selectChatModel) return chatModelList;
if (item.type === FlowNodeInputTypeEnum.selectCQModel) return cqModelList;
if (item.type === FlowNodeInputTypeEnum.selectExtractModel) return extractModelList;
return [];
})().map((item) => ({
const { llmModelList } = useSystemStore();
const modelList = llmModelList.map((item) => ({
model: item.model,
name: item.name,
maxResponse: item.maxResponse

View File

@@ -10,7 +10,7 @@ import { useTranslation } from 'next-i18next';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { chatModelList } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import dynamic from 'next/dynamic';
import MyIcon from '@fastgpt/web/components/common/Icon';
@@ -21,6 +21,7 @@ const DatasetParamsModal = dynamic(() => import('@/components/core/module/Datase
const SelectDatasetRender = ({ inputs = [], item, moduleId }: RenderInputProps) => {
const { t } = useTranslation();
const theme = useTheme();
const { llmModelList } = useSystemStore();
const [nodes, setNodes] = useState<useFlowProviderStoreType['nodes']>([]);
const [data, setData] = useState({
searchMode: DatasetSearchModeEnum.embedding,
@@ -49,7 +50,7 @@ const SelectDatasetRender = ({ inputs = [], item, moduleId }: RenderInputProps)
const model =
item.data.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const quoteMaxToken =
chatModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
llmModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
}

View File

@@ -6,14 +6,15 @@ import { useTranslation } from 'next-i18next';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { chatModelList } from '@/web/common/system/staticData';
import MyIcon from '@fastgpt/web/components/common/Icon';
import DatasetParamsModal from '@/components/core/module/DatasetParamsModal';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
const { nodes } = useFlowProviderStore();
const { t } = useTranslation();
const { llmModelList } = useSystemStore();
const [data, setData] = useState({
searchMode: DatasetSearchModeEnum.embedding,
limit: 5,
@@ -29,14 +30,14 @@ const SelectDatasetParam = ({ inputs = [], moduleId }: RenderInputProps) => {
const model =
item.data.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const quoteMaxToken =
chatModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
llmModelList.find((item) => item.model === model)?.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
}
});
return maxTokens;
}, [nodes]);
}, [llmModelList, nodes]);
const { isOpen, onOpen, onClose } = useDisclosure();

View File

@@ -8,7 +8,7 @@ import MySlider from '@/components/Slider';
const SliderRender = ({ item, moduleId }: RenderInputProps) => {
const { t } = useTranslation();
return (
<Box pt={5} pb={4} px={2}>
<Box px={2}>
<MySlider
markList={item.markList}
width={'100%'}

View File

@@ -4,37 +4,42 @@ import { useFlowProviderStore, onChangeNode } from '../../../../FlowProvider';
import { useTranslation } from 'next-i18next';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import {
formatVariablesIcon,
formatEditorVariablePickerIcon,
getGuideModule,
splitGuideModule
} from '@fastgpt/global/core/module/utils';
const TextareaRender = ({ item, moduleId }: RenderInputProps) => {
const TextareaRender = ({ inputs = [], item, moduleId }: RenderInputProps) => {
const { t } = useTranslation();
const [, startTst] = useTransition();
const { nodes } = useFlowProviderStore();
// get variable
const variables = useMemo(
() =>
formatVariablesIcon(
splitGuideModule(getGuideModule(nodes.map((node) => node.data)))?.variableModules || []
),
[nodes]
);
const variables = useMemo(() => {
const globalVariables = formatEditorVariablePickerIcon(
splitGuideModule(getGuideModule(nodes.map((node) => node.data)))?.variableModules || []
);
const moduleVariables = formatEditorVariablePickerIcon(
inputs
.filter((input) => input.edit)
.map((item) => ({
key: item.key,
label: item.label
}))
);
return [...globalVariables, ...moduleVariables];
}, [inputs, nodes]);
const onChange = useCallback(
(e: string) => {
startTst(() => {
onChangeNode({
moduleId,
type: 'updateInput',
key: item.key,
value: {
...item,
value: e
}
});
onChangeNode({
moduleId,
type: 'updateInput',
key: item.key,
value: {
...item,
value: e
}
});
},
[item, moduleId]
@@ -46,7 +51,7 @@ const TextareaRender = ({ item, moduleId }: RenderInputProps) => {
title={t(item.label)}
h={150}
placeholder={t(item.placeholder || '')}
defaultValue={item.value}
value={item.value}
onChange={onChange}
/>
);

View File

@@ -19,6 +19,9 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
[FlowNodeTypeEnum.historyNode]: NodeSimple,
[FlowNodeTypeEnum.chatNode]: NodeSimple,
[FlowNodeTypeEnum.datasetSearchNode]: NodeSimple,
[FlowNodeTypeEnum.datasetConcatNode]: dynamic(
() => import('./components/nodes/NodeDatasetConcat')
),
[FlowNodeTypeEnum.answerNode]: dynamic(() => import('./components/nodes/NodeAnswer')),
[FlowNodeTypeEnum.classifyQuestion]: dynamic(() => import('./components/nodes/NodeCQNode')),
[FlowNodeTypeEnum.contentExtract]: dynamic(() => import('./components/nodes/NodeExtract')),

View File

@@ -14,7 +14,7 @@ export const flowNode2Modules = ({
const modules: ModuleItemType[] = nodes.map((item) => ({
moduleId: item.data.moduleId,
name: item.data.name,
avatar: item.data.avatar,
// avatar: item.data.avatar,
flowType: item.data.flowType,
showStatus: item.data.showStatus,
position: item.position,

View File

@@ -32,7 +32,7 @@ import { useLoading } from '@/web/common/hooks/useLoading';
import dayjs from 'dayjs';
import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@/components/MyModal';
@@ -40,6 +40,7 @@ import { useForm } from 'react-hook-form';
import { useRequest } from '@/web/common/hooks/useRequest';
import MyTooltip from '@/components/MyTooltip';
import { getDocPath } from '@/web/common/system/doc';
import MyMenu from '@/components/MyMenu';
type EditProps = EditApiKeyProps & { _id?: string };
const defaultEditData: EditProps = {
@@ -54,6 +55,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
const { Loading } = useLoading();
const theme = useTheme();
const { copyData } = useCopyData();
const { feConfigs } = useSystemStore();
const [baseUrl, setBaseUrl] = useState('https://fastgpt.in/api');
const [editData, setEditData] = useState<EditProps>();
const [apiKey, setApiKey] = useState('');
@@ -177,35 +179,37 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
: t('common.Un used')}
</Td>
<Td>
<Menu autoSelect={false} isLazy>
<MenuButton
_hover={{ bg: 'myWhite.600 ' }}
cursor={'pointer'}
borderRadius={'md'}
>
<MyIcon name={'more'} w={'14px'} p={2} />
</MenuButton>
<MenuList color={'myGray.700'} minW={`120px !important`} zIndex={10}>
<MenuItem
onClick={() =>
<MyMenu
offset={[-50, 5]}
Button={
<MyIcon
name={'more'}
w={'14px'}
p={2}
_hover={{ bg: 'myWhite.600 ' }}
cursor={'pointer'}
borderRadius={'md'}
/>
}
menuList={[
{
label: t('common.Edit'),
icon: 'edit',
onClick: () =>
setEditData({
_id,
name,
limit,
appId
})
}
py={[2, 3]}
>
<MyIcon name={'edit'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Edit')}</Box>
</MenuItem>
<MenuItem onClick={() => onclickRemove(_id)} py={[2, 3]}>
<MyIcon name={'delete'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Delete')}</Box>
</MenuItem>
</MenuList>
</Menu>
},
{
label: t('common.Delete'),
icon: 'delete',
onClick: () => onclickRemove(_id)
}
]}
/>
</Td>
</Tr>
))}
@@ -285,6 +289,7 @@ function EditKeyModal({
}) {
const { t } = useTranslation();
const isEdit = useMemo(() => !!defaultData._id, [defaultData]);
const { feConfigs } = useSystemStore();
const {
register,

View File

@@ -3,7 +3,7 @@ import { useForm } from 'react-hook-form';
import { useTranslation } from 'next-i18next';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useRequest } from '@/web/common/hooks/useRequest';
import MyModal from '@/components/MyModal';

View File

@@ -42,7 +42,7 @@ import { useLoading } from '@/web/common/hooks/useLoading';
import { FormDataType, defaultForm } from './EditModal';
import MyMenu from '@/components/MyMenu';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
const EditModal = dynamic(() => import('./EditModal'));
const InviteModal = dynamic(() => import('./InviteModal'));
@@ -324,11 +324,13 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
item.role !== TeamMemberRoleEnum.owner && (
<MyMenu
width={20}
trigger="click"
Button={
<MenuButton
_hover={{
bg: 'myWhite.600'
}}
borderRadius={'md'}
px={2}
py={1}
lineHeight={1}
@@ -344,7 +346,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
menuList={[
{
isActive: item.role === TeamMemberRoleEnum.visitor,
child: t('user.team.Invite Role Visitor Tip'),
label: t('user.team.Invite Role Visitor Tip'),
onClick: () => {
onUpdateMember({
teamId: item.teamId,
@@ -355,7 +357,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
},
{
isActive: item.role === TeamMemberRoleEnum.admin,
child: t('user.team.Invite Role Admin Tip'),
label: t('user.team.Invite Role Admin Tip'),
onClick: () => {
onUpdateMember({
teamId: item.teamId,
@@ -367,7 +369,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
...(item.status === TeamMemberStatusEnum.reject
? [
{
child: t('user.team.Reinvite'),
label: t('user.team.Reinvite'),
onClick: () => {
onUpdateMember({
teamId: item.teamId,
@@ -379,7 +381,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
]
: []),
{
child: t('user.team.Remove Member Tip'),
label: t('user.team.Remove Member Tip'),
onClick: () =>
openRemoveMember(
() =>

View File

@@ -4,13 +4,14 @@ import { useUserStore } from '@/web/support/user/useUserStore';
import { useTranslation } from 'next-i18next';
import MyTooltip from '@/components/MyTooltip';
import dynamic from 'next/dynamic';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@/web/common/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useToast } from '@fastgpt/web/hooks/useToast';
const TeamManageModal = dynamic(() => import('../TeamManageModal'));
const TeamMenu = () => {
const theme = useTheme();
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const { userInfo } = useUserStore();
const { toast } = useToast();

View File

@@ -15,15 +15,16 @@ 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 { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
const UpdateInviteModal = () => {
const { t } = useTranslation();
const theme = useTheme();
const { toast } = useToast();
const { ConfirmModal, openConfirm } = useConfirm({});
const { feConfigs } = useSystemStore();
const { data: inviteList = [], refetch } = useQuery(['getInviteList'], () =>
feConfigs.isPlus ? getTeamList(TeamMemberStatusEnum.waiting) : []

View File

@@ -1,29 +1,21 @@
import React from 'react';
import { Box, CloseButton } from '@chakra-ui/react';
import {
chatModelList,
vectorModelList,
qaModelList,
cqModelList,
extractModelList,
qgModelList,
audioSpeechModelList,
reRankModelList,
whisperModel
} from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import ReactDOM from 'react-dom';
import Markdown from '@/components/Markdown';
const Price = ({ onClose }: { onClose: () => void }) => {
const { llmModelList, vectorModelList, audioSpeechModelList, whisperModel } = useSystemStore();
const list = [
{
title: '对话模型',
title: 'AI语言模型',
describe: '',
md: `
| 模型 | 输入价格(¥) | 输出价格(¥) |
| --- | --- | --- |
${chatModelList
${llmModelList
?.map((item) => `| ${item.name} | ${item.inputPrice}/1k tokens | ${item.outputPrice}/1k tokens |`)
.join('\n')}`
},
@@ -36,51 +28,6 @@ ${chatModelList
${vectorModelList?.map((item) => `| ${item.name} | ${item.inputPrice}/1k 字符 |`).join('\n')}
`
},
{
title: '文件预处理模型(QA 拆分)',
describe: '',
md: `
| 模型 | 价格(¥) |
| --- | --- |
${qaModelList?.map((item) => `| ${item.name} | ${item.inputPrice}/1k 字符 |`).join('\n')}
`
},
{
title: '问题分类',
describe: '',
md: `
| 模型 | 输入价格(¥) | 输出价格(¥) |
| --- | --- | --- |
${cqModelList
?.map(
(item) => `| ${item.name} | ${item.inputPrice}/1k tokens | ${item.outputPrice}/1k tokens |`
)
.join('\n')}`
},
{
title: '内容提取',
describe: '',
md: `
| 模型 | 输入价格(¥) | 输出价格(¥) |
| --- | --- | --- |
${extractModelList
?.map(
(item) => `| ${item.name} | ${item.inputPrice}/1k tokens | ${item.outputPrice}/1k tokens |`
)
.join('\n')}`
},
{
title: '下一步指引',
describe: '',
md: `
| 模型 | 输入价格(¥) | 输出价格(¥) |
| --- | --- | --- |
${qgModelList
?.map(
(item) => `| ${item.name} | ${item.inputPrice}/1k tokens | ${item.outputPrice}/1k tokens |`
)
.join('\n')}`
},
{
title: '语音播放',
describe: '',

View File

@@ -26,8 +26,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useRouter } from 'next/router';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@/web/common/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
import MySelect from '@/components/Select';
import {
@@ -40,21 +39,20 @@ import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools
import { useUserStore } from '@/web/support/user/useUserStore';
const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
const datasetStoreFreeSize = feConfigs?.subscription?.datasetStoreFreeSize || 0;
const datasetStorePrice = feConfigs?.subscription?.datasetStorePrice || 0;
const { subPlans } = useSystemStore();
const datasetStorePrice = subPlans?.extraDatasetSize?.price || 0;
const { t } = useTranslation();
const { toast } = useToast();
const router = useRouter();
const { ConfirmModal, openConfirm } = useConfirm({});
const { userInfo } = useUserStore();
const [datasetSize, setDatasetSize] = useState(0);
const [isRenew, setIsRenew] = useState('false');
const { data: datasetSub } = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub, {
const { data: teamSubPlan } = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub, {
onSuccess(res) {
setIsRenew(res?.sub?.status === SubStatusEnum.active ? 'true' : 'false');
setDatasetSize((res?.sub?.nextExtraDatasetSize || 0) / 1000);
setIsRenew(res?.extraDatasetSize?.status === SubStatusEnum.active ? 'true' : 'false');
setDatasetSize((res?.extraDatasetSize?.nextExtraDatasetSize || 0) / 1000);
}
});
@@ -88,7 +86,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
<Box>
<Flex>
<Box flex={'0 0 100px'}>:</Box>
<Box>{datasetSub?.sub?.currentExtraDatasetSize || 0}</Box>
<Box>{teamSubPlan?.extraDatasetSize?.currentExtraDatasetSize || 0}</Box>
</Flex>
<Flex>
<Box flex={'0 0 100px'}>:</Box>
@@ -96,7 +94,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
</Flex>
<Flex>
<Box flex={'0 0 100px'}>:</Box>
<Box>{formatStorePrice2Read(res.newPrice)}</Box>
<Box>{formatStorePrice2Read(res.newPlanPrice)}</Box>
</Flex>
<Flex>
<Box flex={'0 0 100px'}>:</Box>
@@ -151,7 +149,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
</Flex>
<Markdown
source={`
| 免费知识库 | ${datasetStoreFreeSize}条 |
| 套餐知识库容量 | ${teamSubPlan?.standardMaxDatasetSize || Infinity}条 |
| --- | --- |
| 额外知识库 | ${datasetStorePrice}元/1000条/月 |
`}
@@ -160,29 +158,29 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
<Flex mt={4}>
<Box flex={'0 0 120px'}>{t('support.wallet.subscription.Current dataset store')}: </Box>
<Box ml={2} fontWeight={'bold'} flex={1}>
{datasetSub?.sub?.currentExtraDatasetSize || 0}
{teamSubPlan?.extraDatasetSize?.currentExtraDatasetSize || 0}
{t('core.dataset.data.unit')}
</Box>
</Flex>
{datasetSub?.sub?.nextExtraDatasetSize !== undefined && (
{teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize !== undefined && (
<Flex mt={4}>
<Box flex={'0 0 120px'}>{t('support.wallet.subscription.Next sub dataset size')}: </Box>
<Box ml={2} fontWeight={'bold'} flex={1}>
{datasetSub?.sub?.nextExtraDatasetSize || 0}
{teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize || 0}
{t('core.dataset.data.unit')}
</Box>
</Flex>
)}
{!!datasetSub?.sub?.startTime && (
{!!teamSubPlan?.extraDatasetSize?.startTime && (
<Flex mt={3}>
<Box flex={'0 0 120px'}>: </Box>
<Box ml={2}>{formatTime2YMDHM(datasetSub?.sub?.startTime)}</Box>
<Box ml={2}>{formatTime2YMDHM(teamSubPlan?.extraDatasetSize?.startTime)}</Box>
</Flex>
)}
{!!datasetSub?.sub?.expiredTime && (
{!!teamSubPlan?.extraDatasetSize?.expiredTime && (
<Flex mt={3}>
<Box flex={'0 0 120px'}>: </Box>
<Box ml={2}>{formatTime2YMDHM(datasetSub?.sub?.expiredTime)}</Box>
<Box ml={2}>{formatTime2YMDHM(teamSubPlan?.extraDatasetSize?.expiredTime)}</Box>
</Flex>
)}
<Flex mt={3} alignItems={'center'}>
@@ -205,7 +203,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
<NumberInput
flex={1}
min={0}
max={1000}
max={10000}
step={1}
value={datasetSize}
position={'relative'}
@@ -213,7 +211,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
setDatasetSize(Number(e));
}}
>
<NumberInputField value={datasetSize} step={1} min={0} max={1000} />
<NumberInputField value={datasetSize} step={1} min={0} max={10000} />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
@@ -227,7 +225,7 @@ const SubDatasetModal = ({ onClose }: { onClose: () => void }) => {
<Button variant={'whiteBase'} onClick={onClose}>
{t('common.Close')}
</Button>
{datasetSize * 1000 !== datasetSub?.sub?.nextExtraDatasetSize && (
{datasetSize * 1000 !== teamSubPlan?.extraDatasetSize?.nextExtraDatasetSize && (
<Button ml={3} isLoading={isLoading} onClick={onClickPreviewCheck}>
{t('common.Confirm')}
</Button>