feat(message_summary): add group overview stats section

This commit is contained in:
liuwei
2026-04-13 09:18:44 +08:00
parent 0e3eda8865
commit 0f0acc1729
3 changed files with 95 additions and 3 deletions

View File

@@ -557,3 +557,37 @@ class MessageStorageDB(BaseDBOperator):
group_id)
result = self.execute_query(sql, params)
return result[0]['count'] if result else 0
def get_message_stats_by_date_range(self, group_id: str, start_time: datetime, end_time: datetime) -> Dict:
"""统计指定时间范围内的群消息概览"""
sql = """
SELECT
COUNT(*) AS total_count,
COUNT(DISTINCT sender) AS participant_count,
SUM(CASE WHEN message_type = 1 THEN 1 ELSE 0 END) AS text_count,
SUM(CASE WHEN message_type = 3 THEN 1 ELSE 0 END) AS image_count,
SUM(CASE WHEN message_type IN (43, 62) THEN 1 ELSE 0 END) AS video_count,
SUM(CASE WHEN message_type = 49 THEN 1 ELSE 0 END) AS link_count,
SUM(CASE WHEN message_type IN (47, 1048625, 1090519089) THEN 1 ELSE 0 END) AS emoji_count
FROM messages
WHERE timestamp >= %s
AND timestamp <= %s
AND group_id = %s
AND sender IS NOT NULL
AND sender <> ''
"""
params = (
start_time.strftime('%Y-%m-%d %H:%M:%S'),
end_time.strftime('%Y-%m-%d %H:%M:%S'),
group_id,
)
result = self.execute_query(sql, params, fetch_one=True) or {}
return {
"total_count": int(result.get("total_count") or 0),
"participant_count": int(result.get("participant_count") or 0),
"text_count": int(result.get("text_count") or 0),
"image_count": int(result.get("image_count") or 0),
"video_count": int(result.get("video_count") or 0),
"link_count": int(result.get("link_count") or 0),
"emoji_count": int(result.get("emoji_count") or 0),
}

View File

@@ -160,6 +160,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
return False, None
period_start, period_end = self._resolve_manual_summary_range(custom_date)
message_count = self.message_storage.count_messages_by_date_range(group_id, period_start, period_end)
message_stats = self.message_storage.get_message_stats_by_date_range(group_id, period_start, period_end)
if message_count < 100:
await self.bot.send_text_message(
group_id,
@@ -191,6 +192,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
period_start=period_start,
period_end=period_end,
message_count=message_count,
message_stats=message_stats,
)
if res:
return True, "异步总结已启动"
@@ -210,11 +212,12 @@ class MessageSummaryPlugin(MessagePluginInterface):
period_start: Optional[datetime] = None,
period_end: Optional[datetime] = None,
message_count: Optional[int] = None,
message_stats: Optional[Dict[str, int]] = None,
):
"""异步生成并发送总结"""
try:
# 生成总结
summary, image_path = await self._generate_summary(chat_content, group_name)
summary, image_path = await self._generate_summary(chat_content, group_name, message_stats=message_stats)
if image_path:
# 图片生成成功,发送图片
@@ -449,7 +452,12 @@ class MessageSummaryPlugin(MessagePluginInterface):
self.LOG.error(f"群总结入库失败: group_id={group_id}, period_key={summary_record['period_key']}")
return saved
async def _generate_summary(self, chat_content: str, group_name: str) -> Tuple[str, Optional[str]]:
async def _generate_summary(
self,
chat_content: str,
group_name: str,
message_stats: Optional[Dict[str, int]] = None,
) -> Tuple[str, Optional[str]]:
"""生成总结"""
content_compress = chat_content
try:
@@ -483,6 +491,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
answer = self._clean_summary_output(response.get("text", ""))
metadata = {"usage": response.get("usage", {}) or {}}
spath = ""
answer = self._prepend_stats_section(answer, message_stats or {})
answer = self._append_usage_info(answer, metadata)
if answer and len(answer.strip()) > 0:
@@ -513,6 +522,25 @@ class MessageSummaryPlugin(MessagePluginInterface):
return "生成总结时出错", None
@staticmethod
def _prepend_stats_section(summary: str, message_stats: Dict[str, int]) -> str:
stats = message_stats or {}
if not summary or not summary.strip():
return summary
section_lines = [
"## 群概览",
f"- 总统计条目数:{int(stats.get('total_count') or 0)}",
f"- 参与人数:{int(stats.get('participant_count') or 0)}",
f"- 文本消息:{int(stats.get('text_count') or 0)}",
f"- 图片消息:{int(stats.get('image_count') or 0)}",
f"- 视频消息:{int(stats.get('video_count') or 0)}",
f"- 链接消息:{int(stats.get('link_count') or 0)}",
f"- 表情消息:{int(stats.get('emoji_count') or 0)}",
]
section = "\n".join(section_lines)
return f"{section}\n\n{summary.strip()}"
async def daily_summary_job(self):
"""定时任务每天早上9点总结昨天的聊天信息"""
try:
@@ -561,6 +589,11 @@ class MessageSummaryPlugin(MessagePluginInterface):
continue
self.LOG.info(f"{group_id} 昨天有 {message_count} 条消息,开始获取内容")
message_stats = self.message_storage.get_message_stats_by_date_range(
group_id,
yesterday_start,
yesterday_end,
)
# 获取群成员信息
group_members = ContactManager.get_instance().get_group_members(group_id)
@@ -592,7 +625,11 @@ class MessageSummaryPlugin(MessagePluginInterface):
)
# 生成总结
summary, image_path = await self._generate_summary(chat_content, group_name)
summary, image_path = await self._generate_summary(
chat_content,
group_name,
message_stats=message_stats,
)
if image_path:
# 图片生成成功,发送图片

View File

@@ -551,6 +551,27 @@ class MessageStorage:
logger.error(f"统计消息数量出错: {e}")
return 0
def get_message_stats_by_date_range(self, group_id, start_time: datetime, end_time: datetime) -> Dict:
"""获取指定时间范围内的群消息概览统计"""
try:
stats = self.message_db.get_message_stats_by_date_range(group_id, start_time, end_time)
logger.info(
f"{group_id}{start_time}{end_time} 的消息概览: "
f"total={stats.get('total_count', 0)}, participants={stats.get('participant_count', 0)}"
)
return stats
except Exception as e:
logger.error(f"获取消息概览统计出错: {e}")
return {
"total_count": 0,
"participant_count": 0,
"text_count": 0,
"image_count": 0,
"video_count": 0,
"link_count": 0,
"emoji_count": 0,
}
def _format_messages_optimized(self, messages: list, all_contacts: dict) -> str:
"""优化的消息格式化方法,减少冗余