mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-29 01:40:51 +00:00
perf: code and inform
This commit is contained in:
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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]) {
|
||||
|
@@ -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,
|
||||
|
@@ -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, {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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 |`}
|
||||
|
@@ -63,8 +63,9 @@ export async function generateQA(): Promise<any> {
|
||||
// 请求 chatgpt 获取回答
|
||||
const response = await Promise.all(
|
||||
[data.q].map((text) =>
|
||||
modelServiceToolMap[OpenAiChatEnum.GPT3516k]
|
||||
modelServiceToolMap
|
||||
.chatCompletion({
|
||||
model: OpenAiChatEnum.GPT3516k,
|
||||
apiKey: systemAuthKey,
|
||||
temperature: 0.8,
|
||||
messages: [
|
||||
|
16
client/src/service/events/sendInform.ts
Normal file
16
client/src/service/events/sendInform.ts
Normal file
@@ -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();
|
||||
}
|
||||
};
|
@@ -20,6 +20,8 @@ export async function connectToDatabase(): Promise<void> {
|
||||
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({
|
||||
|
@@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -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<ChatCompletionResponseType>;
|
||||
streamResponse: (data: StreamResponseType) => Promise<StreamResponseReturnType>;
|
||||
}
|
||||
> = {
|
||||
[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
|
||||
});
|
||||
|
||||
|
@@ -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
|
||||
});
|
||||
|
||||
|
4
client/src/types/index.d.ts
vendored
4
client/src/types/index.d.ts
vendored
@@ -21,7 +21,9 @@ declare global {
|
||||
var QRCode: any;
|
||||
var qaQueueLen: number;
|
||||
var vectorQueueLen: number;
|
||||
var OpenAiEncMap: Record<string, Tiktoken>;
|
||||
var OpenAiEncMap: Tiktoken;
|
||||
var sendInformQueue: (() => Promise<void>)[];
|
||||
var sendInformQueueLen: number;
|
||||
var systemEnv: {
|
||||
vectorMaxProcess: number;
|
||||
qaMaxProcess: number;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
};
|
||||
|
@@ -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)));
|
||||
|
Reference in New Issue
Block a user