perf: auto load icons (#688)

* perf: icon

* perf: icon

* doc

* perf: simple edit ui

* doc

* doc

* doc

* doc
This commit is contained in:
Archer
2024-01-03 23:51:12 +08:00
committed by GitHub
parent 2fc6e921e0
commit c2abbb579f
246 changed files with 2189 additions and 1380 deletions

View File

@@ -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';

View File

@@ -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';

View File

@@ -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();

View File

@@ -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();

View File

@@ -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 = () => {

View File

@@ -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
}

View File

@@ -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'}

View File

@@ -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'}>

View File

@@ -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';

View File

@@ -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>

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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'}

View File

@@ -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'}

View File

@@ -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';

View File

@@ -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';

View File

@@ -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'}

View File

@@ -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'}

View File

@@ -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]
);

View File

@@ -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>

View File

@@ -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%'}

View File

@@ -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')
) : (

View 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

View File

@@ -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';

View File

@@ -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,

View File

@@ -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>

View File

@@ -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'}

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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`
}
]

View File

@@ -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'}

View File

@@ -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);

View File

@@ -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';

View File

@@ -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'
}