diff --git a/src/database/stats.service.ts b/src/database/stats.service.ts index fa6dde73..09e3d98e 100644 --- a/src/database/stats.service.ts +++ b/src/database/stats.service.ts @@ -70,6 +70,51 @@ export class StatsService { return rows.length ? +rows[0].count : 0 } + public async getNewUsers (daysPeriod = 0): Promise { + const currentTime = moment() + const dateStart = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(daysPeriod, 'days') + .unix() + + const dateEnd = currentTime.unix() + + const query = logRepository + .createQueryBuilder('logs') + .select('distinct("FirstInsertTime")') + .from(subQuery => + subQuery + .select('"tgUserId", MIN("createdAt") AS "FirstInsertTime"') + .from(BotLog, 'logs') + .groupBy('"tgUserId"'), 'first_inserts') + if (daysPeriod > 0) { + query.where(`"FirstInsertTime" BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + } + const result = await query.execute() + // console.log(dateStart, dateEnd, result.length) + return result.length + } + + // Doesn't check last 7 days. + public async getOnetimeUsers (): Promise { + const bufferDays = 7 + const bufferDate = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(bufferDays, 'days') + .unix() + + const query = await logRepository + .createQueryBuilder('logs') + .select('count("tgUserId") AS row_count, "tgUserId", MAX("createdAt") AS max_created') + .where(`"createdAt" < TO_TIMESTAMP(${bufferDate})`) + .groupBy('"tgUserId"') + .getRawMany() + const result = query.filter(row => row.row_count === '1') + return result.length + } + public async getTotalMessages (daysPeriod = 0, onlySupportedCommands = false): Promise { const currentTime = moment() const dateStart = moment() @@ -83,8 +128,9 @@ export class StatsService { const query = logRepository .createQueryBuilder('logs') .select('count(*)') - .where(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) - + if (daysPeriod > 0) { + query.where(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + } if (onlySupportedCommands) { query.andWhere('logs.isSupportedCommand=true') } @@ -113,6 +159,23 @@ export class StatsService { return rows } + public async getRevenueFromLog (daysPeriod = 7): Promise { + const currentTime = moment() + const dateStart = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(daysPeriod, 'days') + .unix() + + const dateEnd = currentTime.unix() + const result = await logRepository.createQueryBuilder('logs') + .select('SUM(CAST(logs.amountCredits AS NUMERIC)) AS revenue') + .where('logs.isSupportedCommand=true') + .andWhere(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + .execute() + return result[0].revenue + } + public async addCommandStat ({ tgUserId, rawMessage, command }: { tgUserId: number, rawMessage: string, command: string }): Promise { const stat = new StatBotCommand() diff --git a/src/modules/open-ai/helpers.ts b/src/modules/open-ai/helpers.ts index 0e8a1e22..468be8d8 100644 --- a/src/modules/open-ai/helpers.ts +++ b/src/modules/open-ai/helpers.ts @@ -27,7 +27,7 @@ export const SupportedCommands = { export const MAX_TRIES = 3 -const DALLE_PREFIX_LIST = ['i. ', ',', 'image ', 'd.', 'img ', 'i '] +const DALLE_PREFIX_LIST = ['i. ', ',', 'image ', 'd.', 'img '] export const isMentioned = ( ctx: OnMessageContext | OnCallBackQueryData diff --git a/src/modules/schedule/index.ts b/src/modules/schedule/index.ts index 0b50bddc..1ed95d75 100644 --- a/src/modules/schedule/index.ts +++ b/src/modules/schedule/index.ts @@ -92,8 +92,12 @@ export class BotSchedule { swapTradingVolume, balance, + uniqueUsersCount, + totalMessage, + weeklyUsers, - dailyMessages + newUsers, + weeklyRevenue ] = await Promise.all([ getDailyMetrics(MetricsDailyType.totalFee, 7), getDailyMetrics(MetricsDailyType.walletsCount, 7), @@ -104,8 +108,12 @@ export class BotSchedule { getTradingVolume(7), getAddressBalance(this.holderAddress), + statsService.getUniqueUsersCount(), + statsService.getTotalMessages(0, true), + statsService.getActiveUsers(7), - statsService.getTotalMessages(1, true) + statsService.getNewUsers(7), + getBotFee(this.holderAddress, 7) // statsService.getRevenue(100) ]) const networkFeesSum = networkFeesWeekly.reduce((sum, item) => sum + +item.value, 0) @@ -123,13 +131,19 @@ export class BotSchedule { 'Total assets, monthly stakes, weekly swaps: ' + `*$${abbreviateNumber(bridgeTVL)}*, ${abbreviateNumber(totalStakeONE)}, $${abbreviateNumber(swapTradingVolumeSum)}` + const oneBotWeeklyMetrics = + 'Bot weekly earns, active users, new users: ' + + `*${abbreviateNumber(+weeklyRevenue)}* ONE` + + `, ${lessThan100(abbreviateNumber(weeklyUsers))}` + + `, ${lessThan100(abbreviateNumber(newUsers))}` + const oneBotMetrics = - 'Bot total earns, weekly users, daily messages: ' + + 'Bot total earns, users, messages: ' + `*${abbreviateNumber(balance / Math.pow(10, 18))}* ONE` + - `, ${lessThan100(abbreviateNumber(weeklyUsers))}` + - `, ${lessThan100(abbreviateNumber(dailyMessages))}` + `, ${lessThan100(abbreviateNumber(uniqueUsersCount))}` + + `, ${lessThan100(abbreviateNumber(totalMessage))}` - return `${networkUsage}\n${assetsUpdate}\n${oneBotMetrics}` + return `${networkUsage}\n${assetsUpdate}\n${oneBotWeeklyMetrics}\n${oneBotMetrics}` } public async generateReportEngagementByCommand (days: number): Promise { @@ -163,7 +177,10 @@ export class BotSchedule { weeklyUsers, totalMessages, totalSupportedMessages, - engagementByCommand + engagementByCommand, + onetimeUsers, + newUsers, + totalUsers ] = await Promise.all([ this.getBotFeeReport(this.holderAddress), getBotFee(this.holderAddress, 7), @@ -173,7 +190,10 @@ export class BotSchedule { statsService.getActiveUsers(7), statsService.getTotalMessages(7), statsService.getTotalMessages(7, true), - this.generateReportEngagementByCommand(7) + this.generateReportEngagementByCommand(7), + statsService.getOnetimeUsers(), + statsService.getNewUsers(7), + statsService.getUniqueUsersCount() ]) const report = `\nBot fees: *${botFeesReport}*` + @@ -182,8 +202,11 @@ export class BotSchedule { `\nTotal fees users pay in ONE: *${abbreviateNumber(totalOne)}*` + `\nTotal fees users pay in free credits: *${abbreviateNumber(totalCredits)}*` + `\nWeekly active users: *${abbreviateNumber(weeklyUsers)}*` + + `\nWeekly new users: *${abbreviateNumber(newUsers)}*` + `\nWeekly user engagement (any commands): *${abbreviateNumber(totalMessages)}*` + `\nWeekly user engagement (commands supported by bot): *${abbreviateNumber(totalSupportedMessages)}*` + + `\nTotal users: *${totalUsers}*` + + `\nOne-time users: *${onetimeUsers}*` + `\n\n${engagementByCommand}` return report } diff --git a/src/modules/translate/TranslateBot.ts b/src/modules/translate/TranslateBot.ts index 37ab7e7d..8c2b975c 100644 --- a/src/modules/translate/TranslateBot.ts +++ b/src/modules/translate/TranslateBot.ts @@ -9,7 +9,14 @@ enum SupportedCommands { } // const SupportedLangCommands = ['bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nb', 'nl', 'pl', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'zh', 'en', 'pt'] -const SupportedLangCommands = ['af', 'sq', 'am', 'ar', 'hy', 'as', 'ay', 'az', 'bm', 'eu', 'be', 'bn', 'bho', 'bs', 'bg', 'ca', 'ceb', 'ny', 'zh', 'zh-TW', 'co', 'hr', 'cs', 'da', 'dv', 'doi', 'nl', 'en', 'eo', 'et', 'ee', 'tl', 'fi', 'fr', 'fy', 'gl', 'lg', 'ka', 'de', 'el', 'gn', 'gu', 'ht', 'ha', 'haw', 'iw', 'hi', 'hmn', 'hu', 'is', 'ig', 'ilo', 'id', 'ga', 'it', 'ja', 'jw', 'kn', 'kk', 'km', 'rw', 'gom', 'ko', 'kri', 'ku', 'ckb', 'ky', 'lo', 'la', 'lv', 'ln', 'lt', 'lb', 'mk', 'mai', 'mg', 'ms', 'ml', 'mt', 'mi', 'mr', 'mni-Mtei', 'lus', 'mn', 'my', 'ne', 'nso', 'no', 'or', 'om', 'ps', 'fa', 'pl', 'pt', 'pa', 'qu', 'ro', 'ru', 'sm', 'sa', 'gd', 'sr', 'st', 'sn', 'sd', 'si', 'sk', 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tg', 'ta', 'tt', 'te', 'th', 'ti', 'ts', 'tr', 'tk', 'ak', 'uk', 'ur', 'ug', 'uz', 'vi', 'cy', 'xh', 'yi', 'yo', 'zu', 'he', 'jv', 'zh-CN'] +const SupportedLangCommands = ['af', 'sq', 'ar', 'hy', 'as', 'ay', 'az', 'bm', 'eu', 'bn', 'bho', 'bs', 'bg', 'ca', 'ceb', + 'zh', 'zh-TW', 'co', 'cs', 'da', 'dv', 'doi', 'nl', 'en', 'eo', 'et', 'ee', 'tl', 'fi', 'fr', 'fy', 'gl', 'lg', 'ka', + 'de', 'el', 'gn', 'gu', 'ht', 'haw', 'iw', 'hi', 'hr', 'hmn', 'hu', 'is', 'ig', 'ilo', 'id', 'ga', 'it', 'ja', 'jw', 'kn', + 'kk', 'km', 'rw', 'gom', 'ko', 'kri', 'ku', 'ckb', 'ky', 'lo', 'la', 'lv', 'ln', 'lt', 'lb', 'mk', 'mai', 'mg', 'ms', + 'ml', 'mt', 'mi', 'mr', 'mni-Mtei', 'lus', 'mn', 'my', 'ne', 'nso', 'or', 'om', 'ps', 'fa', 'pl', 'pt', 'pa', 'qu', 'ro', + 'ru', 'sm', 'sa', 'gd', 'sr', 'st', 'sn', 'sd', 'si', 'sk', 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tg', 'ta', 'tt', 'te', + 'th', 'ti', 'ts', 'tr', 'tk', 'ak', 'uk', 'ur', 'ug', 'uz', 'vi', 'cy', 'xh', 'yi', 'yo', 'zu', 'he', 'jv', 'zh-CN'] +// SupportedLangCommands.concat(['am', 'be', 'ny', 'ha', 'no']) removed to avoid common words in prefix export class TranslateBot implements PayableBot { public readonly module = 'TranslateBot'