Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"type": "function",
"function": {
"name": "analyze_join_statistics",
"description": "分析群的加群情况,提供加群人数统计和趋势分析。包含:按时间筛选成员、人数统计、加群趋势分析、可选的成员列表。",
"parameters": {
"type": "object",
"properties": {
"group_id": {
"type": "integer",
"description": "群号。如果已在群聊中,通常会自动获取。"
},
"start_time": {
"type": "string",
"description": "开始时间,格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-01 00:00:00"
},
"end_time": {
"type": "string",
"description": "结束时间,格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-10 23:59:59"
},
"include_trend": {
"type": "boolean",
"description": "是否包含趋势分析,默认 true",
"default": true
},
"include_member_list": {
"type": "boolean",
"description": "是否返回成员列表,默认 false",
"default": false
},
"member_limit": {
"type": "integer",
"description": "返回成员列表的数量限制(最大100),默认 20",
"default": 20
}
},
"required": []
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
"""加群统计分析工具"""

import logging
from typing import Any, Dict
from datetime import datetime

from Undefined.utils.time_utils import parse_time_range, format_datetime
from Undefined.utils.member_utils import filter_by_join_time, analyze_join_trend

logger = logging.getLogger(__name__)


async def execute(args: Dict[str, Any], context: Dict[str, Any]) -> str:
"""分析群的加群情况"""
request_id = str(context.get("request_id", "-"))
group_id = args.get("group_id") or context.get("group_id")
start_time = args.get("start_time")
end_time = args.get("end_time")
include_trend = args.get("include_trend", True)
include_member_list = args.get("include_member_list", False)

# 1. 参数验证
if not group_id:
return "请提供群号(group_id 参数),或者在群聊中调用"

try:
group_id = int(group_id)
except (ValueError, TypeError):
return "参数类型错误:group_id 必须是整数"

# 验证和规范化数值参数
try:
member_limit_raw = args.get("member_limit", 20)
member_limit = int(member_limit_raw) if member_limit_raw is not None else 20
if member_limit < 0:
return "参数错误:member_limit 必须是非负整数"
member_limit = min(member_limit, 100)
except (ValueError, TypeError):
return "参数类型错误:member_limit 必须是整数"

# 2. 解析时间范围
start_dt, end_dt = parse_time_range(start_time, end_time)

# 验证时间格式
if start_time and start_dt is None:
return "开始时间格式错误,请使用格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-01 00:00:00"
if end_time and end_dt is None:
return "结束时间格式错误,请使用格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-10 23:59:59"

onebot_client = context.get("onebot_client")
if not onebot_client:
return "加群统计功能不可用(OneBot 客户端未设置)"

try:
# 3. 获取群成员列表
logger.info(f"开始获取群 {group_id} 的成员列表")
member_list = await onebot_client.get_group_member_list(group_id)
logger.info(f"获取到 {len(member_list)} 个成员")

if not member_list:
return f"群 {group_id} 没有成员数据"

# 4. 按加群时间筛选
filtered_members = filter_by_join_time(member_list, start_dt, end_dt)

if not filtered_members:
time_range_str = ""
if start_dt or end_dt:
time_range_str = f"在时间范围 {format_datetime(start_dt)} ~ {format_datetime(end_dt)} 内"
return f"{time_range_str}没有成员加群"

# 5. 格式化返回
result_parts = ["【加群统计分析】"]
result_parts.append(f"群号: {group_id}")

if start_dt or end_dt:
result_parts.append(
f"时间范围: {format_datetime(start_dt)} ~ {format_datetime(end_dt)}"
)

result_parts.append("")
result_parts.append("━━━━━━━━━━━━")
result_parts.append("📊 加群统计")
result_parts.append(f"总人数: {len(filtered_members)} 人")

# 找出首次和最后加群时间
join_times = []
for member in filtered_members:
join_time = member.get("join_time")
if join_time:
try:
if isinstance(join_time, (int, float)):
join_dt = datetime.fromtimestamp(join_time)
join_times.append(join_dt)
except (ValueError, OSError, OverflowError):
pass

if join_times:
first_join = min(join_times)
last_join = max(join_times)
result_parts.append(f"首次加群: {first_join.strftime('%Y-%m-%d %H:%M:%S')}")
result_parts.append(f"最后加群: {last_join.strftime('%Y-%m-%d %H:%M:%S')}")

# 6. 可选:趋势分析
if include_trend:
trend_stats = analyze_join_trend(filtered_members)
if trend_stats:
result_parts.append("")
result_parts.append("━━━━━━━━━━━━")
result_parts.append("📈 加群趋势")
result_parts.append(
f" • 平均每天: {trend_stats.get('avg_per_day', 0)} 人"
)

peak_date = trend_stats.get("peak_date")
peak_count = trend_stats.get("peak_count", 0)
if peak_date:
result_parts.append(
f" • 加群高峰日: {peak_date} ({peak_count} 人)"
)

daily_stats = trend_stats.get("daily_stats", {})
if daily_stats:
result_parts.append("")
result_parts.append("每日加群人数:")
# 按日期排序
sorted_dates = sorted(daily_stats.items())
for date_str, count in sorted_dates:
# 使用简单的条形图
bar = "█" * min(count, 20)
result_parts.append(f" {date_str}: {bar} {count} 人")

# 7. 可选:成员列表
if include_member_list:
result_parts.append("")
result_parts.append(
f"新成员列表 (显示前 {min(member_limit, len(filtered_members))} 人)"
)

# 按加群时间排序
sorted_members = sorted(
filtered_members, key=lambda m: m.get("join_time", 0)
)

for i, member in enumerate(sorted_members[:member_limit], 1):
nickname = member.get("card") or member.get("nickname", "未知")
user_id = member.get("user_id", 0)
join_time = member.get("join_time")
join_time_str = ""
if join_time:
try:
if isinstance(join_time, (int, float)):
join_dt = datetime.fromtimestamp(join_time)
join_time_str = join_dt.strftime("%Y-%m-%d %H:%M:%S")
except (ValueError, OSError, OverflowError):
pass

result_parts.append(
f"{i}. {nickname} ({user_id}) - 加群: {join_time_str}"
)

return "\n".join(result_parts)

except Exception as e:
logger.exception(
"分析加群统计失败: group=%s request_id=%s err=%s",
group_id,
request_id,
e,
)
return f"分析失败:{str(e)}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"type": "function",
"function": {
"name": "analyze_member_messages",
"description": "分析指定群成员的消息情况,提供全面的消息统计和活跃度分析。包含:消息数量统计、消息类型分布、活跃时段分析、可选的消息内容获取。",
"parameters": {
"type": "object",
"properties": {
"group_id": {
"type": "integer",
"description": "群号。如果已在群聊中,通常会自动获取。"
},
"user_id": {
"type": "integer",
"description": "要分析的成员QQ号"
},
"start_time": {
"type": "string",
"description": "开始时间,格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-01 00:00:00"
},
"end_time": {
"type": "string",
"description": "结束时间,格式:YYYY-MM-DD HH:MM:SS,例如:2024-02-10 23:59:59"
},
"include_messages": {
"type": "boolean",
"description": "是否返回具体消息内容,默认 false",
"default": false
},
"message_limit": {
"type": "integer",
"description": "返回消息内容的数量限制(最大100),默认 20",
"default": 20
},
"max_history_count": {
"type": "integer",
"description": "最多获取的历史消息数量(最大5000),默认 2000",
"default": 2000
}
},
"required": [
"user_id"
]
}
}
}
Loading