From 2a45fe520b533ee1d9a5c800b9af197c084c41ee Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Tue, 4 Jul 2023 21:24:32 +0800 Subject: [PATCH] perf: code and inform --- client/public/docs/chatProblem.md | 2 +- client/public/docs/intro.md | 2 +- client/src/constants/model.ts | 2 +- client/src/pages/api/openapi/chat/chat.ts | 3 +- .../src/pages/api/openapi/kb/appKbSearch.ts | 6 +- client/src/pages/api/openapi/kb/pushData.ts | 3 +- .../pages/api/openapi/v1/chat/completions.ts | 3 +- client/src/pages/api/system/getModels.ts | 1 + client/src/pages/api/user/inform/send.ts | 38 +++++----- .../src/pages/number/components/PayModal.tsx | 2 +- client/src/service/events/generateQA.ts | 3 +- client/src/service/events/sendInform.ts | 16 +++++ client/src/service/mongo.ts | 2 + client/src/service/utils/auth.ts | 30 ++------ client/src/service/utils/chat/index.ts | 71 +++++-------------- client/src/service/utils/chat/openai.ts | 6 +- client/src/types/index.d.ts | 4 +- client/src/utils/file.ts | 2 +- client/src/utils/plugin/index.ts | 32 ++------- client/src/utils/plugin/openai.ts | 32 ++------- 20 files changed, 97 insertions(+), 163 deletions(-) create mode 100644 client/src/service/events/sendInform.ts diff --git a/client/public/docs/chatProblem.md b/client/public/docs/chatProblem.md index 31e50c8c9..8aa016575 100644 --- a/client/public/docs/chatProblem.md +++ b/client/public/docs/chatProblem.md @@ -7,7 +7,7 @@ | 计费项 | 价格: 元/ 1K tokens(包含上下文)| | --- | --- | | 知识库 - 索引 | 0.001 | -| chatgpt - 对话 | 0.025 | +| chatgpt - 对话 | 0.015 | | chatgpt16K - 对话 | 0.025 | | gpt4 - 对话 | 0.45 | | 文件拆分 | 0.025 | diff --git a/client/public/docs/intro.md b/client/public/docs/intro.md index 01efd890b..918575fe5 100644 --- a/client/public/docs/intro.md +++ b/client/public/docs/intro.md @@ -19,7 +19,7 @@ FastGpt 项目完全开源,可随意私有化部署,去除平台风险忧虑 | 计费项 | 价格: 元/ 1K tokens(包含上下文)| | --- | --- | | 知识库 - 索引 | 0.001 | -| chatgpt - 对话 | 0.025 | +| chatgpt - 对话 | 0.015 | | chatgpt16K - 对话 | 0.025 | | gpt4 - 对话 | 0.45 | | 文件拆分 | 0.025 | diff --git a/client/src/constants/model.ts b/client/src/constants/model.ts index fcf9e7969..79dbf0cde 100644 --- a/client/src/constants/model.ts +++ b/client/src/constants/model.ts @@ -31,7 +31,7 @@ export const ChatModelMap = { contextMaxToken: 4000, systemMaxToken: 2400, maxTemperature: 1.2, - price: 2.5 + price: 1.5 }, [OpenAiChatEnum.GPT3516k]: { chatModel: OpenAiChatEnum.GPT3516k, diff --git a/client/src/pages/api/openapi/chat/chat.ts b/client/src/pages/api/openapi/chat/chat.ts index 967a7cca7..210cac9a4 100644 --- a/client/src/pages/api/openapi/chat/chat.ts +++ b/client/src/pages/api/openapi/chat/chat.ts @@ -129,7 +129,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex // 发出请求 const { streamResponse, responseMessages, responseText, totalTokens } = - await modelServiceToolMap[model.chat.chatModel].chatCompletion({ + await modelServiceToolMap.chatCompletion({ + model: model.chat.chatModel, apiKey, temperature: +temperature, messages: completePrompts, diff --git a/client/src/pages/api/openapi/kb/appKbSearch.ts b/client/src/pages/api/openapi/kb/appKbSearch.ts index f3102e9bd..77bdde4f4 100644 --- a/client/src/pages/api/openapi/kb/appKbSearch.ts +++ b/client/src/pages/api/openapi/kb/appKbSearch.ts @@ -150,13 +150,15 @@ export async function appKbSearch({ } ]; - const fixedSystemTokens = modelToolMap[model.chat.chatModel].countTokens({ + const fixedSystemTokens = modelToolMap.countTokens({ + model: model.chat.chatModel, messages: [...userSystemPrompt, ...userLimitPrompt] }); // filter part quote by maxToken - const sliceResult = modelToolMap[model.chat.chatModel] + const sliceResult = modelToolMap .tokenSlice({ + model: model.chat.chatModel, maxToken: modelConstantsData.systemMaxToken - fixedSystemTokens, messages: filterSearch.map((item, i) => ({ obj: ChatRoleEnum.System, diff --git a/client/src/pages/api/openapi/kb/pushData.ts b/client/src/pages/api/openapi/kb/pushData.ts index 7ca3b8e4f..d3fad4f7a 100644 --- a/client/src/pages/api/openapi/kb/pushData.ts +++ b/client/src/pages/api/openapi/kb/pushData.ts @@ -78,7 +78,8 @@ export async function pushDataToKb({ if (mode === TrainingModeEnum.qa) { // count token - const token = modelToolMap[OpenAiChatEnum.GPT3516k].countTokens({ + const token = modelToolMap.countTokens({ + model: OpenAiChatEnum.GPT3516k, messages: [{ obj: 'System', value: item.q }] }); if (token > modeMaxToken[TrainingModeEnum.qa]) { diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts index 11929e6aa..17491f5a3 100644 --- a/client/src/pages/api/openapi/v1/chat/completions.ts +++ b/client/src/pages/api/openapi/v1/chat/completions.ts @@ -196,7 +196,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex // start model api. responseText and totalTokens: valid only if stream = false const { streamResponse, responseMessages, responseText, totalTokens } = - await modelServiceToolMap[model.chat.chatModel].chatCompletion({ + await modelServiceToolMap.chatCompletion({ + model: model.chat.chatModel, apiKey: userOpenAiKey || apiKey, temperature: +temperature, maxToken: model.chat.maxToken, diff --git a/client/src/pages/api/system/getModels.ts b/client/src/pages/api/system/getModels.ts index 83767c63f..6ef858907 100644 --- a/client/src/pages/api/system/getModels.ts +++ b/client/src/pages/api/system/getModels.ts @@ -9,6 +9,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) chatModelList.push(ChatModelMap[OpenAiChatEnum.GPT3516k]); chatModelList.push(ChatModelMap[OpenAiChatEnum.GPT35]); + chatModelList.push(ChatModelMap[OpenAiChatEnum.textada001]); chatModelList.push(ChatModelMap[OpenAiChatEnum.GPT4]); jsonRes(res, { diff --git a/client/src/pages/api/user/inform/send.ts b/client/src/pages/api/user/inform/send.ts index 7ff6d91e1..0644e3cac 100644 --- a/client/src/pages/api/user/inform/send.ts +++ b/client/src/pages/api/user/inform/send.ts @@ -4,6 +4,7 @@ import { jsonRes } from '@/service/response'; import { connectToDatabase, Inform, User } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; import { InformTypeEnum } from '@/constants/user'; +import { startSendInform } from '@/service/events/sendInform'; export type Props = { type: `${InformTypeEnum}`; @@ -37,25 +38,26 @@ export async function sendInform({ type, title, content, userId }: Props) { try { if (userId) { - // skip it if have same inform within 5 minutes - const inform = await Inform.findOne({ - type, - title, - content, - userId, - read: false, - time: { $lte: new Date(Date.now() + 5 * 60 * 1000) } + global.sendInformQueue.push(async () => { + // skip it if have same inform within 5 minutes + const inform = await Inform.findOne({ + type, + title, + content, + userId, + time: { $gte: new Date(Date.now() - 5 * 60 * 1000) } + }); + + if (inform) return; + + await Inform.create({ + type, + title, + content, + userId + }); }); - - if (inform) return; - - await Inform.create({ - type, - title, - content, - userId - }); - + startSendInform(); return; } diff --git a/client/src/pages/number/components/PayModal.tsx b/client/src/pages/number/components/PayModal.tsx index 1e3cc5e9c..27d51b410 100644 --- a/client/src/pages/number/components/PayModal.tsx +++ b/client/src/pages/number/components/PayModal.tsx @@ -114,7 +114,7 @@ const PayModal = ({ onClose }: { onClose: () => void }) => { | 计费项 | 价格: 元/ 1K tokens(包含上下文)| | --- | --- | | 知识库 - 索引 | 0.001 | -| chatgpt - 对话 | 0.025 | +| chatgpt - 对话 | 0.015 | | chatgpt16K - 对话 | 0.025 | | gpt4 - 对话 | 0.45 | | 文件拆分 | 0.025 |`} diff --git a/client/src/service/events/generateQA.ts b/client/src/service/events/generateQA.ts index 85b3727ae..d4125c0e0 100644 --- a/client/src/service/events/generateQA.ts +++ b/client/src/service/events/generateQA.ts @@ -63,8 +63,9 @@ export async function generateQA(): Promise { // 请求 chatgpt 获取回答 const response = await Promise.all( [data.q].map((text) => - modelServiceToolMap[OpenAiChatEnum.GPT3516k] + modelServiceToolMap .chatCompletion({ + model: OpenAiChatEnum.GPT3516k, apiKey: systemAuthKey, temperature: 0.8, messages: [ diff --git a/client/src/service/events/sendInform.ts b/client/src/service/events/sendInform.ts new file mode 100644 index 000000000..d43f32737 --- /dev/null +++ b/client/src/service/events/sendInform.ts @@ -0,0 +1,16 @@ +export const startSendInform = async () => { + if (global.sendInformQueue.length === 0 || global.sendInformQueueLen > 0) return; + global.sendInformQueueLen++; + + try { + const fn = global.sendInformQueue[global.sendInformQueue.length - 1]; + await fn(); + global.sendInformQueue.pop(); + global.sendInformQueueLen--; + + startSendInform(); + } catch (error) { + global.sendInformQueueLen--; + startSendInform(); + } +}; diff --git a/client/src/service/mongo.ts b/client/src/service/mongo.ts index fa5ff2e6c..673fe2145 100644 --- a/client/src/service/mongo.ts +++ b/client/src/service/mongo.ts @@ -20,6 +20,8 @@ export async function connectToDatabase(): Promise { pgIvfflatProbe: 10, sensitiveCheck: false }; + global.sendInformQueue = []; + global.sendInformQueueLen = 0; // proxy obj if (process.env.AXIOS_PROXY_HOST && process.env.AXIOS_PROXY_PORT) { global.httpsAgent = tunnel.httpsOverHttp({ diff --git a/client/src/service/utils/auth.ts b/client/src/service/utils/auth.ts index 638b9b764..ba234b45d 100644 --- a/client/src/service/utils/auth.ts +++ b/client/src/service/utils/auth.ts @@ -181,33 +181,13 @@ export const getApiKey = async ({ return Promise.reject(ERROR_ENUM.unAuthorization); } - const keyMap = { - [OpenAiChatEnum.GPT35]: { - userOpenAiKey: user.openaiKey || '', - systemAuthKey: getSystemOpenAiKey() - }, - [OpenAiChatEnum.GPT3516k]: { - userOpenAiKey: user.openaiKey || '', - systemAuthKey: getSystemOpenAiKey() - }, - [OpenAiChatEnum.GPT4]: { - userOpenAiKey: user.openaiKey || '', - systemAuthKey: getSystemOpenAiKey() - }, - [OpenAiChatEnum.GPT432k]: { - userOpenAiKey: user.openaiKey || '', - systemAuthKey: getSystemOpenAiKey() - } - }; - - if (!keyMap[model]) { - return Promise.reject('App model is exists'); - } + const userOpenAiKey = user.openaiKey || ''; + const systemAuthKey = getSystemOpenAiKey(); // 有自己的key - if (!mustPay && keyMap[model].userOpenAiKey) { + if (!mustPay && userOpenAiKey) { return { - userOpenAiKey: keyMap[model].userOpenAiKey, + userOpenAiKey, systemAuthKey: '' }; } @@ -219,7 +199,7 @@ export const getApiKey = async ({ return { userOpenAiKey: '', - systemAuthKey: keyMap[model].systemAuthKey + systemAuthKey }; }; diff --git a/client/src/service/utils/chat/index.ts b/client/src/service/utils/chat/index.ts index 9bf69cb87..22d66c71e 100644 --- a/client/src/service/utils/chat/index.ts +++ b/client/src/service/utils/chat/index.ts @@ -27,6 +27,7 @@ export type StreamResponseType = { chatResponse: any; prompts: ChatItemType[]; res: NextApiResponse; + model: `${OpenAiChatEnum}`; [key: string]: any; }; export type StreamResponseReturnType = { @@ -35,49 +36,9 @@ export type StreamResponseReturnType = { finishMessages: ChatItemType[]; }; -export const modelServiceToolMap: Record< - ChatModelType, - { - chatCompletion: (data: ChatCompletionType) => Promise; - streamResponse: (data: StreamResponseType) => Promise; - } -> = { - [OpenAiChatEnum.GPT35]: { - chatCompletion: (data: ChatCompletionType) => - chatResponse({ model: OpenAiChatEnum.GPT35, ...data }), - streamResponse: (data: StreamResponseType) => - openAiStreamResponse({ - model: OpenAiChatEnum.GPT35, - ...data - }) - }, - [OpenAiChatEnum.GPT3516k]: { - chatCompletion: (data: ChatCompletionType) => - chatResponse({ model: OpenAiChatEnum.GPT3516k, ...data }), - streamResponse: (data: StreamResponseType) => - openAiStreamResponse({ - model: OpenAiChatEnum.GPT3516k, - ...data - }) - }, - [OpenAiChatEnum.GPT4]: { - chatCompletion: (data: ChatCompletionType) => - chatResponse({ model: OpenAiChatEnum.GPT4, ...data }), - streamResponse: (data: StreamResponseType) => - openAiStreamResponse({ - model: OpenAiChatEnum.GPT4, - ...data - }) - }, - [OpenAiChatEnum.GPT432k]: { - chatCompletion: (data: ChatCompletionType) => - chatResponse({ model: OpenAiChatEnum.GPT432k, ...data }), - streamResponse: (data: StreamResponseType) => - openAiStreamResponse({ - model: OpenAiChatEnum.GPT432k, - ...data - }) - } +export const modelServiceToolMap = { + chatCompletion: chatResponse, + streamResponse: openAiStreamResponse }; /* delete invalid symbol */ @@ -124,7 +85,8 @@ export const ChatContextFilter = ({ } // 去掉 system 的 token - maxTokens -= modelToolMap[model].countTokens({ + maxTokens -= modelToolMap.countTokens({ + model, messages: systemPrompts }); @@ -135,7 +97,8 @@ export const ChatContextFilter = ({ for (let i = chatPrompts.length - 1; i >= 0; i--) { chats.unshift(chatPrompts[i]); - const tokens = modelToolMap[model].countTokens({ + const tokens = modelToolMap.countTokens({ + model, messages: chats }); @@ -164,13 +127,14 @@ export const resStreamResponse = async ({ res.setHeader('X-Accel-Buffering', 'no'); res.setHeader('Cache-Control', 'no-cache, no-transform'); - const { responseContent, totalTokens, finishMessages } = await modelServiceToolMap[ - model - ].streamResponse({ - chatResponse, - prompts, - res - }); + const { responseContent, totalTokens, finishMessages } = await modelServiceToolMap.streamResponse( + { + chatResponse, + prompts, + res, + model + } + ); return { responseContent, totalTokens, finishMessages }; }; @@ -259,7 +223,8 @@ export const V2_StreamResponse = async ({ value: responseContent }); - const totalTokens = modelToolMap[model].countTokens({ + const totalTokens = modelToolMap.countTokens({ + model, messages: finishMessages }); diff --git a/client/src/service/utils/chat/openai.ts b/client/src/service/utils/chat/openai.ts index fe8150769..30cb96184 100644 --- a/client/src/service/utils/chat/openai.ts +++ b/client/src/service/utils/chat/openai.ts @@ -35,7 +35,8 @@ export const chatResponse = async ({ const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false }); const chatAPI = getOpenAIApi(apiKey); - const promptsToken = modelToolMap[model].countTokens({ + const promptsToken = modelToolMap.countTokens({ + model, messages: filterMessages }); @@ -116,7 +117,8 @@ export const openAiStreamResponse = async ({ value: responseContent }); - const totalTokens = modelToolMap[model].countTokens({ + const totalTokens = modelToolMap.countTokens({ + model, messages: finishMessages }); diff --git a/client/src/types/index.d.ts b/client/src/types/index.d.ts index 884b62049..ac15af282 100644 --- a/client/src/types/index.d.ts +++ b/client/src/types/index.d.ts @@ -21,7 +21,9 @@ declare global { var QRCode: any; var qaQueueLen: number; var vectorQueueLen: number; - var OpenAiEncMap: Record; + var OpenAiEncMap: Tiktoken; + var sendInformQueue: (() => Promise)[]; + var sendInformQueueLen: number; var systemEnv: { vectorMaxProcess: number; qaMaxProcess: number; diff --git a/client/src/utils/file.ts b/client/src/utils/file.ts index c2504c082..fec9e39eb 100644 --- a/client/src/utils/file.ts +++ b/client/src/utils/file.ts @@ -152,7 +152,7 @@ export const splitText_token = ({ text, maxLen }: { text: string; maxLen: number const slideLen = Math.floor(maxLen * 0.3); try { - const enc = getOpenAiEncMap()[OpenAiChatEnum.GPT35]; + const enc = getOpenAiEncMap(); // filter empty text. encode sentence const encodeText = enc.encode(text); diff --git a/client/src/utils/plugin/index.ts b/client/src/utils/plugin/index.ts index 425a1cbe3..96153f7d8 100644 --- a/client/src/utils/plugin/index.ts +++ b/client/src/utils/plugin/index.ts @@ -4,32 +4,8 @@ import type { ChatItemType } from '@/types/chat'; import { countOpenAIToken, openAiSliceTextByToken } from './openai'; import { gpt_chatItemTokenSlice } from '@/pages/api/openapi/text/gptMessagesSlice'; -export const modelToolMap: Record< - ChatModelType, - { - countTokens: (data: { messages: ChatItemType[] }) => number; - sliceText: (data: { text: string; length: number }) => string; - tokenSlice: (data: { messages: ChatItemType[]; maxToken: number }) => ChatItemType[]; - } -> = { - [OpenAiChatEnum.GPT35]: { - countTokens: ({ messages }) => countOpenAIToken({ model: OpenAiChatEnum.GPT35, messages }), - sliceText: (data) => openAiSliceTextByToken({ model: OpenAiChatEnum.GPT35, ...data }), - tokenSlice: (data) => gpt_chatItemTokenSlice({ model: OpenAiChatEnum.GPT35, ...data }) - }, - [OpenAiChatEnum.GPT3516k]: { - countTokens: ({ messages }) => countOpenAIToken({ model: OpenAiChatEnum.GPT3516k, messages }), - sliceText: (data) => openAiSliceTextByToken({ model: OpenAiChatEnum.GPT3516k, ...data }), - tokenSlice: (data) => gpt_chatItemTokenSlice({ model: OpenAiChatEnum.GPT3516k, ...data }) - }, - [OpenAiChatEnum.GPT4]: { - countTokens: ({ messages }) => countOpenAIToken({ model: OpenAiChatEnum.GPT4, messages }), - sliceText: (data) => openAiSliceTextByToken({ model: OpenAiChatEnum.GPT4, ...data }), - tokenSlice: (data) => gpt_chatItemTokenSlice({ model: OpenAiChatEnum.GPT4, ...data }) - }, - [OpenAiChatEnum.GPT432k]: { - countTokens: ({ messages }) => countOpenAIToken({ model: OpenAiChatEnum.GPT432k, messages }), - sliceText: (data) => openAiSliceTextByToken({ model: OpenAiChatEnum.GPT432k, ...data }), - tokenSlice: (data) => gpt_chatItemTokenSlice({ model: OpenAiChatEnum.GPT432k, ...data }) - } +export const modelToolMap = { + countTokens: countOpenAIToken, + sliceText: openAiSliceTextByToken, + tokenSlice: gpt_chatItemTokenSlice }; diff --git a/client/src/utils/plugin/openai.ts b/client/src/utils/plugin/openai.ts index 93a3fb42d..cf2595469 100644 --- a/client/src/utils/plugin/openai.ts +++ b/client/src/utils/plugin/openai.ts @@ -4,7 +4,6 @@ import { ChatRoleEnum } from '@/constants/chat'; import { ChatCompletionRequestMessageRoleEnum } from 'openai'; import { OpenAiChatEnum } from '@/constants/model'; import axios from 'axios'; -import dayjs from 'dayjs'; import type { MessageItemType } from '@/pages/api/openapi/v1/chat/completions'; export const getOpenAiEncMap = () => { @@ -14,28 +13,11 @@ export const getOpenAiEncMap = () => { if (typeof global !== 'undefined' && global.OpenAiEncMap) { return global.OpenAiEncMap; } - const enc = { - [OpenAiChatEnum.GPT35]: encoding_for_model('gpt-3.5-turbo', { - '<|im_start|>': 100264, - '<|im_end|>': 100265, - '<|im_sep|>': 100266 - }), - [OpenAiChatEnum.GPT3516k]: encoding_for_model('gpt-3.5-turbo', { - '<|im_start|>': 100264, - '<|im_end|>': 100265, - '<|im_sep|>': 100266 - }), - [OpenAiChatEnum.GPT4]: encoding_for_model('gpt-4', { - '<|im_start|>': 100264, - '<|im_end|>': 100265, - '<|im_sep|>': 100266 - }), - [OpenAiChatEnum.GPT432k]: encoding_for_model('gpt-4-32k', { - '<|im_start|>': 100264, - '<|im_end|>': 100265, - '<|im_sep|>': 100266 - }) - }; + const enc = encoding_for_model('gpt-3.5-turbo', { + '<|im_start|>': 100264, + '<|im_end|>': 100265, + '<|im_sep|>': 100266 + }); if (typeof window !== 'undefined') { window.OpenAiEncMap = enc; @@ -78,7 +60,7 @@ export function countOpenAIToken({ const adaptMessages = adaptChatItem_openAI({ messages, reserveId: true }); const token = adaptMessages.reduce((sum, item) => { const text = `${item.role}\n${item.content}`; - const enc = getOpenAiEncMap()[model]; + const enc = getOpenAiEncMap(); const encodeText = enc.encode(text); const tokens = encodeText.length + diffVal; return sum + tokens; @@ -96,7 +78,7 @@ export const openAiSliceTextByToken = ({ text: string; length: number; }) => { - const enc = getOpenAiEncMap()[model]; + const enc = getOpenAiEncMap(); const encodeText = enc.encode(text); const decoder = new TextDecoder(); return decoder.decode(enc.decode(encodeText.slice(0, length)));