| #!/usr/bin/env node |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| const redis = require('../src/models/redis') |
| const logger = require('../src/utils/logger') |
|
|
| |
| const args = process.argv.slice(2) |
| const shouldClean = args.includes('--clean') |
|
|
| |
| const models = [ |
| 'claude-sonnet-4-20250514', |
| 'claude-3-5-sonnet-20241022', |
| 'claude-3-5-haiku-20241022', |
| 'claude-3-opus-20240229' |
| ] |
|
|
| |
| async function generateDataForDate(apiKeyId, date, dayOffset) { |
| const client = redis.getClientSafe() |
| const dateStr = date.toISOString().split('T')[0] |
| const month = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}` |
|
|
| |
| const requestCount = Math.max(5, 20 - dayOffset * 2) |
|
|
| logger.info(`📊 Generating ${requestCount} requests for ${dateStr}`) |
|
|
| for (let i = 0; i < requestCount; i++) { |
| |
| const model = models[Math.floor(Math.random() * models.length)] |
|
|
| |
| const inputTokens = Math.floor(Math.random() * 2000) + 500 |
| const outputTokens = Math.floor(Math.random() * 3000) + 1000 |
| const cacheCreateTokens = Math.random() > 0.7 ? Math.floor(Math.random() * 1000) : 0 |
| const cacheReadTokens = Math.random() > 0.5 ? Math.floor(Math.random() * 500) : 0 |
|
|
| const coreTokens = inputTokens + outputTokens |
| const allTokens = inputTokens + outputTokens + cacheCreateTokens + cacheReadTokens |
|
|
| |
| const totalKey = `usage:${apiKeyId}` |
| const dailyKey = `usage:daily:${apiKeyId}:${dateStr}` |
| const monthlyKey = `usage:monthly:${apiKeyId}:${month}` |
| const modelDailyKey = `usage:model:daily:${model}:${dateStr}` |
| const modelMonthlyKey = `usage:model:monthly:${model}:${month}` |
| const keyModelDailyKey = `usage:${apiKeyId}:model:daily:${model}:${dateStr}` |
| const keyModelMonthlyKey = `usage:${apiKeyId}:model:monthly:${model}:${month}` |
|
|
| await Promise.all([ |
| |
| client.hincrby(totalKey, 'totalTokens', coreTokens), |
| client.hincrby(totalKey, 'totalInputTokens', inputTokens), |
| client.hincrby(totalKey, 'totalOutputTokens', outputTokens), |
| client.hincrby(totalKey, 'totalCacheCreateTokens', cacheCreateTokens), |
| client.hincrby(totalKey, 'totalCacheReadTokens', cacheReadTokens), |
| client.hincrby(totalKey, 'totalAllTokens', allTokens), |
| client.hincrby(totalKey, 'totalRequests', 1), |
|
|
| |
| client.hincrby(dailyKey, 'tokens', coreTokens), |
| client.hincrby(dailyKey, 'inputTokens', inputTokens), |
| client.hincrby(dailyKey, 'outputTokens', outputTokens), |
| client.hincrby(dailyKey, 'cacheCreateTokens', cacheCreateTokens), |
| client.hincrby(dailyKey, 'cacheReadTokens', cacheReadTokens), |
| client.hincrby(dailyKey, 'allTokens', allTokens), |
| client.hincrby(dailyKey, 'requests', 1), |
|
|
| |
| client.hincrby(monthlyKey, 'tokens', coreTokens), |
| client.hincrby(monthlyKey, 'inputTokens', inputTokens), |
| client.hincrby(monthlyKey, 'outputTokens', outputTokens), |
| client.hincrby(monthlyKey, 'cacheCreateTokens', cacheCreateTokens), |
| client.hincrby(monthlyKey, 'cacheReadTokens', cacheReadTokens), |
| client.hincrby(monthlyKey, 'allTokens', allTokens), |
| client.hincrby(monthlyKey, 'requests', 1), |
|
|
| |
| client.hincrby(modelDailyKey, 'totalInputTokens', inputTokens), |
| client.hincrby(modelDailyKey, 'totalOutputTokens', outputTokens), |
| client.hincrby(modelDailyKey, 'totalCacheCreateTokens', cacheCreateTokens), |
| client.hincrby(modelDailyKey, 'totalCacheReadTokens', cacheReadTokens), |
| client.hincrby(modelDailyKey, 'totalAllTokens', allTokens), |
| client.hincrby(modelDailyKey, 'requests', 1), |
|
|
| |
| client.hincrby(modelMonthlyKey, 'totalInputTokens', inputTokens), |
| client.hincrby(modelMonthlyKey, 'totalOutputTokens', outputTokens), |
| client.hincrby(modelMonthlyKey, 'totalCacheCreateTokens', cacheCreateTokens), |
| client.hincrby(modelMonthlyKey, 'totalCacheReadTokens', cacheReadTokens), |
| client.hincrby(modelMonthlyKey, 'totalAllTokens', allTokens), |
| client.hincrby(modelMonthlyKey, 'requests', 1), |
|
|
| |
| |
| client.hincrby(keyModelDailyKey, 'inputTokens', inputTokens), |
| client.hincrby(keyModelDailyKey, 'outputTokens', outputTokens), |
| client.hincrby(keyModelDailyKey, 'cacheCreateTokens', cacheCreateTokens), |
| client.hincrby(keyModelDailyKey, 'cacheReadTokens', cacheReadTokens), |
| client.hincrby(keyModelDailyKey, 'allTokens', allTokens), |
| client.hincrby(keyModelDailyKey, 'totalInputTokens', inputTokens), |
| client.hincrby(keyModelDailyKey, 'totalOutputTokens', outputTokens), |
| client.hincrby(keyModelDailyKey, 'totalCacheCreateTokens', cacheCreateTokens), |
| client.hincrby(keyModelDailyKey, 'totalCacheReadTokens', cacheReadTokens), |
| client.hincrby(keyModelDailyKey, 'totalAllTokens', allTokens), |
| client.hincrby(keyModelDailyKey, 'requests', 1), |
|
|
| |
| client.hincrby(keyModelMonthlyKey, 'inputTokens', inputTokens), |
| client.hincrby(keyModelMonthlyKey, 'outputTokens', outputTokens), |
| client.hincrby(keyModelMonthlyKey, 'cacheCreateTokens', cacheCreateTokens), |
| client.hincrby(keyModelMonthlyKey, 'cacheReadTokens', cacheReadTokens), |
| client.hincrby(keyModelMonthlyKey, 'allTokens', allTokens), |
| client.hincrby(keyModelMonthlyKey, 'totalInputTokens', inputTokens), |
| client.hincrby(keyModelMonthlyKey, 'totalOutputTokens', outputTokens), |
| client.hincrby(keyModelMonthlyKey, 'totalCacheCreateTokens', cacheCreateTokens), |
| client.hincrby(keyModelMonthlyKey, 'totalCacheReadTokens', cacheReadTokens), |
| client.hincrby(keyModelMonthlyKey, 'totalAllTokens', allTokens), |
| client.hincrby(keyModelMonthlyKey, 'requests', 1) |
| ]) |
| } |
| } |
|
|
| |
| async function cleanTestData() { |
| const client = redis.getClientSafe() |
| const apiKeyService = require('../src/services/apiKeyService') |
|
|
| logger.info('🧹 Cleaning test data...') |
|
|
| |
| const allKeys = await apiKeyService.getAllApiKeys() |
|
|
| |
| const testKeys = allKeys.filter((key) => key.name && key.name.startsWith('Test API Key')) |
|
|
| for (const testKey of testKeys) { |
| const apiKeyId = testKey.id |
|
|
| |
| const patterns = [ |
| `usage:${apiKeyId}`, |
| `usage:daily:${apiKeyId}:*`, |
| `usage:monthly:${apiKeyId}:*`, |
| `usage:${apiKeyId}:model:daily:*`, |
| `usage:${apiKeyId}:model:monthly:*` |
| ] |
|
|
| for (const pattern of patterns) { |
| const keys = await client.keys(pattern) |
| if (keys.length > 0) { |
| await client.del(...keys) |
| logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`) |
| } |
| } |
|
|
| |
| await apiKeyService.deleteApiKey(apiKeyId) |
| logger.info(`🗑️ Deleted test API Key: ${testKey.name} (${apiKeyId})`) |
| } |
|
|
| |
| const modelPatterns = ['usage:model:daily:*', 'usage:model:monthly:*'] |
|
|
| for (const pattern of modelPatterns) { |
| const keys = await client.keys(pattern) |
| if (keys.length > 0) { |
| await client.del(...keys) |
| logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`) |
| } |
| } |
| } |
|
|
| |
| async function main() { |
| try { |
| await redis.connect() |
| logger.success('✅ Connected to Redis') |
|
|
| |
| const apiKeyService = require('../src/services/apiKeyService') |
| const testApiKeys = [] |
| const createdKeys = [] |
|
|
| |
| logger.info('📝 Creating test API Keys...') |
|
|
| for (let i = 1; i <= 3; i++) { |
| const newKey = await apiKeyService.generateApiKey({ |
| name: `Test API Key ${i}`, |
| description: `Test key for historical data generation ${i}`, |
| tokenLimit: 10000000, |
| concurrencyLimit: 10, |
| rateLimitWindow: 60, |
| rateLimitRequests: 100 |
| }) |
|
|
| testApiKeys.push(newKey.id) |
| createdKeys.push(newKey) |
| logger.success(`✅ Created test API Key: ${newKey.name} (${newKey.id})`) |
| logger.info(` 🔑 API Key: ${newKey.apiKey}`) |
| } |
|
|
| if (shouldClean) { |
| await cleanTestData() |
| logger.success('✅ Test data cleaned successfully') |
| return |
| } |
|
|
| |
| const now = new Date() |
|
|
| for (const apiKeyId of testApiKeys) { |
| logger.info(`\n🔄 Generating data for API Key: ${apiKeyId}`) |
|
|
| |
| for (let dayOffset = 0; dayOffset < 30; dayOffset++) { |
| const date = new Date(now) |
| date.setDate(date.getDate() - dayOffset) |
|
|
| await generateDataForDate(apiKeyId, date, dayOffset) |
| } |
|
|
| logger.success(`✅ Generated 30 days of historical data for API Key: ${apiKeyId}`) |
| } |
|
|
| |
| logger.info('\n📊 Test Data Summary:') |
| logger.info('='.repeat(60)) |
|
|
| for (const apiKeyId of testApiKeys) { |
| const totalKey = `usage:${apiKeyId}` |
| const totalData = await redis.getClientSafe().hgetall(totalKey) |
|
|
| if (totalData && Object.keys(totalData).length > 0) { |
| logger.info(`\nAPI Key: ${apiKeyId}`) |
| logger.info(` Total Requests: ${totalData.totalRequests || 0}`) |
| logger.info(` Total Tokens (Core): ${totalData.totalTokens || 0}`) |
| logger.info(` Total Tokens (All): ${totalData.totalAllTokens || 0}`) |
| logger.info(` Input Tokens: ${totalData.totalInputTokens || 0}`) |
| logger.info(` Output Tokens: ${totalData.totalOutputTokens || 0}`) |
| logger.info(` Cache Create Tokens: ${totalData.totalCacheCreateTokens || 0}`) |
| logger.info(` Cache Read Tokens: ${totalData.totalCacheReadTokens || 0}`) |
| } |
| } |
|
|
| logger.info(`\n${'='.repeat(60)}`) |
| logger.success('\n✅ Test data generation completed!') |
| logger.info('\n📋 Created API Keys:') |
| for (const key of createdKeys) { |
| logger.info(`- ${key.name}: ${key.apiKey}`) |
| } |
| logger.info('\n💡 Tips:') |
| logger.info('- Check the admin panel to see the different time ranges') |
| logger.info('- Use --clean flag to remove all test data and API Keys') |
| logger.info('- The script generates more recent data to simulate real usage patterns') |
| } catch (error) { |
| logger.error('❌ Error:', error) |
| } finally { |
| await redis.disconnect() |
| } |
| } |
|
|
| |
| main().catch((error) => { |
| logger.error('💥 Unexpected error:', error) |
| process.exit(1) |
| }) |
|
|