(days: number = 7)
| 127 | * Get aggregated statistics for the last N days. |
| 128 | */ |
| 129 | export async function getStats(days: number = 7): Promise<AggregatedStats> { |
| 130 | const logFiles = await getLogFiles(); |
| 131 | const filesToRead = logFiles.slice(0, days); |
| 132 | |
| 133 | const dailyBreakdown: DailyStats[] = []; |
| 134 | const allByTier: Record<string, { count: number; cost: number }> = {}; |
| 135 | const allByModel: Record<string, { count: number; cost: number }> = {}; |
| 136 | let totalRequests = 0; |
| 137 | let totalCost = 0; |
| 138 | let totalBaselineCost = 0; |
| 139 | let totalLatency = 0; |
| 140 | |
| 141 | for (const file of filesToRead) { |
| 142 | const date = file.replace("usage-", "").replace(".jsonl", ""); |
| 143 | const filePath = join(LOG_DIR, file); |
| 144 | const entries = await parseLogFile(filePath); |
| 145 | |
| 146 | if (entries.length === 0) continue; |
| 147 | |
| 148 | const dayStats = aggregateDay(date, entries); |
| 149 | dailyBreakdown.push(dayStats); |
| 150 | |
| 151 | totalRequests += dayStats.totalRequests; |
| 152 | totalCost += dayStats.totalCost; |
| 153 | totalBaselineCost += dayStats.totalBaselineCost; |
| 154 | totalLatency += dayStats.avgLatencyMs * dayStats.totalRequests; |
| 155 | |
| 156 | // Merge tier stats |
| 157 | for (const [tier, stats] of Object.entries(dayStats.byTier)) { |
| 158 | if (!allByTier[tier]) allByTier[tier] = { count: 0, cost: 0 }; |
| 159 | allByTier[tier].count += stats.count; |
| 160 | allByTier[tier].cost += stats.cost; |
| 161 | } |
| 162 | |
| 163 | // Merge model stats |
| 164 | for (const [model, stats] of Object.entries(dayStats.byModel)) { |
| 165 | if (!allByModel[model]) allByModel[model] = { count: 0, cost: 0 }; |
| 166 | allByModel[model].count += stats.count; |
| 167 | allByModel[model].cost += stats.cost; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | // Calculate percentages |
| 172 | const byTierWithPercentage: Record<string, { count: number; cost: number; percentage: number }> = |
| 173 | {}; |
| 174 | for (const [tier, stats] of Object.entries(allByTier)) { |
| 175 | byTierWithPercentage[tier] = { |
| 176 | ...stats, |
| 177 | percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0, |
| 178 | }; |
| 179 | } |
| 180 | |
| 181 | const byModelWithPercentage: Record<string, { count: number; cost: number; percentage: number }> = |
| 182 | {}; |
| 183 | for (const [model, stats] of Object.entries(allByModel)) { |
| 184 | byModelWithPercentage[model] = { |
| 185 | ...stats, |
| 186 | percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0, |
no test coverage detected