perf: config fe

This commit is contained in:
archer
2023-07-19 10:59:49 +08:00
parent 7a76f54148
commit 47af8d1c3d
18 changed files with 340 additions and 230 deletions

View File

@@ -14,13 +14,10 @@ import { useToast } from '@/hooks/useToast';
import { useCopyData, voiceBroadcast, hasVoiceApi, getErrText } from '@/utils/tools';
import { Box, Card, Flex, Input, Textarea, Button, useTheme } from '@chakra-ui/react';
import { useUserStore } from '@/store/user';
import { feConfigs } from '@/store/static';
import { Types } from 'mongoose';
import { HUMAN_ICON, quoteLenKey, rawSearchKey } from '@/constants/chat';
import Markdown from '@/components/Markdown';
import { EventNameEnum } from '../Markdown/constant';
import MyIcon from '@/components/Icon';
import Avatar from '@/components/Avatar';
import { adaptChatItem_openAI } from '@/utils/plugin/openai';
import { useMarkdown } from '@/hooks/useMarkdown';
@@ -32,14 +29,17 @@ import { fileDownload } from '@/utils/file';
import { htmlTemplate } from '@/constants/common';
import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global';
import dynamic from 'next/dynamic';
const QuoteModal = dynamic(() => import('./QuoteModal'));
import { QuoteItemType } from '@/pages/api/app/modules/kb/search';
import { FlowModuleTypeEnum } from '@/constants/flow';
import MyTooltip from '../MyTooltip';
import dynamic from 'next/dynamic';
const QuoteModal = dynamic(() => import('./QuoteModal'));
import MyIcon from '@/components/Icon';
import Avatar from '@/components/Avatar';
import Markdown from '@/components/Markdown';
import MySelect from '@/components/Select';
import MyTooltip from '../MyTooltip';
import styles from './index.module.scss';
const textareaMinH = '22px';
@@ -393,7 +393,12 @@ const ChatBox = (
};
const showEmpty = useMemo(
() => showEmptyIntro && chatHistory.length === 0 && !variableModules?.length && !welcomeText,
() =>
feConfigs.show_emptyChat &&
showEmptyIntro &&
chatHistory.length === 0 &&
!variableModules?.length &&
!welcomeText,
[chatHistory.length, showEmptyIntro, variableModules, welcomeText]
);

View File

@@ -1,13 +1,14 @@
import React, { useMemo } from 'react';
import { Box, Flex, Link } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import MyIcon from '../Icon';
import { useUserStore } from '@/store/user';
import { useChatStore } from '@/store/chat';
import Avatar from '../Avatar';
import { HUMAN_ICON } from '@/constants/chat';
import { feConfigs } from '@/store/static';
import NextLink from 'next/link';
import Badge from '../Badge';
import Avatar from '../Avatar';
import MyIcon from '../Icon';
export enum NavbarTypeEnum {
normal = 'normal',
@@ -41,13 +42,17 @@ const Navbar = ({ unread }: { unread: number }) => {
link: `/kb/list`,
activeLink: ['/kb/list', '/kb/detail']
},
{
label: '市场',
icon: 'appStoreLight',
activeIcon: 'appStoreFill',
link: '/appStore',
activeLink: ['/appStore']
},
...(feConfigs.show_appStore
? [
{
label: '市场',
icon: 'appStoreLight',
activeIcon: 'appStoreFill',
link: '/appStore',
activeLink: ['/appStore']
}
]
: []),
{
label: '账号',
icon: 'meLight',
@@ -138,17 +143,19 @@ const Navbar = ({ unread }: { unread: number }) => {
</Link>
</Box>
)}
<Box>
<Link
as={NextLink}
href="https://github.com/labring/FastGPT"
target={'_blank'}
{...itemStyles}
color={'#9096a5'}
>
<MyIcon name={'git'} width={'22px'} height={'22px'} />
</Link>
</Box>
{feConfigs.show_git && (
<Box>
<Link
as={NextLink}
href="https://github.com/labring/FastGPT"
target={'_blank'}
{...itemStyles}
color={'#9096a5'}
>
<MyIcon name={'git'} width={'22px'} height={'22px'} />
</Link>
</Box>
)}
</Flex>
);
};

View File

