perf: push chat log (#3109)
This commit is contained in:
@@ -52,7 +52,6 @@ const ChatSchema = new Schema({
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
enum: Object.keys(ChatSourceMap),
|
||||
required: true
|
||||
},
|
||||
shareId: {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { addLog } from '../../common/system/log';
|
||||
import { MongoChatItem } from './chatItemSchema';
|
||||
import { MongoChat } from './chatSchema';
|
||||
import axios from 'axios';
|
||||
import { AIChatItemType, ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { AIChatItemType, ChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||
|
||||
export type Metadata = {
|
||||
[key: string]: {
|
||||
@@ -26,8 +27,8 @@ export const pushChatLog = ({
|
||||
}) => {
|
||||
const interval = Number(process.env.CHAT_LOG_INTERVAL);
|
||||
const url = process.env.CHAT_LOG_URL;
|
||||
if (interval > 0 && url) {
|
||||
addLog.info(`[ChatLogPush] push chat log after ${interval}ms`, {
|
||||
if (!isNaN(interval) && interval > 0 && url) {
|
||||
addLog.debug(`[ChatLogPush] push chat log after ${interval}ms`, {
|
||||
appId,
|
||||
chatItemIdHuman,
|
||||
chatItemIdAi
|
||||
@@ -82,7 +83,7 @@ const pushChatLogInternal = async ({
|
||||
}) => {
|
||||
try {
|
||||
const [chatItemHuman, chatItemAi] = await Promise.all([
|
||||
MongoChatItem.findById(chatItemIdHuman).lean(),
|
||||
MongoChatItem.findById(chatItemIdHuman).lean() as Promise<UserChatItemType>,
|
||||
MongoChatItem.findById(chatItemIdAi).lean() as Promise<AIChatItemType>
|
||||
]);
|
||||
|
||||
@@ -103,8 +104,52 @@ const pushChatLogInternal = async ({
|
||||
|
||||
const uid = chat.outLinkUid || chat.tmbId;
|
||||
// Pop last two items
|
||||
const question = chatItemHuman.value[chatItemHuman.value.length - 1]?.text?.content;
|
||||
const answer = chatItemAi.value[chatItemAi.value.length - 1]?.text?.content;
|
||||
const question = chatItemHuman.value
|
||||
.map((item) => {
|
||||
if (item.type === ChatItemValueTypeEnum.text) {
|
||||
return item.text?.content;
|
||||
} else if (item.type === ChatItemValueTypeEnum.file) {
|
||||
if (item.file?.type === 'image') {
|
||||
return ``;
|
||||
}
|
||||
return `[${item.file?.name}](${item.file?.url})`;
|
||||
}
|
||||
return '';
|
||||
})
|
||||
.join('\n');
|
||||
const answer = chatItemAi.value
|
||||
.map((item) => {
|
||||
const text = [];
|
||||
if (item.text?.content) {
|
||||
text.push(item.text?.content);
|
||||
}
|
||||
if (item.tools) {
|
||||
text.push(
|
||||
item.tools.map(
|
||||
(tool) =>
|
||||
`\`\`\`json
|
||||
${JSON.stringify(
|
||||
{
|
||||
name: tool.toolName,
|
||||
params: tool.params,
|
||||
response: tool.response
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
\`\`\``
|
||||
)
|
||||
);
|
||||
}
|
||||
if (item.interactive) {
|
||||
text.push(`\`\`\`json
|
||||
${JSON.stringify(item.interactive, null, 2)}
|
||||
\`\`\``);
|
||||
}
|
||||
return text.join('\n');
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
if (!question || !answer) {
|
||||
addLog.error('[ChatLogPush] question or answer is empty', {
|
||||
question: chatItemHuman.value,
|
||||
@@ -112,11 +157,13 @@ const pushChatLogInternal = async ({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// computed response time
|
||||
const responseData = chatItemAi.responseData;
|
||||
const responseTime =
|
||||
responseData?.reduce((acc, item) => acc + (item?.runningTime ?? 0), 0) || 0;
|
||||
|
||||
const sourceIdPrefix = process.env.SOURCE_ID_PREFIX ?? '';
|
||||
const sourceIdPrefix = process.env.CHAT_LOG_SOURCE_ID_PREFIX ?? 'fastgpt-';
|
||||
|
||||
const chatLog: ChatLog = {
|
||||
title: chat.title,
|
||||
@@ -141,14 +188,7 @@ const pushChatLogInternal = async ({
|
||||
createdAt: new Date(chatItemAi.time).getTime(),
|
||||
sourceId: `${sourceIdPrefix}${appId}`
|
||||
};
|
||||
await axios
|
||||
.post(`${url}/api/chat/push`, chatLog)
|
||||
.then((res) => {
|
||||
addLog.info('[ChatLogPush] push success', res.data);
|
||||
})
|
||||
.catch((e) => {
|
||||
addLog.error('[ChatLogPush] push failed', { e, resData: e.response?.data });
|
||||
});
|
||||
await axios.post(`${url}/api/chat/push`, chatLog);
|
||||
} catch (e) {
|
||||
addLog.error('[ChatLogPush] error', e);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type Props = {
|
||||
variables?: Record<string, any>;
|
||||
isUpdateUseTime: boolean;
|
||||
newTitle: string;
|
||||
source: `${ChatSourceEnum}`;
|
||||
source: string;
|
||||
shareId?: string;
|
||||
outLinkUid?: string;
|
||||
content: [UserChatItemType & { dataId?: string }, AIChatItemType & { dataId?: string }];
|
||||
|
||||
@@ -11,7 +11,7 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
try {
|
||||
const openApi = await MongoOpenApi.findOne({ apiKey: apikey.trim() });
|
||||
const openApi = await MongoOpenApi.findOne({ apiKey: apikey.trim() }).lean();
|
||||
if (!openApi) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthApiKey);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
// @ts-ignore
|
||||
if (global.feConfigs?.isPlus) {
|
||||
await POST('/support/openapi/authLimit', {
|
||||
openApi: openApi.toObject()
|
||||
openApi
|
||||
} as AuthOpenApiLimitProps);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ export async function authOpenApiKey({ apikey }: { apikey: string }) {
|
||||
apikey,
|
||||
teamId: String(openApi.teamId),
|
||||
tmbId: String(openApi.tmbId),
|
||||
appId: openApi.appId || ''
|
||||
appId: openApi.appId || '',
|
||||
sourceName: openApi.name
|
||||
};
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
|
||||
@@ -313,14 +313,15 @@ export async function parseHeaderCert({
|
||||
})();
|
||||
|
||||
// auth apikey
|
||||
const { teamId, tmbId, appId: apiKeyAppId = '' } = await authOpenApiKey({ apikey });
|
||||
const { teamId, tmbId, appId: apiKeyAppId = '', sourceName } = await authOpenApiKey({ apikey });
|
||||
|
||||
return {
|
||||
uid: '',
|
||||
teamId,
|
||||
tmbId,
|
||||
apikey,
|
||||
appId: apiKeyAppId || authorizationAppid
|
||||
appId: apiKeyAppId || authorizationAppid,
|
||||
sourceName
|
||||
};
|
||||
}
|
||||
// root user
|
||||
@@ -332,48 +333,50 @@ export async function parseHeaderCert({
|
||||
|
||||
const { cookie, token, rootkey, authorization } = (req.headers || {}) as ReqHeaderAuthType;
|
||||
|
||||
const { uid, teamId, tmbId, appId, openApiKey, authType, isRoot } = await (async () => {
|
||||
if (authApiKey && authorization) {
|
||||
// apikey from authorization
|
||||
const authResponse = await parseAuthorization(authorization);
|
||||
return {
|
||||
uid: authResponse.uid,
|
||||
teamId: authResponse.teamId,
|
||||
tmbId: authResponse.tmbId,
|
||||
appId: authResponse.appId,
|
||||
openApiKey: authResponse.apikey,
|
||||
authType: AuthUserTypeEnum.apikey
|
||||
};
|
||||
}
|
||||
if (authToken && (token || cookie)) {
|
||||
// user token(from fastgpt web)
|
||||
const res = await authCookieToken(cookie, token);
|
||||
return {
|
||||
uid: res.userId,
|
||||
teamId: res.teamId,
|
||||
tmbId: res.tmbId,
|
||||
appId: '',
|
||||
openApiKey: '',
|
||||
authType: AuthUserTypeEnum.token,
|
||||
isRoot: res.isRoot
|
||||
};
|
||||
}
|
||||
if (authRoot && rootkey) {
|
||||
await parseRootKey(rootkey);
|
||||
// root user
|
||||
return {
|
||||
uid: '',
|
||||
teamId: '',
|
||||
tmbId: '',
|
||||
appId: '',
|
||||
openApiKey: '',
|
||||
authType: AuthUserTypeEnum.root,
|
||||
isRoot: true
|
||||
};
|
||||
}
|
||||
const { uid, teamId, tmbId, appId, openApiKey, authType, isRoot, sourceName } =
|
||||
await (async () => {
|
||||
if (authApiKey && authorization) {
|
||||
// apikey from authorization
|
||||
const authResponse = await parseAuthorization(authorization);
|
||||
return {
|
||||
uid: authResponse.uid,
|
||||
teamId: authResponse.teamId,
|
||||
tmbId: authResponse.tmbId,
|
||||
appId: authResponse.appId,
|
||||
openApiKey: authResponse.apikey,
|
||||
authType: AuthUserTypeEnum.apikey,
|
||||
sourceName: authResponse.sourceName
|
||||
};
|
||||
}
|
||||
if (authToken && (token || cookie)) {
|
||||
// user token(from fastgpt web)
|
||||
const res = await authCookieToken(cookie, token);
|
||||
return {
|
||||
uid: res.userId,
|
||||
teamId: res.teamId,
|
||||
tmbId: res.tmbId,
|
||||
appId: '',
|
||||
openApiKey: '',
|
||||
authType: AuthUserTypeEnum.token,
|
||||
isRoot: res.isRoot
|
||||
};
|
||||
}
|
||||
if (authRoot && rootkey) {
|
||||
await parseRootKey(rootkey);
|
||||
// root user
|
||||
return {
|
||||
uid: '',
|
||||
teamId: '',
|
||||
tmbId: '',
|
||||
appId: '',
|
||||
openApiKey: '',
|
||||
authType: AuthUserTypeEnum.root,
|
||||
isRoot: true
|
||||
};
|
||||
}
|
||||
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
})();
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
})();
|
||||
|
||||
if (!authRoot && (!teamId || !tmbId)) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
@@ -385,6 +388,7 @@ export async function parseHeaderCert({
|
||||
tmbId: String(tmbId),
|
||||
appId,
|
||||
authType,
|
||||
sourceName,
|
||||
apikey: openApiKey,
|
||||
isRoot: !!isRoot
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user