| | const { logger } = require('@librechat/data-schemas'); |
| | const { ViolationTypes } = require('librechat-data-provider'); |
| | const { createAutoRefillTransaction } = require('./Transaction'); |
| | const { logViolation } = require('~/cache'); |
| | const { getMultiplier } = require('./tx'); |
| | const { Balance } = require('~/db/models'); |
| |
|
| | function isInvalidDate(date) { |
| | return isNaN(date); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | const checkBalanceRecord = async function ({ |
| | user, |
| | model, |
| | endpoint, |
| | valueKey, |
| | tokenType, |
| | amount, |
| | endpointTokenConfig, |
| | }) { |
| | const multiplier = getMultiplier({ valueKey, tokenType, model, endpoint, endpointTokenConfig }); |
| | const tokenCost = amount * multiplier; |
| |
|
| | |
| | let record = await Balance.findOne({ user }).lean(); |
| | if (!record) { |
| | logger.debug('[Balance.check] No balance record found for user', { user }); |
| | return { |
| | canSpend: false, |
| | balance: 0, |
| | tokenCost, |
| | }; |
| | } |
| | let balance = record.tokenCredits; |
| |
|
| | logger.debug('[Balance.check] Initial state', { |
| | user, |
| | model, |
| | endpoint, |
| | valueKey, |
| | tokenType, |
| | amount, |
| | balance, |
| | multiplier, |
| | endpointTokenConfig: !!endpointTokenConfig, |
| | }); |
| |
|
| | |
| | if (balance - tokenCost <= 0 && record.autoRefillEnabled && record.refillAmount > 0) { |
| | const lastRefillDate = new Date(record.lastRefill); |
| | const now = new Date(); |
| | if ( |
| | isInvalidDate(lastRefillDate) || |
| | now >= |
| | addIntervalToDate(lastRefillDate, record.refillIntervalValue, record.refillIntervalUnit) |
| | ) { |
| | try { |
| | |
| | const result = await createAutoRefillTransaction({ |
| | user: user, |
| | tokenType: 'credits', |
| | context: 'autoRefill', |
| | rawAmount: record.refillAmount, |
| | }); |
| | balance = result.balance; |
| | } catch (error) { |
| | logger.error('[Balance.check] Failed to record transaction for auto-refill', error); |
| | } |
| | } |
| | } |
| |
|
| | logger.debug('[Balance.check] Token cost', { tokenCost }); |
| | return { canSpend: balance >= tokenCost, balance, tokenCost }; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const addIntervalToDate = (date, value, unit) => { |
| | const result = new Date(date); |
| | switch (unit) { |
| | case 'seconds': |
| | result.setSeconds(result.getSeconds() + value); |
| | break; |
| | case 'minutes': |
| | result.setMinutes(result.getMinutes() + value); |
| | break; |
| | case 'hours': |
| | result.setHours(result.getHours() + value); |
| | break; |
| | case 'days': |
| | result.setDate(result.getDate() + value); |
| | break; |
| | case 'weeks': |
| | result.setDate(result.getDate() + value * 7); |
| | break; |
| | case 'months': |
| | result.setMonth(result.getMonth() + value); |
| | break; |
| | default: |
| | break; |
| | } |
| | return result; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const checkBalance = async ({ req, res, txData }) => { |
| | const { canSpend, balance, tokenCost } = await checkBalanceRecord(txData); |
| | if (canSpend) { |
| | return true; |
| | } |
| |
|
| | const type = ViolationTypes.TOKEN_BALANCE; |
| | const errorMessage = { |
| | type, |
| | balance, |
| | tokenCost, |
| | promptTokens: txData.amount, |
| | }; |
| |
|
| | if (txData.generations && txData.generations.length > 0) { |
| | errorMessage.generations = txData.generations; |
| | } |
| |
|
| | await logViolation(req, res, type, errorMessage, 0); |
| | throw new Error(JSON.stringify(errorMessage)); |
| | }; |
| |
|
| | module.exports = { |
| | checkBalance, |
| | }; |
| |
|