From 222d4114fcbe130bca408af663d4e5e488d39753 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sun, 15 Jun 2025 20:34:37 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=8F=90=E4=BE=9B=E6=9B=B4?= =?UTF-8?q?=E5=A4=9A=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/normal_chat/normal_chat.py | 8 +- src/chat/normal_chat/normal_chat_planner.py | 2 +- src/chat/utils/statistic.py | 421 +++++++++++++++++++- src/common/logger.py | 2 +- 4 files changed, 408 insertions(+), 25 deletions(-) diff --git a/src/chat/normal_chat/normal_chat.py b/src/chat/normal_chat/normal_chat.py index 0ae9385f0..95e89aa72 100644 --- a/src/chat/normal_chat/normal_chat.py +++ b/src/chat/normal_chat/normal_chat.py @@ -811,10 +811,10 @@ class NormalChat: # 检查是否满足关系构建条件 should_build_relation = ( - total_messages >= 50 # 50条消息必定满足 - or (total_messages >= 35 and time_elapsed >= 600) # 35条且10分钟 - or (total_messages >= 25 and time_elapsed >= 1800) # 25条且30分钟 - or (total_messages >= 10 and time_elapsed >= 3600) # 10条且1小时 + total_messages >= 40 # 40条消息必定满足 + or (total_messages >= 25 and time_elapsed >= 600) # 25条且10分钟 + or (total_messages >= 20 and time_elapsed >= 900) # 20条且30分钟 + or (total_messages >= 10 and time_elapsed >= 1800) # 10条且1小时 ) if should_build_relation: diff --git a/src/chat/normal_chat/normal_chat_planner.py b/src/chat/normal_chat/normal_chat_planner.py index 581dcd82f..f1610981d 100644 --- a/src/chat/normal_chat/normal_chat_planner.py +++ b/src/chat/normal_chat/normal_chat_planner.py @@ -67,7 +67,7 @@ class NormalChatPlanner: # LLM规划器配置 self.planner_llm = LLMRequest( model=global_config.model.planner, - request_type="normal_chat.planner", # 用于normal_chat动作规划 + request_type="normal.planner", # 用于normal_chat动作规划 ) self.action_manager = action_manager diff --git a/src/chat/utils/statistic.py b/src/chat/utils/statistic.py index 567ec24cc..458605ecd 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -7,7 +7,7 @@ from src.common.logger import get_logger from src.manager.async_task_manager import AsyncTask from ...common.database.database import db # This db is the Peewee database instance -from ...common.database.database_model import OnlineTime, LLMUsage, Messages # Import the Peewee model +from ...common.database.database_model import OnlineTime, LLMUsage, Messages, ChatStreams # Import the Peewee model from src.manager.local_store_manager import local_storage logger = get_logger("maibot_statistic") @@ -18,18 +18,23 @@ TOTAL_COST = "total_cost" REQ_CNT_BY_TYPE = "requests_by_type" REQ_CNT_BY_USER = "requests_by_user" REQ_CNT_BY_MODEL = "requests_by_model" +REQ_CNT_BY_MODULE = "requests_by_module" IN_TOK_BY_TYPE = "in_tokens_by_type" IN_TOK_BY_USER = "in_tokens_by_user" IN_TOK_BY_MODEL = "in_tokens_by_model" +IN_TOK_BY_MODULE = "in_tokens_by_module" OUT_TOK_BY_TYPE = "out_tokens_by_type" OUT_TOK_BY_USER = "out_tokens_by_user" OUT_TOK_BY_MODEL = "out_tokens_by_model" +OUT_TOK_BY_MODULE = "out_tokens_by_module" TOTAL_TOK_BY_TYPE = "tokens_by_type" TOTAL_TOK_BY_USER = "tokens_by_user" TOTAL_TOK_BY_MODEL = "tokens_by_model" +TOTAL_TOK_BY_MODULE = "tokens_by_module" COST_BY_TYPE = "costs_by_type" COST_BY_USER = "costs_by_user" COST_BY_MODEL = "costs_by_model" +COST_BY_MODULE = "costs_by_module" ONLINE_TIME = "online_time" TOTAL_MSG_CNT = "total_messages" MSG_CNT_BY_CHAT = "messages_by_chat" @@ -149,6 +154,7 @@ class StatisticOutputTask(AsyncTask): ("all_time", now - deploy_time, "自部署以来"), # 必须保留"all_time" ("last_7_days", timedelta(days=7), "最近7天"), ("last_24_hours", timedelta(days=1), "最近24小时"), + ("last_3_hours", timedelta(hours=3), "最近3小时"), ("last_hour", timedelta(hours=1), "最近1小时"), ] """ @@ -212,19 +218,24 @@ class StatisticOutputTask(AsyncTask): REQ_CNT_BY_TYPE: defaultdict(int), REQ_CNT_BY_USER: defaultdict(int), REQ_CNT_BY_MODEL: defaultdict(int), + REQ_CNT_BY_MODULE: defaultdict(int), IN_TOK_BY_TYPE: defaultdict(int), IN_TOK_BY_USER: defaultdict(int), IN_TOK_BY_MODEL: defaultdict(int), + IN_TOK_BY_MODULE: defaultdict(int), OUT_TOK_BY_TYPE: defaultdict(int), OUT_TOK_BY_USER: defaultdict(int), OUT_TOK_BY_MODEL: defaultdict(int), + OUT_TOK_BY_MODULE: defaultdict(int), TOTAL_TOK_BY_TYPE: defaultdict(int), TOTAL_TOK_BY_USER: defaultdict(int), TOTAL_TOK_BY_MODEL: defaultdict(int), + TOTAL_TOK_BY_MODULE: defaultdict(int), TOTAL_COST: 0.0, COST_BY_TYPE: defaultdict(float), COST_BY_USER: defaultdict(float), COST_BY_MODEL: defaultdict(float), + COST_BY_MODULE: defaultdict(float), } for period_key, _ in collect_period } @@ -242,10 +253,14 @@ class StatisticOutputTask(AsyncTask): request_type = record.request_type or "unknown" user_id = record.user_id or "unknown" # user_id is TextField, already string model_name = record.model_name or "unknown" + + # 提取模块名:如果请求类型包含".",取第一个"."之前的部分 + module_name = request_type.split('.')[0] if '.' in request_type else request_type stats[period_key][REQ_CNT_BY_TYPE][request_type] += 1 stats[period_key][REQ_CNT_BY_USER][user_id] += 1 stats[period_key][REQ_CNT_BY_MODEL][model_name] += 1 + stats[period_key][REQ_CNT_BY_MODULE][module_name] += 1 prompt_tokens = record.prompt_tokens or 0 completion_tokens = record.completion_tokens or 0 @@ -254,20 +269,24 @@ class StatisticOutputTask(AsyncTask): stats[period_key][IN_TOK_BY_TYPE][request_type] += prompt_tokens stats[period_key][IN_TOK_BY_USER][user_id] += prompt_tokens stats[period_key][IN_TOK_BY_MODEL][model_name] += prompt_tokens + stats[period_key][IN_TOK_BY_MODULE][module_name] += prompt_tokens stats[period_key][OUT_TOK_BY_TYPE][request_type] += completion_tokens stats[period_key][OUT_TOK_BY_USER][user_id] += completion_tokens stats[period_key][OUT_TOK_BY_MODEL][model_name] += completion_tokens + stats[period_key][OUT_TOK_BY_MODULE][module_name] += completion_tokens stats[period_key][TOTAL_TOK_BY_TYPE][request_type] += total_tokens stats[period_key][TOTAL_TOK_BY_USER][user_id] += total_tokens stats[period_key][TOTAL_TOK_BY_MODEL][model_name] += total_tokens + stats[period_key][TOTAL_TOK_BY_MODULE][module_name] += total_tokens cost = record.cost or 0.0 stats[period_key][TOTAL_COST] += cost stats[period_key][COST_BY_TYPE][request_type] += cost stats[period_key][COST_BY_USER][user_id] += cost stats[period_key][COST_BY_MODEL][model_name] += cost + stats[period_key][COST_BY_MODULE][module_name] += cost break return stats @@ -492,6 +511,8 @@ class StatisticOutputTask(AsyncTask): f'' for period in self.stat_period ] + # 添加图表选项卡 + tab_list.append('') def _format_stat_data(stat_data: dict[str, Any], div_id: str, start_time: datetime) -> str: """ @@ -530,20 +551,21 @@ class StatisticOutputTask(AsyncTask): for req_type, count in sorted(stat_data[REQ_CNT_BY_TYPE].items()) ] ) - # 按用户分类统计 - user_rows = "\n".join( + # 按模块分类统计 + module_rows = "\n".join( [ f"" - f"{user_id}" + f"{module_name}" f"{count}" - f"{stat_data[IN_TOK_BY_USER][user_id]}" - f"{stat_data[OUT_TOK_BY_USER][user_id]}" - f"{stat_data[TOTAL_TOK_BY_USER][user_id]}" - f"{stat_data[COST_BY_USER][user_id]:.4f} ¥" + f"{stat_data[IN_TOK_BY_MODULE][module_name]}" + f"{stat_data[OUT_TOK_BY_MODULE][module_name]}" + f"{stat_data[TOTAL_TOK_BY_MODULE][module_name]}" + f"{stat_data[COST_BY_MODULE][module_name]:.4f} ¥" f"" - for user_id, count in sorted(stat_data[REQ_CNT_BY_USER].items()) + for module_name, count in sorted(stat_data[REQ_CNT_BY_MODULE].items()) ] ) + # 聊天消息统计 chat_rows = "\n".join( [ @@ -571,6 +593,16 @@ class StatisticOutputTask(AsyncTask): +

