diff --git a/router.py b/router.py index 9a1f0c8..8c3be12 100644 --- a/router.py +++ b/router.py @@ -1196,21 +1196,27 @@ async def stats_proxy(request: Request, model: Optional[str] = None): # Get time series data for the last 30 days (43200 minutes = 30 days) # Assuming entries are grouped by minute, 30 days = 43200 entries max time_series = [] + endpoint_totals = defaultdict(int) # Track tokens per endpoint + async for entry in db.get_latest_time_series(limit=50000): if entry['model'] == model: time_series.append({ + 'endpoint': entry['endpoint'], 'timestamp': entry['timestamp'], 'input_tokens': entry['input_tokens'], 'output_tokens': entry['output_tokens'], 'total_tokens': entry['total_tokens'] }) + # Accumulate total tokens per endpoint + endpoint_totals[entry['endpoint']] += entry['total_tokens'] return { 'model': model, 'input_tokens': token_data['input_tokens'], 'output_tokens': token_data['output_tokens'], 'total_tokens': token_data['total_tokens'], - 'time_series': time_series + 'time_series': time_series, + 'endpoint_distribution': dict(endpoint_totals) } # ------------------------------------------------------------- diff --git a/static/index.html b/static/index.html index 42a7cd7..17e2ce0 100644 --- a/static/index.html +++ b/static/index.html @@ -232,6 +232,12 @@ height: 300px; margin-top: 1rem; } + .pie-chart-container { + position: relative; + height: 250px; + margin-top: 1rem; + max-width: 400px; + }
@@ -376,23 +382,32 @@ function renderTimeSeriesChart(timeSeriesData, chart, minutes) { return; } - // Filter data based on selected timeframe - const now = new Date(); - const cutoffTime = now.getTime() - (minutes * 60 * 1000); + // Filter data based on selected timeframe (use UTC for consistency) + const now = Date.now(); + const cutoffTime = now - (minutes * 60 * 1000); // Group data by hour for better visualization const groupedData = {}; timeSeriesData.forEach(item => { - const timestamp = item.timestamp * 1000; - if (timestamp >= cutoffTime) { - const date = new Date(timestamp); - // Group by hour (local time) - const hourStr = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); + // Database stores UTC timestamps, multiply by 1000 to get milliseconds + const timestampMs = item.timestamp * 1000; + + if (timestampMs >= cutoffTime) { + // Convert UTC timestamp to local time for display + const date = new Date(timestampMs); + // Group by hour and minute in local time + const hourStr = date.toLocaleString([], { + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); if (!groupedData[hourStr]) { groupedData[hourStr] = { input: 0, - output: 0 + output: 0, + timestamp: timestampMs // Keep for sorting }; } groupedData[hourStr].input += item.input_tokens || 0; @@ -400,10 +415,11 @@ function renderTimeSeriesChart(timeSeriesData, chart, minutes) { } }); - // Convert to arrays for chart - const labels = Object.keys(groupedData).sort(); - const inputData = labels.map(hour => groupedData[hour].input); - const outputData = labels.map(hour => groupedData[hour].output); + // Convert to arrays for chart, sorted by timestamp + const sortedEntries = Object.entries(groupedData).sort((a, b) => a[1].timestamp - b[1].timestamp); + const labels = sortedEntries.map(([label]) => label); + const inputData = sortedEntries.map(([, data]) => data.input); + const outputData = sortedEntries.map(([, data]) => data.output); console.log('Chart updated with', labels.length, 'data points'); @@ -770,6 +786,10 @@ function renderTimeSeriesChart(timeSeriesData, chart, minutes) {Input tokens: ${data.input_tokens}
Output tokens: ${data.output_tokens}
Total tokens: ${data.total_tokens}
+