Merge branch 'dev' of https://github.com/MaiM-with-u/MaiBot into dev
This commit is contained in:
@@ -151,7 +151,7 @@ class HeartFChatting:
|
||||
|
||||
# 存储回调函数
|
||||
self.on_stop_focus_chat = on_stop_focus_chat
|
||||
|
||||
|
||||
# 初始化性能记录器
|
||||
# 如果没有指定版本号,则使用全局版本管理器的版本号
|
||||
actual_version = performance_version or get_hfc_version()
|
||||
@@ -407,17 +407,17 @@ class HeartFChatting:
|
||||
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||
+ processor_time_log
|
||||
)
|
||||
|
||||
|
||||
# 记录性能数据
|
||||
try:
|
||||
action_result = self._current_cycle_detail.loop_plan_info.get('action_result', {})
|
||||
action_result = self._current_cycle_detail.loop_plan_info.get("action_result", {})
|
||||
cycle_performance_data = {
|
||||
"cycle_id": self._current_cycle_detail.cycle_id,
|
||||
"action_type": action_result.get('action_type', 'unknown'),
|
||||
"action_type": action_result.get("action_type", "unknown"),
|
||||
"total_time": self._current_cycle_detail.end_time - self._current_cycle_detail.start_time,
|
||||
"step_times": cycle_timers.copy(),
|
||||
"reasoning": action_result.get('reasoning', ''),
|
||||
"success": self._current_cycle_detail.loop_action_info.get('action_taken', False),
|
||||
"reasoning": action_result.get("reasoning", ""),
|
||||
"success": self._current_cycle_detail.loop_action_info.get("action_taken", False),
|
||||
}
|
||||
self.performance_logger.record_cycle(cycle_performance_data)
|
||||
except Exception as perf_e:
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
from typing import Dict, List, Any
|
||||
from pathlib import Path
|
||||
from src.common.logger import get_logger
|
||||
|
||||
@@ -11,32 +9,34 @@ logger = get_logger("hfc_performance")
|
||||
|
||||
class HFCPerformanceLogger:
|
||||
"""HFC性能记录管理器"""
|
||||
|
||||
|
||||
# 版本号常量,可在启动时修改
|
||||
INTERNAL_VERSION = "v1.0.0"
|
||||
|
||||
|
||||
def __init__(self, chat_id: str, version: str = None):
|
||||
self.chat_id = chat_id
|
||||
self.version = version or self.INTERNAL_VERSION
|
||||
self.log_dir = Path("log/hfc_loop")
|
||||
self.data_dir = Path("data/hfc")
|
||||
self.session_start_time = datetime.now()
|
||||
|
||||
|
||||
# 确保目录存在
|
||||
self.log_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
# 当前会话的日志文件,包含版本号
|
||||
version_suffix = self.version.replace(".", "_")
|
||||
self.session_file = self.log_dir / f"{chat_id}_{version_suffix}_{self.session_start_time.strftime('%Y%m%d_%H%M%S')}.json"
|
||||
self.session_file = (
|
||||
self.log_dir / f"{chat_id}_{version_suffix}_{self.session_start_time.strftime('%Y%m%d_%H%M%S')}.json"
|
||||
)
|
||||
self.current_session_data = []
|
||||
|
||||
|
||||
# 统计数据文件
|
||||
self.stats_file = self.data_dir / "time.json"
|
||||
|
||||
|
||||
# 初始化时计算历史统计数据
|
||||
self._update_historical_stats()
|
||||
|
||||
|
||||
def record_cycle(self, cycle_data: Dict[str, Any]):
|
||||
"""记录单次循环数据"""
|
||||
try:
|
||||
@@ -50,112 +50,110 @@ class HFCPerformanceLogger:
|
||||
"total_time": cycle_data.get("total_time", 0),
|
||||
"step_times": cycle_data.get("step_times", {}),
|
||||
"reasoning": cycle_data.get("reasoning", ""),
|
||||
"success": cycle_data.get("success", False)
|
||||
"success": cycle_data.get("success", False),
|
||||
}
|
||||
|
||||
|
||||
# 添加到当前会话数据
|
||||
self.current_session_data.append(record)
|
||||
|
||||
|
||||
# 立即写入文件(防止数据丢失)
|
||||
self._write_session_data()
|
||||
|
||||
logger.debug(f"记录HFC循环数据: cycle_id={record['cycle_id']}, action={record['action_type']}, time={record['total_time']:.2f}s")
|
||||
|
||||
|
||||
logger.debug(
|
||||
f"记录HFC循环数据: cycle_id={record['cycle_id']}, action={record['action_type']}, time={record['total_time']:.2f}s"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"记录HFC循环数据失败: {e}")
|
||||
|
||||
|
||||
def _write_session_data(self):
|
||||
"""写入当前会话数据到文件"""
|
||||
try:
|
||||
with open(self.session_file, 'w', encoding='utf-8') as f:
|
||||
with open(self.session_file, "w", encoding="utf-8") as f:
|
||||
json.dump(self.current_session_data, f, ensure_ascii=False, indent=2)
|
||||
except Exception as e:
|
||||
logger.error(f"写入会话数据失败: {e}")
|
||||
|
||||
|
||||
def _update_historical_stats(self):
|
||||
"""更新历史统计数据"""
|
||||
try:
|
||||
# 读取所有历史会话文件
|
||||
all_records = []
|
||||
|
||||
|
||||
# 读取当前chat_id的所有历史文件(包括不同版本)
|
||||
for file_path in self.log_dir.glob(f"{self.chat_id}_*.json"):
|
||||
if file_path == self.session_file:
|
||||
continue # 跳过当前会话文件
|
||||
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
records = json.load(f)
|
||||
if isinstance(records, list):
|
||||
all_records.extend(records)
|
||||
except Exception as e:
|
||||
logger.warning(f"读取历史文件 {file_path} 失败: {e}")
|
||||
|
||||
|
||||
if not all_records:
|
||||
logger.info(f"没有找到 chat_id={self.chat_id} 的历史数据")
|
||||
return
|
||||
|
||||
|
||||
# 计算统计数据
|
||||
stats = self._calculate_stats(all_records)
|
||||
|
||||
|
||||
# 更新统计文件
|
||||
self._update_stats_file(stats)
|
||||
|
||||
|
||||
logger.info(f"更新了 chat_id={self.chat_id} 的历史统计数据,共 {len(all_records)} 条记录")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"更新历史统计数据失败: {e}")
|
||||
|
||||
|
||||
def _calculate_stats(self, records: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""计算统计数据"""
|
||||
if not records:
|
||||
return {}
|
||||
|
||||
|
||||
# 按动作类型分组
|
||||
action_groups = {}
|
||||
total_times = []
|
||||
step_time_totals = {}
|
||||
|
||||
|
||||
for record in records:
|
||||
action_type = record.get("action_type", "unknown")
|
||||
total_time = record.get("total_time", 0)
|
||||
step_times = record.get("step_times", {})
|
||||
|
||||
|
||||
if action_type not in action_groups:
|
||||
action_groups[action_type] = {
|
||||
"count": 0,
|
||||
"total_times": [],
|
||||
"step_times": {}
|
||||
}
|
||||
|
||||
action_groups[action_type] = {"count": 0, "total_times": [], "step_times": {}}
|
||||
|
||||
action_groups[action_type]["count"] += 1
|
||||
action_groups[action_type]["total_times"].append(total_time)
|
||||
total_times.append(total_time)
|
||||
|
||||
|
||||
# 记录步骤时间
|
||||
for step_name, step_time in step_times.items():
|
||||
if step_name not in action_groups[action_type]["step_times"]:
|
||||
action_groups[action_type]["step_times"][step_name] = []
|
||||
action_groups[action_type]["step_times"][step_name].append(step_time)
|
||||
|
||||
|
||||
if step_name not in step_time_totals:
|
||||
step_time_totals[step_name] = []
|
||||
step_time_totals[step_name].append(step_time)
|
||||
|
||||
|
||||
# 计算各种平均值和比例
|
||||
total_records = len(records)
|
||||
|
||||
|
||||
# 整体统计
|
||||
overall_stats = {
|
||||
"total_records": total_records,
|
||||
"avg_total_time": sum(total_times) / len(total_times) if total_times else 0,
|
||||
"avg_step_times": {}
|
||||
"avg_step_times": {},
|
||||
}
|
||||
|
||||
|
||||
# 各步骤平均时间
|
||||
for step_name, times in step_time_totals.items():
|
||||
overall_stats["avg_step_times"][step_name] = sum(times) / len(times) if times else 0
|
||||
|
||||
|
||||
# 按动作类型统计
|
||||
action_stats = {}
|
||||
for action_type, data in action_groups.items():
|
||||
@@ -163,76 +161,78 @@ class HFCPerformanceLogger:
|
||||
"count": data["count"],
|
||||
"percentage": (data["count"] / total_records) * 100,
|
||||
"avg_total_time": sum(data["total_times"]) / len(data["total_times"]) if data["total_times"] else 0,
|
||||
"avg_step_times": {}
|
||||
"avg_step_times": {},
|
||||
}
|
||||
|
||||
|
||||
# 该动作各步骤平均时间
|
||||
for step_name, times in data["step_times"].items():
|
||||
action_stats[action_type]["avg_step_times"][step_name] = sum(times) / len(times) if times else 0
|
||||
|
||||
|
||||
return {
|
||||
"chat_id": self.chat_id,
|
||||
"version": self.version,
|
||||
"last_updated": datetime.now().isoformat(),
|
||||
"overall": overall_stats,
|
||||
"by_action": action_stats
|
||||
"by_action": action_stats,
|
||||
}
|
||||
|
||||
|
||||
def _update_stats_file(self, new_stats: Dict[str, Any]):
|
||||
"""更新统计文件"""
|
||||
try:
|
||||
# 读取现有统计数据
|
||||
existing_stats = {}
|
||||
if self.stats_file.exists():
|
||||
with open(self.stats_file, 'r', encoding='utf-8') as f:
|
||||
with open(self.stats_file, "r", encoding="utf-8") as f:
|
||||
existing_stats = json.load(f)
|
||||
|
||||
|
||||
# 更新当前chat_id和版本的统计数据
|
||||
stats_key = f"{self.chat_id}_{self.version}"
|
||||
existing_stats[stats_key] = new_stats
|
||||
|
||||
|
||||
# 写回文件
|
||||
with open(self.stats_file, 'w', encoding='utf-8') as f:
|
||||
with open(self.stats_file, "w", encoding="utf-8") as f:
|
||||
json.dump(existing_stats, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"更新统计文件失败: {e}")
|
||||
|
||||
|
||||
def get_current_session_stats(self) -> Dict[str, Any]:
|
||||
"""获取当前会话的统计数据"""
|
||||
if not self.current_session_data:
|
||||
return {}
|
||||
|
||||
|
||||
return self._calculate_stats(self.current_session_data)
|
||||
|
||||
|
||||
def finalize_session(self):
|
||||
"""结束会话,进行最终统计"""
|
||||
try:
|
||||
if self.current_session_data:
|
||||
# 计算当前会话统计数据
|
||||
current_stats = self._calculate_stats(self.current_session_data)
|
||||
|
||||
self._calculate_stats(self.current_session_data)
|
||||
|
||||
# 合并历史数据重新计算总体统计
|
||||
all_records = self.current_session_data[:]
|
||||
|
||||
|
||||
# 读取历史数据
|
||||
for file_path in self.log_dir.glob(f"{self.chat_id}_*.json"):
|
||||
if file_path == self.session_file:
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
records = json.load(f)
|
||||
if isinstance(records, list):
|
||||
all_records.extend(records)
|
||||
except Exception as e:
|
||||
logger.warning(f"读取历史文件 {file_path} 失败: {e}")
|
||||
|
||||
|
||||
# 重新计算总体统计
|
||||
total_stats = self._calculate_stats(all_records)
|
||||
self._update_stats_file(total_stats)
|
||||
|
||||
logger.info(f"完成会话统计,当前会话 {len(self.current_session_data)} 条记录,总共 {len(all_records)} 条记录")
|
||||
|
||||
|
||||
logger.info(
|
||||
f"完成会话统计,当前会话 {len(self.current_session_data)} 条记录,总共 {len(all_records)} 条记录"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"结束会话统计失败: {e}")
|
||||
logger.error(f"结束会话统计失败: {e}")
|
||||
|
||||
@@ -18,21 +18,21 @@ logger = get_logger("hfc_version")
|
||||
|
||||
class HFCVersionManager:
|
||||
"""HFC版本号管理器"""
|
||||
|
||||
|
||||
# 默认版本号
|
||||
DEFAULT_VERSION = "v1.0.0"
|
||||
|
||||
|
||||
# 当前运行时版本号
|
||||
_current_version: Optional[str] = None
|
||||
|
||||
|
||||
@classmethod
|
||||
def set_version(cls, version: str) -> bool:
|
||||
"""
|
||||
设置当前运行时版本号
|
||||
|
||||
|
||||
参数:
|
||||
version: 版本号字符串,格式如 v1.0.0 或 1.0.0
|
||||
|
||||
|
||||
返回:
|
||||
bool: 设置是否成功
|
||||
"""
|
||||
@@ -48,103 +48,103 @@ class HFCVersionManager:
|
||||
except Exception as e:
|
||||
logger.error(f"设置版本号失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_version(cls) -> str:
|
||||
"""
|
||||
获取当前版本号
|
||||
|
||||
|
||||
返回:
|
||||
str: 当前版本号
|
||||
"""
|
||||
if cls._current_version:
|
||||
return cls._current_version
|
||||
|
||||
|
||||
# 尝试从环境变量获取
|
||||
env_version = os.getenv("HFC_PERFORMANCE_VERSION")
|
||||
if env_version:
|
||||
if cls.set_version(env_version):
|
||||
return cls._current_version
|
||||
|
||||
|
||||
# 返回默认版本号
|
||||
return cls.DEFAULT_VERSION
|
||||
|
||||
|
||||
@classmethod
|
||||
def auto_generate_version(cls, base_version: str = None) -> str:
|
||||
"""
|
||||
自动生成版本号(基于时间戳)
|
||||
|
||||
|
||||
参数:
|
||||
base_version: 基础版本号,如果不提供则使用默认版本
|
||||
|
||||
|
||||
返回:
|
||||
str: 生成的版本号
|
||||
"""
|
||||
if not base_version:
|
||||
base_version = cls.DEFAULT_VERSION
|
||||
|
||||
|
||||
# 提取基础版本号的主要部分
|
||||
base_match = re.match(r'v?(\d+\.\d+)', base_version)
|
||||
base_match = re.match(r"v?(\d+\.\d+)", base_version)
|
||||
if base_match:
|
||||
base_part = base_match.group(1)
|
||||
else:
|
||||
base_part = "1.0"
|
||||
|
||||
|
||||
# 添加时间戳
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
|
||||
generated_version = f"v{base_part}.{timestamp}"
|
||||
|
||||
|
||||
cls.set_version(generated_version)
|
||||
logger.info(f"自动生成版本号: {generated_version}")
|
||||
|
||||
|
||||
return generated_version
|
||||
|
||||
|
||||
@classmethod
|
||||
def _validate_version(cls, version: str) -> Optional[str]:
|
||||
"""
|
||||
验证版本号格式
|
||||
|
||||
|
||||
参数:
|
||||
version: 待验证的版本号
|
||||
|
||||
|
||||
返回:
|
||||
Optional[str]: 验证后的版本号,失败返回None
|
||||
"""
|
||||
if not version or not isinstance(version, str):
|
||||
return None
|
||||
|
||||
|
||||
version = version.strip()
|
||||
|
||||
|
||||
# 支持的格式:
|
||||
# v1.0.0, 1.0.0, v1.0, 1.0, v1.0.0.20241222_1530 等
|
||||
patterns = [
|
||||
r'^v?(\d+\.\d+\.\d+)$', # v1.0.0 或 1.0.0
|
||||
r'^v?(\d+\.\d+)$', # v1.0 或 1.0
|
||||
r'^v?(\d+\.\d+\.\d+\.\w+)$', # v1.0.0.build 或 1.0.0.build
|
||||
r'^v?(\d+\.\d+\.\w+)$', # v1.0.build 或 1.0.build
|
||||
r"^v?(\d+\.\d+\.\d+)$", # v1.0.0 或 1.0.0
|
||||
r"^v?(\d+\.\d+)$", # v1.0 或 1.0
|
||||
r"^v?(\d+\.\d+\.\d+\.\w+)$", # v1.0.0.build 或 1.0.0.build
|
||||
r"^v?(\d+\.\d+\.\w+)$", # v1.0.build 或 1.0.build
|
||||
]
|
||||
|
||||
|
||||
for pattern in patterns:
|
||||
match = re.match(pattern, version)
|
||||
if match:
|
||||
# 确保版本号以v开头
|
||||
if not version.startswith('v'):
|
||||
version = 'v' + version
|
||||
if not version.startswith("v"):
|
||||
version = "v" + version
|
||||
return version
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@classmethod
|
||||
def reset_version(cls):
|
||||
"""重置版本号为默认值"""
|
||||
cls._current_version = None
|
||||
logger.info("HFC版本号已重置为默认值")
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_version_info(cls) -> dict:
|
||||
"""
|
||||
获取版本信息
|
||||
|
||||
|
||||
返回:
|
||||
dict: 版本相关信息
|
||||
"""
|
||||
@@ -154,7 +154,7 @@ class HFCVersionManager:
|
||||
"default_version": cls.DEFAULT_VERSION,
|
||||
"is_custom": current != cls.DEFAULT_VERSION,
|
||||
"env_version": os.getenv("HFC_PERFORMANCE_VERSION"),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
@@ -182,4 +182,4 @@ def reset_hfc_version():
|
||||
# 在模块加载时显示当前版本信息
|
||||
if __name__ != "__main__":
|
||||
current_version = HFCVersionManager.get_version()
|
||||
logger.debug(f"HFC性能记录模块已加载,当前版本: {current_version}")
|
||||
logger.debug(f"HFC性能记录模块已加载,当前版本: {current_version}")
|
||||
|
||||
@@ -345,6 +345,7 @@ class ChatManager:
|
||||
async def load_all_streams(self):
|
||||
"""从数据库加载所有聊天流"""
|
||||
logger.info("正在从数据库加载所有聊天流")
|
||||
|
||||
def _db_load_all_streams_sync():
|
||||
loaded_streams_data = []
|
||||
for model_instance in ChatStreams.select():
|
||||
|
||||
@@ -197,36 +197,30 @@ class StatisticOutputTask(AsyncTask):
|
||||
logger.info("\n" + "\n".join(output))
|
||||
|
||||
async def run(self):
|
||||
try:
|
||||
try:
|
||||
now = datetime.now()
|
||||
|
||||
|
||||
# 使用线程池并行执行耗时操作
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
# 在线程池中并行执行数据收集和之前的HTML生成(如果存在)
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
logger.info("正在收集统计数据...")
|
||||
|
||||
|
||||
# 数据收集任务
|
||||
collect_task = loop.run_in_executor(
|
||||
executor, self._collect_all_statistics, now
|
||||
)
|
||||
|
||||
collect_task = loop.run_in_executor(executor, self._collect_all_statistics, now)
|
||||
|
||||
# 等待数据收集完成
|
||||
stats = await collect_task
|
||||
logger.info("统计数据收集完成")
|
||||
|
||||
|
||||
# 并行执行控制台输出和HTML报告生成
|
||||
console_task = loop.run_in_executor(
|
||||
executor, self._statistic_console_output, stats, now
|
||||
)
|
||||
html_task = loop.run_in_executor(
|
||||
executor, self._generate_html_report, stats, now
|
||||
)
|
||||
|
||||
console_task = loop.run_in_executor(executor, self._statistic_console_output, stats, now)
|
||||
html_task = loop.run_in_executor(executor, self._generate_html_report, stats, now)
|
||||
|
||||
# 等待两个输出任务完成
|
||||
await asyncio.gather(console_task, html_task)
|
||||
|
||||
|
||||
logger.info("统计数据输出完成")
|
||||
except Exception as e:
|
||||
logger.exception(f"输出统计数据过程中发生异常,错误信息:{e}")
|
||||
@@ -236,41 +230,38 @@ class StatisticOutputTask(AsyncTask):
|
||||
备选方案:完全异步后台运行统计输出
|
||||
使用此方法可以让统计任务完全非阻塞
|
||||
"""
|
||||
|
||||
async def _async_collect_and_output():
|
||||
try:
|
||||
import concurrent.futures
|
||||
|
||||
|
||||
now = datetime.now()
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
logger.info("正在后台收集统计数据...")
|
||||
|
||||
|
||||
# 创建后台任务,不等待完成
|
||||
collect_task = asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._collect_all_statistics, now)
|
||||
)
|
||||
|
||||
|
||||
stats = await collect_task
|
||||
logger.info("统计数据收集完成")
|
||||
|
||||
|
||||
# 创建并发的输出任务
|
||||
output_tasks = [
|
||||
asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._statistic_console_output, stats, now)
|
||||
),
|
||||
asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._generate_html_report, stats, now)
|
||||
)
|
||||
asyncio.create_task(loop.run_in_executor(executor, self._statistic_console_output, stats, now)),
|
||||
asyncio.create_task(loop.run_in_executor(executor, self._generate_html_report, stats, now)),
|
||||
]
|
||||
|
||||
|
||||
# 等待所有输出任务完成
|
||||
await asyncio.gather(*output_tasks)
|
||||
|
||||
|
||||
logger.info("统计数据后台输出完成")
|
||||
except Exception as e:
|
||||
logger.exception(f"后台统计数据输出过程中发生异常:{e}")
|
||||
|
||||
|
||||
# 创建后台任务,立即返回
|
||||
asyncio.create_task(_async_collect_and_output())
|
||||
|
||||
@@ -1619,7 +1610,7 @@ class AsyncStatisticOutputTask(AsyncTask):
|
||||
def __init__(self, record_file_path: str = "maibot_statistics.html"):
|
||||
# 延迟0秒启动,运行间隔300秒
|
||||
super().__init__(task_name="Async Statistics Data Output Task", wait_before_start=0, run_interval=300)
|
||||
|
||||
|
||||
# 直接复用 StatisticOutputTask 的初始化逻辑
|
||||
temp_stat_task = StatisticOutputTask(record_file_path)
|
||||
self.name_mapping = temp_stat_task.name_mapping
|
||||
@@ -1628,49 +1619,46 @@ class AsyncStatisticOutputTask(AsyncTask):
|
||||
|
||||
async def run(self):
|
||||
"""完全异步执行统计任务"""
|
||||
|
||||
async def _async_collect_and_output():
|
||||
try:
|
||||
now = datetime.now()
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
logger.info("正在后台收集统计数据...")
|
||||
|
||||
|
||||
# 数据收集任务
|
||||
collect_task = asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._collect_all_statistics, now)
|
||||
)
|
||||
|
||||
|
||||
stats = await collect_task
|
||||
logger.info("统计数据收集完成")
|
||||
|
||||
|
||||
# 创建并发的输出任务
|
||||
output_tasks = [
|
||||
asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._statistic_console_output, stats, now)
|
||||
),
|
||||
asyncio.create_task(
|
||||
loop.run_in_executor(executor, self._generate_html_report, stats, now)
|
||||
)
|
||||
asyncio.create_task(loop.run_in_executor(executor, self._statistic_console_output, stats, now)),
|
||||
asyncio.create_task(loop.run_in_executor(executor, self._generate_html_report, stats, now)),
|
||||
]
|
||||
|
||||
|
||||
# 等待所有输出任务完成
|
||||
await asyncio.gather(*output_tasks)
|
||||
|
||||
|
||||
logger.info("统计数据后台输出完成")
|
||||
except Exception as e:
|
||||
logger.exception(f"后台统计数据输出过程中发生异常:{e}")
|
||||
|
||||
|
||||
# 创建后台任务,立即返回
|
||||
asyncio.create_task(_async_collect_and_output())
|
||||
|
||||
# 复用 StatisticOutputTask 的所有方法
|
||||
def _collect_all_statistics(self, now: datetime):
|
||||
return StatisticOutputTask._collect_all_statistics(self, now)
|
||||
|
||||
|
||||
def _statistic_console_output(self, stats: Dict[str, Any], now: datetime):
|
||||
return StatisticOutputTask._statistic_console_output(self, stats, now)
|
||||
|
||||
|
||||
def _generate_html_report(self, stats: dict[str, Any], now: datetime):
|
||||
return StatisticOutputTask._generate_html_report(self, stats, now)
|
||||
|
||||
@@ -1678,11 +1666,11 @@ class AsyncStatisticOutputTask(AsyncTask):
|
||||
@staticmethod
|
||||
def _collect_model_request_for_period(collect_period: List[Tuple[str, datetime]]) -> Dict[str, Any]:
|
||||
return StatisticOutputTask._collect_model_request_for_period(collect_period)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@staticmethod
|
||||
def _collect_online_time_for_period(collect_period: List[Tuple[str, datetime]], now: datetime) -> Dict[str, Any]:
|
||||
return StatisticOutputTask._collect_online_time_for_period(collect_period, now)
|
||||
|
||||
|
||||
def _collect_message_count_for_period(self, collect_period: List[Tuple[str, datetime]]) -> Dict[str, Any]:
|
||||
return StatisticOutputTask._collect_message_count_for_period(self, collect_period)
|
||||
|
||||
@@ -1699,13 +1687,13 @@ class AsyncStatisticOutputTask(AsyncTask):
|
||||
|
||||
def _format_chat_stat(self, stats: Dict[str, Any]) -> str:
|
||||
return StatisticOutputTask._format_chat_stat(self, stats)
|
||||
|
||||
|
||||
def _generate_chart_data(self, stat: dict[str, Any]) -> dict:
|
||||
return StatisticOutputTask._generate_chart_data(self, stat)
|
||||
|
||||
|
||||
def _collect_interval_data(self, now: datetime, hours: int, interval_minutes: int) -> dict:
|
||||
return StatisticOutputTask._collect_interval_data(self, now, hours, interval_minutes)
|
||||
|
||||
|
||||
def _generate_chart_tab(self, chart_data: dict) -> str:
|
||||
return StatisticOutputTask._generate_chart_tab(self, chart_data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user