nonebot-plugin-dialectlist 2.3.1__tar.gz → 2.4.1__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.
Files changed (21) hide show
  1. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/PKG-INFO +2 -8
  2. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/README.md +0 -6
  3. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/__init__.py +17 -19
  4. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/config.py +4 -4
  5. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/model.py +2 -7
  6. nonebot_plugin_dialectlist-2.4.1/nonebot_plugin_dialectlist/storage.py +130 -0
  7. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/utils.py +25 -19
  8. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist.egg-info/PKG-INFO +2 -8
  9. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist.egg-info/requires.txt +1 -1
  10. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/pyproject.toml +2 -2
  11. nonebot_plugin_dialectlist-2.3.1/nonebot_plugin_dialectlist/storage.py +0 -2
  12. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/MANIFEST.in +0 -0
  13. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/template/avatar/default.jpg +0 -0
  14. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/template/css/style.css +0 -0
  15. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/template/rank_template.j2 +0 -0
  16. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/time.py +0 -0
  17. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist/usage.py +0 -0
  18. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist.egg-info/SOURCES.txt +0 -0
  19. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist.egg-info/dependency_links.txt +0 -0
  20. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/nonebot_plugin_dialectlist.egg-info/top_level.txt +0 -0
  21. {nonebot_plugin_dialectlist-2.3.1 → nonebot_plugin_dialectlist-2.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-dialectlist
3
- Version: 2.3.1
3
+ Version: 2.4.1
4
4
  Summary: 看看你群群友有多能说
5
5
  Author-email: Chen_Xu233 <woyerpa@outlook.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Requires-Dist: nonebot-plugin-orm[default]
12
12
  Requires-Dist: nonebot-plugin-apscheduler>=0.4.0
13
13
  Requires-Dist: nonebot-plugin-alconna>=0.50.2
14
14
  Requires-Dist: nonebot-plugin-cesaa>=0.4.0
15
- Requires-Dist: nonebot-plugin-userinfo>=0.2.4
15
+ Requires-Dist: nonebot-plugin-userinfo>=0.2.6
16
16
  Requires-Dist: nonebot-plugin-htmlrender>=0.3.3
17
17
  Requires-Dist: nonebot2>=2.3.2
18
18
  Requires-Dist: pillow>=10.4.0
@@ -186,12 +186,6 @@ __!!注意!!__
186
186
 
187
187
  - [x] 私聊的查询(超级用户可以任意查询群聊的信息)一半完成
188
188
 
189
- - [ ] 提供多样化的渲染器配置(html 渲染,pillow 渲染,统计绘图软件渲染)
190
-
191
- - [ ] 使用管理员权限直接获取 QQ 官方统计的今日消息量以优化代码运行速度
192
-
193
- - [ ] 为 pillow 渲染方式提供插件的加载方式(什么?插件里的插件???)
194
-
195
189
  - [ ] 特殊的储存方案优化消息统计
196
190
 
197
191
  - [ ] 查询带某关键词的消息量
@@ -158,12 +158,6 @@ __!!注意!!__
158
158
 
159
159
  - [x] 私聊的查询(超级用户可以任意查询群聊的信息)一半完成
160
160
 
161
- - [ ] 提供多样化的渲染器配置(html 渲染,pillow 渲染,统计绘图软件渲染)
162
-
163
- - [ ] 使用管理员权限直接获取 QQ 官方统计的今日消息量以优化代码运行速度
164
-
165
- - [ ] 为 pillow 渲染方式提供插件的加载方式(什么?插件里的插件???)
166
-
167
161
  - [ ] 特殊的储存方案优化消息统计
168
162
 
169
163
  - [ ] 查询带某关键词的消息量
@@ -16,6 +16,7 @@ from datetime import datetime, timedelta
16
16
  from arclet.alconna import ArparmaBehavior
17
17
  from arclet.alconna.arparma import Arparma
18
18
 
19
+ from nonebot import on_command
19
20
  from nonebot.log import logger
20
21
  from nonebot.typing import T_State
21
22
  from nonebot.params import Arg, Depends
@@ -30,8 +31,7 @@ from nonebot_plugin_alconna import (
30
31
  from nonebot_plugin_chatrecorder import get_message_records
31
32
  from nonebot_plugin_session import Session, SessionIdType, extract_session
32
33
 
33
- # from . import migrations #抄词云的部分代码,还不知道这有什么用
34
- # from .function import *
34
+ from .storage import get_cache,build_cache
35
35
  from .config import Config, plugin_config
36
36
  from .usage import __usage__
37
37
  from .time import (
@@ -45,7 +45,6 @@ from .utils import (
45
45
  get_rank_image,
46
46
  persist_id2user_id,
47
47
  get_user_infos,
48
- # get_user_info2,
49
48
  )
50
49
 
51
50
  __plugin_meta__ = PluginMetadata(
@@ -58,7 +57,6 @@ __plugin_meta__ = PluginMetadata(
58
57
  "nonebot_plugin_chatrecorder", "nonebot_plugin_saa", "nonebot_plugin_alconna"
59
58
  ),
60
59
  config=Config,
61
- # extra={"orm_version_location": migrations},
62
60
  )
63
61
 
64
62
 
@@ -76,6 +74,13 @@ def wrapper(slot: Union[int, str], content: Optional[str], context) -> str:
76
74
  return content
77
75
  return "" # pragma: no cover
78
76
 
77
+ build_cache_cmd = on_command("build_cache", aliases={"重建缓存"}, block=True)
78
+
79
+ @build_cache_cmd.handle()
80
+ async def _build_cache(bot: Bot, event: Event):
81
+ await saa.Text("正在重建缓存,请稍等。").send(reply=True)
82
+ await build_cache()
83
+ await saa.Text("重建缓存完成。").send(reply=True)
79
84
 
80
85
  rank_cmd = on_alconna(
81
86
  Alconna(
@@ -187,8 +192,6 @@ async def _group_message(
187
192
  except ValueError:
188
193
  await rank_cmd.finish("请输入正确的日期,不然我没法理解呢!")
189
194
 
190
- logger.debug(f"命令解析花费时间:{t.time() - t1}")
191
-
192
195
 
193
196
  @rank_cmd.got(
194
197
  "start",
@@ -221,8 +224,11 @@ async def handle_rank(
221
224
  await saa.Text("没有指定群哦").finish()
222
225
 
223
226
  if plugin_config.counting_cache:
224
- raise Exception("我草缓存功能还没端上来呢,你怎么就先用上了")
227
+ t1 = t.time()
228
+ raw_rank = await get_cache(start, stop, id)
229
+ logger.debug(f"获取计数消息花费时间:{t.time() - t1}")
225
230
  else:
231
+ t1 = t.time()
226
232
  messages = await get_message_records(
227
233
  id2s=[id],
228
234
  id_type=SessionIdType.GROUP,
@@ -233,14 +239,13 @@ async def handle_rank(
233
239
  time_stop=stop,
234
240
  exclude_id1s=plugin_config.excluded_people,
235
241
  )
236
-
237
- if not messages:
238
- await saa.Text("明明这个时间段都没有人说话怎么会有话痨榜呢?").finish()
239
-
240
242
  raw_rank = msg_counter(messages)
243
+ logger.debug(f"获取计数消息花费时间:{t.time() - t1}")
244
+
245
+ if not raw_rank:
246
+ await saa.Text("明明这个时间段都没有人说话怎么会有话痨榜呢?").finish()
241
247
 
242
248
  rank = got_rank(raw_rank)
243
- logger.debug(rank)
244
249
  ids = await persist_id2user_id([int(i[0]) for i in rank])
245
250
  for i in range(len(rank)):
246
251
  rank[i][0] = str(ids[i])
@@ -276,10 +281,3 @@ async def handle_rank(
276
281
  logger.debug(f"群聊消息渲染图片花费时间:{t.time() - t1}")
277
282
 
278
283
  await msg.finish(reply=True)
279
-
280
-
281
- # @scheduler.scheduled_job(
282
- # "dialectlist", day="*/2", id="xxx", args=[1], kwargs={"arg2": 2}
283
- # )
284
- # async def __():
285
- # pass
@@ -6,12 +6,12 @@ from nonebot import get_driver, get_plugin_config
6
6
  class ScopedConfig(BaseModel):
7
7
  get_num: int = 5 # 获取人数数量
8
8
  font: str = "SimHei" # 字体格式
9
- suffix: bool = False # 是否显示后缀
10
- excluded_self: bool = True
9
+ suffix: bool = True # 是否显示后缀
10
+ excluded_self: bool = True # 是否排除自己
11
11
  visualization: bool = True # 是否可视化
12
- counting_cache: bool = False # 计数缓存(没有完工)
12
+ counting_cache: bool = False # 计数缓存(能够提高回复速度)
13
13
  excluded_people: List[str] = [] # 排除的人的QQ号
14
- timezone: Optional[str] = "Asia/Shanghai"
14
+ timezone: Optional[str] = "Asia/Shanghai" # 时区,影响统计时间
15
15
  string_suffix: str = "统计花费时间:{timecost}秒" # 消息格式后缀
16
16
  template_path: str = "./template/rank_template.j2" # 模板路径
17
17
  string_format: str = "第{index}名:\n{nickname},{chatdatanum}条消息\n" # 消息格式
@@ -14,14 +14,9 @@ class UserRankInfo(UserInfo):
14
14
  user_avatar_bytes: bytes
15
15
 
16
16
 
17
- # class MsgCountDayData(BaseModel):
18
- # session_id: str
19
- # session_bnum: int
20
-
21
-
22
17
  class MessageCountCache(Model):
23
18
  __table_args__ = {"extend_existing": True}
24
- id: Mapped[int] = mapped_column(primary_key=True)
19
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
25
20
  time: Mapped[datetime]
26
- session_id: Mapped[int] = mapped_column(Integer)
21
+ session_id: Mapped[int] = mapped_column(Integer, index=True)
27
22
  session_bnum: Mapped[int] = mapped_column(Integer)
@@ -0,0 +1,130 @@
1
+ import os
2
+ import json
3
+ from datetime import datetime
4
+ from sqlalchemy import delete, or_, select
5
+
6
+ from nonebot import get_driver
7
+ from nonebot.log import logger
8
+ from nonebot.params import Depends
9
+ from nonebot.adapters import Event,Bot
10
+ from nonebot.message import event_postprocessor
11
+
12
+ from .model import MessageCountCache
13
+ from .config import plugin_config
14
+
15
+ from nonebot_plugin_localstore import get_data_file
16
+ from nonebot_plugin_chatrecorder import get_message_records
17
+ from nonebot_plugin_chatrecorder.utils import remove_timezone
18
+ from nonebot_plugin_session import extract_session, Session
19
+ from nonebot_plugin_session_orm import SessionModel, get_session_persist_id
20
+ from nonebot_plugin_orm import get_session
21
+
22
+
23
+ async def get_cache(time_start: datetime, time_stop: datetime, group_id: str):
24
+ async with get_session() as db_session:
25
+ where = [or_(SessionModel.id2 == group_id)]
26
+ statement = select(SessionModel).where(*where)
27
+
28
+ sessions = (await db_session.scalars(statement)).all()
29
+
30
+ where = [
31
+ or_(*[MessageCountCache.session_id == session.id for session in sessions])
32
+ ]
33
+ statement = select(MessageCountCache).where(*where)
34
+ where.append(or_(MessageCountCache.time >= remove_timezone(time_start)))
35
+ where.append(or_(MessageCountCache.time <= remove_timezone(time_stop)))
36
+ statement = select(MessageCountCache).where(*where)
37
+
38
+ user_caches = (await db_session.scalars(statement)).all()
39
+ raw_rank = {}
40
+ for i in user_caches:
41
+ raw_rank[i.session_id] = raw_rank.get(i.session_id, 0) + i.session_bnum
42
+ return raw_rank
43
+
44
+
45
+ async def build_cache():
46
+ async with get_session() as db_session:
47
+ await db_session.execute(delete(MessageCountCache))
48
+ await db_session.commit()
49
+ logger.info("先前可能存在的缓存已清空")
50
+ messages = await get_message_records(types=["message"])
51
+ async with get_session() as db_session:
52
+ for msg in messages:
53
+ msg_session_id = msg.session_persist_id
54
+
55
+ where = [or_(MessageCountCache.session_id == msg_session_id)]
56
+ where.append(
57
+ or_(
58
+ MessageCountCache.time
59
+ == remove_timezone(msg.time.replace(hour=1, minute=0, second=0, microsecond=0))
60
+ )
61
+ )
62
+ statement = select(MessageCountCache).where(*where)
63
+
64
+ user_cache = (await db_session.scalars(statement)).all()
65
+
66
+ if user_cache:
67
+ user_cache[0].session_bnum += 1
68
+ else:
69
+ user_cache = MessageCountCache(
70
+ session_id=msg.session_persist_id,
71
+ time=remove_timezone(msg.time.replace(hour=1, minute=0, second=0, microsecond=0)),
72
+ session_bnum=1,
73
+ )
74
+ db_session.add(user_cache)
75
+ await db_session.commit()
76
+
77
+ logger.info("缓存构建完成")
78
+
79
+
80
+ driver = get_driver()
81
+
82
+
83
+ @driver.on_startup
84
+ async def _():
85
+ if not plugin_config.counting_cache:
86
+ return
87
+ f_name = get_data_file("nonebot-plugin-dialectlist", "is-pre-cached.json")
88
+ if not os.path.exists(f_name):
89
+ with open(f_name, "w", encoding="utf-8") as f:
90
+ s = json.dumps({"is-pre-cached": False}, ensure_ascii=False, indent=4)
91
+ f.write(s)
92
+
93
+ with open(f_name, "r", encoding="utf-8") as f:
94
+ if json.load(f)["is-pre-cached"]:
95
+ return
96
+ logger.info("未检查到缓存,开始构建缓存")
97
+ with open(f_name, "w", encoding="utf-8") as f:
98
+ await build_cache()
99
+ json.dump({"is-pre-cached": True}, f, ensure_ascii=False, indent=4)
100
+
101
+
102
+ @event_postprocessor
103
+ async def _(bot: Bot, event: Event,session: Session = Depends(extract_session)):
104
+ if not plugin_config.counting_cache:
105
+ return
106
+ if not session.id2:
107
+ return
108
+ if event.get_type() != "message":
109
+ return
110
+ now = datetime.now()
111
+ now = now.replace(hour=1, minute=0, second=0, microsecond=0)
112
+
113
+ async with get_session() as db_session:
114
+ session_id = await get_session_persist_id(session)
115
+ logger.debug("session_id:"+str(session_id))
116
+ where = [or_(MessageCountCache.session_id == session_id)]
117
+ where.append(or_(MessageCountCache.time == remove_timezone(now)))
118
+ statement = select(MessageCountCache).where(*where)
119
+ user_cache = (await db_session.scalars(statement)).first()
120
+ if user_cache:
121
+ user_cache.session_bnum += 1
122
+ else:
123
+ user_cache = MessageCountCache(
124
+ session_id=session_id,
125
+ time=remove_timezone(now),
126
+ session_bnum=1,
127
+ )
128
+ db_session.add(user_cache)
129
+ await db_session.commit()
130
+ logger.debug("已计入缓存")
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import httpx
2
3
  import asyncio
3
4
  import unicodedata
4
5
 
@@ -15,6 +16,7 @@ from nonebot.adapters import Bot, Event
15
16
  from nonebot_plugin_orm import get_session
16
17
  from nonebot_plugin_session import Session, SessionLevel, extract_session
17
18
  from nonebot_plugin_userinfo import get_user_info, UserInfo
19
+ from nonebot_plugin_userinfo.exception import NetworkError
18
20
  from nonebot_plugin_localstore import get_cache_dir
19
21
  from nonebot_plugin_htmlrender import template_to_pic
20
22
  from nonebot_plugin_session_orm import SessionModel
@@ -26,16 +28,6 @@ from .config import plugin_config
26
28
 
27
29
  cache_path = get_cache_dir("nonebot_plugin_dialectlist")
28
30
 
29
- # 暂时不做考虑
30
- # def admin_permission():
31
- # permission = SUPERUSER
32
- # with contextlib.suppress(ImportError):
33
- # from nonebot.adapters.onebot.v11.permission import GROUP_ADMIN, GROUP_OWNER
34
-
35
- # permission = permission | GROUP_ADMIN | GROUP_OWNER
36
-
37
- # return permission
38
-
39
31
 
40
32
  async def ensure_group(matcher: Matcher, session: Session = Depends(extract_session)):
41
33
  """确保在群组中使用"""
@@ -202,6 +194,19 @@ async def _get_user_default_avatar() -> bytes:
202
194
  ).read()
203
195
  return img
204
196
 
197
+ async def _get_user_avatar(user: UserInfo, client: httpx.AsyncClient) -> bytes:
198
+ if not user.user_avatar:
199
+ return await _get_user_default_avatar()
200
+ url = user.user_avatar.get_url()
201
+ for i in range(3):
202
+ try:
203
+ resp = await client.get(url, timeout=10)
204
+ resp.raise_for_status()
205
+ return resp.content
206
+ except Exception as e:
207
+ logger.warning(f"Error downloading {url}, retry {i}/3: {e}")
208
+ await asyncio.sleep(3)
209
+ raise NetworkError(f"{url} 下载失败!")
205
210
 
206
211
  def get_default_user_info() -> UserInfo:
207
212
  user_info = UserInfo(
@@ -210,7 +215,6 @@ def get_default_user_info() -> UserInfo:
210
215
  )
211
216
  return user_info
212
217
 
213
-
214
218
  async def get_user_infos(
215
219
  bot: Bot, event: Event, rank: List, use_cache: bool = True
216
220
  ) -> List[UserRankInfo]:
@@ -218,15 +222,17 @@ async def get_user_infos(
218
222
  user_ids = [i[0] for i in rank]
219
223
  pool = [get_user_info(bot, event, id, use_cache) for id in user_ids]
220
224
  user_infos = await asyncio.gather(*pool)
225
+
226
+ async with httpx.AsyncClient() as client:
227
+ pool = []
228
+ for i in user_infos:
229
+ if not i:
230
+ pool.append(_get_user_default_avatar())
231
+ continue
232
+ if i.user_avatar:
233
+ pool.append(_get_user_avatar(i, client))
234
+ user_avatars = await asyncio.gather(*pool)
221
235
 
222
- pool = []
223
- for i in user_infos:
224
- if not i:
225
- pool.append(_get_user_default_avatar())
226
- continue
227
- if i.user_avatar:
228
- pool.append(i.user_avatar.get_image())
229
- user_avatars = await asyncio.gather(*pool)
230
236
  for i in user_avatars:
231
237
  if not i:
232
238
  user_avatars[user_avatars.index(i)] = await _get_user_default_avatar()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-dialectlist
3
- Version: 2.3.1
3
+ Version: 2.4.1
4
4
  Summary: 看看你群群友有多能说
5
5
  Author-email: Chen_Xu233 <woyerpa@outlook.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Requires-Dist: nonebot-plugin-orm[default]
12
12
  Requires-Dist: nonebot-plugin-apscheduler>=0.4.0
13
13
  Requires-Dist: nonebot-plugin-alconna>=0.50.2
14
14
  Requires-Dist: nonebot-plugin-cesaa>=0.4.0
15
- Requires-Dist: nonebot-plugin-userinfo>=0.2.4
15
+ Requires-Dist: nonebot-plugin-userinfo>=0.2.6
16
16
  Requires-Dist: nonebot-plugin-htmlrender>=0.3.3
17
17
  Requires-Dist: nonebot2>=2.3.2
18
18
  Requires-Dist: pillow>=10.4.0
@@ -186,12 +186,6 @@ __!!注意!!__
186
186
 
187
187
  - [x] 私聊的查询(超级用户可以任意查询群聊的信息)一半完成
188
188
 
189
- - [ ] 提供多样化的渲染器配置(html 渲染,pillow 渲染,统计绘图软件渲染)
190
-
191
- - [ ] 使用管理员权限直接获取 QQ 官方统计的今日消息量以优化代码运行速度
192
-
193
- - [ ] 为 pillow 渲染方式提供插件的加载方式(什么?插件里的插件???)
194
-
195
189
  - [ ] 特殊的储存方案优化消息统计
196
190
 
197
191
  - [ ] 查询带某关键词的消息量
@@ -4,7 +4,7 @@ nonebot-plugin-orm[default]
4
4
  nonebot-plugin-apscheduler>=0.4.0
5
5
  nonebot-plugin-alconna>=0.50.2
6
6
  nonebot-plugin-cesaa>=0.4.0
7
- nonebot-plugin-userinfo>=0.2.4
7
+ nonebot-plugin-userinfo>=0.2.6
8
8
  nonebot-plugin-htmlrender>=0.3.3
9
9
  nonebot2>=2.3.2
10
10
  pillow>=10.4.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-dialectlist"
3
- version = "2.3.1"
3
+ version = "2.4.1"
4
4
  description = "看看你群群友有多能说"
5
5
  authors = [
6
6
  {name = "Chen_Xu233", email = "woyerpa@outlook.com"},
@@ -12,7 +12,7 @@ dependencies = [
12
12
  "nonebot-plugin-apscheduler>=0.4.0",
13
13
  "nonebot-plugin-alconna>=0.50.2",
14
14
  "nonebot-plugin-cesaa>=0.4.0",
15
- "nonebot-plugin-userinfo>=0.2.4",
15
+ "nonebot-plugin-userinfo>=0.2.6",
16
16
  "nonebot-plugin-htmlrender>=0.3.3",
17
17
  "nonebot2>=2.3.2",
18
18
  "pillow>=10.4.0",
@@ -1,2 +0,0 @@
1
- # TODO 使用计数缓存进行数据库查询优化,避免一次性查询过多消息导致内存爆炸。
2
- from nonebot_plugin_orm import Model