@@ -1,9 +1,9 @@
import React, { useMemo } from 'react';
import { useRouter } from 'next/router';
import MyIcon from '../Icon';
import { Flex, Box } from '@chakra-ui/react';
import { useChatStore } from '@/store/chat';
import Badge from '../Badge';
import MyIcon from '../Icon';
const NavbarPhone = ({ unread }: { unread: number }) => {
const router = useRouter();

View File

@@ -17,5 +17,6 @@ export const Input_Template_History: FlowInputItemType = {
export const Input_Template_UserChatInput: FlowInputItemType = {
key: SystemInputEnum.userChatInput,
type: FlowInputItemTypeEnum.target,
label: '用户问题'
label: '用户问题',
required: true
};

View File

@@ -6,7 +6,7 @@ import {
type ChatModelItemType,
type VectorModelItemType
} from '@/types/model';
import { readFileSync } from 'fs';
import type { FeConfigsType } from '@/types';
export type InitDateResponse = {
beianText: string;
@@ -15,48 +15,7 @@ export type InitDateResponse = {
chatModels: ChatModelItemType[];
qaModels: QAModelItemType[];
vectorModels: VectorModelItemType[];
};
const defaultmodels = {
'FastAI-4k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-4k',
contextMaxToken: 4000,
systemMaxToken: 2400,
maxTemperature: 1.2,
price: 1.5
},
'FastAI-16k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-16k',
contextMaxToken: 16000,
systemMaxToken: 8000,
maxTemperature: 1.2,
price: 3
},
'FastAI-Plus': {
model: 'gpt-4',
name: 'FastAI-Plus',
contextMaxToken: 8000,
systemMaxToken: 4000,
maxTemperature: 1.2,
price: 45
}
};
const defaultQaModels = {
'FastAI-16k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-16k',
maxToken: 16000,
price: 3
}
};
const defaultVectorModels = {
'text-embedding-ada-002': {
model: 'text-embedding-ada-002',
name: 'Embedding-2',
price: 0.2
}
feConfigs: FeConfigsType;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -69,46 +28,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
jsonRes<InitDateResponse>(res, {
data: {
...envs,
...initSystemModels()
chatModels: global.chatModels,
qaModels: global.qaModels,
vectorModels: global.vectorModels,
feConfigs: global.feConfigs
}
});
}
export function initSystemModels() {
const { chatModels, qaModels, vectorModels } = (() => {
try {
const chatModels = Object.values(JSON.parse(readFileSync('data/ChatModels.json', 'utf-8')));
const qaModels = Object.values(JSON.parse(readFileSync('data/QAModels.json', 'utf-8')));
const vectorModels = Object.values(
JSON.parse(readFileSync('data/VectorModels.json', 'utf-8'))
);
return {
chatModels,
qaModels,
vectorModels
};
} catch (error) {
console.log(error);
return {
chatModels: Object.values(defaultmodels),
qaModels: Object.values(defaultQaModels),
vectorModels: Object.values(defaultVectorModels)
};
}
})() as {
chatModels: ChatModelItemType[];
qaModels: QAModelItemType[];
vectorModels: VectorModelItemType[];
};
global.chatModels = chatModels;
global.qaModels = qaModels;
global.vectorModels = vectorModels;
return {
chatModels,
qaModels,
vectorModels
};
}

View File

