diff --git a/client/data/FeConfig.json b/client/data/FeConfig.json new file mode 100644 index 000000000..8a2b55763 --- /dev/null +++ b/client/data/FeConfig.json @@ -0,0 +1,9 @@ +{ + "show_emptyChat": false, + "show_register": false, + "show_appStore": false, + "show_promotion": false, + "show_userDetail": false, + "show_git": false, + "authorText": "Made by FastGpt Team." +} diff --git a/client/public/docs/chatProblem.md b/client/public/docs/chatProblem.md index 8b5420961..7802d77a3 100644 --- a/client/public/docs/chatProblem.md +++ b/client/public/docs/chatProblem.md @@ -1,7 +1,7 @@ ### 常见问题 **反馈问卷**: 如果你遇到任何使用问题或有期望的功能,可以[填写该问卷](https://www.wjx.cn/vm/rLIw1uD.aspx#) -**Git 地址**: [项目地址。V4-preview 暂未开源,在正式版发布后会开源。](https://github.com/c121914yu/FastGPT) +**Git 地址**: [项目地址。V4-preview 暂未开源,在正式版发布后会开源。](https://github.com/labring/FastGPT) **问题文档**: [先看文档,再提问](https://kjqvjse66l.feishu.cn/docx/HtrgdT0pkonP4kxGx8qcu6XDnGh) **价格表** | 计费项 | 价格: 元/ 1K tokens(包含上下文)| diff --git a/client/src/components/ChatBox/index.tsx b/client/src/components/ChatBox/index.tsx index e10087ee9..2f3c14159 100644 --- a/client/src/components/ChatBox/index.tsx +++ b/client/src/components/ChatBox/index.tsx @@ -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] ); diff --git a/client/src/components/Layout/navbar.tsx b/client/src/components/Layout/navbar.tsx index 01fcd2b89..c1ddaeb26 100644 --- a/client/src/components/Layout/navbar.tsx +++ b/client/src/components/Layout/navbar.tsx @@ -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 }) => { )} - - - - - + {feConfigs.show_git && ( + + + + + + )} ); }; diff --git a/client/src/components/Layout/navbarPhone.tsx b/client/src/components/Layout/navbarPhone.tsx index af502f74f..240e90983 100644 --- a/client/src/components/Layout/navbarPhone.tsx +++ b/client/src/components/Layout/navbarPhone.tsx @@ -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(); diff --git a/client/src/constants/flow/inputTemplate.ts b/client/src/constants/flow/inputTemplate.ts index 912c783fc..3dbef267a 100644 --- a/client/src/constants/flow/inputTemplate.ts +++ b/client/src/constants/flow/inputTemplate.ts @@ -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 }; diff --git a/client/src/pages/api/system/getInitData.ts b/client/src/pages/api/system/getInitData.ts index 1d746a0c1..e8f3a05f9 100644 --- a/client/src/pages/api/system/getInitData.ts +++ b/client/src/pages/api/system/getInitData.ts @@ -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(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 - }; -} diff --git a/client/src/pages/api/system/updateEnv.ts b/client/src/pages/api/system/updateEnv.ts index 5b0dd7bde..fa11e2c42 100644 --- a/client/src/pages/api/system/updateEnv.ts +++ b/client/src/pages/api/system/updateEnv.ts @@ -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; +} diff --git a/client/src/pages/api/user/sendAuthCode.ts b/client/src/pages/api/user/sendAuthCode.ts index 17f272c54..40747baaa 100644 --- a/client/src/pages/api/user/sendAuthCode.ts +++ b/client/src/pages/api/user/sendAuthCode.ts @@ -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 分钟内是否有重复数据 diff --git a/client/src/pages/chat/components/ChatHeader.tsx b/client/src/pages/chat/components/ChatHeader.tsx index 87104815b..0212041d0 100644 --- a/client/src/pages/chat/components/ChatHeader.tsx +++ b/client/src/pages/chat/components/ChatHeader.tsx @@ -25,8 +25,8 @@ const ChatHeader = ({ return ( { - - - {beianText && ( - - {beianText} - - )} + {feConfigs?.authorText && ( + + + {beianText && ( + + {beianText} + + )} - Made by FastGpt Team. - - + {feConfigs?.authorText} + + + )} ); }; diff --git a/client/src/pages/number/index.tsx b/client/src/pages/number/index.tsx index c799f3e38..de2d1c445 100644 --- a/client/src/pages/number/index.tsx +++ b/client/src/pages/number/index.tsx @@ -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({ + const { reset } = useForm({ defaultValues: userInfo as UserType }); const { toast } = useToast(); @@ -146,105 +147,117 @@ const NumberSetting = ({ tableType }: { tableType: `${TableEnum}` }) => { ); return ( - - - - - - 账号信息 - - - - - 头像: - - - - 账号: - {userInfo?.username} - - - - 余额: - - {userInfo?.balance} 元 + <> + + + + + + 账号信息 - - - - - - 我的邀请 - - {[ - { label: '佣金比例', value: `${userInfo?.promotion.rate || 15}%` }, - { label: '已注册用户数', value: `${invitedAmount}人` }, - { label: '可用佣金', value: `¥${residueAmount}` } - ].map((item) => ( - - {item.label} - {item.value} + + 头像: + - ))} - - - - + + 账号: + {userInfo?.username} + + {feConfigs.show_userDetail && ( + + + 余额: + + {userInfo?.balance} 元 + + + + + )} + + {feConfigs.show_userDetail && ( + + + 我的邀请 + + {[ + { label: '佣金比例', value: `${userInfo?.promotion.rate || 15}%` }, + { label: '已注册用户数', value: `${invitedAmount}人` }, + { label: '可用佣金', value: `¥${residueAmount}` } + ].map((item) => ( + + {item.label} + {item.value} + + ))} + + + + )} + - - router.replace(`/number?type=${id}`)} - /> - - {(() => { - const item = tableList.current.find((item) => item.id === tableType); - - return item ? item.Component : null; - })()} - - + {feConfigs.show_userDetail && ( + + router.replace(`/number?type=${id}`)} + /> + + {(() => { + const item = tableList.current.find((item) => item.id === tableType); + return item ? item.Component : null; + })()} + + + )} + {isOpenPayModal && } {isOpenWxConcat && } - + ); }; diff --git a/client/src/pages/tools/index.tsx b/client/src/pages/tools/index.tsx index 71150b91b..5deb9f498 100644 --- a/client/src/pages/tools/index.tsx +++ b/client/src/pages/tools/index.tsx @@ -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 = () => { diff --git a/client/src/service/mongo.ts b/client/src/service/mongo.ts index 7805be576..1e06c3a9d 100644 --- a/client/src/service/mongo.ts +++ b/client/src/service/mongo.ts @@ -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 { }; 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 { } }); } + + // init function initSystemModels(); + initFeConfig(); updateSystemEnv(); try { diff --git a/client/src/store/static.ts b/client/src/store/static.ts index ffdbbf64b..c98cab820 100644 --- a/client/src/store/static.ts +++ b/client/src/store/static.ts @@ -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 => { chatModelList = res.chatModels; qaModelList = res.qaModels; vectorModelList = res.vectorModels; + feConfigs = res.feConfigs; beianText = res.beianText; googleVerKey = res.googleVerKey; baiduTongji = res.baiduTongji; diff --git a/client/src/types/index.d.ts b/client/src/types/index.d.ts index ac226047f..38b912c16 100644 --- a/client/src/types/index.d.ts +++ b/client/src/types/index.d.ts @@ -13,6 +13,16 @@ export type PagingData = { 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; diff --git a/docs/zh/modules/imgs/intro1.png b/docs/zh/modules/imgs/intro1.png new file mode 100644 index 000000000..4aff501a5 Binary files /dev/null and b/docs/zh/modules/imgs/intro1.png differ diff --git a/docs/zh/modules/intro.md b/docs/zh/modules/intro.md new file mode 100644 index 000000000..45e825f61 --- /dev/null +++ b/docs/zh/modules/intro.md @@ -0,0 +1,19 @@ +# 模块编排介绍 + +FastGpt V4 后将采用新的交互方式来构建 AI 应用。使用了“节点”编排的方式去掉原先的表单方式。提高可玩性和扩展性的同时也提高了上手的门槛,这篇文章就来简单介绍一下 “预览版” 的模块编排基本使用方法。 + +![模块](./imgs/intro1.png) + +预览版仅包含了 8 个模块,你可以利用它们来完全实现 V3 的知识库功能。此外,预览版还加入了问题分类模块,可以实现多路线任务。 + +## 基础知识 + +### 什么是模块 + +在程序中,模块可以理解为一个个 function 或者接口。对于非技术背景同学,可以理解为它就是一个**步骤**。将多个模块一个个拼接起来,即可一步步的去实现最终的 AI 输出。 + +### 如何阅读和理解 + +1. 建议从左往右阅读。 +2. 从 **用户问题** 模块开始。用户问题模块,代表的是用户发送了一段文本,触发任务开始。 +3.