按模块分类统计

+ + + + + + {module_rows} + +
模块名称调用次数输入Token输出TokenToken总量累计花费
+

按请求类型分类统计

@@ -581,16 +613,6 @@ class StatisticOutputTask(AsyncTask):
-

按用户分类统计

- - - - - - {user_rows} - -
用户名称调用次数输入Token输出TokenToken总量累计花费
-

聊天消息统计

@@ -613,6 +635,10 @@ class StatisticOutputTask(AsyncTask): _format_stat_data(stat["all_time"], "all_time", datetime.fromtimestamp(local_storage["deploy_time"])) ) + # 添加图表内容 + chart_data = self._generate_chart_data(stat) + tab_content_list.append(self._generate_chart_tab(chart_data)) + joined_tab_list = "\n".join(tab_list) joined_tab_content = "\n".join(tab_content_list) @@ -624,6 +650,7 @@ class StatisticOutputTask(AsyncTask): MaiBot运行统计报告 + + + + + ''' diff --git a/src/common/logger.py b/src/common/logger.py index 794423bdb..4b9d9132e 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -326,7 +326,7 @@ MODULE_COLORS = { "working_memory": "\033[38;5;22m", # 深绿色 "memory_activator": "\033[38;5;28m", # 绿色 # 插件系统 - "plugin_manager": "\033[38;5;196m", # 红色 + "plugin_manager": "\033[38;5;208m", # 红色 "base_plugin": "\033[38;5;202m", # 橙红色 "base_command": "\033[38;5;208m", # 橙色 "component_registry": "\033[38;5;214m", # 橙黄色