@@ -2,6 +2,11 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response';
import { authUser } from '@/service/utils/auth';
import { readFileSync } from 'fs';
import {
type QAModelItemType,
type ChatModelItemType,
type VectorModelItemType
} from '@/types/model';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await authUser({ req, authRoot: true });
@@ -22,3 +27,97 @@ export async function updateSystemEnv() {
console.log('update system env error');
}
}
const defaultmodels = {
'FastAI-4k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-4k',
contextMaxToken: 4000,
systemMaxToken: 2400,
maxTemperature: 1.2,
price: 1.5
},
'FastAI-16k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-16k',
contextMaxToken: 16000,
systemMaxToken: 8000,
maxTemperature: 1.2,
price: 3
},
'FastAI-Plus': {
model: 'gpt-4',
name: 'FastAI-Plus',
contextMaxToken: 8000,
systemMaxToken: 4000,
maxTemperature: 1.2,
price: 45
}
};
const defaultQaModels = {
'FastAI-16k': {
model: 'gpt-3.5-turbo',
name: 'FastAI-16k',
maxToken: 16000,
price: 3
}
};
const defaultVectorModels = {
'text-embedding-ada-002': {
model: 'text-embedding-ada-002',
name: 'Embedding-2',
price: 0.2
}
};
export function initSystemModels() {
const { chatModels, qaModels, vectorModels } = (() => {
try {
const chatModels = Object.values(JSON.parse(readFileSync('data/ChatModels.json', 'utf-8')));
const qaModels = Object.values(JSON.parse(readFileSync('data/QAModels.json', 'utf-8')));
const vectorModels = Object.values(
JSON.parse(readFileSync('data/VectorModels.json', 'utf-8'))
);
return {
chatModels,
qaModels,
vectorModels
};
} catch (error) {
console.log(error);
return {
chatModels: Object.values(defaultmodels),
qaModels: Object.values(defaultQaModels),
vectorModels: Object.values(defaultVectorModels)
};
}
})() as {
chatModels: ChatModelItemType[];
qaModels: QAModelItemType[];
vectorModels: VectorModelItemType[];
};
global.chatModels = chatModels;
global.qaModels = qaModels;
global.vectorModels = vectorModels;
console.log({
chatModels,
qaModels,
vectorModels
});
return {
chatModels,
qaModels,
vectorModels
};
}
export function initFeConfig() {
const feConfig = JSON.parse(readFileSync('data/FeConfig.json', 'utf-8'));
global.feConfigs = feConfig;
console.log(feConfig);
return feConfig;
}

View File

@@ -32,6 +32,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await connectToDatabase();
// register switch
if (type === UserAuthTypeEnum.register && !global.feConfigs.show_register) {
throw new Error('Register is closed');
}
const code = nanoid();
// 判断 1 分钟内是否有重复数据

View File

