From 0dd3e21c79c0f6b56b80374ce56d49cab886a830 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Tue, 14 Oct 2025 12:18:07 +0800 Subject: [PATCH] Update statistic.py --- src/chat/utils/statistic.py | 68 ++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/src/chat/utils/statistic.py b/src/chat/utils/statistic.py index 97ef1cc0..2c4dd619 100644 --- a/src/chat/utils/statistic.py +++ b/src/chat/utils/statistic.py @@ -492,10 +492,15 @@ class StatisticOutputTask(AsyncTask): continue # Update name_mapping - if chat_id in self.name_mapping: - if chat_name != self.name_mapping[chat_id][0] and message_time_ts > self.name_mapping[chat_id][1]: + try: + if chat_id in self.name_mapping: + if chat_name != self.name_mapping[chat_id][0] and message_time_ts > self.name_mapping[chat_id][1]: + self.name_mapping[chat_id] = (chat_name, message_time_ts) + else: self.name_mapping[chat_id] = (chat_name, message_time_ts) - else: + except (IndexError, TypeError) as e: + logger.warning(f"更新 name_mapping 时发生错误,chat_id: {chat_id}, 错误: {e}") + # 重置为正确的格式 self.name_mapping[chat_id] = (chat_name, message_time_ts) for idx, (_, period_start_dt) in enumerate(collect_period): @@ -518,7 +523,21 @@ class StatisticOutputTask(AsyncTask): # 如果存在上次完整统计数据,则使用该数据进行增量统计 last_stat: Dict[str, Any] = local_storage["last_full_statistics"] # 上次完整统计数据 # type: ignore - self.name_mapping = last_stat["name_mapping"] # 上次完整统计数据的名称映射 + # 修复 name_mapping 数据类型不匹配问题 + # JSON 中存储为列表,但代码期望为元组 + raw_name_mapping = last_stat["name_mapping"] + self.name_mapping = {} + for chat_id, value in raw_name_mapping.items(): + if isinstance(value, list) and len(value) == 2: + # 将列表转换为元组 + self.name_mapping[chat_id] = (value[0], value[1]) + elif isinstance(value, tuple) and len(value) == 2: + # 已经是元组,直接使用 + self.name_mapping[chat_id] = value + else: + # 数据格式不正确,跳过或使用默认值 + logger.warning(f"name_mapping 中 chat_id {chat_id} 的数据格式不正确: {value}") + continue last_all_time_stat = last_stat["stat_data"] # 上次完整统计的统计数据 last_stat_timestamp = datetime.fromtimestamp(last_stat["timestamp"]) # 上次完整统计数据的时间戳 self.stat_period = [item for item in self.stat_period if item[0] != "all_time"] # 删除"所有时间"的统计时段 @@ -571,8 +590,14 @@ class StatisticOutputTask(AsyncTask): # 更新上次完整统计数据的时间戳 # 将所有defaultdict转换为普通dict以避免类型冲突 clean_stat_data = self._convert_defaultdict_to_dict(stat["all_time"]) + + # 将 name_mapping 中的元组转换为列表,因为JSON不支持元组 + json_safe_name_mapping = {} + for chat_id, (chat_name, timestamp) in self.name_mapping.items(): + json_safe_name_mapping[chat_id] = [chat_name, timestamp] + local_storage["last_full_statistics"] = { - "name_mapping": self.name_mapping, + "name_mapping": json_safe_name_mapping, "stat_data": clean_stat_data, "timestamp": now.timestamp(), } @@ -651,10 +676,13 @@ class StatisticOutputTask(AsyncTask): if stats[TOTAL_MSG_CNT] <= 0: return "" output = ["聊天消息统计:", " 联系人/群组名称 消息数量"] - output.extend( - f"{self.name_mapping[chat_id][0][:32]:<32} {count:>10}" - for chat_id, count in sorted(stats[MSG_CNT_BY_CHAT].items()) - ) + for chat_id, count in sorted(stats[MSG_CNT_BY_CHAT].items()): + try: + chat_name = self.name_mapping.get(chat_id, ("未知聊天", 0))[0] + output.append(f"{chat_name[:32]:<32} {count:>10}") + except (IndexError, TypeError) as e: + logger.warning(f"格式化聊天统计时发生错误,chat_id: {chat_id}, 错误: {e}") + output.append(f"{'未知聊天':<32} {count:>10}") output.append("") return "\n".join(output) @@ -770,14 +798,16 @@ class StatisticOutputTask(AsyncTask): ) # 聊天消息统计 - chat_rows = "\n".join( - [ - f"{self.name_mapping[chat_id][0]}{count}" - for chat_id, count in sorted(stat_data[MSG_CNT_BY_CHAT].items()) - ] - if stat_data[MSG_CNT_BY_CHAT] - else ["暂无数据"] - ) + chat_rows = [] + for chat_id, count in sorted(stat_data[MSG_CNT_BY_CHAT].items()): + try: + chat_name = self.name_mapping.get(chat_id, ("未知聊天", 0))[0] + chat_rows.append(f"{chat_name}{count}") + except (IndexError, TypeError) as e: + logger.warning(f"生成HTML聊天统计时发生错误,chat_id: {chat_id}, 错误: {e}") + chat_rows.append(f"未知聊天{count}") + + chat_rows_html = "\n".join(chat_rows) if chat_rows else "暂无数据" # 生成HTML return f"""
@@ -824,7 +854,7 @@ class StatisticOutputTask(AsyncTask): 联系人/群组名称消息数量 - {chat_rows} + {chat_rows_html} @@ -975,7 +1005,7 @@ class StatisticOutputTask(AsyncTask): }} // 聊天消息分布饼图 - const chatLabels = {[self.name_mapping[chat_id][0] for chat_id in sorted(stat_data[MSG_CNT_BY_CHAT].keys())] if stat_data[MSG_CNT_BY_CHAT] else []}; + const chatLabels = {[self.name_mapping.get(chat_id, ("未知聊天", 0))[0] for chat_id in sorted(stat_data[MSG_CNT_BY_CHAT].keys())] if stat_data[MSG_CNT_BY_CHAT] else []}; if (chatLabels.length > 0) {{ const chatData = {{ labels: chatLabels,