nonebot-plugin-group-heat 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-group-heat
3
+ Version: 0.1.0
4
+ Summary: 群热度统计插件 - 实时查询群内热度,生成昨日热度折线图
5
+ Author-email: Wojusensei <3442006415@qq.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Wojusensei/nonebot-plugin-group-heat
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: nonebot2>=2.3.0
12
+ Requires-Dist: nonebot-adapter-onebot>=2.0.0
13
+ Requires-Dist: nonebot-plugin-localstore>=0.5.0
14
+ Requires-Dist: matplotlib>=3.5.0
15
+ Requires-Dist: numpy>=1.21.0
16
+
17
+ # nonebot-plugin-group-heat
18
+
19
+ 群热度统计插件 for NoneBot2
20
+
21
+ ## 功能
22
+
23
+ - `/群热度` - 获取过去30分钟的群热度值,附带 bot 评价
24
+ - `/昨日热度图` - 生成昨日每30分钟的热度折线图,并显示平均热度
25
+
26
+ ## 热度计算规则
27
+
28
+ | 消息类型 | 热度值 |
29
+ |---------|--------|
30
+ | 文本消息 | +0.05 |
31
+ | 表情包 | +0.20 |
32
+ | 文件(图片/视频/语音等) | +0.30 |
33
+ | 其他消息 | 不计入 |
34
+
35
+ - 每个统计周期的初始热度为 -10°
36
+
37
+ ## 评价机制
38
+
39
+ | 热度范围 | 评价 |
40
+ |---------|------|
41
+ | < 0 | 群成冰块啦,群主快开暖气 |
42
+ | 0 ~ 10 | 是冬天到了吗,好冷www |
43
+ | 10 ~ 20 | 温度非常舒适,大家继续努力~ |
44
+ | 20 ~ 30 | 群热度达到最佳状态! |
45
+ | 30 ~ 39 | 好热,群主快开空调! |
46
+ | ≥ 39 | 请发送高温补贴喵。。 |
47
+
48
+ ## 安装
49
+
50
+ ```bash
51
+ nb plugin install nonebot-plugin-group-heat
52
+ pip install nonebot-plugin-group-heat(也可以)
53
+
54
+ ## 使用
55
+ 在群聊中发送以下命令:
56
+
57
+ /群热度 - 查询过去30分钟的群热度
58
+
59
+ /昨日热度图 - 获取昨日热度折线图
60
+
61
+ ## 开源协议
62
+ MIT
@@ -0,0 +1,46 @@
1
+ # nonebot-plugin-group-heat
2
+
3
+ 群热度统计插件 for NoneBot2
4
+
5
+ ## 功能
6
+
7
+ - `/群热度` - 获取过去30分钟的群热度值,附带 bot 评价
8
+ - `/昨日热度图` - 生成昨日每30分钟的热度折线图,并显示平均热度
9
+
10
+ ## 热度计算规则
11
+
12
+ | 消息类型 | 热度值 |
13
+ |---------|--------|
14
+ | 文本消息 | +0.05 |
15
+ | 表情包 | +0.20 |
16
+ | 文件(图片/视频/语音等) | +0.30 |
17
+ | 其他消息 | 不计入 |
18
+
19
+ - 每个统计周期的初始热度为 -10°
20
+
21
+ ## 评价机制
22
+
23
+ | 热度范围 | 评价 |
24
+ |---------|------|
25
+ | < 0 | 群成冰块啦,群主快开暖气 |
26
+ | 0 ~ 10 | 是冬天到了吗,好冷www |
27
+ | 10 ~ 20 | 温度非常舒适,大家继续努力~ |
28
+ | 20 ~ 30 | 群热度达到最佳状态! |
29
+ | 30 ~ 39 | 好热,群主快开空调! |
30
+ | ≥ 39 | 请发送高温补贴喵。。 |
31
+
32
+ ## 安装
33
+
34
+ ```bash
35
+ nb plugin install nonebot-plugin-group-heat
36
+ pip install nonebot-plugin-group-heat(也可以)
37
+
38
+ ## 使用
39
+ 在群聊中发送以下命令:
40
+
41
+ /群热度 - 查询过去30分钟的群热度
42
+
43
+ /昨日热度图 - 获取昨日热度折线图
44
+
45
+ ## 开源协议
46
+ MIT
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "nonebot-plugin-group-heat"
7
+ version = "0.1.0"
8
+ description = "群热度统计插件 - 实时查询群内热度,生成昨日热度折线图"
9
+ authors = [{name = "Wojusensei", email = "3442006415@qq.com"}]
10
+ readme = "README.md"
11
+ license = {text = "MIT"}
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ ]
15
+ dependencies = [
16
+ "nonebot2>=2.3.0",
17
+ "nonebot-adapter-onebot>=2.0.0",
18
+ "nonebot-plugin-localstore>=0.5.0",
19
+ "matplotlib>=3.5.0",
20
+ "numpy>=1.21.0",
21
+ ]
22
+ requires-python = ">=3.9"
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/Wojusensei/nonebot-plugin-group-heat"
26
+
27
+ [tool.setuptools]
28
+ packages = ["nonebot_plugin_group_heat"]
29
+ package-dir = {"" = "src"}
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,128 @@
1
+ from nonebot.plugin import PluginMetadata
2
+ from nonebot.adapters.onebot.v11 import Event, Bot, MessageSegment
3
+ from nonebot.adapters.onebot.v11.event import GroupMessageEvent
4
+ from .config import Config
5
+
6
+
7
+ __plugin_meta__ = PluginMetadata(
8
+ name="群热度统计",
9
+ description="统计群内热度,支持实时查询和昨日热度图",
10
+ usage=(
11
+ "/群热度 - 获取过去30分钟的群热度\n"
12
+ "/昨日热度图 - 获取昨日每30分钟的热度折线图和平均热度"
13
+ ),
14
+ type="application",
15
+ homepage="https://github.com/Wojusensei/nonebot-plugin-group-heat",
16
+ config=Config,
17
+ supported_adapters={"~onebot.v11"},
18
+ )
19
+
20
+
21
+ # 延迟导入其他需要 NoneBot 初始化的模块
22
+ _imported = False
23
+
24
+
25
+ def _import_all():
26
+ global _imported
27
+ if _imported:
28
+ return
29
+ global re, datetime, on_command, on_message, get_driver, CommandArg, logger
30
+ global init_db, add_message, get_recent_heat, get_yesterday_heat
31
+ global draw_heat_line, get_heat_comment
32
+
33
+ import re
34
+ from datetime import datetime
35
+ from nonebot import on_command, on_message, get_driver
36
+ from nonebot.params import CommandArg
37
+ from nonebot.log import logger
38
+
39
+ from .database import init_db, add_message, get_recent_heat, get_yesterday_heat
40
+ from .heat_image import draw_heat_line, get_heat_comment
41
+
42
+ _imported = True
43
+
44
+
45
+ async def get_message_type(event: Event) -> str:
46
+ msg = event.get_message()
47
+ for seg in msg:
48
+ if seg.type == "text":
49
+ return "text"
50
+ elif seg.type == "face":
51
+ return "sticker"
52
+ elif seg.type in ["file", "image", "record", "video"]:
53
+ return "file"
54
+ return "other"
55
+
56
+
57
+ try:
58
+ _import_all()
59
+ driver = get_driver()
60
+
61
+ @driver.on_startup
62
+ async def startup():
63
+ await init_db()
64
+ logger.info("群热度插件数据库初始化完成")
65
+ except ValueError:
66
+ pass
67
+
68
+
69
+ try:
70
+ _import_all()
71
+ msg_recorder = on_message(priority=1, block=False)
72
+
73
+ @msg_recorder.handle()
74
+ async def record_message(bot: Bot, event: Event):
75
+ if not isinstance(event, GroupMessageEvent):
76
+ return
77
+ group_id = event.group_id
78
+ user_id = event.user_id
79
+ msg_type = await get_message_type(event)
80
+ timestamp = datetime.now().timestamp()
81
+ await add_message(group_id, user_id, msg_type, timestamp)
82
+ except ValueError:
83
+ pass
84
+
85
+
86
+ try:
87
+ _import_all()
88
+ heat_cmd = on_command("/群热度", aliases={"群热度"}, priority=10, block=True)
89
+
90
+ @heat_cmd.handle()
91
+ async def handle_heat(event: Event):
92
+ if not isinstance(event, GroupMessageEvent):
93
+ await heat_cmd.finish("该命令仅支持群聊")
94
+ group_id = event.group_id
95
+ try:
96
+ heat = await get_recent_heat(group_id, minutes=30)
97
+ comment = get_heat_comment(heat)
98
+ await heat_cmd.finish(f"过去30分钟的群热度:{heat:.2f}°\n{comment}")
99
+ except Exception as e:
100
+ logger.error(f"获取群热度失败: {e}")
101
+ await heat_cmd.finish("获取热度失败,请稍后再试")
102
+ except ValueError:
103
+ pass
104
+
105
+
106
+ try:
107
+ _import_all()
108
+ yesterday_cmd = on_command("/昨日热度图", aliases={"昨日热度图"}, priority=10, block=True)
109
+
110
+ @yesterday_cmd.handle()
111
+ async def handle_yesterday(event: Event):
112
+ if not isinstance(event, GroupMessageEvent):
113
+ await yesterday_cmd.finish("该命令仅支持群聊")
114
+ group_id = event.group_id
115
+ try:
116
+ heat_values, time_labels, avg_heat = await get_yesterday_heat(group_id)
117
+ if not heat_values:
118
+ await yesterday_cmd.finish("暂无昨日数据,请明天再来~")
119
+ img_path = draw_heat_line(heat_values, time_labels, avg_heat)
120
+ comment = get_heat_comment(avg_heat)
121
+ msg = f"昨日群平均热度:{avg_heat:.2f}°\n{comment}"
122
+ await yesterday_cmd.send(MessageSegment.image(img_path))
123
+ await yesterday_cmd.finish(msg)
124
+ except Exception as e:
125
+ logger.error(f"生成昨日热度图失败: {e}")
126
+ await yesterday_cmd.finish("生成热度图失败,请稍后再试")
127
+ except ValueError:
128
+ pass
@@ -0,0 +1,7 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Config(BaseModel):
5
+ """Plugin Config"""
6
+ # 无需配置,即装即用
7
+ pass
@@ -0,0 +1,116 @@
1
+ import sqlite3
2
+ import asyncio
3
+ from pathlib import Path
4
+ from datetime import datetime, timedelta
5
+ from typing import List, Tuple
6
+
7
+
8
+ def get_data_dir():
9
+ from nonebot_plugin_localstore import get_data_dir as _get_data_dir
10
+ return _get_data_dir("nonebot_plugin_group_heat")
11
+
12
+
13
+ def get_db_path():
14
+ data_dir = get_data_dir()
15
+ data_dir.mkdir(parents=True, exist_ok=True)
16
+ return data_dir / "heat.db"
17
+
18
+
19
+ async def init_db():
20
+ def _init():
21
+ conn = sqlite3.connect(str(get_db_path()))
22
+ c = conn.cursor()
23
+ c.execute('''
24
+ CREATE TABLE IF NOT EXISTS messages (
25
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ group_id INTEGER NOT NULL,
27
+ user_id INTEGER NOT NULL,
28
+ msg_type TEXT NOT NULL,
29
+ timestamp REAL NOT NULL
30
+ )
31
+ ''')
32
+ c.execute('CREATE INDEX IF NOT EXISTS idx_group_time ON messages (group_id, timestamp)')
33
+ conn.commit()
34
+ conn.close()
35
+ await asyncio.get_event_loop().run_in_executor(None, _init)
36
+
37
+
38
+ async def add_message(group_id: int, user_id: int, msg_type: str, timestamp: float):
39
+ def _add():
40
+ conn = sqlite3.connect(str(get_db_path()))
41
+ c = conn.cursor()
42
+ c.execute(
43
+ "INSERT INTO messages (group_id, user_id, msg_type, timestamp) VALUES (?, ?, ?, ?)",
44
+ (group_id, user_id, msg_type, timestamp)
45
+ )
46
+ conn.commit()
47
+ conn.close()
48
+ await asyncio.get_event_loop().run_in_executor(None, _add)
49
+
50
+
51
+ async def get_recent_heat(group_id: int, minutes: int = 30) -> float:
52
+ now = datetime.now().timestamp()
53
+ start = now - minutes * 60
54
+
55
+ def _calc():
56
+ conn = sqlite3.connect(str(get_db_path()))
57
+ c = conn.cursor()
58
+ c.execute('SELECT msg_type FROM messages WHERE group_id = ? AND timestamp >= ?', (group_id, start))
59
+ rows = c.fetchall()
60
+ conn.close()
61
+ heat = -10.0
62
+ for row in rows:
63
+ msg_type = row[0]
64
+ if msg_type == 'text':
65
+ heat += 0.05
66
+ elif msg_type == 'sticker':
67
+ heat += 0.2
68
+ elif msg_type == 'file':
69
+ heat += 0.3
70
+ return heat
71
+ return await asyncio.get_event_loop().run_in_executor(None, _calc)
72
+
73
+
74
+ async def get_yesterday_heat(group_id: int) -> Tuple[List[float], List[str], float]:
75
+ now = datetime.now()
76
+ yesterday_start = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=1)
77
+ yesterday_end = yesterday_start + timedelta(days=1)
78
+
79
+ intervals = []
80
+ current = yesterday_start
81
+ while current < yesterday_end:
82
+ intervals.append(current)
83
+ current += timedelta(minutes=30)
84
+
85
+ heat_values = []
86
+ time_labels = []
87
+
88
+ for interval_start in intervals:
89
+ interval_end = interval_start + timedelta(minutes=30)
90
+ start_ts = interval_start.timestamp()
91
+ end_ts = interval_end.timestamp()
92
+
93
+ def _calc_interval():
94
+ conn = sqlite3.connect(str(get_db_path()))
95
+ c = conn.cursor()
96
+ c.execute('SELECT msg_type FROM messages WHERE group_id = ? AND timestamp >= ? AND timestamp < ?',
97
+ (group_id, start_ts, end_ts))
98
+ rows = c.fetchall()
99
+ conn.close()
100
+ heat = -10.0
101
+ for row in rows:
102
+ t = row[0]
103
+ if t == 'text':
104
+ heat += 0.05
105
+ elif t == 'sticker':
106
+ heat += 0.2
107
+ elif t == 'file':
108
+ heat += 0.3
109
+ return heat
110
+
111
+ heat = await asyncio.get_event_loop().run_in_executor(None, _calc_interval)
112
+ heat_values.append(heat)
113
+ time_labels.append(interval_start.strftime("%H:%M"))
114
+
115
+ avg_heat = sum(heat_values) / len(heat_values) if heat_values else -10.0
116
+ return heat_values, time_labels, avg_heat
@@ -0,0 +1,58 @@
1
+ import matplotlib
2
+ matplotlib.use('Agg')
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+
9
+ def get_cache_dir():
10
+ from nonebot_plugin_localstore import get_cache_dir as _get_cache_dir
11
+ cache_dir = _get_cache_dir("nonebot_plugin_group_heat")
12
+ cache_dir.mkdir(parents=True, exist_ok=True)
13
+ return cache_dir
14
+
15
+
16
+ def draw_heat_line(heat_values: List[float], time_labels: List[str], avg_heat: float) -> Path:
17
+ plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']
18
+ plt.rcParams['axes.unicode_minus'] = False
19
+
20
+ fig, ax = plt.subplots(figsize=(14, 6))
21
+ x = np.arange(len(heat_values))
22
+
23
+ ax.plot(x, heat_values, marker='o', linestyle='-', color='#FF6B6B', linewidth=2, markersize=6)
24
+ ax.fill_between(x, heat_values, -10, alpha=0.2, color='orange')
25
+ ax.axhline(y=avg_heat, color='blue', linestyle='--', linewidth=1.5, label=f'平均热度: {avg_heat:.2f}')
26
+
27
+ ax.set_xlabel('时间 (每30分钟)', fontsize=12)
28
+ ax.set_ylabel('热度值', fontsize=12)
29
+ ax.set_title('昨日群热度变化趋势图', fontsize=14, fontweight='bold')
30
+
31
+ tick_step = max(1, len(time_labels) // 12)
32
+ ax.set_xticks(x[::tick_step])
33
+ ax.set_xticklabels(time_labels[::tick_step], rotation=45, ha='right', fontsize=8)
34
+
35
+ ax.grid(True, alpha=0.3)
36
+ ax.legend(loc='upper right')
37
+ plt.tight_layout()
38
+
39
+ img_path = get_cache_dir() / "yesterday_heat.png"
40
+ plt.savefig(img_path, dpi=100, bbox_inches='tight')
41
+ plt.close(fig)
42
+
43
+ return img_path
44
+
45
+
46
+ def get_heat_comment(heat: float) -> str:
47
+ if heat < 0:
48
+ return "群成冰块啦,群主快开暖气"
49
+ elif heat < 10:
50
+ return "是冬天到了吗,好冷www"
51
+ elif heat < 20:
52
+ return "温度非常舒适,大家继续努力~"
53
+ elif heat < 30:
54
+ return "群热度达到最佳状态!"
55
+ elif heat < 39:
56
+ return "好热,群主快开空调!"
57
+ else:
58
+ return "请发送高温补贴喵。。"
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-group-heat
3
+ Version: 0.1.0
4
+ Summary: 群热度统计插件 - 实时查询群内热度,生成昨日热度折线图
5
+ Author-email: Wojusensei <3442006415@qq.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Wojusensei/nonebot-plugin-group-heat
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: nonebot2>=2.3.0
12
+ Requires-Dist: nonebot-adapter-onebot>=2.0.0
13
+ Requires-Dist: nonebot-plugin-localstore>=0.5.0
14
+ Requires-Dist: matplotlib>=3.5.0
15
+ Requires-Dist: numpy>=1.21.0
16
+
17
+ # nonebot-plugin-group-heat
18
+
19
+ 群热度统计插件 for NoneBot2
20
+
21
+ ## 功能
22
+
23
+ - `/群热度` - 获取过去30分钟的群热度值,附带 bot 评价
24
+ - `/昨日热度图` - 生成昨日每30分钟的热度折线图,并显示平均热度
25
+
26
+ ## 热度计算规则
27
+
28
+ | 消息类型 | 热度值 |
29
+ |---------|--------|
30
+ | 文本消息 | +0.05 |
31
+ | 表情包 | +0.20 |
32
+ | 文件(图片/视频/语音等) | +0.30 |
33
+ | 其他消息 | 不计入 |
34
+
35
+ - 每个统计周期的初始热度为 -10°
36
+
37
+ ## 评价机制
38
+
39
+ | 热度范围 | 评价 |
40
+ |---------|------|
41
+ | < 0 | 群成冰块啦,群主快开暖气 |
42
+ | 0 ~ 10 | 是冬天到了吗,好冷www |
43
+ | 10 ~ 20 | 温度非常舒适,大家继续努力~ |
44
+ | 20 ~ 30 | 群热度达到最佳状态! |
45
+ | 30 ~ 39 | 好热,群主快开空调! |
46
+ | ≥ 39 | 请发送高温补贴喵。。 |
47
+
48
+ ## 安装
49
+
50
+ ```bash
51
+ nb plugin install nonebot-plugin-group-heat
52
+ pip install nonebot-plugin-group-heat(也可以)
53
+
54
+ ## 使用
55
+ 在群聊中发送以下命令:
56
+
57
+ /群热度 - 查询过去30分钟的群热度
58
+
59
+ /昨日热度图 - 获取昨日热度折线图
60
+
61
+ ## 开源协议
62
+ MIT
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/nonebot_plugin_group_heat/__init__.py
4
+ src/nonebot_plugin_group_heat/config.py
5
+ src/nonebot_plugin_group_heat/database.py
6
+ src/nonebot_plugin_group_heat/heat_image.py
7
+ src/nonebot_plugin_group_heat.egg-info/PKG-INFO
8
+ src/nonebot_plugin_group_heat.egg-info/SOURCES.txt
9
+ src/nonebot_plugin_group_heat.egg-info/dependency_links.txt
10
+ src/nonebot_plugin_group_heat.egg-info/requires.txt
11
+ src/nonebot_plugin_group_heat.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ nonebot2>=2.3.0
2
+ nonebot-adapter-onebot>=2.0.0
3
+ nonebot-plugin-localstore>=0.5.0
4
+ matplotlib>=3.5.0
5
+ numpy>=1.21.0