diff --git a/src/chat/utils/report_generator.py b/src/chat/utils/report_generator.py index 3bc974757..e23a1d75e 100644 --- a/src/chat/utils/report_generator.py +++ b/src/chat/utils/report_generator.py @@ -2,12 +2,13 @@ 该模块用于生成HTML格式的统计报告。 """ -from datetime import datetime, timedelta -from typing import Any import json import os -from jinja2 import Environment, FileSystemLoader +from datetime import datetime, timedelta +from typing import Any + import aiofiles +from jinja2 import Environment, FileSystemLoader from .statistic_keys import * # noqa: F403 diff --git a/src/chat/utils/statistic.py b/src/chat/utils/statistic.py index ea89700c6..5b1ce7826 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -412,9 +412,9 @@ class StatisticOutputTask(AsyncTask): (REQ_CNT_BY_MODEL, "model"), (REQ_CNT_BY_MODULE, "module"), ]: - time_cost_key = f"time_costs_by_{items}" - avg_key = f"avg_time_costs_by_{items}" - std_key = f"std_time_costs_by_{items}" + time_cost_key = f"TIME_COST_BY_{items.upper()}" + avg_key = f"AVG_TIME_COST_BY_{items.upper()}" + std_key = f"STD_TIME_COST_BY_{items.upper()}" for item_name in period_stats[category_key]: time_costs = period_stats[time_cost_key].get(item_name, []) diff --git a/src/chat/utils/templates/report.css b/src/chat/utils/templates/report.css index 05a9c3ceb..2229be785 100644 --- a/src/chat/utils/templates/report.css +++ b/src/chat/utils/templates/report.css @@ -3,22 +3,20 @@ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; padding: 20px; - background-color: #F8F9FA; /* Light grey background */ - color: #495057; /* Softer text color */ + background-color: #f0f4f8; /* Light blue-gray background */ + color: #333; /* Darker text for better contrast */ line-height: 1.6; } /* Main Container */ .container { - max-width: 1200px; + max-width: 95%; /* Make container almost full-width */ margin: 20px auto; background-color: #FFFFFF; /* Pure white background */ padding: 30px; - border-radius: 8px; - box-shadow: 0 4px 12px rgba(0,0,0,0.05); - border: 1px solid #EAEAEA; + border-radius: 12px; /* Slightly more rounded corners */ + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.07); /* Softer, deeper shadow */ } - /* Dashboard Layout */ .dashboard-layout { display: flex; @@ -56,28 +54,28 @@ h1 { text-align: center; font-size: 2.2em; margin-bottom: 20px; - color: #4A90E2; /* Main blue for title */ + color: #2A6CB5; /* A deeper, more professional blue */ } h2 { font-size: 1.5em; margin-top: 40px; margin-bottom: 15px; - border-bottom: 2px solid #EAEAEA; + border-bottom: 2px solid #DDE6ED; /* Lighter border color */ } /* Info Banners */ .info-item { - background-color: #E9ECEF; - padding: 10px 15px; - border-radius: 6px; + background-color: #E9F2FA; /* Light blue background */ + padding: 12px 18px; + border-radius: 8px; margin-bottom: 20px; font-size: 0.95em; - border: 1px solid #DEE2E6; + border: 1px solid #D1E3F4; /* Light blue border */ } .info-item strong { - color: #4A90E2; + color: #2A6CB5; /* Deeper blue for emphasis */ } /* Tabs */ @@ -101,12 +99,13 @@ h2 { } .tabs button:hover { - color: #212529; + color: #2A6CB5; + background-color: #f0f4f8; /* Subtle hover background */ } .tabs button.active { - color: #4A90E2; - border-bottom-color: #4A90E2; + color: #2A6CB5; /* Active tab color */ + border-bottom-color: #2A6CB5; /* Active tab border color */ } .tab-content { @@ -131,7 +130,7 @@ h2 { padding: 20px; border-radius: 8px; text-align: center; - border: 1px solid #EAEAEA; + border: 1px solid #DDE6ED; /* Lighter border */ transition: all 0.3s ease; } @@ -166,9 +165,8 @@ th, td { text-align: left; border-bottom: 1px solid #EAEAEA; } - th { - background-color: #4A90E2; + background-color: #4A90E2; /* Main theme blue */ color: white; font-weight: bold; font-size: 0.95em; @@ -177,11 +175,11 @@ th { } tr:nth-child(even) { - background-color: #F8F9FA; + background-color: #F7FAFC; /* Very light blue for alternate rows */ } tr:hover { - background-color: #E9ECEF; + background-color: #E9F2FA; /* Light blue for hover */ } /* Chart Container in Sidebar */ diff --git a/src/chat/utils/templates/report.html b/src/chat/utils/templates/report.html index 9ac7d2e3e..b70146063 100644 --- a/src/chat/utils/templates/report.html +++ b/src/chat/utils/templates/report.html @@ -14,6 +14,10 @@
{{ tab_list }}
{{ tab_content }} + \ No newline at end of file diff --git a/src/chat/utils/templates/report.js b/src/chat/utils/templates/report.js index 7f944cb3a..8cec90b56 100644 --- a/src/chat/utils/templates/report.js +++ b/src/chat/utils/templates/report.js @@ -11,9 +11,15 @@ function showTab(evt, tabName) { } document.addEventListener('DOMContentLoaded', function () { - // This is a placeholder for chart data which will be injected by python. - const allChartData = JSON.parse('{{ all_chart_data }}') -; + // Chart data is injected by python via the HTML template. + let allChartData = {}; + try { + allChartData = JSON.parse(all_chart_data_json_string); + } catch (e) { + console.error("Failed to parse all_chart_data:", e); + console.error("Problematic all_chart_data string:", all_chart_data_json_string); + } + let currentCharts = {}; const chartConfigs = { totalCost: { id: 'totalCostChart', title: '总花费', yAxisLabel: '花费 (¥)', dataKey: 'total_cost_data', fill: true }, @@ -73,8 +79,14 @@ document.addEventListener('DOMContentLoaded', function () { } // Static charts - const staticChartData = JSON.parse('{{ static_chart_data }}') -; + let staticChartData = {}; + try { + staticChartData = JSON.parse(static_chart_data_json_string); + } catch (e) { + console.error("Failed to parse static_chart_data:", e); + console.error("Problematic static_chart_data string:", static_chart_data_json_string); + } + Object.keys(staticChartData).forEach(period_id => { const providerCostData = staticChartData[period_id].provider_cost_data; const modelCostData = staticChartData[period_id].model_cost_data; @@ -82,7 +94,7 @@ document.addEventListener('DOMContentLoaded', function () { // Provider Cost Pie Chart const providerCtx = document.getElementById(`providerCostPieChart_${period_id}`); - if (providerCtx && providerCostData && providerCostData.data.length > 0) { + if (providerCtx && providerCostData && providerCostData.data && providerCostData.data.length > 0) { new Chart(providerCtx, { type: 'pie', data: { @@ -106,7 +118,7 @@ document.addEventListener('DOMContentLoaded', function () { // Model Cost Bar Chart const modelCtx = document.getElementById(`modelCostBarChart_${period_id}`); - if (modelCtx && modelCostData && modelCostData.data.length > 0) { + if (modelCtx && modelCostData && modelCostData.data && modelCostData.data.length > 0) { new Chart(modelCtx, { type: 'bar', data: {