@@ -25,8 +25,8 @@ const ChatHeader = ({
return (
<Flex
alignItems={'center'}
py={[3, 5]}
px={[3, 5]}
h={['46px', '60px']}
borderBottom={theme.borders.base}
borderBottomColor={'gray.200'}
color={'myGray.900'}

View File

@@ -5,6 +5,7 @@ import { useMarkdown } from '@/hooks/useMarkdown';
import { useRouter } from 'next/router';
import { useGlobalStore } from '@/store/global';
import { beianText } from '@/store/static';
import { feConfigs } from '@/store/static';
import styles from './index.module.scss';
import axios from 'axios';
@@ -209,17 +210,19 @@ const Home = () => {
</Flex>
</Flex>
<Box w={'100%'} mt={'100vh'} px={[5, 10]} pb={[5, 10]}>
<Card p={5} mt={4} textAlign={'center'}>
{beianText && (
<Link href="https://beian.miit.gov.cn/" target="_blank">
{beianText}
</Link>
)}
{feConfigs?.authorText && (
<Box w={'100%'} mt={'100vh'} px={[5, 10]} pb={[5, 10]}>
<Card p={5} mt={4} textAlign={'center'}>
{beianText && (
<Link href="https://beian.miit.gov.cn/" target="_blank">
{beianText}
</Link>
)}
<Box>Made by FastGpt Team.</Box>
</Card>
</Box>
<Box>{feConfigs?.authorText}</Box>
</Card>
</Box>
)}
</Flex>
);
};

View File

@@ -14,6 +14,7 @@ import dynamic from 'next/dynamic';
import { useSelectFile } from '@/hooks/useSelectFile';
import { compressImg } from '@/utils/file';
import { getErrText, useCopyData } from '@/utils/tools';
import { feConfigs } from '@/store/static';
import Loading from '@/components/Loading';
import Avatar from '@/components/Avatar';
@@ -58,7 +59,7 @@ const NumberSetting = ({ tableType }: { tableType: `${TableEnum}` }) => {
const { copyData } = useCopyData();
const { userInfo, updateUserInfo, initUserInfo, setUserInfo } = useUserStore();
const { setLoading } = useGlobalStore();
const { register, handleSubmit, reset } = useForm<UserUpdateParams>({
const { reset } = useForm<UserUpdateParams>({
defaultValues: userInfo as UserType
});
const { toast } = useToast();
@@ -146,105 +147,117 @@ const NumberSetting = ({ tableType }: { tableType: `${TableEnum}` }) => {
);
return (
<Box py={[5, 10]} px={'5vw'}>
<Grid gridTemplateColumns={['1fr', '3fr 300px']} gridGap={4}>
<Card px={6} py={4}>
<Flex justifyContent={'space-between'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
<Button variant={'base'} size={'xs'} onClick={onclickLogOut}>
退
</Button>
</Flex>
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Avatar
src={userInfo?.avatar}
w={['28px', '36px']}
h={['28px', '36px']}
cursor={'pointer'}
title={'点击切换头像'}
onClick={onOpenSelectFile}
/>
</Flex>
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>{userInfo?.username}</Box>
</Flex>
<Box mt={6}>
<Flex alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>
<strong>{userInfo?.balance}</strong>
<>
<Box py={[5, 10]} px={'5vw'}>
<Grid gridTemplateColumns={['1fr', '3fr 300px']} gridGap={4}>
<Card px={6} py={4}>
<Flex justifyContent={'space-between'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
<Button variant={'base'} size={'xs'} onClick={onclickLogOut}>
退
</Button>
</Flex>
</Box>
</Card>
<Card px={6} py={4}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
{[
{ label: '佣金比例', value: `${userInfo?.promotion.rate || 15}%` },
{ label: '已注册用户数', value: `${invitedAmount}` },
{ label: '可用佣金', value: `${residueAmount}` }
].map((item) => (
<Flex key={item.label} alignItems={'center'} mt={4} justifyContent={'space-between'}>
<Box w={'120px'}>{item.label}</Box>
<Box fontWeight={'bold'}>{item.value}</Box>
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Avatar
src={userInfo?.avatar}
w={['28px', '36px']}
h={['28px', '36px']}
cursor={'pointer'}
title={'点击切换头像'}
onClick={onOpenSelectFile}
/>
</Flex>
))}
<Button
mt={4}
variant={'base'}
w={'100%'}
onClick={() =>
copyData(`${location.origin}/?inviterId=${userInfo?._id}`, '已复制邀请链接')
}
>
</Button>
<Button
mt={4}
leftIcon={<MyIcon name="withdraw" w={'22px'} />}
px={4}
title={residueAmount < 50 ? '最低提现额度为50元' : ''}
isDisabled={residueAmount < 50}
variant={'base'}
colorScheme={'myBlue'}
onClick={onOpenWxConcat}
>
{residueAmount < 50 ? '50元起提' : '提现'}
</Button>
</Card>
</Grid>
<Flex mt={6} alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>{userInfo?.username}</Box>
</Flex>
{feConfigs.show_userDetail && (
<Box mt={6}>
<Flex alignItems={'center'}>
<Box flex={'0 0 50px'}>:</Box>
<Box>
<strong>{userInfo?.balance}</strong>
</Box>
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
</Button>
</Flex>
</Box>
)}
</Card>
{feConfigs.show_userDetail && (
<Card px={6} py={4}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
{[
{ label: '佣金比例', value: `${userInfo?.promotion.rate || 15}%` },
{ label: '已注册用户数', value: `${invitedAmount}` },
{ label: '可用佣金', value: `${residueAmount}` }
].map((item) => (
<Flex
key={item.label}
alignItems={'center'}
mt={4}
justifyContent={'space-between'}
>
<Box w={'120px'}>{item.label}</Box>
<Box fontWeight={'bold'}>{item.value}</Box>
</Flex>
))}
<Button
mt={4}
variant={'base'}
w={'100%'}
onClick={() =>
copyData(`${location.origin}/?inviterId=${userInfo?._id}`, '已复制邀请链接')
}
>
</Button>
<Button
mt={4}
leftIcon={<MyIcon name="withdraw" w={'22px'} />}
px={4}
title={residueAmount < 50 ? '最低提现额度为50元' : ''}
isDisabled={residueAmount < 50}
variant={'base'}
colorScheme={'myBlue'}
onClick={onOpenWxConcat}
>
{residueAmount < 50 ? '50元起提' : '提现'}
</Button>
</Card>
)}
</Grid>
<Card mt={4} px={[3, 6]} py={4}>
<Tabs
m={'auto'}
w={'200px'}
list={tableList.current}
activeId={tableType}
size={'sm'}
onChange={(id: any) => router.replace(`/number?type=${id}`)}
/>
<Box minH={'300px'}>
{(() => {
const item = tableList.current.find((item) => item.id === tableType);
return item ? item.Component : null;
})()}
</Box>
</Card>
{feConfigs.show_userDetail && (
<Card mt={4} px={[3, 6]} py={4}>
<Tabs
m={'auto'}
w={'200px'}
list={tableList.current}
activeId={tableType}
size={'sm'}
onChange={(id: any) => router.replace(`/number?type=${id}`)}
/>
<Box minH={'300px'}>
{(() => {
const item = tableList.current.find((item) => item.id === tableType);
return item ? item.Component : null;
})()}
</Box>
</Card>
)}
</Box>
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
{isOpenWxConcat && <WxConcat onClose={onCloseWxConcat} />}
<File onSelect={onSelectFile} />
</Box>
</>
);
};

View File

@@ -3,6 +3,7 @@ import { Box, Flex } from '@chakra-ui/react';
import { ChevronRightIcon } from '@chakra-ui/icons';
import MyIcon from '@/components/Icon';
import { useRouter } from 'next/router';
import { feConfigs } from '@/store/static';
const list = [
{
@@ -10,16 +11,24 @@ const list = [
label: '我的知识库',
link: '/kb/list'
},
{
icon: 'appStoreLight',
label: 'AI应用市场',
link: '/appStore'
},
{
icon: 'git',
label: 'Git项目地址',
link: 'https://github.com/labring/FastGPT'
}
...(feConfigs.show_appStore
? [
{
icon: 'appStoreLight',
label: 'AI应用市场',
link: '/appStore'
}
]
: []),
...(feConfigs.show_git
? [
{
icon: 'git',
label: 'Git项目地址',
link: 'https://github.com/labring/FastGPT'
}
]
: [])
];
const Tools = () => {

View File

@@ -1,8 +1,7 @@
import mongoose from 'mongoose';
import tunnel from 'tunnel';
import { startQueue } from './utils/tools';
import { updateSystemEnv } from '@/pages/api/system/updateEnv';
import { initSystemModels } from '@/pages/api/system/getInitData';
import { updateSystemEnv, initSystemModels, initFeConfig } from '@/pages/api/system/updateEnv';
/**
* 连接 MongoDB 数据库
@@ -24,6 +23,7 @@ export async function connectToDatabase(): Promise<void> {
};
global.sendInformQueue = [];
global.sendInformQueueLen = 0;
global.feConfigs = {};
// proxy obj
if (process.env.AXIOS_PROXY_HOST && process.env.AXIOS_PROXY_PORT) {
global.httpsAgent = tunnel.httpsOverHttp({
@@ -33,7 +33,10 @@ export async function connectToDatabase(): Promise<void> {
}
});
}
// init function
initSystemModels();
initFeConfig();
updateSystemEnv();
try {

View File

@@ -6,6 +6,7 @@ import {
import type { InitDateResponse } from '@/pages/api/system/getInitData';
import { getInitData } from '@/api/system';
import { delay } from '@/utils/tools';
import { FeConfigsType } from '@/types';
export let beianText = '';
export let googleVerKey = '';
@@ -13,6 +14,7 @@ export let baiduTongji = '';
export let chatModelList: ChatModelItemType[] = [];
export let qaModelList: QAModelItemType[] = [];
export let vectorModelList: VectorModelItemType[] = [];
export let feConfigs: FeConfigsType = {};
let retryTimes = 3;
@@ -23,6 +25,7 @@ export const clientInitData = async (): Promise<InitDateResponse> => {
chatModelList = res.chatModels;
qaModelList = res.qaModels;
vectorModelList = res.vectorModels;
feConfigs = res.feConfigs;
beianText = res.beianText;
googleVerKey = res.googleVerKey;
baiduTongji = res.baiduTongji;

View File

@@ -13,6 +13,16 @@ export type PagingData<T> = {
export type RequestPaging = { pageNum: number; pageSize: number; [key]: any };
export type FeConfigsType = {
show_emptyChat?: boolean;
show_register?: boolean;
show_appStore?: boolean;
show_promotion?: boolean;
show_userDetail?: boolean;
show_git?: false;
authorText?: string;
};
declare global {
var mongodb: Mongoose | string | null;
var pgClient: Pool | null;
@@ -31,6 +41,7 @@ declare global {
var chatModels: ChatModelItemType[];
var qaModels: QAModelItemType[];
var vectorModels: VectorModelItemType[];
var feConfigs: FeConfigsType;
interface Window {
['pdfjs-dist/build/pdf']: any;