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>

View File

@@ -1,6 +1,4 @@
import type {
ChatModelItemType,
FunctionModelItemType,
LLMModelItemType,
VectorModelItemType,
AudioSpeechModels,
@@ -10,18 +8,16 @@ import type {
import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types/index.d';
import { AppSimpleEditConfigTemplateType } from '@fastgpt/global/core/app/type';
import { SubPlanType } from '@fastgpt/global/support/wallet/sub/type';
export type InitDateResponse = {
chatModels: ChatModelItemType[];
qaModels: LLMModelItemType[];
cqModels: FunctionModelItemType[];
extractModels: FunctionModelItemType[];
llmModels: LLMModelItemType[];
vectorModels: VectorModelItemType[];
audioSpeechModels: AudioSpeechModels[];
reRankModels: ReRankModelItemType[];
qgModes: LLMModelItemType[];
whisperModel: WhisperModelType;
feConfigs: FastGPTFeConfigsType;
subPlans?: SubPlanType;
systemVersion: string;
simpleModeTemplates: AppSimpleEditConfigTemplateType[];
};

View File

@@ -8,7 +8,7 @@ import { theme } from '@/web/styles/theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import NProgress from 'nprogress'; //nprogress module
import Router from 'next/router';
import { clientInitData, feConfigs } from '@/web/common/system/staticData';
import { clientInitData } from '@/web/common/system/staticData';
import { appWithTranslation, useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
@@ -39,7 +39,7 @@ function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const { hiId } = router.query as { hiId?: string };
const { i18n } = useTranslation();
const { loadGitStar } = useSystemStore();
const { loadGitStar, setInitd, feConfigs } = useSystemStore();
const [scripts, setScripts] = useState<FastGPTFeConfigsType['scripts']>([]);
const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI');
@@ -65,6 +65,7 @@ function App({ Component, pageProps }: AppProps) {
}
setScripts(scripts || []);
setInitd();
})();
// add window error track

View File

@@ -107,7 +107,7 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>{t('wallet.bill.Source')}:</Box>
<Box>{BillSourceMap[bill.source]?.label}</Box>
<Box>{t(BillSourceMap[bill.source]?.label)}</Box>
</Flex>
<Flex alignItems={'center'} pb={4}>
<Box flex={'0 0 80px'}>{t('wallet.bill.Total')}:</Box>
@@ -129,7 +129,7 @@ const BillDetail = ({ bill, onClose }: { bill: BillItemType; onClose: () => void
{hasCharsLen && <Th>{t('wallet.bill.Text Length')}</Th>}
{hasDuration && <Th>{t('wallet.bill.Duration')}</Th>}
{hasDatasetSize && (
<Th>{t('support.user.team.subscription.type.extraDatasetSize')}</Th>
<Th>{t('support.wallet.subscription.type.extraDatasetSize')}</Th>
)}
<Th>()</Th>
</Tr>

View File

@@ -45,7 +45,10 @@ const BillTable = () => {
const sourceList = useMemo(
() => [
{ label: t('common.All'), value: '' },
...Object.entries(BillSourceMap).map(([key, value]) => ({ label: value.label, value: key }))
...Object.entries(BillSourceMap).map(([key, value]) => ({
label: t(value.label),
value: key
}))
],
[t]
);
@@ -152,7 +155,7 @@ const BillTable = () => {
<Tr key={item.id}>
{/* <Td>{item.memberName}</Td> */}
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
<Td>{BillSourceMap[item.source]?.label}</Td>
<Td>{t(BillSourceMap[item.source]?.label)}</Td>
<Td>{t(item.appName) || '-'}</Td>
<Td>{item.total}</Td>
<Td>

View File

@@ -13,14 +13,14 @@ import {
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useUserStore } from '@/web/support/user/useUserStore';
import type { UserType } from '@fastgpt/global/support/user/type.d';
import { useQuery } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { feConfigs, systemVersion } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import { timezoneList } from '@fastgpt/global/common/time/timezone';
import Avatar from '@/components/Avatar';
@@ -44,6 +44,7 @@ const SubDatasetModal = dynamic(() => import('@/components/support/wallet/SubDat
const UserInfo = () => {
const theme = useTheme();
const router = useRouter();
const { feConfigs, systemVersion } = useSystemStore();
const { t, i18n } = useTranslation();
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
const timezones = useRef(timezoneList());
@@ -122,12 +123,11 @@ const UserInfo = () => {
}
});
const { data: datasetSub = { maxSize: 0, usedSize: 0 } } = useQuery(
['getTeamDatasetValidSub'],
getTeamDatasetValidSub
);
const {
data: teamSubPlan = { totalPoints: 0, usedPoints: 0, datasetMaxSize: 800, usedDatasetSize: 0 }
} = useQuery(['getTeamDatasetValidSub'], getTeamDatasetValidSub);
const datasetUsageMap = useMemo(() => {
const rate = datasetSub.usedSize / datasetSub.maxSize;
const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize;
const colorScheme = (() => {
if (rate < 0.5) return 'green';
@@ -138,10 +138,10 @@ const UserInfo = () => {
return {
colorScheme,
value: rate * 100,
maxSize: datasetSub.maxSize,
usedSize: datasetSub.usedSize
maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'),
usedSize: teamSubPlan.usedDatasetSize
};
}, [datasetSub.maxSize, datasetSub.usedSize]);
}, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]);
return (
<Box
@@ -276,7 +276,7 @@ const UserInfo = () => {
<Flex alignItems={'center'}>
<Box flex={'1 0 0'} fontSize={'md'}>
{t('support.user.team.Dataset usage')}:&nbsp;{datasetUsageMap.usedSize}/
{datasetSub.maxSize}
{datasetUsageMap.maxSize}
</Box>
{userInfo?.team?.canWrite && (
<Button size={'sm'} onClick={onOpenSubDatasetModal}>
@@ -316,7 +316,7 @@ const UserInfo = () => {
userSelect={'none'}
textDecoration={'none !important'}
>
<MyIcon name={'common/courseLight'} w={'18px'} />
<MyIcon name={'common/courseLight'} w={'18px'} color={'myGray.600'} />
<Box ml={2} flex={1}>
{t('system.Help Document')}
</Box>
@@ -366,7 +366,7 @@ const UserInfo = () => {
userSelect={'none'}
onClick={onOpenOpenai}
>
<Avatar src={'/imgs/openai.png'} w={'18px'} />
<MyIcon name={'common/openai'} w={'18px'} color={'myGray.600'} />
<Box ml={2} flex={1}>
OpenAI/OneAPI
</Box>

View File

@@ -32,7 +32,7 @@ const OpenAIAccountModal = ({
<MyModal
isOpen
onClose={onClose}
iconSrc="/imgs/modal/openai.svg"
iconSrc="common/openai"
title={t('user.OpenAI Account Setting')}
>
<ModalBody>

View File

@@ -1,7 +1,7 @@
import React, { useState, useCallback } from 'react';
import { ModalFooter, ModalBody, Button, Input, Box, Grid } from '@chakra-ui/react';
import { getPayCode, checkPayResult } from '@/web/support/wallet/pay/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { getErrText } from '@fastgpt/global/common/error/utils';

View File

@@ -16,7 +16,7 @@ import type { PaySchema } from '@fastgpt/global/support/wallet/pay/type.d';
import dayjs from 'dayjs';
import { useQuery } from '@tanstack/react-query';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useLoading } from '@/web/common/hooks/useLoading';
import MyIcon from '@fastgpt/web/components/common/Icon';

View File

@@ -10,7 +10,6 @@ import SideTabs from '@/components/SideTabs';
import Tabs from '@/components/Tabs';
import UserInfo from './components/Info';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { feConfigs } from '@/web/common/system/staticData';
import { useTranslation } from 'next-i18next';
import Script from 'next/script';
@@ -35,6 +34,7 @@ enum TabEnum {
const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const { t } = useTranslation();
const { userInfo, setUserInfo } = useUserStore();
const { feConfigs, isPc } = useSystemStore();
const tabList = [
{
@@ -116,7 +116,6 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const router = useRouter();
const theme = useTheme();
const { isPc } = useSystemStore();
const setCurrentTab = useCallback(
(tab: string) => {

View File

@@ -22,10 +22,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
jsonRes<InitDateResponse>(res, {
data: {
feConfigs: global.feConfigs,
chatModels: global.chatModels,
qaModels: global.qaModels,
cqModels: global.cqModels,
extractModels: global.extractModels,
subPlans: global.subPlans,
llmModels: global.llmModels,
vectorModels: global.vectorModels,
reRankModels:
global.reRankModels?.map((item) => ({
@@ -33,7 +31,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
requestUrl: undefined,
requestAuth: undefined
})) || [],
qgModes: global.qgModels,
whisperModel: global.whisperModel,
audioSpeechModels: global.audioSpeechModels,
systemVersion: global.systemVersion || '0.0.0',
@@ -119,11 +116,8 @@ export async function initSystemConfig() {
...fileRes.systemEnv,
...(dbConfig.systemEnv || {})
},
chatModels: dbConfig.chatModels || fileRes.chatModels || [],
qaModels: dbConfig.qaModels || fileRes.qaModels || [],
cqModels: dbConfig.cqModels || fileRes.cqModels || [],
extractModels: dbConfig.extractModels || fileRes.extractModels || [],
qgModels: dbConfig.qgModels || fileRes.qgModels || [],
subPlans: dbConfig.subPlans || fileRes.subPlans,
llmModels: dbConfig.llmModels || fileRes.llmModels || [],
vectorModels: dbConfig.vectorModels || fileRes.vectorModels || [],
reRankModels: dbConfig.reRankModels || fileRes.reRankModels || [],
audioSpeechModels: dbConfig.audioSpeechModels || fileRes.audioSpeechModels || [],
@@ -133,12 +127,9 @@ export async function initSystemConfig() {
// set config
global.feConfigs = config.feConfigs;
global.systemEnv = config.systemEnv;
global.subPlans = config.subPlans;
global.chatModels = config.chatModels;
global.qaModels = config.qaModels;
global.cqModels = config.cqModels;
global.extractModels = config.extractModels;
global.qgModels = config.qgModels;
global.llmModels = config.llmModels;
global.vectorModels = config.vectorModels;
global.reRankModels = config.reRankModels;
global.audioSpeechModels = config.audioSpeechModels;
@@ -147,11 +138,8 @@ export async function initSystemConfig() {
console.log({
feConfigs: global.feConfigs,
systemEnv: global.systemEnv,
chatModels: global.chatModels,
qaModels: global.qaModels,
cqModels: global.cqModels,
extractModels: global.extractModels,
qgModels: global.qgModels,
subPlans: global.subPlans,
llmModels: global.llmModels,
vectorModels: global.vectorModels,
reRankModels: global.reRankModels,
audioSpeechModels: global.audioSpeechModels,

View File

@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
shareId
});
const qgModel = global.qgModels[0];
const qgModel = global.llmModels[0];
const { result, inputTokens, outputTokens } = await createQuestionGuide({
messages,

View File

@@ -6,6 +6,7 @@ import { MongoApp } from '@fastgpt/service/core/app/schema';
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -21,21 +22,33 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await authApp({ req, authToken: true, appId, per: 'owner' });
// 删除对应的聊天
await MongoChatItem.deleteMany({
appId
});
await MongoChat.deleteMany({
appId
});
// 删除分享链接
await MongoOutLink.deleteMany({
appId
});
// 删除模型
await MongoApp.deleteOne({
_id: appId
await mongoSessionRun(async (session) => {
await MongoChatItem.deleteMany(
{
appId
},
{ session }
);
await MongoChat.deleteMany(
{
appId
},
{ session }
);
// 删除分享链接
await MongoOutLink.deleteMany(
{
appId
},
{ session }
);
// delete app
await MongoApp.deleteOne(
{
_id: appId
},
{ session }
);
});
jsonRes(res);

View File

@@ -8,11 +8,11 @@ import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
import { getExtractModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const { formData, chatModelMaxToken, chatModelList } = req.body as FormatForm2ModulesProps;
const { formData, chatModelMaxToken } = req.body as FormatForm2ModulesProps;
const modules = [
...(formData.dataset.datasets.length > 0
@@ -381,7 +381,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
valueType: 'boolean',
showTargetInApp: false,
showTargetInPlugin: false,
value: true,
@@ -676,7 +676,7 @@ function datasetTemplate({ formData, maxToken }: Props): ModuleItemType[] {
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getExtractModel().model,
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false

View File

@@ -7,7 +7,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type.d';
import type { ModuleItemType } from '@fastgpt/global/core/module/type';
import { FormatForm2ModulesProps } from '@fastgpt/global/core/app/api';
import { getExtractModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -377,7 +377,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
key: 'usingReRank',
type: 'hidden',
label: '',
valueType: 'string',
valueType: 'boolean',
showTargetInApp: false,
showTargetInPlugin: false,
value: formData.dataset.usingReRank,
@@ -686,7 +686,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
label: 'core.module.input.label.aiModel',
required: true,
valueType: 'string',
value: getExtractModel().model,
value: getLLMModel().model,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false

View File

@@ -6,7 +6,7 @@ import type { AppUpdateParams } from '@fastgpt/global/core/app/api';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
import { getChatModel } from '@/service/core/ai/model';
import { getLLMModel } from '@/service/core/ai/model';
/* 获取我的模型 */
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
@@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
if (item.flowType === FlowNodeTypeEnum.chatNode) {
const model =
item.inputs.find((item) => item.key === ModuleInputKeyEnum.aiModel)?.value || '';
const chatModel = getChatModel(model);
const chatModel = getLLMModel(model);
const quoteMaxToken = chatModel.quoteMaxToken || 3000;
maxTokens = Math.max(maxTokens, quoteMaxToken);
@@ -42,7 +42,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
modules.forEach((item) => {
if (item.flowType === FlowNodeTypeEnum.datasetSearchNode) {
item.inputs.forEach((input) => {
if (input.key === ModuleInputKeyEnum.datasetLimit) {
if (input.key === ModuleInputKeyEnum.datasetMaxTokens) {
const val = input.value as number;
if (val > maxTokens) {
input.value = maxTokens;

View File

@@ -5,6 +5,7 @@ import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { DelHistoryProps } from '@/global/core/chat/api';
import { autChatCrud } from '@/service/support/permission/auth/chat';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
/* clear chat history */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -22,13 +23,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
per: 'w'
});
await MongoChatItem.deleteMany({
appId,
chatId
});
await MongoChat.findOneAndRemove({
appId,
chatId
await mongoSessionRun(async (session) => {
await MongoChatItem.deleteMany(
{
appId,
chatId
},
{ session }
);
await MongoChat.findOneAndRemove(
{
appId,
chatId
},
{ session }
);
});
jsonRes(res);

View File

@@ -21,12 +21,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
per: 'w'
});
const { _id } = await createOneCollection({
...body,
teamId,
tmbId
});
jsonRes(res, {
data: await createOneCollection({
...body,
teamId,
tmbId
})
data: _id
});
} catch (err) {
jsonRes(res, {

View File

@@ -1,13 +1,14 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
import { delFileByFileIdList, uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
import { getUploadModel } from '@fastgpt/service/common/file/multer';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
import { FileCreateDatasetCollectionParams } from '@fastgpt/global/core/dataset/api';
import { removeFilesByPaths } from '@fastgpt/service/common/file/utils';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
/**
* Creates the multer uploader
@@ -18,7 +19,7 @@ const upload = getUploadModel({
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
let filePaths: string[] = [];
let fileId: string = '';
const { datasetId } = req.query as { datasetId: string };
try {
@@ -45,7 +46,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { fileMetadata, collectionMetadata, ...collectionData } = data;
// upload file and create collection
const fileId = await uploadFile({
fileId = await uploadFile({
teamId,
tmbId,
bucketName,
@@ -56,7 +57,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// create collection
const collectionId = await createOneCollection({
const { _id: collectionId } = await createOneCollection({
...collectionData,
metadata: collectionMetadata,
teamId,
@@ -69,6 +70,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: collectionId
});
} catch (error) {
if (fileId) {
try {
await delFileByFileIdList({
fileIdList: [fileId],
bucketName: BucketNameEnum.dataset
});
} catch (error) {}
}
jsonRes(res, {
code: 500,
error

View File

@@ -15,8 +15,10 @@ import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dat
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { reloadCollectionChunks } from '@fastgpt/service/core/dataset/collection/utils';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -41,39 +43,51 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 1. check dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(trainingType, new Array(10))
insertLen: predictDataLimitLength(trainingType, new Array(10)),
standardPlans: getStandardSubPlan()
});
// 2. create collection
const collectionId = await createOneCollection({
...body,
name: link,
teamId,
tmbId,
type: DatasetCollectionTypeEnum.link,
const { _id: collectionId } = await mongoSessionRun(async (session) => {
// 2. create collection
const collection = await createOneCollection({
...body,
name: link,
teamId,
tmbId,
type: DatasetCollectionTypeEnum.link,
trainingType,
chunkSize,
chunkSplitter,
qaPrompt,
trainingType,
chunkSize,
chunkSplitter,
qaPrompt,
rawLink: link
});
rawLink: link,
session
});
// 3. create bill and start sync
const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getQAModel(dataset.agentModel).name
});
await reloadCollectionChunks({
collectionId,
tmbId,
billId
// 3. create bill and start sync
const { billId } = await createTrainingBill({
teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getLLMModel(dataset.agentModel).name,
session
});
// load
await reloadCollectionChunks({
collection: {
...collection.toObject(),
datasetId: dataset
},
tmbId,
billId,
session
});
return collection;
});
jsonRes(res, {

View File

@@ -18,7 +18,8 @@ import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller'
import { hashStr } from '@fastgpt/global/common/string/tools';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -52,12 +53,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 2. check dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(trainingType, chunks)
insertLen: predictDataLimitLength(trainingType, chunks),
standardPlans: getStandardSubPlan()
});
// 3. create collection and training bill
const [collectionId, { billId }] = await Promise.all([
const [{ _id: collectionId }, { billId }] = await Promise.all([
createOneCollection({
...body,
teamId,
@@ -79,7 +80,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
appName: name,
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel)?.name,
agentModel: getQAModel(dataset.agentModel)?.name
agentModel: getLLMModel(dataset.agentModel)?.name
})
]);

View File

@@ -4,6 +4,7 @@ import { connectToDatabase } from '@/service/mongo';
import { findCollectionAndChild } from '@fastgpt/service/core/dataset/collection/utils';
import { delCollectionAndRelatedSources } from '@fastgpt/service/core/dataset/collection/controller';
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -32,9 +33,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// delete
await delCollectionAndRelatedSources({
collections
});
await mongoSessionRun((session) =>
delCollectionAndRelatedSources({
collections,
session
})
);
jsonRes(res);
} catch (err) {

View File

@@ -14,8 +14,9 @@ import {
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -27,7 +28,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
throw new Error('CollectionIdId is required');
}
const { collection, teamId, tmbId } = await authDatasetCollection({
const { collection, tmbId } = await authDatasetCollection({
req,
authToken: true,
collectionId,
@@ -51,44 +52,54 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
/* Not the same original text, create and reload */
const vectorModelData = getVectorModel(collection.datasetId.vectorModel);
const agentModelData = getQAModel(collection.datasetId.agentModel);
// create training bill
const { billId } = await createTrainingBill({
teamId: collection.teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: vectorModelData.name,
agentModel: agentModelData.name
});
const agentModelData = getLLMModel(collection.datasetId.agentModel);
// create a collection and delete old
const _id = await createOneCollection({
teamId: collection.teamId,
tmbId: collection.tmbId,
parentId: collection.parentId,
datasetId: collection.datasetId._id,
name: title || collection.name,
type: collection.type,
trainingType: collection.trainingType,
chunkSize: collection.chunkSize,
fileId: collection.fileId,
rawLink: collection.rawLink,
metadata: collection.metadata,
createTime: collection.createTime
});
await mongoSessionRun(async (session) => {
// create training bill
const { billId } = await createTrainingBill({
teamId: collection.teamId,
tmbId,
appName: 'core.dataset.collection.Sync Collection',
billSource: BillSourceEnum.training,
vectorModel: vectorModelData.name,
agentModel: agentModelData.name,
session
});
// start load
await reloadCollectionChunks({
collectionId: _id,
tmbId,
billId,
rawText
});
// create a collection and delete old
const newCol = await createOneCollection({
teamId: collection.teamId,
tmbId: collection.tmbId,
parentId: collection.parentId,
datasetId: collection.datasetId._id,
name: title || collection.name,
type: collection.type,
trainingType: collection.trainingType,
chunkSize: collection.chunkSize,
fileId: collection.fileId,
rawLink: collection.rawLink,
metadata: collection.metadata,
createTime: collection.createTime,
session
});
// delete old collection
await delCollectionAndRelatedSources({
collections: [collection]
// start load
await reloadCollectionChunks({
collection: {
...newCol.toObject(),
datasetId: collection.datasetId
},
tmbId,
billId,
rawText,
session
});
// delete old collection
await delCollectionAndRelatedSources({
collections: [collection],
session
});
});
jsonRes(res, {

View File

@@ -6,7 +6,7 @@ import type { CreateDatasetParams } from '@/global/core/dataset/api.d';
import { createDefaultCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel, getDatasetModel } from '@/service/core/ai/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
type = DatasetTypeEnum.dataset,
avatar,
vectorModel = global.vectorModels[0].model,
agentModel = global.qaModels[0].model
agentModel = getDatasetModel().model
} = req.body as CreateDatasetParams;
// auth
@@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// check model valid
const vectorModelStore = getVectorModel(vectorModel);
const agentModelStore = getQAModel(agentModel);
const agentModelStore = getLLMModel(agentModel);
if (!vectorModelStore || !agentModelStore) {
throw new Error('vectorModel or qaModel is invalid');
}

View File

@@ -17,6 +17,7 @@ import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { InsertOneDatasetDataProps } from '@/global/core/dataset/api';
import { simpleText } from '@fastgpt/global/common/string/tools';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -42,8 +43,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: 1
insertLen: 1,
standardPlans: getStandardSubPlan()
});
// auth collection and get dataset

View File

@@ -11,6 +11,7 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { predictDataLimitLength } from '@fastgpt/global/core/dataset/utils';
import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -37,8 +38,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// auth dataset limit
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: predictDataLimitLength(collection.trainingType, data)
insertLen: predictDataLimitLength(collection.trainingType, data),
standardPlans: getStandardSubPlan()
});
jsonRes<PushDatasetDataResponse>(res, {

View File

@@ -5,6 +5,7 @@ import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
import { delDatasetRelevantData } from '@fastgpt/service/core/dataset/controller';
import { findDatasetAndAllChildren } from '@fastgpt/service/core/dataset/controller';
import { MongoDataset } from '@fastgpt/service/core/dataset/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -32,11 +33,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});
// delete all dataset.data and pg data
await delDatasetRelevantData({ datasets });
// delete dataset data
await MongoDataset.deleteMany({
_id: { $in: datasets.map((d) => d._id) }
await mongoSessionRun(async (session) => {
// delete dataset data
await delDatasetRelevantData({ datasets, session });
await MongoDataset.deleteMany(
{
_id: { $in: datasets.map((d) => d._id) }
},
{ session }
);
});
jsonRes(res);

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import type { DatasetItemType } from '@fastgpt/global/core/dataset/type.d';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
@@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: {
...dataset,
vectorModel: getVectorModel(dataset.vectorModel),
agentModel: getQAModel(dataset.agentModel),
agentModel: getLLMModel(dataset.agentModel),
canWrite,
isOwner
}

View File

@@ -44,7 +44,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// query extension
// const { queries } = await searchQueryExtension({
// query: text,
// model: global.chatModels[0].model
// model: global.llmModel[0].model
// });
const { searchRes, charsLength, ...result } = await searchDatasetData({

View File

@@ -17,6 +17,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await authRequestFromLocal({ req });
// string all value
Object.keys(obj).forEach((key) => {
let val = obj[key];
if (typeof val === 'object') {
val = JSON.stringify(val);
} else if (typeof val === 'number') {
val = String(val);
} else if (typeof val === 'boolean') {
val = val ? 'true' : 'false';
}
obj[key] = val;
});
const textResult = replaceVariable(text, obj);
res.json({

View File

@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const nanoid = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
Math.floor(Math.random() * 14) + 24
Math.floor(Math.random() * 14) + 52
);
const apiKey = `${global.systemEnv?.openapiPrefix || 'fastgpt'}-${nanoid()}`;

View File

@@ -20,7 +20,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const baseUrl = openaiAccount?.baseUrl || openaiBaseUrl;
openaiAccount.baseUrl = baseUrl;
const ai = getAIApi(openaiAccount);
const ai = getAIApi({
userKey: openaiAccount
});
const response = await ai.chat.completions.create({
model: 'gpt-3.5-turbo',

View File

@@ -3,6 +3,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { checkDatasetLimit } from '@fastgpt/service/support/permission/limit/dataset';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -22,8 +23,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await checkDatasetLimit({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize,
insertLen: numberSize
insertLen: numberSize,
standardPlans: getStandardSubPlan()
});
jsonRes(res);

View File

@@ -3,7 +3,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
import { CreateTrainingBillProps } from '@fastgpt/global/support/wallet/bill/api.d';
import { getQAModel, getVectorModel } from '@/service/core/ai/model';
import { getLLMModel, getVectorModel } from '@/service/core/ai/model';
import { createTrainingBill } from '@fastgpt/service/support/wallet/bill/controller';
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
appName: name,
billSource: BillSourceEnum.training,
vectorModel: getVectorModel(dataset.vectorModel).name,
agentModel: getQAModel(dataset.agentModel).name
agentModel: getLLMModel(dataset.agentModel).name
});
jsonRes<string>(res, {

View File

@@ -2,8 +2,9 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { getTeamDatasetValidSub } from '@fastgpt/service/support/wallet/sub/utils';
import { getVectorCountByTeamId } from '@fastgpt/service/common/vectorStore/controller';
import { getTeamSubPlanStatus } from '@fastgpt/service/support/wallet/sub/utils';
import { getStandardSubPlan } from '@/service/support/wallet/sub/utils';
import { FeTeamSubType } from '@fastgpt/global/support/wallet/sub/type';
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -15,20 +16,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
authToken: true
});
const [{ sub, maxSize }, usedSize] = await Promise.all([
getTeamDatasetValidSub({
jsonRes<FeTeamSubType>(res, {
data: await getTeamSubPlanStatus({
teamId,
freeSize: global.feConfigs?.subscription?.datasetStoreFreeSize
}),
getVectorCountByTeamId(teamId)
]);
jsonRes(res, {
data: {
sub,
maxSize,
usedSize
}
standardPlans: getStandardSubPlan()
})
});
} catch (err) {
jsonRes(res, {

View File

@@ -5,12 +5,15 @@ import { withNextCors } from '@fastgpt/service/common/middle/cors';
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
import { connectToDatabase } from '@/service/mongo';
import { authTeamBalance } from '@/service/support/permission/auth/bill';
import { getVectorsByText, GetVectorProps } from '@fastgpt/service/core/ai/embedding';
import { getVectorsByText } from '@fastgpt/service/core/ai/embedding';
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
import { getBillSourceByAuthType } from '@fastgpt/global/support/wallet/bill/tools';
import { getVectorModel } from '@/service/core/ai/model';
type Props = GetVectorProps & {
type Props = {
input: string | string[];
model: string;
dimensions?: number;
billId?: string;
};
@@ -33,7 +36,10 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
await authTeamBalance(teamId);
const { charsLength, vectors } = await getVectorsByText({ input: query, model });
const { charsLength, vectors } = await getVectorsByText({
input: query,
model: getVectorModel(model)
});
res.json({
object: 'list',

View File

@@ -15,7 +15,7 @@ import ChatTest, { type ChatTestComponentRef } from '@/components/core/module/Fl
import { getFlowStore } 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 '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
const ImportSettings = dynamic(() => import('@/components/core/module/Flow/ImportSettings'));

View File

@@ -12,7 +12,7 @@ import {
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
import { AppSchema } from '@fastgpt/global/core/app/type.d';
import { useToast } from '@/web/common/hooks/useToast';
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';

View File

@@ -9,7 +9,7 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useCopyData } from '@/web/common/hooks/useCopyData';
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { fileToBase64 } from '@/web/common/file/utils';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
enum UsingWayEnum {
link = 'link',
@@ -25,6 +25,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
multiple: false,
fileType: 'image/*'
});
const { feConfigs } = useSystemStore();
const VariableTypeList = [
{

View File

@@ -39,19 +39,21 @@ import { useRequest } from '@/web/common/hooks/useRequest';
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
import { OutLinkTypeEnum } from '@fastgpt/global/support/outLink/constant';
import { useTranslation } from 'next-i18next';
import { useToast } from '@/web/common/hooks/useToast';
import { feConfigs } from '@/web/common/system/staticData';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
import dayjs from 'dayjs';
import { getDocPath } from '@/web/common/system/doc';
import dynamic from 'next/dynamic';
import MyMenu from '@/components/MyMenu';
const SelectUsingWayModal = dynamic(() => import('./SelectUsingWayModal'));
const Share = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const { Loading, setIsLoading } = useLoading();
const { feConfigs } = useSystemStore();
const { copyData } = useCopyData();
const [editLinkData, setEditLinkData] = useState<OutLinkEditType>();
const [selectedLinkData, setSelectedLinkData] = useState<OutLinkSchema>();
@@ -135,40 +137,40 @@ const Share = ({ appId }: { appId: string }) => {
{item.lastTime ? t(formatTimeToChatTime(item.lastTime)) : t('common.Un used')}
</Td>
<Td display={'flex'} alignItems={'center'}>
<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
Button={
<MyIcon
name={'more'}
_hover={{ bg: 'myGray.100 ' }}
cursor={'pointer'}
borderRadius={'md'}
w={'14px'}
p={2}
/>
}
menuList={[
{
label: t('core.app.outLink.Select Mode'),
icon: 'copy',
onClick: () => {
setSelectedLinkData(item);
}}
py={[2, 3]}
>
<MyIcon name={'copy'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('core.app.outLink.Select Mode')}</Box>
</MenuItem>
<MenuItem
onClick={() =>
}
},
{
label: t('common.Edit'),
icon: 'edit',
onClick: () =>
setEditLinkData({
_id: item._id,
name: item.name,
responseDetail: item.responseDetail,
limit: item.limit
})
}
py={[2, 3]}
>
<MyIcon name={'edit'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Edit')}</Box>
</MenuItem>
<MenuItem
onClick={async () => {
},
{
label: t('common.Delete'),
icon: 'delete',
onClick: async () => {
setIsLoading(true);
try {
await delShareChatById(item._id);
@@ -177,14 +179,10 @@ const Share = ({ appId }: { appId: string }) => {
console.log(error);
}
setIsLoading(false);
}}
py={[2, 3]}
>
<MyIcon name={'delete'} w={['14px', '16px']} />
<Box ml={[1, 2]}>{t('common.Delete')}</Box>
</MenuItem>
</MenuList>
</Menu>
}
}
]}
/>
</Td>
</Tr>
))}
@@ -249,6 +247,7 @@ function EditLinkModal({
onCreate: (id: string) => void;
onEdit: () => void;
}) {
const { feConfigs } = useSystemStore();
const { t } = useTranslation();
const {
register,

View File

@@ -18,7 +18,7 @@ const OutLink = ({ appId }: { appId: string }) => {
return (
<Box pt={[1, 5]}>
<Box fontWeight={'bold'} fontSize={['md', 'xl']} mb={2} px={[4, 8]}>
{t('core.app.External using')}
{t('core.app.navbar.Publish app')}
</Box>
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
<MyRadio

View File

@@ -3,7 +3,7 @@ import { Box, Flex, Button, IconButton } from '@chakra-ui/react';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { useRouter } from 'next/router';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { AppSchema } from '@fastgpt/global/core/app/type.d';
import { delModelById } from '@/web/core/app/api';
import { useTranslation } from 'next-i18next';
@@ -116,12 +116,12 @@ const AppCard = ({ appId }: { appId: string }) => {
router.replace({
query: {
appId,
currentTab: 'outLink'
currentTab: 'publish'
}
});
}}
>
{t('core.app.navbar.External')}
{t('core.app.navbar.Publish')}
</Button>
{appDetail.isOwner && (
<Button

View File

@@ -18,7 +18,6 @@ const CfrEditModal = ({
}) => {
const { t } = useTranslation();
const [value, setValue] = useState(defaultValue);
const [, startTst] = useTransition();
return (
<MyModal
@@ -38,12 +37,10 @@ const CfrEditModal = ({
h={200}
showOpenModal={false}
placeholder={t('core.module.input.placeholder.cfr background')}
defaultValue={value}
onChange={useCallback((e: string) => {
startTst(() => {
setValue(e);
});
}, [])}
value={value}
onChange={(e) => {
setValue(e);
}}
/>
</Box>
</ModalBody>

View File

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

View File

@@ -15,7 +15,6 @@ import { useForm, useFieldArray } from 'react-hook-form';
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 { chatModelList, simpleModeTemplates } from '@/web/common/system/staticData';
import { chatNodeSystemPromptTip, welcomeTextTip } from '@fastgpt/global/core/module/template/tip';
import { useRequest } from '@/web/common/hooks/useRequest';
import { useConfirm } from '@/web/common/hooks/useConfirm';
@@ -37,7 +36,7 @@ import MyTextarea from '@/components/common/Textarea/MyTextarea/index';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
import SelectAiModel from '@/components/Select/SelectAiModel';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { formatVariablesIcon } from '@fastgpt/global/core/module/utils';
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/module/utils';
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
const DatasetParamsModal = dynamic(() => import('@/components/core/module/DatasetParamsModal'));
@@ -60,7 +59,7 @@ const EditForm = ({
const { t } = useTranslation();
const { appDetail, updateAppDetail } = useAppStore();
const { loadAllDatasets, allDatasets } = useDatasetStore();
const { isPc } = useSystemStore();
const { isPc, llmModelList, reRankModelList, simpleModeTemplates } = useSystemStore();
const [refresh, setRefresh] = useState(false);
const [, startTst] = useTransition();
@@ -100,12 +99,12 @@ const EditForm = ({
});
const variables = watch('userGuide.variables');
const formatVariables = useMemo(() => formatVariablesIcon(variables), [variables]);
const formatVariables = useMemo(() => formatEditorVariablePickerIcon(variables), [variables]);
const aiSystemPrompt = watch('aiSettings.systemPrompt');
const searchMode = watch('dataset.searchMode');
const chatModelSelectList = (() =>
chatModelList.map((item) => ({
llmModelList.map((item) => ({
value: item.model,
label: item.name
})))();
@@ -121,10 +120,10 @@ const EditForm = ({
const tokenLimit = useMemo(() => {
return (
chatModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
llmModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
3000
);
}, [getValues, refresh]);
}, [getValues, llmModelList]);
const datasetSearchMode = useMemo(() => {
if (!searchMode) return '';
@@ -280,7 +279,7 @@ const EditForm = ({
onchange={(val: any) => {
setValue('aiSettings.model', val);
const maxToken =
chatModelList.find((item) => item.model === getValues('aiSettings.model'))
llmModelList.find((item) => item.model === getValues('aiSettings.model'))
?.maxResponse || 4000;
const token = maxToken / 2;
setValue('aiSettings.maxToken', token);
@@ -301,7 +300,7 @@ const EditForm = ({
</Box>
{isInitd && (
<PromptEditor
defaultValue={aiSystemPrompt}
value={aiSystemPrompt}
onChange={(text) => {
startTst(() => {
setValue('aiSettings.systemPrompt', text);
@@ -350,6 +349,13 @@ const EditForm = ({
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
{t('core.dataset.search.search mode')}: {datasetSearchMode}
{', '}
{reRankModelList.length > 0 && (
<>
{t('core.dataset.search.ReRank')}:{' '}
{getValues('dataset.usingReRank') ? '✅' : '✖'}
</>
)}
{', '}
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
{', '}
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}

View File

@@ -2,9 +2,9 @@ import React, { useEffect, useMemo, useCallback } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
import dynamic from 'next/dynamic';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useQuery } from '@tanstack/react-query';
import { feConfigs } from '@/web/common/system/staticData';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import Tabs from '@/components/Tabs';
import SideTabs from '@/components/SideTabs';
@@ -27,7 +27,7 @@ const Logs = dynamic(() => import('./components/Logs'), {});
enum TabEnum {
'simpleEdit' = 'simpleEdit',
'adEdit' = 'adEdit',
'outLink' = 'outLink',
'publish' = 'publish',
'logs' = 'logs',
'startChat' = 'startChat'
}
@@ -36,6 +36,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
const { t } = useTranslation();
const router = useRouter();
const theme = useTheme();
const { feConfigs } = useSystemStore();
const { toast } = useToast();
const { appId } = router.query as { appId: string };
const { appDetail, loadAppDetail, clearAppModules } = useAppStore();
@@ -69,14 +70,14 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
}
]),
{
label: t('core.app.navbar.External'),
id: TabEnum.outLink,
label: t('core.app.navbar.Publish app'),
id: TabEnum.publish,
icon: 'support/outlink/shareLight'
},
{ label: t('app.Chat logs'), id: TabEnum.logs, icon: 'core/app/logsLight' },
{ label: t('core.Start chat'), id: TabEnum.startChat, icon: 'core/chat/chatLight' }
],
[t]
[feConfigs?.hide_app_flow, t]
);
const onCloseFlowEdit = useCallback(() => setCurrentTab(TabEnum.simpleEdit), [setCurrentTab]);
@@ -194,7 +195,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
<FlowEdit app={appDetail} onClose={onCloseFlowEdit} />
)}
{currentTab === TabEnum.logs && <Logs appId={appId} />}
{currentTab === TabEnum.outLink && <OutLink appId={appId} />}
{currentTab === TabEnum.publish && <OutLink appId={appId} />}
</Box>
</Flex>
</PageContainer>

View File

@@ -14,13 +14,12 @@ import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImgFileAndUpload } from '@/web/common/file/controller';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
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 { feConfigs } from '@/web/common/system/staticData';
import Avatar from '@/components/Avatar';
import MyTooltip from '@/components/MyTooltip';
import MyModal from '@/components/MyModal';
@@ -39,7 +38,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
const { toast } = useToast();
const router = useRouter();
const theme = useTheme();
const { isPc } = useSystemStore();
const { isPc, feConfigs } = useSystemStore();
const { register, setValue, getValues, handleSubmit } = useForm<FormType>({
defaultValues: {
avatar: '/icon/logo.svg',

View File

@@ -1,20 +1,10 @@
import React, { useCallback, useEffect } from 'react';
import {
Box,
Grid,
Card,
useTheme,
Flex,
IconButton,
Button,
useDisclosure,
Image
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import { Box, Grid, Flex, IconButton, Button, useDisclosure } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useQuery } from '@tanstack/react-query';
import { AddIcon } from '@chakra-ui/icons';
import { delModelById } from '@/web/core/app/api';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useConfirm } from '@/web/common/hooks/useConfirm';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
@@ -31,7 +21,6 @@ import { useUserStore } from '@/web/support/user/useUserStore';
const MyApps = () => {
const { toast } = useToast();
const { t } = useTranslation();
const theme = useTheme();
const router = useRouter();
const { userInfo } = useUserStore();
const { myApps, loadMyApps } = useAppStore();
@@ -76,9 +65,11 @@ const MyApps = () => {
<Box letterSpacing={1} fontSize={['20px', '24px']} color={'myGray.900'}>
{t('app.My Apps')}
</Box>
<Button leftIcon={<AddIcon />} variant={'primaryOutline'} onClick={onOpenCreateModal}>
{t('common.New Create')}
</Button>
{userInfo?.team?.canWrite && (
<Button leftIcon={<AddIcon />} variant={'primaryOutline'} onClick={onOpenCreateModal}>
{t('common.New Create')}
</Button>
)}
</Flex>
<Grid
py={[4, 6]}

View File

@@ -16,7 +16,7 @@ import { useQuery } from '@tanstack/react-query';
import { streamFetch } from '@/web/common/api/fetch';
import { useChatStore } from '@/web/core/chat/storeChat';
import { useLoading } from '@/web/common/hooks/useLoading';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
@@ -80,7 +80,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
chatId: completionChatId
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
const newTitle =
@@ -126,7 +126,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
return { responseText, responseData, isNewChat: forbidRefresh.current };
},
[appId, chatId, histories, pushHistory, router, setChatData, updateHistory]
[appId, chatId, histories, pushHistory, router, setChatData, t, updateHistory]
);
// get chat app info
@@ -183,7 +183,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
setIsLoading(false);
return null;
},
[setIsLoading, setChatData, router, setLastChatAppId, setLastChatId, toast]
[setIsLoading, setChatData, setLastChatAppId, setLastChatId, toast, t, router]
);
// 初始化聊天框
useQuery(['init', { appId, chatId }], () => {

View File

@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { Box, Flex, useDisclosure, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useQuery } from '@tanstack/react-query';
import { streamFetch } from '@/web/common/api/fetch';
@@ -82,7 +82,7 @@ const OutLink = ({
outLinkUid
},
onMessage: generatingMessage,
abortSignal: controller
abortCtrl: controller
});
const newTitle =

View File

@@ -55,7 +55,7 @@ import ParentPath from '@/components/common/ParentPaths';
import dynamic from 'next/dynamic';
import { useDrag } from '@/web/common/hooks/useDrag';
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
import { useToast } from '@/web/common/hooks/useToast';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyTooltip from '@/components/MyTooltip';
import { useUserStore } from '@/web/support/user/useUserStore';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
@@ -381,8 +381,7 @@ const CollectionCard = () => {
<>
{userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
offset={[-0, 10]}
width={120}
offset={[0, 5]}
Button={
<MenuButton
_hover={{
@@ -408,7 +407,7 @@ const CollectionCard = () => {
}
menuList={[
{
child: (
label: (
<Flex>
<MyIcon name={'common/folderFill'} w={'20px'} mr={2} />
{t('Folder')}
@@ -417,7 +416,7 @@ const CollectionCard = () => {
onClick: () => setEditFolderData({})
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/manualCollection'} mr={2} w={'20px'} />
{t('core.dataset.Manual collection')}
@@ -433,7 +432,7 @@ const CollectionCard = () => {
}
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/fileCollection'} mr={2} w={'20px'} />
{t('core.dataset.Text collection')}
@@ -442,7 +441,7 @@ const CollectionCard = () => {
onClick: onOpenFileSourceSelector
},
{
child: (
label: (
<Flex>
<MyIcon name={'core/dataset/tableCollection'} mr={2} w={'20px'} />
{t('core.dataset.Table collection')}
@@ -627,6 +626,7 @@ const CollectionCard = () => {
{collection.canWrite && userInfo?.team?.role !== TeamMemberRoleEnum.visitor && (
<MyMenu
width={100}
offset={[-70, 5]}
Button={
<MenuButton
w={'22px'}
@@ -655,7 +655,7 @@ const CollectionCard = () => {
...(collection.type === DatasetCollectionTypeEnum.link
? [
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'common/refreshLight'} w={'14px'} mr={2} />
{t('core.dataset.collection.Sync')}
@@ -669,7 +669,7 @@ const CollectionCard = () => {
]
: []),
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'common/file/move'} w={'14px'} mr={2} />
{t('Move')}
@@ -678,7 +678,7 @@ const CollectionCard = () => {
onClick: () => setMoveCollectionData({ collectionId: collection._id })
},
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon name={'edit'} w={'14px'} mr={2} />
{t('Rename')}
@@ -696,7 +696,7 @@ const CollectionCard = () => {
})
},
{
child: (
label: (
<Flex alignItems={'center'}>
<MyIcon
mr={1}

Some files were not shown because too many files have changed in this diff Show More