mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-29 09:44:47 +00:00
perf: auto load icons (#688)
* perf: icon * perf: icon * doc * perf: simple edit ui * doc * doc * doc * doc
This commit is contained in:
@@ -17,7 +17,7 @@ import type { BillItemType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import dayjs from 'dayjs';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
|
||||
import { addDays } from 'date-fns';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
@@ -24,7 +24,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { timezoneList } from '@fastgpt/global/common/time/timezone';
|
||||
import Loading from '@/components/Loading';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { langMap, setLngStore } from '@/web/common/utils/i18n';
|
||||
import { useRouter } from 'next/router';
|
||||
|
@@ -6,7 +6,7 @@ import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import type { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import { formatTimeToChatTime } from '@/utils/tools';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
const BillTable = () => {
|
||||
const theme = useTheme();
|
||||
|
@@ -18,7 +18,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
|
||||
const PayRecordTable = () => {
|
||||
const { Loading, setIsLoading } = useLoading();
|
||||
|
@@ -25,7 +25,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import type { PromotionRecordType } from '@/global/support/api/userRes.d';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const Promotion = () => {
|
||||
|
@@ -38,14 +38,14 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
|
||||
const tabList = [
|
||||
{
|
||||
icon: 'meLight',
|
||||
icon: 'support/user/userLight',
|
||||
label: t('user.Personal Information'),
|
||||
id: TabEnum.info
|
||||
},
|
||||
...(feConfigs?.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'billRecordLight',
|
||||
icon: 'support/bill/billRecordLight',
|
||||
label: t('user.Usage Record'),
|
||||
id: TabEnum.bill
|
||||
}
|
||||
@@ -81,7 +81,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
...(userInfo?.team.canWrite
|
||||
? [
|
||||
{
|
||||
icon: 'apikey',
|
||||
icon: 'support/outlink/apikeyLight',
|
||||
label: t('user.apikey.key'),
|
||||
id: TabEnum.apikey
|
||||
}
|
||||
@@ -90,7 +90,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
...(feConfigs.isPlus
|
||||
? [
|
||||
{
|
||||
icon: 'informLight',
|
||||
icon: 'support/user/informLight',
|
||||
label: t('user.Notice'),
|
||||
id: TabEnum.inform
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import ChatTest, { type ChatTestComponentRef } from '@/components/core/module/Flow/ChatTest';
|
||||
import { getFlowStore } from '@/components/core/module/Flow/FlowProvider';
|
||||
@@ -101,7 +101,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
<MyTooltip label={t('common.Back')} offset={[10, 10]}>
|
||||
<IconButton
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'back'} w={'14px'} />}
|
||||
icon={<MyIcon name={'common/backLight'} w={'14px'} />}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'whiteBase'}
|
||||
aria-label={''}
|
||||
@@ -122,7 +122,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'importLight'} w={['14px', '16px']} />}
|
||||
icon={<MyIcon name={'common/importLight'} w={['14px', '16px']} />}
|
||||
variant={'whitePrimary'}
|
||||
aria-label={'save'}
|
||||
onClick={onOpenImport}
|
||||
@@ -157,7 +157,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
|
||||
<MyTooltip label={'测试对话'}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'chat'} w={['14px', '16px']} />}
|
||||
icon={<MyIcon name={'core/chat/chatLight'} w={['14px', '16px']} />}
|
||||
size={'smSquare'}
|
||||
aria-label={'save'}
|
||||
variant={'whitePrimary'}
|
||||
|
@@ -13,7 +13,7 @@ import {
|
||||
useDisclosure,
|
||||
ModalBody
|
||||
} from '@chakra-ui/react';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import { getAppChatLogs } from '@/web/core/app/api';
|
||||
@@ -315,7 +315,7 @@ const DetailLogsModal = ({
|
||||
_hover={{ bg: 'myGray.100' }}
|
||||
onClick={onClose}
|
||||
>
|
||||
<MyIcon name={'closeLight'} w={'12px'} h={'12px'} color={'myGray.700'} />
|
||||
<MyIcon name={'common/closeLight'} w={'12px'} h={'12px'} color={'myGray.700'} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Box pt={2} flex={'1 0 0'}>
|
||||
|
@@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import { Box, Flex, FlexProps, Grid, Image, ModalBody, Switch, useTheme } from '@chakra-ui/react';
|
||||
import MyRadio from '@/components/common/MyRadio';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import MyIcon from '@/components/Icon';
|
||||
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';
|
||||
|
@@ -21,7 +21,7 @@ import {
|
||||
Link
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
@@ -282,7 +282,7 @@ function EditLinkModal({
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
iconSrc="/imgs/modal/shareLight.svg"
|
||||
iconSrc="/imgs/modal/shareFill.svg"
|
||||
title={isEdit ? t('outlink.Edit Link') : t('outlink.Create Link')}
|
||||
>
|
||||
<ModalBody>
|
||||
|
@@ -24,13 +24,13 @@ const OutLink = ({ appId }: { appId: string }) => {
|
||||
iconSize={'20px'}
|
||||
list={[
|
||||
{
|
||||
icon: 'support/outlink/shareLight',
|
||||
icon: '/imgs/modal/shareFill.svg',
|
||||
title: '免登录窗口',
|
||||
desc: '分享链接给其他用户,无需登录即可直接进行使用',
|
||||
value: OutLinkTypeEnum.share
|
||||
},
|
||||
{
|
||||
icon: 'apikeyFill',
|
||||
icon: 'support/outlink/apikeyFill',
|
||||
title: 'API 访问',
|
||||
desc: '通过 API 接入到已有系统中,或企微、飞书等',
|
||||
value: OutLinkTypeEnum.apikey
|
||||
|
@@ -0,0 +1,148 @@
|
||||
import React, { useState } from 'react';
|
||||
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 { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||
import { delModelById } from '@/web/core/app/api';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import PermissionIconText from '@/components/support/permission/IconText';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
const InfoModal = dynamic(() => import('../InfoModal'));
|
||||
|
||||
const AppCard = ({ appId }: { appId: string }) => {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { appDetail } = useAppStore();
|
||||
const [settingAppInfo, setSettingAppInfo] = useState<AppSchema>();
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app.Confirm Del App Tip')
|
||||
});
|
||||
|
||||
/* 点击删除 */
|
||||
const { mutate: handleDelModel, isLoading } = useRequest({
|
||||
mutationFn: async () => {
|
||||
if (!appDetail) return null;
|
||||
await delModelById(appDetail._id);
|
||||
return 'success';
|
||||
},
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
toast({
|
||||
title: t('common.Delete Success'),
|
||||
status: 'success'
|
||||
});
|
||||
router.replace(`/app/list`);
|
||||
},
|
||||
errorToast: t('common.Delete Failed')
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box px={4}>
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'}>
|
||||
<PermissionIconText permission={appDetail.permission} />
|
||||
</Box>
|
||||
<Box color={'myGray.500'} fontSize={'sm'}>
|
||||
AppId:{' '}
|
||||
<Box as={'span'} userSelect={'all'}>
|
||||
{appId}
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
{/* basic info */}
|
||||
<Box
|
||||
borderWidth={'1px'}
|
||||
borderColor={'primary.1'}
|
||||
borderRadius={'md'}
|
||||
mt={2}
|
||||
px={5}
|
||||
py={4}
|
||||
bg={'primary.50'}
|
||||
position={'relative'}
|
||||
>
|
||||
<Flex alignItems={'center'} py={2}>
|
||||
<Avatar src={appDetail.avatar} borderRadius={'md'} w={'28px'} />
|
||||
<Box ml={3} fontWeight={'bold'} fontSize={'lg'}>
|
||||
{appDetail.name}
|
||||
</Box>
|
||||
{appDetail.isOwner && (
|
||||
<IconButton
|
||||
className="delete"
|
||||
position={'absolute'}
|
||||
top={4}
|
||||
right={4}
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'delete'} w={'14px'} />}
|
||||
variant={'whiteDanger'}
|
||||
borderRadius={'md'}
|
||||
aria-label={'delete'}
|
||||
isLoading={isLoading}
|
||||
onClick={openConfirmDel(handleDelModel)}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<Box
|
||||
flex={1}
|
||||
my={2}
|
||||
className={'textEllipsis3'}
|
||||
wordBreak={'break-all'}
|
||||
color={'myGray.600'}
|
||||
>
|
||||
{appDetail.intro || '快来给应用一个介绍~'}
|
||||
</Box>
|
||||
<Flex>
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'core/chat/chatLight'} w={'16px'} />}
|
||||
onClick={() => router.push(`/chat?appId=${appId}`)}
|
||||
>
|
||||
对话
|
||||
</Button>
|
||||
<Button
|
||||
mx={3}
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'support/outlink/shareLight'} w={'16px'} />}
|
||||
onClick={() => {
|
||||
router.replace({
|
||||
query: {
|
||||
appId,
|
||||
currentTab: 'outLink'
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
外接
|
||||
</Button>
|
||||
{appDetail.isOwner && (
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'common/settingLight'} w={'16px'} />}
|
||||
onClick={() => setSettingAppInfo(appDetail)}
|
||||
>
|
||||
设置
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<ConfirmDelModal />
|
||||
{settingAppInfo && (
|
||||
<InfoModal defaultApp={settingAppInfo} onClose={() => setSettingAppInfo(undefined)} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AppCard);
|
@@ -0,0 +1,61 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import PromptTextarea from '@/components/common/Textarea/PromptTextarea';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
|
||||
const CfrEditModal = ({
|
||||
defaultValue = '',
|
||||
onClose,
|
||||
onFinish
|
||||
}: {
|
||||
defaultValue?: string;
|
||||
onClose: () => void;
|
||||
onFinish: (value: string) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
iconSrc="/imgs/module/cfr.svg"
|
||||
w={'500px'}
|
||||
title={t('core.module.template.cfr')}
|
||||
>
|
||||
<ModalBody>
|
||||
{t('core.app.edit.cfr background prompt')}
|
||||
<MyTooltip label={t('core.app.edit.cfr background tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<PromptTextarea
|
||||
mt={1}
|
||||
flex={1}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={t('core.module.input.placeholder.cfr background')}
|
||||
defaultValue={value}
|
||||
onBlur={(e) => {
|
||||
setValue(e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onFinish(value);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('common.Done')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(CfrEditModal);
|
@@ -0,0 +1,133 @@
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { Box, Flex, IconButton } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||
import { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { streamFetch } from '@/web/common/api/fetch';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { getGuideModule } from '@fastgpt/global/core/module/utils';
|
||||
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
|
||||
const ChatTest = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo } = useUserStore();
|
||||
const { appDetail } = useAppStore();
|
||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||
const [modules, setModules] = useState<ModuleItemType[]>([]);
|
||||
|
||||
const startChat = useCallback(
|
||||
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||
let historyMaxLen = 0;
|
||||
|
||||
modules.forEach((module) => {
|
||||
module.inputs.forEach((input) => {
|
||||
if (
|
||||
(input.key === ModuleInputKeyEnum.history ||
|
||||
input.key === ModuleInputKeyEnum.historyMaxAmount) &&
|
||||
typeof input.value === 'number'
|
||||
) {
|
||||
historyMaxLen = Math.max(historyMaxLen, input.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
const history = chatList.slice(-historyMaxLen - 2, -2);
|
||||
|
||||
// 流请求,获取数据
|
||||
const { responseText, responseData } = await streamFetch({
|
||||
url: '/api/core/chat/chatTest',
|
||||
data: {
|
||||
history,
|
||||
prompt: chatList[chatList.length - 2].value,
|
||||
modules,
|
||||
variables,
|
||||
appId,
|
||||
appName: `调试-${appDetail.name}`
|
||||
},
|
||||
onMessage: generatingMessage,
|
||||
abortSignal: controller
|
||||
});
|
||||
|
||||
return { responseText, responseData };
|
||||
},
|
||||
[modules, appId, appDetail.name]
|
||||
);
|
||||
|
||||
const resetChatBox = useCallback(() => {
|
||||
ChatBoxRef.current?.resetHistory([]);
|
||||
ChatBoxRef.current?.resetVariables();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
resetChatBox();
|
||||
setModules(appDetail.modules);
|
||||
}, [appDetail, resetChatBox]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
flexDirection={'column'}
|
||||
h={'100%'}
|
||||
py={4}
|
||||
overflowX={'auto'}
|
||||
bg={'white'}
|
||||
>
|
||||
<Flex px={[2, 5]}>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'} flex={1}>
|
||||
{t('app.Chat Debug')}
|
||||
</Box>
|
||||
<MyTooltip label={t('core.chat.Restart')}>
|
||||
<IconButton
|
||||
className="chat"
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'common/clearLight'} w={'14px'} />}
|
||||
variant={'whiteDanger'}
|
||||
borderRadius={'md'}
|
||||
aria-label={'delete'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
resetChatBox();
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Box flex={1}>
|
||||
<ChatBox
|
||||
ref={ChatBoxRef}
|
||||
appAvatar={appDetail.avatar}
|
||||
userAvatar={userInfo?.avatar}
|
||||
showMarkIcon
|
||||
userGuideModule={getGuideModule(modules)}
|
||||
showFileSelector={checkChatSupportSelectFileByModules(modules)}
|
||||
onStartChat={startChat}
|
||||
onDelMessage={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
{appDetail.type !== AppTypeEnum.simple && (
|
||||
<Flex
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
right={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
bg={'rgba(255,255,255,0.6)'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
flexDirection={'column'}
|
||||
fontSize={'lg'}
|
||||
color={'black'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
textAlign={'center'}
|
||||
>
|
||||
<Box>{t('app.Advance App TestTip')}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ChatTest);
|
@@ -0,0 +1,546 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Grid,
|
||||
BoxProps,
|
||||
useTheme,
|
||||
useDisclosure,
|
||||
Button,
|
||||
Image
|
||||
} from '@chakra-ui/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||
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';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
|
||||
import { postForm2Modules } from '@/web/core/app/utils';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import MySelect from '@/components/Select';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
||||
import VariableEdit from '@/components/core/module/Flow/components/modules/VariableEdit';
|
||||
import PromptTextarea from '@/components/common/Textarea/PromptTextarea/index';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constant';
|
||||
import SelectAiModel from '@/components/Select/SelectAiModel';
|
||||
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
|
||||
const DatasetParamsModal = dynamic(() => import('@/components/core/module/DatasetParamsModal'));
|
||||
const AIChatSettingsModal = dynamic(() => import('@/components/core/module/AIChatSettingsModal'));
|
||||
const TTSSelect = dynamic(
|
||||
() => import('@/components/core/module/Flow/components/modules/TTSSelect')
|
||||
);
|
||||
const QGSwitch = dynamic(() => import('@/components/core/module/Flow/components/modules/QGSwitch'));
|
||||
const CfrEditModal = dynamic(() => import('./CfrEditModal'));
|
||||
|
||||
const EditForm = ({
|
||||
divRef,
|
||||
isSticky
|
||||
}: {
|
||||
divRef: React.RefObject<HTMLDivElement>;
|
||||
isSticky: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { appDetail, updateAppDetail } = useAppStore();
|
||||
const { loadAllDatasets, allDatasets } = useDatasetStore();
|
||||
const { isPc } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const { register, setValue, getValues, reset, handleSubmit, control } =
|
||||
useForm<AppSimpleEditFormType>({
|
||||
defaultValues: getDefaultAppForm()
|
||||
});
|
||||
|
||||
const { fields: datasets, replace: replaceKbList } = useFieldArray({
|
||||
control,
|
||||
name: 'dataset.datasets'
|
||||
});
|
||||
|
||||
const {
|
||||
isOpen: isOpenAIChatSetting,
|
||||
onOpen: onOpenAIChatSetting,
|
||||
onClose: onCloseAIChatSetting
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenDatasetSelect,
|
||||
onOpen: onOpenKbSelect,
|
||||
onClose: onCloseKbSelect
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenDatasetParams,
|
||||
onOpen: onOpenDatasetParams,
|
||||
onClose: onCloseDatasetParams
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenCfrModal,
|
||||
onOpen: onOpenCfrModal,
|
||||
onClose: onCloseCfrModal
|
||||
} = useDisclosure();
|
||||
|
||||
const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
|
||||
content: t('core.app.edit.Confirm Save App Tip')
|
||||
});
|
||||
|
||||
const chatModelSelectList = useMemo(() => {
|
||||
return chatModelList.map((item) => ({
|
||||
value: item.model,
|
||||
label: item.name
|
||||
}));
|
||||
}, [refresh]);
|
||||
|
||||
const selectDatasets = useMemo(
|
||||
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
|
||||
[allDatasets, datasets]
|
||||
);
|
||||
|
||||
const selectSimpleTemplate = useMemo(
|
||||
() =>
|
||||
simpleModeTemplates?.find((item) => item.id === getValues('templateId')) ||
|
||||
SimpleModeTemplate_FastGPT_Universal,
|
||||
[getValues, refresh]
|
||||
);
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
return (
|
||||
chatModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
|
||||
3000
|
||||
);
|
||||
}, [getValues, refresh]);
|
||||
|
||||
const datasetSearchMode = useMemo(() => {
|
||||
const mode = getValues('dataset.searchMode');
|
||||
if (!mode) return '';
|
||||
return t(DatasetSearchModeMap[mode]?.title);
|
||||
}, [getValues, t, refresh]);
|
||||
|
||||
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
|
||||
mutationFn: async (data: AppSimpleEditFormType) => {
|
||||
const modules = await postForm2Modules(data, data.templateId);
|
||||
|
||||
await updateAppDetail(appDetail._id, {
|
||||
modules,
|
||||
type: AppTypeEnum.simple,
|
||||
simpleTemplateId: data.templateId,
|
||||
permission: undefined
|
||||
});
|
||||
},
|
||||
successToast: t('common.Save Success'),
|
||||
errorToast: t('common.Save Failed')
|
||||
});
|
||||
|
||||
const appModule2Form = useCallback(() => {
|
||||
const formVal = appModules2Form({
|
||||
templateId: appDetail.simpleTemplateId,
|
||||
modules: appDetail.modules
|
||||
});
|
||||
|
||||
reset(formVal);
|
||||
setTimeout(() => {
|
||||
setRefresh((state) => !state);
|
||||
}, 100);
|
||||
}, [appDetail.modules, appDetail.simpleTemplateId, reset]);
|
||||
|
||||
useEffect(() => {
|
||||
appModule2Form();
|
||||
}, [appModule2Form]);
|
||||
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||
|
||||
const BoxStyles: BoxProps = {
|
||||
px: 5,
|
||||
py: '16px',
|
||||
borderBottomWidth: '1px',
|
||||
borderBottomColor: 'borderColor.low'
|
||||
};
|
||||
const BoxBtnStyles: BoxProps = {
|
||||
cursor: 'pointer',
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderRadius: 'md',
|
||||
_hover: {
|
||||
bg: 'myGray.150'
|
||||
}
|
||||
};
|
||||
const LabelStyles: BoxProps = {
|
||||
w: ['60px', '100px'],
|
||||
flexShrink: 0,
|
||||
fontSize: ['sm', 'md']
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* title */}
|
||||
<Flex
|
||||
ref={divRef}
|
||||
position={'sticky'}
|
||||
top={-4}
|
||||
bg={'myGray.25'}
|
||||
py={4}
|
||||
justifyContent={'space-between'}
|
||||
alignItems={'center'}
|
||||
zIndex={10}
|
||||
px={4}
|
||||
{...(isSticky && {
|
||||
borderBottom: theme.borders.base,
|
||||
boxShadow: '0 2px 10px rgba(0,0,0,0.12)'
|
||||
})}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box fontSize={['md', 'xl']} color={'myGray.800'}>
|
||||
{t('core.app.App params config')}
|
||||
</Box>
|
||||
<MyTooltip label={t('core.app.Simple Config Tip')} forceShow>
|
||||
<MyIcon name={'common/questionLight'} color={'myGray.500'} ml={2} />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Button
|
||||
isLoading={isSaving}
|
||||
size={['sm', 'md']}
|
||||
variant={appDetail.type === AppTypeEnum.simple ? 'primary' : 'whitePrimary'}
|
||||
onClick={() => {
|
||||
if (appDetail.type !== AppTypeEnum.simple) {
|
||||
openConfirmSave(handleSubmit((data) => onSubmitSave(data)))();
|
||||
} else {
|
||||
handleSubmit((data) => onSubmitSave(data))();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isPc ? t('core.app.Save and preview') : t('common.Save')}
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<Box px={4}>
|
||||
<Box bg={'white'} borderRadius={'md'} borderWidth={'1px'} borderColor={'borderColor.base'}>
|
||||
{/* simple mode select */}
|
||||
<Flex {...BoxStyles}>
|
||||
<Flex alignItems={'center'} flex={'1 0 0'}>
|
||||
<Image alt={''} src={'/imgs/module/templates.png'} w={'18px'} />
|
||||
<Box mx={2}>{t('core.app.simple.mode template select')}</Box>
|
||||
</Flex>
|
||||
<MySelect
|
||||
w={['200px', '250px']}
|
||||
list={
|
||||
simpleModeTemplates?.map((item) => ({
|
||||
alias: item.name,
|
||||
label: item.desc,
|
||||
value: item.id
|
||||
})) || []
|
||||
}
|
||||
value={getValues('templateId')}
|
||||
onchange={(val) => {
|
||||
setValue('templateId', val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
{/* ai */}
|
||||
{selectSimpleTemplate?.systemForm?.aiSettings && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Image alt={''} src={'/imgs/module/AI.png'} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('app.AI Settings')}
|
||||
</Box>
|
||||
{(selectSimpleTemplate.systemForm.aiSettings.maxToken ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.temperature ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quoteTemplate ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quotePrompt) && (
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'common/settingLight'} w={'14px'} />
|
||||
{t('app.Open AI Advanced Settings')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.model && (
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={getValues(`aiSettings.model`)}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('aiSettings.model', val);
|
||||
const maxToken =
|
||||
chatModelList.find((item) => item.model === getValues('aiSettings.model'))
|
||||
?.maxResponse || 4000;
|
||||
const token = maxToken / 2;
|
||||
setValue('aiSettings.maxToken', token);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.systemPrompt && (
|
||||
<Flex mt={10} alignItems={'flex-start'}>
|
||||
<Box {...LabelStyles}>
|
||||
{t('core.ai.Prompt')}
|
||||
<MyTooltip label={chatNodeSystemPromptTip} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<PromptTextarea
|
||||
flex={1}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={chatNodeSystemPromptTip}
|
||||
defaultValue={getValues('aiSettings.systemPrompt')}
|
||||
onBlur={(e) => {
|
||||
setValue('aiSettings.systemPrompt', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* dataset */}
|
||||
{selectSimpleTemplate?.systemForm?.dataset && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex alignItems={'center'} flex={1}>
|
||||
<Image alt={''} src={'/imgs/module/db.png'} w={'18px'} />
|
||||
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.dataset.datasets && (
|
||||
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
|
||||
<SmallAddIcon />
|
||||
{t('common.Choose')}
|
||||
</Flex>
|
||||
)}
|
||||
{(selectSimpleTemplate.systemForm.dataset.limit ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchMode ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchEmptyText ||
|
||||
selectSimpleTemplate.systemForm.dataset.similarity) && (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
ml={3}
|
||||
{...BoxBtnStyles}
|
||||
onClick={onOpenDatasetParams}
|
||||
>
|
||||
<MyIcon name={'edit'} w={'14px'} mr={1} />
|
||||
{t('common.Params')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{getValues('dataset.datasets').length > 0 && (
|
||||
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
|
||||
{t('core.dataset.search.search mode')}: {datasetSearchMode}
|
||||
{', '}
|
||||
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
|
||||
{', '}
|
||||
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
|
||||
{getValues('dataset.searchEmptyText') === ''
|
||||
? ''
|
||||
: t('core.dataset.Set Empty Result Tip')}
|
||||
</Flex>
|
||||
)}
|
||||
<Grid
|
||||
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
|
||||
gridGap={[2, 4]}
|
||||
>
|
||||
{selectDatasets.map((item) => (
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
|
||||
<Flex
|
||||
overflow={'hidden'}
|
||||
alignItems={'center'}
|
||||
p={2}
|
||||
bg={'white'}
|
||||
boxShadow={
|
||||
'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'
|
||||
}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
cursor={'pointer'}
|
||||
onClick={() =>
|
||||
router.push({
|
||||
pathname: '/dataset/detail',
|
||||
query: {
|
||||
datasetId: item._id
|
||||
}
|
||||
})
|
||||
}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'18px'} mr={1} />
|
||||
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
|
||||
{item.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* cfr */}
|
||||
{selectSimpleTemplate?.systemForm?.cfr && getValues('dataset.datasets').length > 0 && (
|
||||
<Flex {...BoxStyles} alignItems={'center'}>
|
||||
<Image src={'/imgs/module/cfr.svg'} alt={''} w={'18px'} />
|
||||
<Box ml={2}>{t('core.module.template.cfr')}</Box>
|
||||
<MyTooltip label={t('core.module.template.cfr intro')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
<Box flex={1} />
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenCfrModal}>
|
||||
{getValues('cfr.background') === 'none' ? t('common.Not open') : t('common.Opened')}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{/* variable */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.variables && (
|
||||
<Box {...BoxStyles}>
|
||||
<VariableEdit
|
||||
variables={getValues('userGuide.variables')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.variables', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* welcome */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.welcomeText && (
|
||||
<Box {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Image alt={''} src={'/imgs/module/userGuide.png'} w={'18px'} />
|
||||
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
|
||||
<MyTooltip label={welcomeTextTip} forceShow>
|
||||
<QuestionOutlineIcon />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptTextarea
|
||||
mt={2}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={welcomeTextTip}
|
||||
defaultValue={getValues('userGuide.welcomeText')}
|
||||
onBlur={(e) => {
|
||||
setValue('userGuide.welcomeText', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* tts */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.tts && (
|
||||
<Box {...BoxStyles}>
|
||||
<TTSSelect
|
||||
value={getValues('userGuide.tts')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.tts', e);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* question guide */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.questionGuide && (
|
||||
<Box {...BoxStyles} borderBottom={'none'}>
|
||||
<QGSwitch
|
||||
isChecked={getValues('userGuide.questionGuide')}
|
||||
size={'lg'}
|
||||
onChange={(e) => {
|
||||
const value = e.target.checked;
|
||||
setValue('userGuide.questionGuide', value);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<ConfirmSaveModal bg={appDetail.type === AppTypeEnum.simple ? '' : 'red.600'} countDown={5} />
|
||||
{isOpenAIChatSetting && (
|
||||
<AIChatSettingsModal
|
||||
onClose={onCloseAIChatSetting}
|
||||
onSuccess={(e) => {
|
||||
setValue('aiSettings', e);
|
||||
onCloseAIChatSetting();
|
||||
}}
|
||||
defaultData={getValues('aiSettings')}
|
||||
simpleModeTemplate={selectSimpleTemplate}
|
||||
/>
|
||||
)}
|
||||
{isOpenDatasetSelect && (
|
||||
<DatasetSelectModal
|
||||
isOpen={isOpenDatasetSelect}
|
||||
defaultSelectedDatasets={selectDatasets.map((item) => ({
|
||||
datasetId: item._id,
|
||||
vectorModel: item.vectorModel
|
||||
}))}
|
||||
onClose={onCloseKbSelect}
|
||||
onChange={replaceKbList}
|
||||
/>
|
||||
)}
|
||||
{isOpenDatasetParams && (
|
||||
<DatasetParamsModal
|
||||
// {...getValues('dataset')}
|
||||
searchMode={getValues('dataset.searchMode')}
|
||||
searchEmptyText={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.searchEmptyText
|
||||
? getValues('dataset.searchEmptyText')
|
||||
: undefined
|
||||
}
|
||||
limit={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.limit
|
||||
? getValues('dataset.limit')
|
||||
: undefined
|
||||
}
|
||||
similarity={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.similarity
|
||||
? getValues('dataset.similarity')
|
||||
: undefined
|
||||
}
|
||||
usingReRank={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.usingReRank
|
||||
? getValues('dataset.usingReRank')
|
||||
: undefined
|
||||
}
|
||||
maxTokens={tokenLimit}
|
||||
onClose={onCloseDatasetParams}
|
||||
onSuccess={(e) => {
|
||||
setValue('dataset', {
|
||||
...getValues('dataset'),
|
||||
...e
|
||||
});
|
||||
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isOpenCfrModal && (
|
||||
<CfrEditModal
|
||||
onClose={onCloseCfrModal}
|
||||
defaultValue={getValues('cfr.background')}
|
||||
onFinish={(e) => {
|
||||
setValue('cfr.background', e);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(EditForm);
|
@@ -1,813 +1,36 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Grid,
|
||||
BoxProps,
|
||||
Textarea,
|
||||
useTheme,
|
||||
useDisclosure,
|
||||
Button,
|
||||
IconButton,
|
||||
Image
|
||||
} from '@chakra-ui/react';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||
import { useForm, useFieldArray } from 'react-hook-form';
|
||||
import React from 'react';
|
||||
import { Box, Grid } from '@chakra-ui/react';
|
||||
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 type { ModuleItemType } from '@fastgpt/global/core/module/type';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { streamFetch } from '@/web/common/api/fetch';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { AppSchema } from '@fastgpt/global/core/app/type.d';
|
||||
import { delModelById } from '@/web/core/app/api';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getGuideModule } from '@fastgpt/global/core/module/utils';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
import PermissionIconText from '@/components/support/permission/IconText';
|
||||
|
||||
import { checkChatSupportSelectFileByModules } from '@/web/core/chat/utils';
|
||||
import { useSticky } from '@/web/common/hooks/useSticky';
|
||||
import { postForm2Modules } from '@/web/core/app/utils';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import MySelect from '@/components/Select';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
||||
import VariableEdit from '@/components/core/module/Flow/components/modules/VariableEdit';
|
||||
import { ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import PromptTextarea from '@/components/common/Textarea/PromptTextarea/index';
|
||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constant';
|
||||
import SelectAiModel from '@/components/Select/SelectAiModel';
|
||||
|
||||
const InfoModal = dynamic(() => import('../InfoModal'));
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/module/DatasetSelectModal'));
|
||||
const DatasetParamsModal = dynamic(() => import('@/components/core/module/DatasetParamsModal'));
|
||||
const AIChatSettingsModal = dynamic(() => import('@/components/core/module/AIChatSettingsModal'));
|
||||
const TTSSelect = dynamic(
|
||||
() => import('@/components/core/module/Flow/components/modules/TTSSelect')
|
||||
);
|
||||
const QGSwitch = dynamic(() => import('@/components/core/module/Flow/components/modules/QGSwitch'));
|
||||
|
||||
function ConfigForm({
|
||||
divRef,
|
||||
isSticky
|
||||
}: {
|
||||
divRef: React.RefObject<HTMLDivElement>;
|
||||
isSticky: boolean;
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { appDetail, updateAppDetail } = useAppStore();
|
||||
const { loadAllDatasets, allDatasets } = useDatasetStore();
|
||||
const { isPc } = useSystemStore();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const { register, setValue, getValues, reset, handleSubmit, control } =
|
||||
useForm<AppSimpleEditFormType>({
|
||||
defaultValues: getDefaultAppForm()
|
||||
});
|
||||
|
||||
const { fields: datasets, replace: replaceKbList } = useFieldArray({
|
||||
control,
|
||||
name: 'dataset.datasets'
|
||||
});
|
||||
|
||||
const {
|
||||
isOpen: isOpenAIChatSetting,
|
||||
onOpen: onOpenAIChatSetting,
|
||||
onClose: onCloseAIChatSetting
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenDatasetSelect,
|
||||
onOpen: onOpenKbSelect,
|
||||
onClose: onCloseKbSelect
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenDatasetParams,
|
||||
onOpen: onOpenKbParams,
|
||||
onClose: onCloseKbParams
|
||||
} = useDisclosure();
|
||||
|
||||
const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
|
||||
content: t('core.app.edit.Confirm Save App Tip')
|
||||
});
|
||||
|
||||
const chatModelSelectList = useMemo(() => {
|
||||
return chatModelList.map((item) => ({
|
||||
value: item.model,
|
||||
label: item.name
|
||||
}));
|
||||
}, [refresh]);
|
||||
|
||||
const selectDatasets = useMemo(
|
||||
() => allDatasets.filter((item) => datasets.find((dataset) => dataset.datasetId === item._id)),
|
||||
[allDatasets, datasets]
|
||||
);
|
||||
|
||||
const selectSimpleTemplate = useMemo(
|
||||
() =>
|
||||
simpleModeTemplates?.find((item) => item.id === getValues('templateId')) ||
|
||||
SimpleModeTemplate_FastGPT_Universal,
|
||||
[getValues, refresh]
|
||||
);
|
||||
|
||||
const tokenLimit = useMemo(() => {
|
||||
return (
|
||||
chatModelList.find((item) => item.model === getValues('aiSettings.model'))?.quoteMaxToken ||
|
||||
3000
|
||||
);
|
||||
}, [getValues, refresh]);
|
||||
|
||||
const datasetSearchMode = useMemo(() => {
|
||||
const mode = getValues('dataset.searchMode');
|
||||
if (!mode) return '';
|
||||
return t(DatasetSearchModeMap[mode]?.title);
|
||||
}, [getValues, t, refresh]);
|
||||
|
||||
const { mutate: onSubmitSave, isLoading: isSaving } = useRequest({
|
||||
mutationFn: async (data: AppSimpleEditFormType) => {
|
||||
const modules = await postForm2Modules(data, data.templateId);
|
||||
|
||||
await updateAppDetail(appDetail._id, {
|
||||
modules,
|
||||
type: AppTypeEnum.simple,
|
||||
simpleTemplateId: data.templateId,
|
||||
permission: undefined
|
||||
});
|
||||
},
|
||||
successToast: t('common.Save Success'),
|
||||
errorToast: t('common.Save Failed')
|
||||
});
|
||||
|
||||
const appModule2Form = useCallback(() => {
|
||||
const formVal = appModules2Form({
|
||||
templateId: appDetail.simpleTemplateId,
|
||||
modules: appDetail.modules
|
||||
});
|
||||
|
||||
reset(formVal);
|
||||
setTimeout(() => {
|
||||
setRefresh((state) => !state);
|
||||
}, 100);
|
||||
}, [appDetail.modules, appDetail.simpleTemplateId, reset]);
|
||||
|
||||
useEffect(() => {
|
||||
appModule2Form();
|
||||
}, [appModule2Form]);
|
||||
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||
|
||||
const BoxStyles: BoxProps = {
|
||||
bg: 'myWhite.200',
|
||||
px: 4,
|
||||
py: 3,
|
||||
borderRadius: 'lg',
|
||||
border: theme.borders.base
|
||||
};
|
||||
const BoxBtnStyles: BoxProps = {
|
||||
cursor: 'pointer',
|
||||
px: 3,
|
||||
py: '2px',
|
||||
borderRadius: 'md',
|
||||
_hover: {
|
||||
bg: 'myGray.200'
|
||||
}
|
||||
};
|
||||
const LabelStyles: BoxProps = {
|
||||
w: ['60px', '100px'],
|
||||
flexShrink: 0,
|
||||
fontSize: ['sm', 'md']
|
||||
};
|
||||
|
||||
return (
|
||||
<Box mt={2}>
|
||||
{/* title */}
|
||||
<Flex
|
||||
ref={divRef}
|
||||
position={'sticky'}
|
||||
top={-4}
|
||||
bg={'myGray.25'}
|
||||
py={4}
|
||||
justifyContent={'space-between'}
|
||||
alignItems={'center'}
|
||||
zIndex={10}
|
||||
px={4}
|
||||
{...(isSticky && {
|
||||
borderBottom: theme.borders.base,
|
||||
boxShadow: '0 2px 10px rgba(0,0,0,0.12)'
|
||||
})}
|
||||
>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'}>
|
||||
{t('core.app.App params config')}
|
||||
<MyTooltip label={t('core.app.Simple Config Tip')} forceShow>
|
||||
<QuestionOutlineIcon ml={2} fontSize={'md'} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<Button
|
||||
isLoading={isSaving}
|
||||
size={['sm', 'md']}
|
||||
variant={appDetail.type === AppTypeEnum.simple ? 'primary' : 'whitePrimary'}
|
||||
onClick={() => {
|
||||
if (appDetail.type !== AppTypeEnum.simple) {
|
||||
openConfirmSave(handleSubmit((data) => onSubmitSave(data)))();
|
||||
} else {
|
||||
handleSubmit((data) => onSubmitSave(data))();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isPc ? t('core.app.Save and preview') : t('common.Save')}
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<Box px={4}>
|
||||
{/* simple mode select */}
|
||||
<Flex {...BoxStyles}>
|
||||
<Flex alignItems={'center'} flex={'1 0 0'}>
|
||||
<Image alt={''} src={'/imgs/module/templates.png'} w={'18px'} />
|
||||
<Box mx={2}>{t('core.app.simple.mode template select')}</Box>
|
||||
</Flex>
|
||||
<MySelect
|
||||
w={['200px', '250px']}
|
||||
list={
|
||||
simpleModeTemplates?.map((item) => ({
|
||||
alias: item.name,
|
||||
label: item.desc,
|
||||
value: item.id
|
||||
})) || []
|
||||
}
|
||||
value={getValues('templateId')}
|
||||
onchange={(val) => {
|
||||
setValue('templateId', val);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
{/* ai */}
|
||||
{selectSimpleTemplate?.systemForm?.aiSettings && (
|
||||
<Box mt={5} {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Image alt={''} src={'/imgs/module/AI.png'} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('app.AI Settings')}
|
||||
</Box>
|
||||
{(selectSimpleTemplate.systemForm.aiSettings.maxToken ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.temperature ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quoteTemplate ||
|
||||
selectSimpleTemplate.systemForm.aiSettings.quotePrompt) && (
|
||||
<Flex {...BoxBtnStyles} onClick={onOpenAIChatSetting}>
|
||||
<MyIcon mr={1} name={'settingLight'} w={'14px'} />
|
||||
{t('app.Open AI Advanced Settings')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.model && (
|
||||
<Flex alignItems={'center'} mt={5}>
|
||||
<Box {...LabelStyles}>{t('core.ai.Model')}</Box>
|
||||
<Box flex={'1 0 0'}>
|
||||
<SelectAiModel
|
||||
width={'100%'}
|
||||
value={getValues(`aiSettings.model`)}
|
||||
list={chatModelSelectList}
|
||||
onchange={(val: any) => {
|
||||
setValue('aiSettings.model', val);
|
||||
const maxToken =
|
||||
chatModelList.find((item) => item.model === getValues('aiSettings.model'))
|
||||
?.maxResponse || 4000;
|
||||
const token = maxToken / 2;
|
||||
setValue('aiSettings.maxToken', token);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{selectSimpleTemplate.systemForm.aiSettings?.systemPrompt && (
|
||||
<Flex mt={10} alignItems={'flex-start'}>
|
||||
<Box {...LabelStyles}>
|
||||
{t('core.ai.Prompt')}
|
||||
<MyTooltip label={chatNodeSystemPromptTip} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<PromptTextarea
|
||||
flex={1}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={chatNodeSystemPromptTip}
|
||||
defaultValue={getValues('aiSettings.systemPrompt')}
|
||||
onBlur={(e) => {
|
||||
setValue('aiSettings.systemPrompt', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* dataset */}
|
||||
{selectSimpleTemplate?.systemForm?.dataset && (
|
||||
<Box mt={5} {...BoxStyles}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex alignItems={'center'} flex={1}>
|
||||
<Image alt={''} src={'/imgs/module/db.png'} w={'18px'} />
|
||||
<Box ml={2}>{t('core.dataset.Choose Dataset')}</Box>
|
||||
</Flex>
|
||||
{selectSimpleTemplate.systemForm.dataset.datasets && (
|
||||
<Flex alignItems={'center'} {...BoxBtnStyles} onClick={onOpenKbSelect}>
|
||||
<SmallAddIcon />
|
||||
{t('common.Choose')}
|
||||
</Flex>
|
||||
)}
|
||||
{(selectSimpleTemplate.systemForm.dataset.limit ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchMode ||
|
||||
selectSimpleTemplate.systemForm.dataset.searchEmptyText ||
|
||||
selectSimpleTemplate.systemForm.dataset.similarity) && (
|
||||
<Flex alignItems={'center'} ml={3} {...BoxBtnStyles} onClick={onOpenKbParams}>
|
||||
<MyIcon name={'edit'} w={'14px'} mr={1} />
|
||||
{t('common.Params')}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{getValues('dataset.datasets').length > 0 && (
|
||||
<Flex mt={1} color={'myGray.600'} fontSize={'sm'} mb={2}>
|
||||
{t('core.dataset.search.search mode')}: {datasetSearchMode}
|
||||
{', '}
|
||||
{t('core.dataset.search.Min Similarity')}: {getValues('dataset.similarity')}
|
||||
{', '}
|
||||
{t('core.dataset.search.Max Tokens')}: {getValues('dataset.limit')}
|
||||
{getValues('dataset.searchEmptyText') === ''
|
||||
? ''
|
||||
: t('core.dataset.Set Empty Result Tip')}
|
||||
</Flex>
|
||||
)}
|
||||
<Grid
|
||||
gridTemplateColumns={['repeat(2, minmax(0, 1fr))', 'repeat(3, minmax(0, 1fr))']}
|
||||
gridGap={[2, 4]}
|
||||
>
|
||||
{selectDatasets.map((item) => (
|
||||
<MyTooltip key={item._id} label={t('core.dataset.Read Dataset')}>
|
||||
<Flex
|
||||
overflow={'hidden'}
|
||||
alignItems={'center'}
|
||||
p={2}
|
||||
bg={'white'}
|
||||
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
|
||||
borderRadius={'md'}
|
||||
border={theme.borders.base}
|
||||
cursor={'pointer'}
|
||||
onClick={() =>
|
||||
router.push({
|
||||
pathname: '/dataset/detail',
|
||||
query: {
|
||||
datasetId: item._id
|
||||
}
|
||||
})
|
||||
}
|
||||
>
|
||||
<Avatar src={item.avatar} w={'18px'} mr={1} />
|
||||
<Box flex={'1 0 0'} w={0} className={'textEllipsis'} fontSize={'sm'}>
|
||||
{item.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
</MyTooltip>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
{selectSimpleTemplate?.systemForm?.cfr && getValues('dataset.datasets').length > 0 && (
|
||||
<Box mt={10}>
|
||||
<Box {...LabelStyles} w={'auto'}>
|
||||
{t('core.app.edit.cfr background prompt')}
|
||||
<MyTooltip label={t('core.app.edit.cfr background tip')} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
</MyTooltip>
|
||||
</Box>
|
||||
<PromptTextarea
|
||||
mt={1}
|
||||
flex={1}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={t('core.module.input.placeholder.cfr background')}
|
||||
defaultValue={getValues('cfr.background')}
|
||||
onBlur={(e) => {
|
||||
setValue('cfr.background', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* variable */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.variables && (
|
||||
<Box mt={2} {...BoxStyles}>
|
||||
<VariableEdit
|
||||
variables={getValues('userGuide.variables')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.variables', e);
|
||||
setRefresh(!refresh);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* welcome */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.welcomeText && (
|
||||
<Box {...BoxStyles} mt={2}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Image alt={''} src={'/imgs/module/userGuide.png'} w={'18px'} />
|
||||
<Box mx={2}>{t('core.app.Welcome Text')}</Box>
|
||||
<MyTooltip label={welcomeTextTip} forceShow>
|
||||
<QuestionOutlineIcon />
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<PromptTextarea
|
||||
mt={2}
|
||||
bg={'myWhite.400'}
|
||||
rows={5}
|
||||
placeholder={welcomeTextTip}
|
||||
defaultValue={getValues('userGuide.welcomeText')}
|
||||
onBlur={(e) => {
|
||||
setValue('userGuide.welcomeText', e.target.value || '');
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* tts */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.tts && (
|
||||
<Box mt={5} {...BoxStyles}>
|
||||
<TTSSelect
|
||||
value={getValues('userGuide.tts')}
|
||||
onChange={(e) => {
|
||||
setValue('userGuide.tts', e);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* question guide */}
|
||||
{selectSimpleTemplate?.systemForm?.userGuide?.questionGuide && (
|
||||
<Box mt={5} {...BoxStyles}>
|
||||
<QGSwitch
|
||||
isChecked={getValues('userGuide.questionGuide')}
|
||||
size={'lg'}
|
||||
onChange={(e) => {
|
||||
const value = e.target.checked;
|
||||
setValue('userGuide.questionGuide', value);
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<ConfirmSaveModal bg={appDetail.type === AppTypeEnum.simple ? '' : 'red.600'} countDown={5} />
|
||||
{isOpenAIChatSetting && (
|
||||
<AIChatSettingsModal
|
||||
onClose={onCloseAIChatSetting}
|
||||
onSuccess={(e) => {
|
||||
setValue('aiSettings', e);
|
||||
onCloseAIChatSetting();
|
||||
}}
|
||||
defaultData={getValues('aiSettings')}
|
||||
simpleModeTemplate={selectSimpleTemplate}
|
||||
/>
|
||||
)}
|
||||
{isOpenDatasetSelect && (
|
||||
<DatasetSelectModal
|
||||
isOpen={isOpenDatasetSelect}
|
||||
defaultSelectedDatasets={selectDatasets.map((item) => ({
|
||||
datasetId: item._id,
|
||||
vectorModel: item.vectorModel
|
||||
}))}
|
||||
onClose={onCloseKbSelect}
|
||||
onChange={replaceKbList}
|
||||
/>
|
||||
)}
|
||||
{isOpenDatasetParams && (
|
||||
<DatasetParamsModal
|
||||
// {...getValues('dataset')}
|
||||
searchMode={getValues('dataset.searchMode')}
|
||||
searchEmptyText={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.searchEmptyText
|
||||
? getValues('dataset.searchEmptyText')
|
||||
: undefined
|
||||
}
|
||||
limit={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.limit
|
||||
? getValues('dataset.limit')
|
||||
: undefined
|
||||
}
|
||||
similarity={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.similarity
|
||||
? getValues('dataset.similarity')
|
||||
: undefined
|
||||
}
|
||||
usingReRank={
|
||||
selectSimpleTemplate?.systemForm?.dataset?.usingReRank
|
||||
? getValues('dataset.usingReRank')
|
||||
: undefined
|
||||
}
|
||||
maxTokens={tokenLimit}
|
||||
onClose={onCloseKbParams}
|
||||
onSuccess={(e) => {
|
||||
setValue('dataset', {
|
||||
...getValues('dataset'),
|
||||
...e
|
||||
});
|
||||
|
||||
setRefresh((state) => !state);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function Settings({ appId }: { appId: string }) {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { parentRef, divRef, isSticky } = useSticky();
|
||||
const { appDetail } = useAppStore();
|
||||
const [settingAppInfo, setSettingAppInfo] = useState<AppSchema>();
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app.Confirm Del App Tip')
|
||||
});
|
||||
|
||||
/* 点击删除 */
|
||||
const { mutate: handleDelModel, isLoading } = useRequest({
|
||||
mutationFn: async () => {
|
||||
if (!appDetail) return null;
|
||||
await delModelById(appDetail._id);
|
||||
return 'success';
|
||||
},
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
toast({
|
||||
title: t('common.Delete Success'),
|
||||
status: 'success'
|
||||
});
|
||||
router.replace(`/app/list`);
|
||||
},
|
||||
errorToast: t('common.Delete Failed')
|
||||
});
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={parentRef}
|
||||
h={'100%'}
|
||||
borderRight={'1.5px solid'}
|
||||
borderColor={'myGray.200'}
|
||||
pt={[0, 4]}
|
||||
pb={10}
|
||||
overflow={'overlay'}
|
||||
>
|
||||
<Box px={4}>
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'}>
|
||||
<PermissionIconText permission={appDetail.permission} />
|
||||
</Box>
|
||||
<Box color={'myGray.500'} fontSize={'sm'}>
|
||||
AppId:{' '}
|
||||
<Box as={'span'} userSelect={'all'}>
|
||||
{appId}
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
{/* basic info */}
|
||||
<Box
|
||||
borderWidth={'1px'}
|
||||
borderColor={'primary.1'}
|
||||
borderRadius={'md'}
|
||||
mt={2}
|
||||
px={5}
|
||||
py={4}
|
||||
bg={'primary.50'}
|
||||
position={'relative'}
|
||||
>
|
||||
<Flex alignItems={'center'} py={2}>
|
||||
<Avatar src={appDetail.avatar} borderRadius={'md'} w={'28px'} />
|
||||
<Box ml={3} fontWeight={'bold'} fontSize={'lg'}>
|
||||
{appDetail.name}
|
||||
</Box>
|
||||
{appDetail.isOwner && (
|
||||
<IconButton
|
||||
className="delete"
|
||||
position={'absolute'}
|
||||
top={4}
|
||||
right={4}
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'delete'} w={'14px'} />}
|
||||
variant={'whiteDanger'}
|
||||
borderRadius={'md'}
|
||||
aria-label={'delete'}
|
||||
isLoading={isLoading}
|
||||
onClick={openConfirmDel(handleDelModel)}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<Box
|
||||
flex={1}
|
||||
my={2}
|
||||
className={'textEllipsis3'}
|
||||
wordBreak={'break-all'}
|
||||
color={'myGray.600'}
|
||||
>
|
||||
{appDetail.intro || '快来给应用一个介绍~'}
|
||||
</Box>
|
||||
<Flex>
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
|
||||
onClick={() => router.push(`/chat?appId=${appId}`)}
|
||||
>
|
||||
对话
|
||||
</Button>
|
||||
<Button
|
||||
mx={3}
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'shareLight'} w={'16px'} />}
|
||||
onClick={() => {
|
||||
router.replace({
|
||||
query: {
|
||||
appId,
|
||||
currentTab: 'outLink'
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
外接
|
||||
</Button>
|
||||
{appDetail.isOwner && (
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
variant={'whitePrimary'}
|
||||
leftIcon={<MyIcon name={'settingLight'} w={'16px'} />}
|
||||
onClick={() => setSettingAppInfo(appDetail)}
|
||||
>
|
||||
设置
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Box>
|
||||
{/* config form */}
|
||||
<ConfigForm divRef={divRef} isSticky={isSticky} />
|
||||
|
||||
<ConfirmDelModal />
|
||||
{settingAppInfo && (
|
||||
<InfoModal defaultApp={settingAppInfo} onClose={() => setSettingAppInfo(undefined)} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ChatTest({ appId }: { appId: string }) {
|
||||
const { t } = useTranslation();
|
||||
const { userInfo } = useUserStore();
|
||||
const { appDetail } = useAppStore();
|
||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||
const [modules, setModules] = useState<ModuleItemType[]>([]);
|
||||
|
||||
const startChat = useCallback(
|
||||
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||
let historyMaxLen = 0;
|
||||
|
||||
modules.forEach((module) => {
|
||||
module.inputs.forEach((input) => {
|
||||
if (
|
||||
(input.key === ModuleInputKeyEnum.history ||
|
||||
input.key === ModuleInputKeyEnum.historyMaxAmount) &&
|
||||
typeof input.value === 'number'
|
||||
) {
|
||||
historyMaxLen = Math.max(historyMaxLen, input.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
const history = chatList.slice(-historyMaxLen - 2, -2);
|
||||
|
||||
// 流请求,获取数据
|
||||
const { responseText, responseData } = await streamFetch({
|
||||
url: '/api/core/chat/chatTest',
|
||||
data: {
|
||||
history,
|
||||
prompt: chatList[chatList.length - 2].value,
|
||||
modules,
|
||||
variables,
|
||||
appId,
|
||||
appName: `调试-${appDetail.name}`
|
||||
},
|
||||
onMessage: generatingMessage,
|
||||
abortSignal: controller
|
||||
});
|
||||
|
||||
return { responseText, responseData };
|
||||
},
|
||||
[modules, appId, appDetail.name]
|
||||
);
|
||||
|
||||
const resetChatBox = useCallback(() => {
|
||||
ChatBoxRef.current?.resetHistory([]);
|
||||
ChatBoxRef.current?.resetVariables();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
resetChatBox();
|
||||
setModules(appDetail.modules);
|
||||
}, [appDetail, resetChatBox]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
flexDirection={'column'}
|
||||
h={'100%'}
|
||||
py={4}
|
||||
overflowX={'auto'}
|
||||
bg={'white'}
|
||||
>
|
||||
<Flex px={[2, 5]}>
|
||||
<Box fontSize={['md', 'xl']} fontWeight={'bold'} flex={1}>
|
||||
{t('app.Chat Debug')}
|
||||
</Box>
|
||||
<MyTooltip label={t('core.chat.Restart')}>
|
||||
<IconButton
|
||||
className="chat"
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'clear'} w={'14px'} />}
|
||||
variant={'whiteDanger'}
|
||||
borderRadius={'md'}
|
||||
aria-label={'delete'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
resetChatBox();
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Box flex={1}>
|
||||
<ChatBox
|
||||
ref={ChatBoxRef}
|
||||
appAvatar={appDetail.avatar}
|
||||
userAvatar={userInfo?.avatar}
|
||||
showMarkIcon
|
||||
userGuideModule={getGuideModule(modules)}
|
||||
showFileSelector={checkChatSupportSelectFileByModules(modules)}
|
||||
onStartChat={startChat}
|
||||
onDelMessage={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
{appDetail.type !== AppTypeEnum.simple && (
|
||||
<Flex
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
right={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
bg={'rgba(255,255,255,0.6)'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
flexDirection={'column'}
|
||||
fontSize={'lg'}
|
||||
color={'black'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
textAlign={'center'}
|
||||
>
|
||||
<Box>{t('app.Advance App TestTip')}</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
import ChatTest from './ChatTest';
|
||||
import AppCard from './AppCard';
|
||||
import EditForm from './EditForm';
|
||||
|
||||
const SimpleEdit = ({ appId }: { appId: string }) => {
|
||||
const { isPc } = useSystemStore();
|
||||
const { parentRef, divRef, isSticky } = useSticky();
|
||||
|
||||
return (
|
||||
<Grid gridTemplateColumns={['1fr', '550px 1fr']} h={'100%'}>
|
||||
<Settings appId={appId} />
|
||||
<Box
|
||||
ref={parentRef}
|
||||
h={'100%'}
|
||||
borderRight={'1.5px solid'}
|
||||
borderColor={'myGray.200'}
|
||||
pt={[0, 4]}
|
||||
pb={10}
|
||||
overflow={'overlay'}
|
||||
>
|
||||
<AppCard appId={appId} />
|
||||
|
||||
<Box mt={2}>
|
||||
<EditForm divRef={divRef} isSticky={isSticky} />
|
||||
</Box>
|
||||
</Box>
|
||||
{isPc && <ChatTest appId={appId} />}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default SimpleEdit;
|
||||
export default React.memo(SimpleEdit);
|
||||
|
@@ -9,7 +9,7 @@ import { feConfigs } from '@/web/common/system/staticData';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import SideTabs from '@/components/SideTabs';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import Loading from '@/components/Loading';
|
||||
import SimpleEdit from './components/SimpleEdit';
|
||||
@@ -52,13 +52,13 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
|
||||
const tabList = useMemo(
|
||||
() => [
|
||||
{ label: '简易配置', id: TabEnum.simpleEdit, icon: 'overviewLight' },
|
||||
{ label: '简易配置', id: TabEnum.simpleEdit, icon: 'common/overviewLight' },
|
||||
...(feConfigs?.hide_app_flow
|
||||
? []
|
||||
: [{ label: '高级编排', id: TabEnum.adEdit, icon: 'settingLight' }]),
|
||||
{ label: '外部使用', id: TabEnum.outLink, icon: 'shareLight' },
|
||||
: [{ label: '高级编排', id: TabEnum.adEdit, icon: 'common/settingLight' }]),
|
||||
{ label: '外部使用', id: TabEnum.outLink, icon: 'support/outlink/shareLight' },
|
||||
{ label: '对话日志', id: TabEnum.logs, icon: 'core/app/logsLight' },
|
||||
{ label: '立即对话', id: TabEnum.startChat, icon: 'chat' }
|
||||
{ label: '立即对话', id: TabEnum.startChat, icon: 'core/chat/chatLight' }
|
||||
],
|
||||
[]
|
||||
);
|
||||
@@ -139,7 +139,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'primary.500'} />}
|
||||
icon={<MyIcon name={'common/backFill'} w={'18px'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
|
@@ -19,7 +19,7 @@ import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
@@ -164,7 +164,7 @@ const MyApps = () => {
|
||||
variant={'whitePrimary'}
|
||||
icon={
|
||||
<MyTooltip label={'去聊天'}>
|
||||
<MyIcon name={'chat'} w={'14px'} />
|
||||
<MyIcon name={'core/chat/chatLight'} w={'14px'} />
|
||||
</MyTooltip>
|
||||
}
|
||||
aria-label={'chat'}
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Box, Flex, Button, Card } from '@chakra-ui/react';
|
||||
import type { ShareAppItem } from '@/types/app';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Flex, useTheme, Box } from '@chakra-ui/react';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Tag from '@/components/Tag';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import ToolMenu from './ToolMenu';
|
||||
|
@@ -15,7 +15,7 @@ import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import { useRouter } from 'next/router';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import Tabs from '@/components/Tabs';
|
||||
@@ -156,7 +156,7 @@ const ChatHistorySlider = ({
|
||||
h={'100%'}
|
||||
color={'primary.600'}
|
||||
borderRadius={'xl'}
|
||||
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
|
||||
leftIcon={<MyIcon name={'core/chat/chatLight'} w={'16px'} />}
|
||||
overflow={'hidden'}
|
||||
onClick={() => onChangeChat()}
|
||||
>
|
||||
@@ -173,7 +173,7 @@ const ChatHistorySlider = ({
|
||||
borderRadius={'50%'}
|
||||
onClick={openConfirm(onClearHistory)}
|
||||
>
|
||||
<MyIcon name={'clear'} w={'16px'} />
|
||||
<MyIcon name={'common/clearLight'} w={'16px'} />
|
||||
</IconButton>
|
||||
)}
|
||||
</Flex>
|
||||
@@ -211,7 +211,10 @@ const ChatHistorySlider = ({
|
||||
}
|
||||
})}
|
||||
>
|
||||
<MyIcon name={item.id === activeChatId ? 'chatFill' : 'chat'} w={'16px'} />
|
||||
<MyIcon
|
||||
name={item.id === activeChatId ? 'core/chat/chatFill' : 'core/chat/chatLight'}
|
||||
w={'16px'}
|
||||
/>
|
||||
<Box flex={'1 0 0'} ml={3} className="textEllipsis">
|
||||
{item.customTitle || item.title}
|
||||
</Box>
|
||||
@@ -236,7 +239,7 @@ const ChatHistorySlider = ({
|
||||
onSetHistoryTop({ chatId: item.id, top: !item.top });
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'setTop'} w={'16px'}></MyIcon>
|
||||
<MyIcon mr={2} name={'core/chat/setTopLight'} w={'16px'}></MyIcon>
|
||||
{item.top ? '取消置顶' : '置顶'}
|
||||
</MenuItem>
|
||||
)}
|
||||
@@ -254,7 +257,7 @@ const ChatHistorySlider = ({
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'customTitle'} w={'16px'}></MyIcon>
|
||||
<MyIcon mr={2} name={'common/customTitleLight'} w={'16px'}></MyIcon>
|
||||
{t('common.Custom Title')}
|
||||
</MenuItem>
|
||||
)}
|
||||
@@ -326,7 +329,7 @@ const ChatHistorySlider = ({
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'primary.500'} />}
|
||||
icon={<MyIcon name={'common/backFill'} w={'18px'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
|
@@ -3,7 +3,7 @@ import { Flex, Box, IconButton } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useAppStore } from '@/web/core/app/store/useAppStore';
|
||||
|
||||
@@ -28,7 +28,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'primary.500'} />}
|
||||
icon={<MyIcon name={'common/backFill'} w={'18px'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
|
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
|
||||
import { useChatBox } from '@/components/ChatBox';
|
||||
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { Menu, MenuButton, MenuList, MenuItem, Box } from '@chakra-ui/react';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
@@ -12,7 +12,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const menuList = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: 'chat',
|
||||
icon: 'core/chat/chatLight',
|
||||
label: '新对话',
|
||||
onClick: () => {
|
||||
router.replace({
|
||||
@@ -24,16 +24,16 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'apiLight',
|
||||
icon: 'core/app/appApiLight',
|
||||
label: 'HTML导出',
|
||||
onClick: () => onExportChat({ type: 'html', history })
|
||||
},
|
||||
{
|
||||
icon: 'markdown',
|
||||
icon: 'file/markdown',
|
||||
label: 'Markdown导出',
|
||||
onClick: () => onExportChat({ type: 'md', history })
|
||||
},
|
||||
{ icon: 'pdf', label: 'PDF导出', onClick: () => onExportChat({ type: 'pdf', history }) }
|
||||
{ icon: 'file/pdf', label: 'PDF导出', onClick: () => onExportChat({ type: 'pdf', history }) }
|
||||
],
|
||||
[history, onExportChat, router]
|
||||
);
|
||||
|
@@ -28,7 +28,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { debounce } from 'lodash';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import dayjs from 'dayjs';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
@@ -386,7 +386,7 @@ const CollectionCard = () => {
|
||||
color={'white'}
|
||||
h={['28px', '35px']}
|
||||
>
|
||||
<MyIcon name={'importLight'} mr={2} w={'14px'} />
|
||||
<MyIcon name={'common/importLight'} mr={2} w={'14px'} />
|
||||
<Box>{t('dataset.collections.Create And Import')}</Box>
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
|
@@ -29,7 +29,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import InputDataModal, { RawSourceText, type InputDataType } from '../components/InputDataModal';
|
||||
@@ -167,7 +167,7 @@ const DataCard = () => {
|
||||
<Flex alignItems={'center'}>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={['14px', '18px']} color={'primary.500'} />}
|
||||
icon={<MyIcon name={'common/backFill'} w={['14px', '18px']} color={'primary.500'} />}
|
||||
variant={'whitePrimary'}
|
||||
size={'smSquare'}
|
||||
borderRadius={'50%'}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
@@ -392,7 +392,7 @@ const FileSelect = ({
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<Flex justifyContent={'center'} alignItems={'center'}>
|
||||
<MyIcon mr={1} name={'uploadFile'} w={'16px'} />
|
||||
<MyIcon mr={1} name={'file/uploadFile'} w={'16px'} />
|
||||
{isDragging ? (
|
||||
t('file.Release the mouse to upload the file')
|
||||
) : (
|
||||
|
@@ -98,19 +98,19 @@ const ImportData = ({
|
||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(3,1fr)']}
|
||||
list={[
|
||||
{
|
||||
icon: 'indexImport',
|
||||
icon: 'file/indexImport',
|
||||
title: t('core.dataset.import.Chunk Split'),
|
||||
desc: t('core.dataset.import.Chunk Split Tip'),
|
||||
value: ImportTypeEnum.chunk
|
||||
},
|
||||
{
|
||||
icon: 'qaImport',
|
||||
icon: 'file/qaImport',
|
||||
title: t('core.dataset.import.QA Import'),
|
||||
desc: t('core.dataset.import.QA Import Tip'),
|
||||
value: ImportTypeEnum.qa
|
||||
},
|
||||
{
|
||||
icon: 'csvImport',
|
||||
icon: 'file/csv',
|
||||
title: t('core.dataset.import.CSV Import'),
|
||||
desc: t('core.dataset.import.CSV Import Tip'),
|
||||
value: ImportTypeEnum.csv
|
||||
|
@@ -22,8 +22,8 @@ import {
|
||||
} from '@fastgpt/global/core/dataset/constant';
|
||||
import { Box, Flex, Image, useTheme } from '@chakra-ui/react';
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import DeleteIcon, { hoverDeleteStyles } from '@fastgpt/web/components/common/Icon/delete';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { chunksUpload } from '@/web/core/dataset/utils';
|
||||
import { postCreateTrainingBill } from '@/web/support/wallet/bill/api';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
@@ -9,7 +9,7 @@ import {
|
||||
} from '@/web/core/dataset/api';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
@@ -26,7 +26,7 @@ import { DatasetDataIndexTypeEnum } from '@fastgpt/global/core/dataset/constant'
|
||||
import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import SideTabs from '@/components/SideTabs';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import DeleteIcon from '@/components/Icon/delete';
|
||||
import DeleteIcon from '@fastgpt/web/components/common/Icon/delete';
|
||||
import { defaultCollectionDetail } from '@/constants/dataset';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
|
||||
@@ -83,7 +83,7 @@ const InputDataModal = ({
|
||||
});
|
||||
|
||||
const tabList = [
|
||||
{ label: t('dataset.data.edit.Content'), id: TabEnum.content, icon: 'overviewLight' },
|
||||
{ label: t('dataset.data.edit.Content'), id: TabEnum.content, icon: 'common/overviewLight' },
|
||||
{
|
||||
label: t('dataset.data.edit.Index', { amount: indexes.length }),
|
||||
id: TabEnum.index,
|
||||
|
@@ -18,7 +18,7 @@ import {
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { useSearchTestStore, SearchTestStoreItemType } from '@/web/core/dataset/store/searchTest';
|
||||
import { postSearchText } from '@/web/core/dataset/api';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { formatTimeToChatTime } from '@/utils/tools';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
@@ -190,7 +190,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
// {
|
||||
// label: (
|
||||
// <Flex alignItems={'center'}>
|
||||
// <MyIcon mr={2} name={'csvImport'} w={'14px'} color={'primary.600'} />
|
||||
// <MyIcon mr={2} name={'file/csv'} w={'14px'} color={'primary.600'} />
|
||||
// <Box fontSize={'sm'} fontWeight={'bold'} flex={1}>
|
||||
// {t('core.dataset.test.Batch test')}
|
||||
// </Box>
|
||||
@@ -244,7 +244,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
|
||||
}}
|
||||
onClick={onOpen}
|
||||
>
|
||||
<MyIcon mr={2} name={'csvImport'} w={'24px'} />
|
||||
<MyIcon mr={2} name={'file/csv'} w={'24px'} />
|
||||
<Box>
|
||||
{selectFile ? selectFile.name : t('core.dataset.test.Batch test Placeholder')}
|
||||
</Box>
|
||||
|
@@ -7,7 +7,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import SideTabs from '@/components/SideTabs';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import Avatar from '@/components/Avatar';
|
||||
@@ -54,10 +54,10 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
|
||||
const { userInfo } = useUserStore();
|
||||
|
||||
const tabList = [
|
||||
{ label: t('core.dataset.Dataset'), id: TabEnum.collectionCard, icon: 'overviewLight' },
|
||||
{ label: t('core.dataset.Dataset'), id: TabEnum.collectionCard, icon: 'common/overviewLight' },
|
||||
{ label: t('core.dataset.test.Search Test'), id: TabEnum.test, icon: 'kbTest' },
|
||||
...(userInfo?.team.canWrite && datasetDetail.isOwner
|
||||
? [{ label: t('common.Config'), id: TabEnum.info, icon: 'settingLight' }]
|
||||
? [{ label: t('common.Config'), id: TabEnum.info, icon: 'common/settingLight' }]
|
||||
: [])
|
||||
];
|
||||
|
||||
@@ -240,7 +240,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
|
||||
>
|
||||
<IconButton
|
||||
mr={3}
|
||||
icon={<MyIcon name={'backFill'} w={'18px'} color={'primary.500'} />}
|
||||
icon={<MyIcon name={'common/backFill'} w={'18px'} color={'primary.500'} />}
|
||||
bg={'white'}
|
||||
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
|
||||
size={'smSquare'}
|
||||
|
@@ -13,7 +13,7 @@ import {
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
@@ -25,7 +25,7 @@ import {
|
||||
} from '@/web/core/dataset/api';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import dynamic from 'next/dynamic';
|
||||
import {
|
||||
|
@@ -19,7 +19,7 @@ import type { ResLogin } from '@/global/support/api/userRes';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import Avatar from '@/components/Avatar';
|
||||
@@ -86,7 +86,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{
|
||||
label: t('support.user.login.Github'),
|
||||
provider: OAuthEnum.github,
|
||||
icon: 'gitFill',
|
||||
icon: 'common/gitFill',
|
||||
redirectUrl: `https://github.com/login/oauth/authorize?client_id=${feConfigs?.oauth?.github}&redirect_uri=${redirectUri}&state=${state.current}&scope=user:email%20read:user`
|
||||
}
|
||||
]
|
||||
@@ -96,7 +96,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{
|
||||
label: t('support.user.login.Google'),
|
||||
provider: OAuthEnum.google,
|
||||
icon: 'googleFill',
|
||||
icon: 'common/googleFill',
|
||||
redirectUrl: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${feConfigs?.oauth?.google}&redirect_uri=${redirectUri}&state=${state.current}&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20openid&include_granted_scopes=true`
|
||||
}
|
||||
]
|
||||
|
@@ -5,7 +5,7 @@ import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { getFlowStore } from '@/components/core/module/Flow/FlowProvider';
|
||||
import { filterExportModules, flowNode2Modules } from '@/components/core/module/utils';
|
||||
@@ -123,7 +123,7 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
<MyTooltip label={t('common.Back')} offset={[10, 10]}>
|
||||
<IconButton
|
||||
size={'smSquare'}
|
||||
icon={<MyIcon name={'back'} w={'14px'} />}
|
||||
icon={<MyIcon name={'common/backLight'} w={'14px'} />}
|
||||
variant={'whiteBase'}
|
||||
aria-label={''}
|
||||
onClick={() => {
|
||||
@@ -138,7 +138,7 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
<MyTooltip label={t('app.Import Configs')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'importLight'} w={['14px', '16px']} />}
|
||||
icon={<MyIcon name={'common/importLight'} w={['14px', '16px']} />}
|
||||
variant={'whitePrimary'}
|
||||
size={'smSquare'}
|
||||
aria-label={'save'}
|
||||
@@ -163,7 +163,7 @@ const Header = ({ plugin, onClose }: Props) => {
|
||||
<MyTooltip label={t('module.Preview Plugin')}>
|
||||
<IconButton
|
||||
mr={[3, 6]}
|
||||
icon={<MyIcon name={'core/module/previewLight'} w={['14px', '16px']} />}
|
||||
icon={<MyIcon name={'core/modules/previewLight'} w={['14px', '16px']} />}
|
||||
size={'smSquare'}
|
||||
aria-label={'save'}
|
||||
variant={'whitePrimary'}
|
||||
|
@@ -14,7 +14,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { CreateOnePluginParams } from '@fastgpt/global/core/plugin/controller';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||
|
@@ -6,7 +6,7 @@ import { AddIcon } from '@chakra-ui/icons';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import PageContainer from '@/components/PageContainer';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import EditModal, { defaultForm, FormType } from './component/EditModal';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { ChevronRightIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useRouter } from 'next/router';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||
@@ -13,19 +13,10 @@ const Tools = () => {
|
||||
const router = useRouter();
|
||||
const list = [
|
||||
{
|
||||
icon: 'dbLight',
|
||||
icon: 'core/dataset/datasetLight',
|
||||
label: '我的知识库',
|
||||
link: '/dataset/list'
|
||||
},
|
||||
...(feConfigs?.show_appStore
|
||||
? [
|
||||
{
|
||||
icon: 'appStoreLight',
|
||||
label: 'AI应用市场',
|
||||
link: '/appStore'
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
icon: 'common/navbar/pluginLight',
|
||||
label: '自定义模块',
|
||||
@@ -34,7 +25,7 @@ const Tools = () => {
|
||||
...(feConfigs?.show_git
|
||||
? [
|
||||
{
|
||||
icon: 'git',
|
||||
icon: 'common/gitLight',
|
||||
label: 'GitHub 地址',
|
||||
link: 'https://github.com/labring/FastGPT'
|
||||
}
|
||||
|
Reference in New Issue
Block a user