From fe9dd36afeca73f0a05cc8e61ddfed39f56db332 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Tue, 27 Feb 2024 19:07:45 +0800 Subject: [PATCH] plan count and replace invalid chars (#29) * fix: user oneapi * fix: training queue * fix: qa queue * perf: remove space chars * replace invalid chars --- .../content/docs/development/upgrading/469.md | 1 + .../content/docs/workflow/examples/dalle3.md | 2 +- packages/global/core/ai/model.ts | 4 +- packages/service/core/ai/embedding/index.ts | 3 +- packages/service/core/chat/utils.ts | 8 +- .../src/pages/account/components/InfoOld.tsx | 439 ------------------ .../account/components/OpenAIAccountModal.tsx | 5 +- .../src/pages/price/components/Standard.tsx | 4 +- .../app/src/service/common/system/cron.ts | 6 +- .../service/core/dataset/data/controller.ts | 3 + projects/app/src/service/events/generateQA.ts | 22 +- .../app/src/service/events/generateVector.ts | 5 +- .../moduleDispatch/agent/classifyQuestion.ts | 2 +- .../service/moduleDispatch/agent/extract.ts | 2 +- .../src/service/moduleDispatch/chat/oneapi.ts | 2 +- .../src/service/moduleDispatch/plugin/run.ts | 1 - .../src/service/moduleDispatch/tools/http.ts | 1 + projects/app/src/web/core/app/templates.ts | 4 +- 18 files changed, 41 insertions(+), 473 deletions(-) delete mode 100644 projects/app/src/pages/account/components/InfoOld.tsx diff --git a/docSite/content/docs/development/upgrading/469.md b/docSite/content/docs/development/upgrading/469.md index dd746546aef..2a6a8bd75bf 100644 --- a/docSite/content/docs/development/upgrading/469.md +++ b/docSite/content/docs/development/upgrading/469.md @@ -27,3 +27,4 @@ curl --location --request POST 'https://{{host}}/api/init/v469' \ 3. 优化 - 问题补全。增加英文类型。同时可以设置为单独模块,方便复用。 4. 优化 - 重写了计量模式 5. 修复 - 标注功能。 +6. 修复 - qa生成线程计数错误。 diff --git a/docSite/content/docs/workflow/examples/dalle3.md b/docSite/content/docs/workflow/examples/dalle3.md index e5104fc5d9a..d80e918280f 100644 --- a/docSite/content/docs/workflow/examples/dalle3.md +++ b/docSite/content/docs/workflow/examples/dalle3.md @@ -66,7 +66,7 @@ Body: Headers: -`Authorization: sk-xxx` +`Authorization: Bearer sk-xxx` Response: diff --git a/packages/global/core/ai/model.ts b/packages/global/core/ai/model.ts index 8d2dfe1560e..8669fa9484e 100644 --- a/packages/global/core/ai/model.ts +++ b/packages/global/core/ai/model.ts @@ -2,8 +2,8 @@ import type { LLMModelItemType, VectorModelItemType } from './model.d'; export const defaultQAModels: LLMModelItemType[] = [ { - model: 'gpt-3.5-turbo-16k', - name: 'gpt-3.5-turbo-16k', + model: 'gpt-3.5-turbo', + name: 'gpt-3.5-turbo', maxContext: 16000, maxResponse: 16000, quoteMaxToken: 13000, diff --git a/packages/service/core/ai/embedding/index.ts b/packages/service/core/ai/embedding/index.ts index 5845e0b14d9..aa29738c970 100644 --- a/packages/service/core/ai/embedding/index.ts +++ b/packages/service/core/ai/embedding/index.ts @@ -1,5 +1,6 @@ import { VectorModelItemType } from '@fastgpt/global/core/ai/model.d'; import { getAIApi } from '../config'; +import { replaceValidChars } from '../../chat/utils'; type GetVectorProps = { model: VectorModelItemType; @@ -36,7 +37,7 @@ export async function getVectorsByText({ model, input }: GetVectorProps) { } return { - charsLength: input.length, + charsLength: replaceValidChars(input).length, vectors: await Promise.all(res.data.map((item) => unityDimensional(item.embedding))) }; }); diff --git a/packages/service/core/chat/utils.ts b/packages/service/core/chat/utils.ts index 769be3f47d1..a0bde781a0e 100644 --- a/packages/service/core/chat/utils.ts +++ b/packages/service/core/chat/utils.ts @@ -59,11 +59,15 @@ export function ChatContextFilter({ return [...systemPrompts, ...chats]; } +export const replaceValidChars = (str: string) => { + const reg = /[\s\r\n]+/g; + return str.replace(reg, ''); +}; export const countMessagesChars = (messages: ChatItemType[]) => { - return messages.reduce((sum, item) => sum + item.value.length, 0); + return messages.reduce((sum, item) => sum + replaceValidChars(item.value).length, 0); }; export const countGptMessagesChars = (messages: ChatMessageItemType[]) => - messages.reduce((sum, item) => sum + item.content.length, 0); + messages.reduce((sum, item) => sum + replaceValidChars(item.content).length, 0); /** string to vision model. Follow the markdown code block rule for interception: diff --git a/projects/app/src/pages/account/components/InfoOld.tsx b/projects/app/src/pages/account/components/InfoOld.tsx deleted file mode 100644 index 83e16173f82..00000000000 --- a/projects/app/src/pages/account/components/InfoOld.tsx +++ /dev/null @@ -1,439 +0,0 @@ -import React, { useCallback, useMemo, useRef } from 'react'; -import { - Box, - Flex, - Button, - useDisclosure, - useTheme, - Divider, - Select, - Input, - Link, - Progress -} from '@chakra-ui/react'; -import { useForm } from 'react-hook-form'; -import { UserUpdateParams } from '@/types/user'; -import { useToast } from '@fastgpt/web/hooks/useToast'; -import { useUserStore } from '@/web/support/user/useUserStore'; -import type { UserType } from '@fastgpt/global/support/user/type.d'; -import { useQuery } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; -import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; -import { compressImgFileAndUpload } from '@/web/common/file/controller'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { useTranslation } from 'next-i18next'; -import { timezoneList } from '@fastgpt/global/common/time/timezone'; -import Avatar from '@/components/Avatar'; -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'; -import MySelect from '@/components/Select'; -import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; -import { putUpdateMemberName } from '@/web/support/user/team/api'; -import { getDocPath } from '@/web/common/system/doc'; -import { getTeamPlanStatus } from '@/web/support/wallet/sub/api'; -import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants'; - -const TeamMenu = dynamic(() => import('@/components/support/user/team/TeamMenu')); -const PayModal = dynamic(() => import('./PayModal')); -const UpdatePswModal = dynamic(() => import('./UpdatePswModal')); -const OpenAIAccountModal = dynamic(() => import('./OpenAIAccountModal')); - -const UserInfo = () => { - const theme = useTheme(); - const router = useRouter(); - const { feConfigs, systemVersion } = useSystemStore(); - const { t, i18n } = useTranslation(); - const { userInfo, updateUserInfo, initUserInfo } = useUserStore(); - const timezones = useRef(timezoneList()); - const { reset } = useForm({ - defaultValues: userInfo as UserType - }); - - const { toast } = useToast(); - const { - isOpen: isOpenPayModal, - onClose: onClosePayModal, - onOpen: onOpenPayModal - } = useDisclosure(); - const { - isOpen: isOpenUpdatePsw, - onClose: onCloseUpdatePsw, - onOpen: onOpenUpdatePsw - } = useDisclosure(); - const { isOpen: isOpenOpenai, onClose: onCloseOpenai, onOpen: onOpenOpenai } = useDisclosure(); - - const { File, onOpen: onOpenSelectFile } = useSelectFile({ - fileType: '.jpg,.png', - multiple: false - }); - - const onclickSave = useCallback( - async (data: UserType) => { - await updateUserInfo({ - avatar: data.avatar, - timezone: data.timezone, - openaiAccount: data.openaiAccount - }); - reset(data); - toast({ - title: '更新数据成功', - status: 'success' - }); - }, - [reset, toast, updateUserInfo] - ); - - const onSelectFile = useCallback( - async (e: File[]) => { - const file = e[0]; - if (!file || !userInfo) return; - try { - const src = await compressImgFileAndUpload({ - type: MongoImageTypeEnum.userAvatar, - file, - maxW: 300, - maxH: 300 - }); - - onclickSave({ - ...userInfo, - avatar: src - }); - } catch (err: any) { - toast({ - title: typeof err === 'string' ? err : t('common.error.Select avatar failed'), - status: 'warning' - }); - } - }, - [onclickSave, t, toast, userInfo] - ); - - useQuery(['init'], initUserInfo, { - onSuccess(res) { - reset(res); - } - }); - - const { - data: teamSubPlan = { - totalPoints: 0, - usedPoints: 0, - datasetMaxSize: 800, - usedDatasetSize: 0 - } - } = useQuery(['getTeamPlanStatus'], getTeamPlanStatus); - const datasetUsageMap = useMemo(() => { - const rate = teamSubPlan.usedDatasetSize / teamSubPlan.datasetMaxSize; - - const colorScheme = (() => { - if (rate < 0.5) return 'green'; - if (rate < 0.8) return 'yellow'; - return 'red'; - })(); - - return { - colorScheme, - value: rate * 100, - maxSize: teamSubPlan.datasetMaxSize || t('common.Unlimited'), - usedSize: teamSubPlan.usedDatasetSize - }; - }, [teamSubPlan.usedDatasetSize, teamSubPlan.datasetMaxSize, t]); - const aiPointsUsageMap = useMemo(() => { - const rate = teamSubPlan.usedPoints / teamSubPlan.totalPoints; - - const colorScheme = (() => { - if (rate < 0.5) return 'green'; - if (rate < 0.8) return 'yellow'; - return 'red'; - })(); - - return { - colorScheme, - value: rate * 100, - maxSize: teamSubPlan.totalPoints || t('common.Unlimited'), - usedSize: teamSubPlan.usedPoints - }; - }, [teamSubPlan.usedPoints, teamSubPlan.totalPoints, t]); - - return ( - - - - - - - - - - - {t('user.Replace')} - - - - {feConfigs.isPlus && ( - - {t('user.Member Name')}:  - { - const val = e.target.value; - if (val === userInfo?.team?.memberName) return; - try { - putUpdateMemberName(val); - } catch (error) {} - }} - /> - - )} - - {t('user.Account')}:  - {userInfo?.username} - - - {t('user.Team')}:  - - - - - - {t('user.Language')}:  - - ({ - label: lang.label, - value: key - }))} - onchange={(val: any) => { - const lang = val; - setLngStore(lang); - router.replace(router.basePath, router.asPath, { locale: lang }); - }} - /> - - - - {t('user.Timezone')}:  - - - - {t('user.Password')}:  - ***** - - - {feConfigs.isPlus && ( - <> - - - - {t('user.team.Balance')}:  - - - {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)} 元 - - {feConfigs?.show_pay && userInfo?.team?.canWrite && ( - - )} - - - {feConfigs?.show_pay && ( - <> - - - - {t('support.user.team.Dataset usage')}: {datasetUsageMap.usedSize}/ - {datasetUsageMap.maxSize} - - {userInfo?.team?.canWrite && ( - - )} - - - - - - - - - AI积分: {Math.round(teamSubPlan.usedPoints)}/{teamSubPlan.totalPoints} - - - - - - - - )} - - )} - - {feConfigs?.docUrl && ( - - - - {t('system.Help Document')} - - - - V{systemVersion} - - - )} - {feConfigs?.chatbotUrl && ( - - - - {t('common.system.Help Chatbot')} - - - )} - {feConfigs?.show_openai_account && ( - <> - - - - - - - OpenAI/OneAPI 账号 - - - - - - )} - - - {isOpenPayModal && } - {isOpenUpdatePsw && } - {isOpenOpenai && userInfo && ( - - onclickSave({ - ...userInfo, - openaiAccount: data - }) - } - onClose={onCloseOpenai} - /> - )} - - - ); -}; - -export default React.memo(UserInfo); diff --git a/projects/app/src/pages/account/components/OpenAIAccountModal.tsx b/projects/app/src/pages/account/components/OpenAIAccountModal.tsx index 5b8ed0757b0..81d22f85d36 100644 --- a/projects/app/src/pages/account/components/OpenAIAccountModal.tsx +++ b/projects/app/src/pages/account/components/OpenAIAccountModal.tsx @@ -37,8 +37,9 @@ const OpenAIAccountModal = ({ > - 可以填写 OpenAI/OneAPI 的相关秘钥。如果你填写了该内容,在线上平台使用 OpenAI Chat - 模型不会计费(不包含知识库训练、索引生成)。请注意你的 Key 是否有访问对应模型的权限。 + 可以填写 OpenAI/OneAPI + 的相关秘钥。如果你填写了该内容,在线上平台使用【AI对话】、【问题分类】和【内容提取】将会走你填写的Key,不会计费。请注意你的 + Key 是否有访问对应模型的权限。GPT模型可以选择 FastAI。 API Key: diff --git a/projects/app/src/pages/price/components/Standard.tsx b/projects/app/src/pages/price/components/Standard.tsx index bd52756db9e..b339e7c257f 100644 --- a/projects/app/src/pages/price/components/Standard.tsx +++ b/projects/app/src/pages/price/components/Standard.tsx @@ -17,6 +17,7 @@ import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRC import { getWxPayQRCode } from '@/web/support/wallet/bill/api'; import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants'; import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList'; +import { useRouter } from 'next/router'; type ConfirmPayModalProps = { teamBalance: number; @@ -34,8 +35,8 @@ const Standard = ({ refetchTeamSubPlan: () => void; }) => { const { t } = useTranslation(); + const router = useRouter(); const { subPlans, feConfigs } = useSystemStore(); - const { toast } = useToast(); const [confirmPayData, setConfirmPayData] = useState(); const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month); @@ -67,6 +68,7 @@ const Standard = ({ mutationFn: (data: StandardSubPlanParams) => postUpdateStandardSub(data), onSuccess() { refetchTeamSubPlan(); + router.reload(); }, successToast: t('support.wallet.subscription.Standard update success'), errorToast: t('support.wallet.subscription.Standard update fail') diff --git a/projects/app/src/service/common/system/cron.ts b/projects/app/src/service/common/system/cron.ts index 8f837f40d7c..fa2f4096d27 100644 --- a/projects/app/src/service/common/system/cron.ts +++ b/projects/app/src/service/common/system/cron.ts @@ -1,6 +1,5 @@ import { initSystemConfig } from '@/pages/api/common/system/getInitData'; -import { generateQA } from '@/service/events/generateQA'; -import { generateVector } from '@/service/events/generateVector'; +import { startQueue } from '@/service/utils/tools'; import { setCron } from '@fastgpt/service/common/system/cron'; export const startCron = () => { @@ -17,7 +16,6 @@ export const setUpdateSystemConfigCron = () => { export const setTrainingQueueCron = () => { setCron('*/1 * * * *', () => { - generateVector(); - generateQA(); + startQueue(); }); }; diff --git a/projects/app/src/service/core/dataset/data/controller.ts b/projects/app/src/service/core/dataset/data/controller.ts index c5b463bbc5f..f8f2a5bacff 100644 --- a/projects/app/src/service/core/dataset/data/controller.ts +++ b/projects/app/src/service/core/dataset/data/controller.ts @@ -35,6 +35,7 @@ import type { import { pushDataListToTrainingQueue } from '@fastgpt/service/core/dataset/training/controller'; import { getVectorModel } from '../../ai/model'; import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; +import { startQueue } from '@/service/utils/tools'; export async function pushDataToTrainingQueue( props: { @@ -48,6 +49,8 @@ export async function pushDataToTrainingQueue( datasetModelList: global.llmModels }); + startQueue(); + return result; } diff --git a/projects/app/src/service/events/generateQA.ts b/projects/app/src/service/events/generateQA.ts index 53cba40f886..6d96a027247 100644 --- a/projects/app/src/service/events/generateQA.ts +++ b/projects/app/src/service/events/generateQA.ts @@ -7,16 +7,16 @@ import { addLog } from '@fastgpt/service/common/system/log'; import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter'; import { replaceVariable } from '@fastgpt/global/common/string/tools'; import { Prompt_AgentQA } from '@/global/core/prompt/agent'; -import { getErrText } from '@fastgpt/global/common/error/utils'; import type { PushDatasetDataChunkProps } from '@fastgpt/global/core/dataset/api.d'; import { pushDataToTrainingQueue } from '@/service/core/dataset/data/controller'; import { getLLMModel } from '../core/ai/model'; import { checkInvalidChunkAndLock, checkTeamAiPointsAndLock } from './utils'; +import { countGptMessagesChars } from '@fastgpt/service/core/chat/utils'; const reduceQueue = () => { global.qaQueueLen = global.qaQueueLen > 0 ? global.qaQueueLen - 1 : 0; - return global.vectorQueueLen === 0; + return global.qaQueueLen === 0; }; export async function generateQA(): Promise { @@ -83,11 +83,11 @@ export async function generateQA(): Promise { reduceQueue(); return generateQA(); } - console.log('Start QA Training'); // auth balance - if (await checkTeamAiPointsAndLock(data.teamId, data.tmbId)) { + if (!(await checkTeamAiPointsAndLock(data.teamId, data.tmbId))) { + console.log('balance not enough'); reduceQueue(); return generateQA(); } @@ -119,6 +119,12 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`; const qaArr = formatSplitText(answer, text); // 格式化后的QA对 + addLog.info(`QA Training Finish`, { + time: `${(Date.now() - startTime) / 1000}s`, + splitLength: qaArr.length, + usage: chatResponse.usage + }); + // get vector and insert const { insertLen } = await pushDataToTrainingQueue({ teamId: data.teamId, @@ -135,18 +141,12 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`; // delete data from training await MongoDatasetTraining.findByIdAndDelete(data._id); - addLog.info(`QA Training Finish`, { - time: `${(Date.now() - startTime) / 1000}s`, - splitLength: qaArr.length, - usage: chatResponse.usage - }); - // add bill if (insertLen > 0) { pushQAUsage({ teamId: data.teamId, tmbId: data.tmbId, - charsLength: `${prompt}${answer}`.length, + charsLength: countGptMessagesChars(messages).length, billId: data.billId, model }); diff --git a/projects/app/src/service/events/generateVector.ts b/projects/app/src/service/events/generateVector.ts index 563692ffd1c..6b11322613b 100644 --- a/projects/app/src/service/events/generateVector.ts +++ b/projects/app/src/service/events/generateVector.ts @@ -1,8 +1,6 @@ import { insertData2Dataset } from '@/service/core/dataset/data/controller'; import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema'; import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constants'; -import { addLog } from '@fastgpt/service/common/system/log'; -import { getErrText } from '@fastgpt/global/common/error/utils'; import { pushGenerateVectorUsage } from '@/service/support/wallet/usage/push'; import { checkInvalidChunkAndLock, checkTeamAiPointsAndLock } from './utils'; import { delay } from '@fastgpt/global/common/system/utils'; @@ -15,9 +13,8 @@ const reduceQueue = () => { /* 索引生成队列。每导入一次,就是一个单独的线程 */ export async function generateVector(): Promise { - if (global.vectorQueueLen >= 1) return; + if (global.vectorQueueLen >= global.systemEnv.vectorMaxProcess) return; global.vectorQueueLen++; - await delay(2000); const start = Date.now(); // get training data diff --git a/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts b/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts index 6eba9ad0435..eab7dae1778 100644 --- a/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts +++ b/projects/app/src/service/moduleDispatch/agent/classifyQuestion.ts @@ -83,7 +83,7 @@ export const dispatchClassifyQuestion = async (props: Props): Promise { [ModuleOutputKeyEnum.moduleDispatchBills]: [ { moduleName: name, - totalPoints, + totalPoints: user.openaiAccount?.key ? 0 : totalPoints, model: modelName, charsLength } diff --git a/projects/app/src/service/moduleDispatch/chat/oneapi.ts b/projects/app/src/service/moduleDispatch/chat/oneapi.ts index 80ec8e999b4..9e91cacdb6c 100644 --- a/projects/app/src/service/moduleDispatch/chat/oneapi.ts +++ b/projects/app/src/service/moduleDispatch/chat/oneapi.ts @@ -211,7 +211,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise