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):
+ 按模块分类统计
+
+
+ | 模块名称 | 调用次数 | 输入Token | 输出Token | Token总量 | 累计花费 |
+
+
+ {module_rows}
+
+
+
按请求类型分类统计
@@ -581,16 +613,6 @@ class StatisticOutputTask(AsyncTask):
- 按用户分类统计
-
-
- | 用户名称 | 调用次数 | 输入Token | 输出Token | Token总量 | 累计花费 |
-
-
- {user_rows}
-
-
-
聊天消息统计
@@ -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", # 橙黄色