diff --git a/src/chat/utils/report_generator.py b/src/chat/utils/report_generator.py
index 5526781fa..3bc974757 100644
--- a/src/chat/utils/report_generator.py
+++ b/src/chat/utils/report_generator.py
@@ -1,9 +1,12 @@
"""
该模块用于生成HTML格式的统计报告。
"""
+
from datetime import datetime, timedelta
from typing import Any
-
+import json
+import os
+from jinja2 import Environment, FileSystemLoader
import aiofiles
from .statistic_keys import * # noqa: F403
@@ -48,6 +51,9 @@ class HTMLReportGenerator:
self.name_mapping = name_mapping
self.stat_period = stat_period
self.deploy_time = deploy_time
+ # 初始化Jinja2环境
+ template_dir = os.path.join(os.path.dirname(__file__), "templates")
+ self.jinja_env = Environment(loader=FileSystemLoader(template_dir))
def _format_stat_data_div(self, stat_data: dict[str, Any], div_id: str, start_time: datetime, now: datetime) -> str:
"""
@@ -152,134 +158,37 @@ class HTMLReportGenerator:
"""
-
# 增加饼图和条形图
- static_charts = self._generate_static_charts_div(stat_data, div_id) # 该功能尚未实现
- return f"""
-
-
- 统计时段:
- {start_time.strftime("%Y-%m-%d %H:%M:%S")} ~ {now.strftime("%Y-%m-%d %H:%M:%S")}
-
- {summary_cards}
- {static_charts}
+ static_charts = self._generate_static_charts_div(stat_data, div_id)
+ template = self.jinja_env.get_template("tab_content.html")
+ return template.render(
+ div_id=div_id,
+ start_time=start_time.strftime("%Y-%m-%d %H:%M:%S"),
+ end_time=now.strftime("%Y-%m-%d %H:%M:%S"),
+ summary_cards=summary_cards,
+ static_charts=static_charts,
+ model_rows=model_rows,
+ provider_rows=provider_rows,
+ module_rows=module_rows,
+ type_rows=type_rows,
+ chat_rows=chat_rows,
+ )
-
按模型分类统计
-
- 模型名称 调用次数 平均Token数 Token总量 TPS 每K Token成本 累计花费 平均耗时(秒)
- {model_rows}
-
-
-
按供应商分类统计
-
- 供应商名称 调用次数 Token总量 TPS 每K Token成本 累计花费
- {provider_rows}
-
-
-
按模块分类统计
-
-
- 模块名称 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒)
-
- {module_rows}
-
-
-
按请求类型分类统计
-
-
- 请求类型 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒)
-
- {type_rows}
-
-
-
聊天消息统计
-
-
- 联系人/群组名称 消息数量
-
- {chat_rows}
-
-
- """
def _generate_chart_tab(self, chart_data: dict) -> str:
"""生成图表选项卡的HTML内容。"""
- return f"""
-
-
数据图表
-
- 时间范围:
- 6小时
- 12小时
- 24小时
- 48小时
-
-
-
-
-
+ template = self.jinja_env.get_template("charts_tab.html")
+ return template.render()
+
+ def _generate_static_charts_div(self, stat_data: dict[str, Any], div_id: str)-> str:
"""
+ 生成静态图表的HTML div。
+
+ :param stat_data: 统计数据。
+ :param div_id: The ID for the period, used to uniquely identify chart canvases.
+ :return: 渲染后的HTML字符串。
+ """
+ template = self.jinja_env.get_template("static_charts.html")
+ return template.render(period_id=div_id)
async def generate_report(self, stat: dict[str, Any], chart_data: dict, now: datetime, output_path: str):
"""
@@ -290,157 +199,50 @@ class HTMLReportGenerator:
:param now: 当前时间。
:param output_path: 输出文件路径。
"""
- tab_list = [
+ tab_list_html = [
f'
+
数据图表
+
+ 时间范围:
+ 6小时
+ 12小时
+ 24小时
+ 48小时
+
+
+
\ No newline at end of file
diff --git a/src/chat/utils/templates/report.css b/src/chat/utils/templates/report.css
new file mode 100644
index 000000000..1c6603e5d
--- /dev/null
+++ b/src/chat/utils/templates/report.css
@@ -0,0 +1,177 @@
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ margin: 0;
+ padding: 20px;
+ background-color: #f4f7f6;
+ color: #333;
+ line-height: 1.6;
+}
+
+.container {
+ max-width: 900px;
+ margin: 20px auto;
+ background-color: #fff;
+ padding: 25px;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+h1, h2 {
+ color: #2c3e50;
+ border-bottom: 2px solid #3498db;
+ padding-bottom: 10px;
+ margin-top: 0;
+}
+
+h1 {
+ text-align: center;
+ font-size: 2em;
+}
+
+h2 {
+ font-size: 1.5em;
+ margin-top: 30px;
+}
+
+p {
+ margin-bottom: 10px;
+}
+
+.info-item {
+ background-color: #ecf0f1;
+ padding: 8px 12px;
+ border-radius: 4px;
+ margin-bottom: 8px;
+ font-size: 0.95em;
+}
+
+.info-item strong {
+ color: #2980b9;
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 15px;
+ font-size: 0.9em;
+}
+
+th, td {
+ border: 1px solid #ddd;
+ padding: 10px;
+ text-align: left;
+}
+
+th {
+ background-color: #3498db;
+ color: white;
+ font-weight: bold;
+}
+
+tr:nth-child(even) {
+ background-color: #f9f9f9;
+}
+
+.footer {
+ text-align: center;
+ margin-top: 30px;
+ font-size: 0.8em;
+ color: #7f8c8d;
+}
+
+.tabs {
+ overflow: hidden;
+ background: #ecf0f1;
+ display: flex;
+}
+
+.tabs button {
+ background: inherit;
+ border: none;
+ outline: none;
+ padding: 14px 16px;
+ cursor: pointer;
+ transition: 0.3s;
+ font-size: 16px;
+}
+
+.tabs button:hover {
+ background-color: #d4dbdc;
+}
+
+.tabs button.active {
+ background-color: #b3bbbd;
+}
+
+.tab-content {
+ display: none;
+ padding: 20px;
+ background-color: #fff;
+ border: 1px solid #ccc;
+}
+
+.tab-content.active {
+ display: block;
+}
+
+.summary-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: 15px;
+ margin: 20px 0;
+}
+
+.card {
+ background-color: #ecf0f1;
+ padding: 15px;
+ border-radius: 5px;
+ text-align: center;
+}
+
+.card h3 {
+ margin: 0 0 10px;
+ font-size: 1em;
+ color: #2c3e50;
+}
+
+.card p {
+ margin: 0;
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #34495e;
+}
+
+.chart-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+ margin-top: 20px;
+}
+
+.chart-container {
+ position: relative;
+ height: 40vh;
+ width: 100%;
+}
+
+.time-range-btn {
+ background-color: #ecf0f1;
+ border: 1px solid #bdc3c7;
+ color: #2c3e50;
+ padding: 8px 16px;
+ margin: 0 5px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: all 0.3s ease;
+}
+
+.time-range-btn:hover {
+ background-color: #d5dbdb;
+}
+
+.time-range-btn.active {
+ background-color: #3498db;
+ color: white;
+ border-color: #2980b9;
+}
\ No newline at end of file
diff --git a/src/chat/utils/templates/report.html b/src/chat/utils/templates/report.html
new file mode 100644
index 000000000..9ac7d2e3e
--- /dev/null
+++ b/src/chat/utils/templates/report.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+ 统计时段:
+ {{ start_time }} ~ {{ end_time }}
+
+ {{ summary_cards }}
+ {{ static_charts }}
+
+
按模型分类统计
+
+ 模型名称 调用次数 平均Token数 Token总量 TPS 每K Token成本 累计花费 平均耗时(秒)
+ {{ model_rows }}
+
+
+
按供应商分类统计
+
+ 供应商名称 调用次数 Token总量 TPS 每K Token成本 累计花费
+ {{ provider_rows }}
+
+
+
按模块分类统计
+
+
+ 模块名称 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒)
+
+ {{ module_rows }}
+
+
+
按请求类型分类统计
+
+
+ 请求类型 调用次数 输入Token 输出Token Token总量 累计花费 平均耗时(秒) 标准差(秒)
+
+ {{ type_rows }}
+
+
+
聊天消息统计
+
+
+ 联系人/群组名称 消息数量
+
+ {{ chat_rows }}
+
+
\ No newline at end of file