(dateFilter?: DateFilter)
| 438 | } |
| 439 | |
| 440 | async function aggregateStats(dateFilter?: DateFilter): Promise<SessionStats> { |
| 441 | const allSessions = await getAllSessions() |
| 442 | |
| 443 | // filter sessions by date if filter is provided |
| 444 | const sessions = dateFilter |
| 445 | ? allSessions.filter((session) => { |
| 446 | const created = new Date(session.time.created) |
| 447 | return created >= dateFilter.from && created <= dateFilter.to |
| 448 | }) |
| 449 | : allSessions |
| 450 | |
| 451 | const stats: SessionStats = { |
| 452 | totalSessions: sessions.length, |
| 453 | totalTokens: 0, |
| 454 | totalCost: 0, |
| 455 | activeDays: 0, |
| 456 | longestStreak: 0, |
| 457 | currentStreak: 0, |
| 458 | longestSession: 0, |
| 459 | peakHour: 12, |
| 460 | modelUsage: {}, |
| 461 | dailyActivity: {}, |
| 462 | dailyCost: {}, |
| 463 | hourlyActivity: {}, |
| 464 | tokenBreakdown: { |
| 465 | input: 0, |
| 466 | output: 0, |
| 467 | cacheRead: 0, |
| 468 | cacheWrite: 0, |
| 469 | }, |
| 470 | costBreakdown: { |
| 471 | input: 0, |
| 472 | output: 0, |
| 473 | cacheRead: 0, |
| 474 | cacheWrite: 0, |
| 475 | }, |
| 476 | costPerDay: 0, |
| 477 | costPerSession: 0, |
| 478 | } |
| 479 | |
| 480 | if (sessions.length === 0) return stats |
| 481 | |
| 482 | const activeDaysSet = new Set<string>() |
| 483 | |
| 484 | for (const session of sessions) { |
| 485 | const duration = session.time.updated - session.time.created |
| 486 | if (duration > stats.longestSession) { |
| 487 | stats.longestSession = duration |
| 488 | } |
| 489 | |
| 490 | const dateKey = new Date(session.time.created).toISOString().split("T")[0] |
| 491 | activeDaysSet.add(dateKey) |
| 492 | |
| 493 | const hour = new Date(session.time.created).getHours() |
| 494 | stats.hourlyActivity[hour] = (stats.hourlyActivity[hour] || 0) + 1 |
| 495 | } |
| 496 | |
| 497 | // process messages in batches |
no test coverage detected