diff --git a/src/bot.ts b/src/bot.ts index 633d1e36..8ceab7f0 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -19,7 +19,7 @@ import { type BotSessionData, type OnCallBackQueryData, type OnMessageContext, type PayableBot, type PayableBotConfig, - SessionState, type UtilityBot + RequestState, type UtilityBot } from './modules/types' import { mainMenu } from './pages' import { TranslateBot } from './modules/translate/TranslateBot' @@ -104,6 +104,15 @@ Sentry.setTags({ botName: config.botName }) ES.init() bot.use(async (ctx: BotContext, next: NextFunction): Promise => { + ctx.transient = { + refunded: false, + analytics: { + module: '', + firstResponseTime: 0n, + actualResponseTime: 0n, + sessionState: RequestState.Initial + } + } const transaction = Sentry.startTransaction({ name: 'bot-command' }) const entities = ctx.entities() const startTime = now() @@ -125,28 +134,28 @@ bot.use(async (ctx: BotContext, next: NextFunction): Promise => { } await next() transaction.finish() - if (ctx.session.analytics.module) { + if (ctx.transient.analytics.module) { const userId = Number(ctx.message?.from?.id ?? '0') const username = ctx.message?.from?.username ?? '' - if (!ctx.session.analytics.actualResponseTime) { - ctx.session.analytics.actualResponseTime = now() + if (!ctx.transient.analytics.actualResponseTime) { + ctx.transient.analytics.actualResponseTime = now() } - if (!ctx.session.analytics.firstResponseTime) { - ctx.session.analytics.firstResponseTime = ctx.session.analytics.actualResponseTime + if (!ctx.transient.analytics.firstResponseTime) { + ctx.transient.analytics.firstResponseTime = ctx.transient.analytics.actualResponseTime } const totalProcessingTime = (now() - startTime).toString() - const firstResponseTime = (ctx.session.analytics.firstResponseTime - startTime).toString() - const actualResponseTime = (ctx.session.analytics.actualResponseTime - startTime).toString() + const firstResponseTime = (ctx.transient.analytics.firstResponseTime - startTime).toString() + const actualResponseTime = (ctx.transient.analytics.actualResponseTime - startTime).toString() ES.add({ command, text: ctx.message?.text ?? '', - module: ctx.session.analytics.module, + module: ctx.transient.analytics.module, userId, username, firstResponseTime, actualResponseTime, - refunded: ctx.session.refunded, - sessionState: ctx.session.analytics.sessionState, + refunded: ctx.transient.refunded, + sessionState: ctx.transient.analytics.sessionState, totalProcessingTime }).catch((ex: any) => { logger.error({ errorMsg: ex.message }, 'Failed to add data to ES') @@ -186,13 +195,6 @@ function createInitialSessionData (): BotSessionData { usage: 0, isProcessingQueue: false, requestQueue: [] - }, - refunded: false, - analytics: { - module: '', - firstResponseTime: 0n, - actualResponseTime: 0n, - sessionState: SessionState.Initial } } } diff --git a/src/modules/1country/index.ts b/src/modules/1country/index.ts index 4c4321d5..78ebfb49 100644 --- a/src/modules/1country/index.ts +++ b/src/modules/1country/index.ts @@ -7,7 +7,7 @@ import { chatService } from '../../database/services' import { relayApi } from './api/relayApi' import { isDomainAvailable, validateDomainName } from './utils/domain' import { appText } from './utils/text' -import { type OnMessageContext, type OnCallBackQueryData, type PayableBot, SessionState } from '../types' +import { type OnMessageContext, type OnCallBackQueryData, type PayableBot, RequestState } from '../types' import { type BotPayments } from '../payment' import { getCommandNamePrompt, getUrl } from './utils/' import { isAdmin } from '../open-ai/utils/context' @@ -82,7 +82,7 @@ export class OneCountryBot implements PayableBot { } public async onEvent (ctx: OnMessageContext | OnCallBackQueryData): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module if (!this.isSupportedEvent(ctx)) { this.logger.warn(`### unsupported command ${ctx.message?.text}`) return @@ -140,23 +140,23 @@ export class OneCountryBot implements PayableBot { this.logger.warn('### unsupported command') await ctx.reply('### unsupported command', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error } onVistitCmd = async (ctx: OnMessageContext | OnCallBackQueryData): Promise => { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } if (!ctx.match) { await ctx.reply('Error: Missing 1.country domain', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error return } @@ -167,18 +167,18 @@ export class OneCountryBot implements PayableBot { reply_markup: keyboard, message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success } onSet = async (ctx: OnMessageContext | OnCallBackQueryData): Promise => { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } if (!ctx.match) { @@ -201,8 +201,8 @@ export class OneCountryBot implements PayableBot { }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error return } if (!isValidUrl(url)) { @@ -212,15 +212,15 @@ export class OneCountryBot implements PayableBot { }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error return } // ************** dc set process ******************** await ctx.reply('Subdomain created') console.log(subdomain) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success // ****** //// } else { await ctx.reply(appText.setParameterError, { @@ -231,8 +231,8 @@ export class OneCountryBot implements PayableBot { }) } } catch (e) { - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() await this.onError(ctx, e) } } @@ -240,11 +240,11 @@ export class OneCountryBot implements PayableBot { async onRegister (ctx: OnMessageContext | OnCallBackQueryData): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const { prompt } = getCommandNamePrompt(ctx, SupportedCommands) @@ -252,8 +252,8 @@ export class OneCountryBot implements PayableBot { let msgId = 0 if (!prompt && !lastDomain) { await ctx.reply('Write a domain name', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error return } if (!prompt && lastDomain) { @@ -262,8 +262,8 @@ export class OneCountryBot implements PayableBot { !(await this.payments.rent(ctx as OnMessageContext, lastDomain)) // to be implemented ) { await this.onNotBalanceMessage(ctx) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() } else { const fullUrl = getUrl(lastDomain, true) await ctx.reply(`The Domain ${fullUrl} was registered`, { @@ -275,8 +275,8 @@ export class OneCountryBot implements PayableBot { // message_thread_id: ctx.message?.message_thread_id, // disable_web_page_preview: false // }) - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success + ctx.transient.analytics.actualResponseTime = now() return } } @@ -289,13 +289,13 @@ export class OneCountryBot implements PayableBot { parse_mode: 'Markdown', message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error return } ctx.session.oneCountry.lastDomain = domain msgId = (await ctx.reply('Checking name...')).message_id - ctx.session.analytics.firstResponseTime = now() + ctx.transient.analytics.firstResponseTime = now() const response = await isDomainAvailable(domain) const domainAvailable = response.isAvailable let msg = `The name *${domain}* ` @@ -311,17 +311,17 @@ export class OneCountryBot implements PayableBot { msg += `${response.priceOne} for 30 days\n` } msg += `${appText.registerConfirmation}, or ${appText.registerKeepWriting}` - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success + ctx.transient.analytics.actualResponseTime = now() } if (ctx.chat?.id) { await ctx.api.editMessageText(ctx.chat.id, msgId, msg, { parse_mode: 'Markdown' }) } - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success + ctx.transient.analytics.actualResponseTime = now() } catch (e) { - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() await this.onError(ctx, e) } } @@ -336,9 +336,9 @@ export class OneCountryBot implements PayableBot { const balanceMessage = appText.notEnoughBalance .replaceAll('$CREDITS', balanceOne) .replaceAll('$WALLET_ADDRESS', account?.address ?? '') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, balanceMessage, { parseMode: 'Markdown' }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } onRenewCmd = async (ctx: OnMessageContext | OnCallBackQueryData): Promise => { @@ -399,8 +399,8 @@ export class OneCountryBot implements PayableBot { if (await isAdmin(ctx, false, true)) { if (!ctx.match) { await ctx.reply('Error: Missing 1.country domain', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() return } const url = getUrl(ctx.match as string) @@ -408,10 +408,10 @@ export class OneCountryBot implements PayableBot { const response = await relayApi().createCert({ domain: url }) if (!response.error) { await ctx.reply(`The SSL certificate of ${url} was renewed`, { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } else { await ctx.reply(`${response.error}`, { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } } catch (e) { Sentry.captureException(e) @@ -421,14 +421,14 @@ export class OneCountryBot implements PayableBot { await ctx.reply( e instanceof AxiosError ? e.response?.data.error : appText.axiosError, { message_thread_id: ctx.message?.message_thread_id } ) - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } else { await ctx.reply('This command is reserved', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() } } @@ -438,7 +438,7 @@ export class OneCountryBot implements PayableBot { try { await relayApi().genNFT({ domain: url }) await ctx.reply('NFT metadata generated', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e) { Sentry.captureException(e) this.logger.error( @@ -451,14 +451,14 @@ export class OneCountryBot implements PayableBot { ? e.response?.data.error : 'There was an error processing your request', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } else { await ctx.reply('This command is reserved', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() } } @@ -484,12 +484,12 @@ export class OneCountryBot implements PayableBot { parse_mode: 'Markdown', message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } else { await ctx.reply('This command is reserved', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } onEnableSubomain = async (ctx: OnMessageContext): Promise => { @@ -531,7 +531,7 @@ export class OneCountryBot implements PayableBot { retryCount: number = MAX_TRIES, msg?: string ): Promise { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error Sentry.setContext('open-ai', { retryCount, msg }) Sentry.captureException(ex) if (retryCount === 0) { @@ -545,7 +545,7 @@ export class OneCountryBot implements PayableBot { ctx, 'Error: The bot does not have permission to send photos in chat' ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } else if (ex.error_code === 429) { this.botSuspended = true const retryAfter = ex.parameters.retry_after @@ -562,7 +562,7 @@ export class OneCountryBot implements PayableBot { ctx.from.username ? ctx.from.username : '' } Bot has reached limit, wait ${retryAfter} seconds` ).catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() if (method === 'editMessageText') { ctx.session.openAi.chatGpt.chatConversation.pop() // deletes last prompt } @@ -578,7 +578,7 @@ export class OneCountryBot implements PayableBot { await sendMessage(ctx, 'Error handling your request') .catch(async (e) => { await this.onError(ctx, e, retryCount - 1) } ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } } diff --git a/src/modules/document-handler/index.ts b/src/modules/document-handler/index.ts index 5c862290..617d6c94 100644 --- a/src/modules/document-handler/index.ts +++ b/src/modules/document-handler/index.ts @@ -1,4 +1,4 @@ -import { type OnMessageContext, type PayableBot, type RefundCallback, SessionState } from '../types' +import { type OnMessageContext, type PayableBot, type RefundCallback, RequestState } from '../types' import * as Sentry from '@sentry/node' import { now } from '../../utils/perf' @@ -11,18 +11,18 @@ export class DocumentHandler implements PayableBot { } public async onEvent (ctx: OnMessageContext, refundCallback: RefundCallback): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module try { const file = await ctx.getFile() console.log(file) await ctx.reply('you did it kid') - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (ex) { Sentry.captureException(ex) await ctx.reply('you failed kid') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } diff --git a/src/modules/llms/index.ts b/src/modules/llms/index.ts index 8e7d09d7..bdfda290 100644 --- a/src/modules/llms/index.ts +++ b/src/modules/llms/index.ts @@ -7,7 +7,7 @@ import { type OnMessageContext, type OnCallBackQueryData, type ChatConversation, - type ChatPayload, type PayableBot, SessionState + type ChatPayload, type PayableBot, RequestState } from '../types' import { appText } from '../open-ai/utils/text' import { chatService } from '../../database/services' @@ -68,7 +68,7 @@ export class LlmsBot implements PayableBot { } public async onEvent (ctx: OnMessageContext | OnCallBackQueryData): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module const isSupportedEvent = this.isSupportedEvent(ctx) if (!isSupportedEvent && ctx.chat?.type !== 'private') { this.logger.warn(`### unsupported command ${ctx.message?.text}`) @@ -89,11 +89,11 @@ export class LlmsBot implements PayableBot { return } this.logger.warn('### unsupported command') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, '### unsupported command').catch(async (e) => { await this.onError(ctx, e, MAX_TRIES, '### unsupported command') }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } private async hasBalance (ctx: OnMessageContext | OnCallBackQueryData): Promise { @@ -197,9 +197,9 @@ export class LlmsBot implements PayableBot { async onPrefix (ctx: OnMessageContext | OnCallBackQueryData, model: string): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const { prompt } = getCommandNamePrompt( @@ -225,9 +225,9 @@ export class LlmsBot implements PayableBot { async onChat (ctx: OnMessageContext | OnCallBackQueryData, model: string): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const prompt = ctx.match ? ctx.match : ctx.message?.text @@ -261,11 +261,11 @@ export class LlmsBot implements PayableBot { chatConversation[chatConversation.length - 1].content }_` : appText.introText - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success await sendMessage(ctx, msg, { parseMode: 'Markdown' }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const chat: ChatConversation = { @@ -316,9 +316,9 @@ export class LlmsBot implements PayableBot { const balanceMessage = appText.notEnoughBalance .replaceAll('$CREDITS', balanceOne) .replaceAll('$WALLET_ADDRESS', account?.address ?? '') - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success await sendMessage(ctx, balanceMessage, { parseMode: 'Markdown' }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } async onError ( @@ -327,7 +327,7 @@ export class LlmsBot implements PayableBot { retryCount: number = MAX_TRIES, msg?: string ): Promise { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error Sentry.setContext('llms', { retryCount, msg }) Sentry.captureException(e) if (retryCount === 0) { @@ -341,7 +341,7 @@ export class LlmsBot implements PayableBot { ctx, 'Error: The bot does not have permission to send photos in chat' ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } else if (e.error_code === 429) { this.botSuspended = true const retryAfter = e.parameters.retry_after @@ -358,7 +358,7 @@ export class LlmsBot implements PayableBot { ctx.from.username ? ctx.from.username : '' } Bot has reached limit, wait ${retryAfter} seconds` ).catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() if (method === 'editMessageText') { ctx.session.llms.chatConversation.pop() // deletes last prompt } @@ -368,12 +368,12 @@ export class LlmsBot implements PayableBot { this.logger.error( `On method "${e.method}" | ${e.error_code} - ${e.description}` ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } else { this.logger.error(`${e.toString()}`) await sendMessage(ctx, 'Error handling your request').catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } } diff --git a/src/modules/open-ai/index.ts b/src/modules/open-ai/index.ts index b507c516..2d76cc33 100644 --- a/src/modules/open-ai/index.ts +++ b/src/modules/open-ai/index.ts @@ -10,7 +10,7 @@ import { type OnCallBackQueryData, type OnMessageContext, type PayableBot, - SessionState + RequestState } from '../types' import { alterGeneratedImg, @@ -141,14 +141,14 @@ export class OpenAIBot implements PayableBot { } public async onEvent (ctx: OnMessageContext | OnCallBackQueryData): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module if (!(this.isSupportedEvent(ctx)) && (ctx.chat?.type !== 'private') && !ctx.session.openAi.chatGpt.isFreePromptChatGroups) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error this.logger.warn(`### unsupported command ${ctx.message?.text}`) return } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success if ( ctx.hasCommand(SupportedCommands.chat.name) || (ctx.message?.text?.startsWith('chat ') && ctx.chat?.type === 'private') @@ -254,12 +254,12 @@ export class OpenAIBot implements PayableBot { } this.logger.warn('### unsupported command') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, '### unsupported command') .catch(async (e) => { await this.onError(ctx, e, MAX_TRIES, '### unsupported command') }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } private async hasBalance (ctx: OnMessageContext | OnCallBackQueryData): Promise { @@ -291,14 +291,14 @@ export class OpenAIBot implements PayableBot { await this.onError(ctx, e, MAX_TRIES) }) })) - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success + ctx.transient.analytics.actualResponseTime = now() } else { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'Bot disabled').catch(async (e) => { await this.onError(ctx, e, MAX_TRIES, 'Bot disabled') }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } catch (e) { await this.onError( @@ -319,7 +319,7 @@ export class OpenAIBot implements PayableBot { const fileId = photo?.pop()?.file_id // with pop() get full image quality if (!fileId) { await ctx.reply('Cannot retrieve the image file. Please try again.') - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const file = await ctx.api.getFile(fileId) @@ -359,7 +359,7 @@ export class OpenAIBot implements PayableBot { const { conversation, ctx, model } = data try { if (!msgId) { - ctx.session.analytics.firstResponseTime = now() + ctx.transient.analytics.firstResponseTime = now() msgId = ( await ctx.reply('...', { message_thread_id: @@ -383,8 +383,8 @@ export class OpenAIBot implements PayableBot { ctx.chatAction = null } if (completion) { - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success + ctx.transient.analytics.actualResponseTime = now() const price = getPromptPrice(completion, data) this.logger.info( `streamChatCompletion result = tokens: ${ @@ -409,11 +409,11 @@ export class OpenAIBot implements PayableBot { async onSum (ctx: OnMessageContext | OnCallBackQueryData): Promise { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } try { @@ -429,11 +429,11 @@ export class OpenAIBot implements PayableBot { 'sum' ) } else { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'Error: Missing url').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } catch (e) { await this.onError(ctx, e) @@ -456,7 +456,7 @@ export class OpenAIBot implements PayableBot { }> { try { if (retryCount === 0) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage( ctx, 'Url not supported, incorrect web site address or missing user credentials', @@ -464,7 +464,7 @@ export class OpenAIBot implements PayableBot { ).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } let price = 0 @@ -480,9 +480,9 @@ export class OpenAIBot implements PayableBot { if (ctx.chat?.id && ctx.message?.message_id) { await ctx.api.deleteMessage(ctx.chat?.id, ctx.message?.message_id) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success await sendMessage(ctx, maskedPrompt) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } const webCrawlerStatusMsgId = ( await ctx.reply('...', { @@ -491,7 +491,7 @@ export class OpenAIBot implements PayableBot { ctx.message?.reply_to_message?.message_thread_id }) ).message_id - ctx.session.analytics.firstResponseTime = now() + ctx.transient.analytics.firstResponseTime = now() const webContent = await getWebContent( url, webCrawlerMaxTokens, @@ -582,11 +582,11 @@ export class OpenAIBot implements PayableBot { async onMention (ctx: OnMessageContext | OnCallBackQueryData): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const { username } = ctx.me @@ -608,11 +608,11 @@ export class OpenAIBot implements PayableBot { async onPrefix (ctx: OnMessageContext | OnCallBackQueryData): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const { prompt } = getCommandNamePrompt( @@ -637,9 +637,9 @@ export class OpenAIBot implements PayableBot { async onPrivateChat (ctx: OnMessageContext | OnCallBackQueryData): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } ctx.session.openAi.chatGpt.requestQueue.push( @@ -673,9 +673,9 @@ export class OpenAIBot implements PayableBot { async onChat (ctx: OnMessageContext | OnCallBackQueryData): Promise { try { if (this.botSuspended) { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'The bot is suspended').catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const prompt = ctx.match ? ctx.match : ctx.message?.text @@ -709,9 +709,9 @@ export class OpenAIBot implements PayableBot { chatConversation[chatConversation.length - 1].content }_` : appText.introText - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success await sendMessage(ctx, msg, { parseMode: 'Markdown' }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() return } const { url } = hasUrl(ctx, prompt) @@ -754,18 +754,18 @@ export class OpenAIBot implements PayableBot { async onLast (ctx: OnMessageContext | OnCallBackQueryData): Promise { if (ctx.session.openAi.chatGpt.chatConversation.length > 0) { const chat = ctx.session.openAi.chatGpt.chatConversation - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success await sendMessage( ctx, `${appText.gptLast}\n_${chat[chat.length - 1].content}_`, { parseMode: 'Markdown' } ).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } else { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, 'To start a conversation please write */ask*', { parseMode: 'Markdown' }) .catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } @@ -785,9 +785,9 @@ export class OpenAIBot implements PayableBot { const balanceMessage = appText.notEnoughBalance .replaceAll('$CREDITS', balanceOne) .replaceAll('$WALLET_ADDRESS', account?.address ?? '') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error await sendMessage(ctx, balanceMessage, { parseMode: 'Markdown' }).catch(async (e) => { await this.onError(ctx, e) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } async onError ( @@ -796,7 +796,7 @@ export class OpenAIBot implements PayableBot { retryCount: number = MAX_TRIES, msg?: string ): Promise { - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error Sentry.setContext('open-ai', { retryCount, msg }) Sentry.captureException(ex) if (retryCount === 0) { @@ -810,7 +810,7 @@ export class OpenAIBot implements PayableBot { ctx, 'Error: The bot does not have permission to send photos in chat' ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } else if (ex.error_code === 429) { this.botSuspended = true const retryAfter = ex.parameters.retry_after @@ -827,7 +827,7 @@ export class OpenAIBot implements PayableBot { ctx.from.username ? ctx.from.username : '' } Bot has reached limit, wait ${retryAfter} seconds` ).catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() if (method === 'editMessageText') { ctx.session.openAi.chatGpt.chatConversation.pop() // deletes last prompt } @@ -844,21 +844,21 @@ export class OpenAIBot implements PayableBot { this.logger.error(`OPENAI Error ${ex.status}(${ex.code}) - ${ex.message}`) if (ex.code === 'context_length_exceeded') { await sendMessage(ctx, ex.message).catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() await this.onEnd(ctx) } else { await sendMessage( ctx, 'Error accessing OpenAI (ChatGPT). Please try later' ).catch(async (e) => { await this.onError(ctx, e, retryCount - 1) }) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } else { this.logger.error(`${ex.toString()}`) await sendMessage(ctx, 'Error handling your request') .catch(async (e) => { await this.onError(ctx, e, retryCount - 1) } ) - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } } diff --git a/src/modules/qrcode/QRCodeBot.ts b/src/modules/qrcode/QRCodeBot.ts index 14afe9e9..0c1b9ca2 100644 --- a/src/modules/qrcode/QRCodeBot.ts +++ b/src/modules/qrcode/QRCodeBot.ts @@ -8,7 +8,7 @@ import { type OnMessageContext, type PayableBot, type RefundCallback, - SessionState + RequestState } from '../types' import { type Automatic1111Config } from './Automatic1111Configs' import { automatic1111DefaultConfig } from './Automatic1111DefaultConfig' @@ -59,11 +59,11 @@ export class QRCodeBot implements PayableBot { ctx: OnMessageContext | OnCallBackQueryData, refundCallback: RefundCallback ): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module if (!this.isSupportedEvent(ctx)) { await ctx.reply(`Unsupported command: ${ctx.message?.text}`, { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Unsupported command') return } @@ -84,8 +84,8 @@ export class QRCodeBot implements PayableBot { if (!msg) { await ctx.reply('Error: message is too old') - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Error: message is too old') return } @@ -94,8 +94,8 @@ export class QRCodeBot implements PayableBot { if (cmd.error ?? !cmd.command ?? !cmd.url ?? !cmd.prompt) { await ctx.reply("Message haven't contain command: " + msg, { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback("Message haven't contain command: ") return } @@ -112,8 +112,8 @@ export class QRCodeBot implements PayableBot { } } catch (ex) { Sentry.captureException(ex) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() if (ex instanceof Error) { this.logger.info('Error ' + ex.message) refundCallback(ex.message) @@ -127,8 +127,8 @@ export class QRCodeBot implements PayableBot { await ctx.reply('Unsupported command', { message_thread_id: ctx.message?.message_thread_id }) this.logger.info('Unsupported command') - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Unsupported command') } @@ -206,8 +206,8 @@ export class QRCodeBot implements PayableBot { } catch (ex) { Sentry.captureException(ex) ctx.chatAction = null - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() this.logger.error(`ex ${ex}`) await ctx.reply('Internal error', { message_thread_id: ctx.message?.message_thread_id }) throw new Error('Internal error') @@ -228,7 +228,7 @@ export class QRCodeBot implements PayableBot { } ) this.logger.info('sent qr code') - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success return true } catch (e: any) { Sentry.captureException(e) @@ -259,10 +259,10 @@ export class QRCodeBot implements PayableBot { msgExtras ) } - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error return false } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } diff --git a/src/modules/sd-images/SDImagesBotBase.ts b/src/modules/sd-images/SDImagesBotBase.ts index b501c319..736dde53 100644 --- a/src/modules/sd-images/SDImagesBotBase.ts +++ b/src/modules/sd-images/SDImagesBotBase.ts @@ -1,5 +1,5 @@ import { getModelByParam, type IModel, SDNodeApi } from './api' -import { type OnCallBackQueryData, type OnMessageContext, SessionState } from '../types' +import { type OnCallBackQueryData, type OnMessageContext, RequestState } from '../types' import { getTelegramFileUrl, loadFile, sleep, uuidv4 } from './utils' import { GrammyError, InputFile } from 'grammy' import { COMMAND } from './helpers' @@ -121,7 +121,7 @@ export class SDImagesBotBase { const { message_id } = await ctx.reply( `You are #${balancerOperaton.queueTotalNumber + 1} in line for making images. The wait time is about ${(balancerOperaton.queueNumber + 1) * 15} seconds.`, { message_thread_id: ctx.message?.message_thread_id } ) - ctx.session.analytics.firstResponseTime = now() + ctx.transient.analytics.firstResponseTime = now() // waiting queue while (balancerOperaton.status === OPERATION_STATUS.WAITING) { await sleep(5000 * balancerOperaton.queueNumber || 500) @@ -173,7 +173,7 @@ export class SDImagesBotBase { if (ctx.chat?.id && queueMessageId) { await ctx.api.deleteMessage(ctx.chat?.id, queueMessageId) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { if (balancerOperatonId) { await completeOperation(balancerOperatonId, OPERATION_STATUS.ERROR) @@ -191,7 +191,7 @@ export class SDImagesBotBase { this.logger.error(e.toString()) await ctx.reply('Error: something went wrong... Refunding payments', msgExtras) } - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error refundCallback() } } @@ -264,7 +264,7 @@ export class SDImagesBotBase { if (ctx.chat?.id && queueMessageId) { await ctx.api.deleteMessage(ctx.chat?.id, queueMessageId) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { const msgExtras: MessageExtras = { message_thread_id: ctx.message?.message_thread_id } if (e instanceof GrammyError) { @@ -277,10 +277,10 @@ export class SDImagesBotBase { this.logger.error(e.toString()) await ctx.reply('Error: something went wrong... Refunding payments', msgExtras) } - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error refundCallback() } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } if (balancerOperatonId) { @@ -357,7 +357,7 @@ export class SDImagesBotBase { }), `/${modelAlias} ` ) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { const topicId = ctx.message?.message_thread_id const msgExtras: MessageExtras = {} @@ -374,14 +374,14 @@ export class SDImagesBotBase { this.logger.error(e.toString()) await ctx.reply('Error: something went wrong... Refunding payments', msgExtras) } - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error refundCallback() if (balancerOperatonId) { await completeOperation(balancerOperatonId, OPERATION_STATUS.ERROR) } } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } } diff --git a/src/modules/sd-images/index.ts b/src/modules/sd-images/index.ts index 3fe2c6d3..661e8444 100644 --- a/src/modules/sd-images/index.ts +++ b/src/modules/sd-images/index.ts @@ -1,5 +1,5 @@ import { InlineKeyboard, InputFile } from 'grammy' -import { type OnMessageContext, type OnCallBackQueryData, type PayableBot, SessionState } from '../types' +import { type OnMessageContext, type OnCallBackQueryData, type PayableBot, RequestState } from '../types' import { SDImagesBotBase } from './SDImagesBotBase' import { COMMAND, type IOperation, parseCtx, promptHasBadWords } from './helpers' import { getModelByParam, MODELS_CONFIGS } from './api' @@ -50,7 +50,7 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { ctx: OnMessageContext | OnCallBackQueryData, refundCallback: (reason?: string) => void ): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module if (this.isSupportedCallbackQuery(ctx)) { await this.onImgSelected(ctx, refundCallback) return @@ -61,8 +61,8 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { if (!operation) { console.log(`### unsupported command ${ctx.message?.text}`) await sendMessage(ctx, '### unsupported command') - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Unsupported command'); return } @@ -77,15 +77,15 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { ctx, 'Your prompt has been flagged for potentially generating illegal or malicious content. If you believe there has been a mistake, please reach out to support.' ) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Prompt has bad words'); return } if (prompt.length > 1000) { await ctx.reply('Your prompt is too long. Please shorten your prompt and try again.') - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error + ctx.transient.analytics.actualResponseTime = now() refundCallback('Prompt is too long') return } @@ -134,15 +134,15 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { `${model.name}: ${model.link} \n \nUsing: /${model.aliases[0]} /${model.aliases[1]} /${model.aliases[2]} \n` ) } - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success return } console.log('### unsupported command') await sendMessage(ctx, '### unsupported command') - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error } onImagesCmd = async ( @@ -193,14 +193,14 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { message_thread_id: ctx.message?.message_thread_id } ) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { Sentry.captureException(e) refundCallback(e.message) await sendMessage(ctx, 'Error: something went wrong...') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } if (balancerOperatonId) { @@ -260,14 +260,14 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { seed: session?.all_seeds && Number(session.all_seeds[+params - 1]) }) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { Sentry.captureException(e) refundCallback(e.message) await sendMessage(ctx, 'Error: something went wrong...') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } @@ -304,14 +304,14 @@ export class SDImagesBot extends SDImagesBotBase implements PayableBot { reply_markup: keyboard, message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } catch (e: any) { Sentry.captureException(e) refundCallback(e) await sendMessage(ctx, 'Error: something went wrong...') - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() } } } diff --git a/src/modules/translate/TranslateBot.ts b/src/modules/translate/TranslateBot.ts index 629357fb..94f88b0a 100644 --- a/src/modules/translate/TranslateBot.ts +++ b/src/modules/translate/TranslateBot.ts @@ -1,4 +1,4 @@ -import { type OnMessageContext, type PayableBot, type RefundCallback, SessionState } from '../types' +import { type OnMessageContext, type PayableBot, type RefundCallback, RequestState } from '../types' import pino, { type Logger } from 'pino' import { mapToTargetLang, translator } from './deeplClient' import { now } from '../../utils/perf' @@ -74,11 +74,11 @@ export class TranslateBot implements PayableBot { } public async onEvent (ctx: OnMessageContext, refundCallback: RefundCallback): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module if (!this.isSupportedEvent(ctx)) { await ctx.reply(`Unsupported command: ${ctx.message?.text}`, { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Error refundCallback('Unsupported command') return } @@ -154,16 +154,16 @@ export class TranslateBot implements PayableBot { ${langList.join(', ')} To disable translation, use the command /translatestop.`) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success } public async stopTranslate (ctx: OnMessageContext): Promise { ctx.chatAction = 'typing' ctx.session.translate.enable = false await ctx.reply('Translation is disabled', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success } public async translateMessage (ctx: OnMessageContext, message: string, targetLangCode: string): Promise { @@ -188,12 +188,12 @@ To disable translation, use the command /translatestop.`) const message = ctx.message.text const progressMessage = await ctx.reply('...', { message_thread_id: ctx.message?.message_thread_id }) - ctx.session.analytics.firstResponseTime = now() + ctx.transient.analytics.firstResponseTime = now() ctx.chatAction = 'typing' if (!message) { - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success return } @@ -216,16 +216,16 @@ To disable translation, use the command /translatestop.`) // // can't detect original language // if (completion01.completion === 'unknown') { // await ctx.api.deleteMessage(ctx.chat.id, progressMessage.message_id) - // ctx.session.analytics.actualResponseTime = now() - // ctx.session.analytics.sessionState = SessionState.Success + // ctx.transient.analytics.actualResponseTime = now() + // ctx.transient.analytics.sessionState = SessionState.Success // return // >>>>>>> master } if (translateResults.length === 0) { await ctx.api.deleteMessage(ctx.chat.id, progressMessage.message_id) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success return } @@ -233,7 +233,7 @@ To disable translation, use the command /translatestop.`) await ctx.api.editMessageText(ctx.chat.id, progressMessage.message_id, responseMessage, { parse_mode: 'Markdown' }) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success } } diff --git a/src/modules/types.ts b/src/modules/types.ts index f47bc514..7336569d 100644 --- a/src/modules/types.ts +++ b/src/modules/types.ts @@ -77,7 +77,7 @@ export interface TranslateBotData { enable: boolean } -export enum SessionState { +export enum RequestState { Initial = 'initial', Error = 'error', Success = 'success' @@ -86,7 +86,7 @@ export enum SessionState { export interface Analytics { firstResponseTime: bigint actualResponseTime: bigint - sessionState: SessionState + sessionState: RequestState module: string } @@ -96,14 +96,20 @@ export interface BotSessionData { openAi: OpenAiSessionData translate: TranslateBotData llms: LmmsSessionData - refunded: boolean - analytics: Analytics +} + +export interface TransientStateContext { + transient: { + analytics: Analytics + refunded: boolean + } } export type BotContext = FileFlavor & ConversationFlavor & -AutoChatActionFlavor> +AutoChatActionFlavor & +TransientStateContext> export type CustomContext = Filter export type OnMessageContext = CustomContext<'message'> diff --git a/src/modules/voice-memo/index.ts b/src/modules/voice-memo/index.ts index 5be2b949..c85a2c7f 100644 --- a/src/modules/voice-memo/index.ts +++ b/src/modules/voice-memo/index.ts @@ -1,4 +1,4 @@ -import { type OnMessageContext, type PayableBot, SessionState } from '../types' +import { type OnMessageContext, type PayableBot, RequestState } from '../types' import pino, { type Logger } from 'pino' import { initTelegramClient } from './MTProtoAPI' import { NewMessage, type NewMessageEvent } from 'telegram/events' @@ -154,7 +154,7 @@ export class VoiceMemo implements PayableBot { } public async onEvent (ctx: OnMessageContext): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module const { voice, audio, from } = ctx.update.message const fileSize = (voice ?? audio)?.file_size const requestKey = `${from.id}_${fileSize}` @@ -205,20 +205,20 @@ export class VoiceMemo implements PayableBot { } else { await ctx.reply(text, { message_thread_id: ctx.message?.message_thread_id }) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } } catch (e) { Sentry.captureException(e) this.logger.error(`Translation error: ${(e as Error).message}`) - ctx.session.analytics.sessionState = SessionState.Error + ctx.transient.analytics.sessionState = RequestState.Error } finally { - ctx.session.analytics.actualResponseTime = now() + ctx.transient.analytics.actualResponseTime = now() this.deleteTempFile(filePath) } } else { this.logger.error(`Cannot find translation job ${requestKey}, skip`) - ctx.session.analytics.actualResponseTime = now() - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.actualResponseTime = now() + ctx.transient.analytics.sessionState = RequestState.Success } } } diff --git a/src/modules/voice-to-text/index.ts b/src/modules/voice-to-text/index.ts index 7ca703ce..60fdaa30 100644 --- a/src/modules/voice-to-text/index.ts +++ b/src/modules/voice-to-text/index.ts @@ -6,7 +6,7 @@ import type { BotPayments } from '../payment' import { speechToText } from '../open-ai/api/openAi' import type { OnMessageContext, PayableBot } from '../types' import { bot } from '../../bot' -import { SessionState } from '../types' +import { RequestState } from '../types' import { download } from '../../utils/files' export class VoiceToTextBot implements PayableBot { @@ -37,7 +37,7 @@ export class VoiceToTextBot implements PayableBot { } public async onEvent (ctx: OnMessageContext): Promise { - ctx.session.analytics.module = this.module + ctx.transient.analytics.module = this.module const { voice, audio } = ctx.message.reply_to_message ?? { voice: undefined, audio: undefined } if (!voice && !audio) { @@ -85,6 +85,6 @@ export class VoiceToTextBot implements PayableBot { await ctx.reply(resultText, { message_thread_id: ctx.message?.message_thread_id }) } - ctx.session.analytics.sessionState = SessionState.Success + ctx.transient.analytics.sessionState = RequestState.Success } }