From 041ceb81d8bc4bdfe72a5c8d80f6438ba7905739 Mon Sep 17 00:00:00 2001 From: snowy Date: Sun, 12 May 2024 02:47:14 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20message=20=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- liteyuki/internal/message/npl.py | 41 ------- liteyuki/liteyuki_main/__init__.py | 2 +- liteyuki/liteyuki_main/core.py | 12 +-- liteyuki/liteyuki_main/dev_tools.py | 6 +- liteyuki/liteyuki_main/loader.py | 10 +- .../plugins/liteyuki_crt_utils/rt_guide.py | 2 +- liteyuki/plugins/liteyuki_eventpush.py | 6 +- liteyuki/plugins/liteyuki_markdowntest.py | 6 +- liteyuki/plugins/liteyuki_minigame/game.py | 2 +- .../plugins/liteyuki_minigame/minesweeper.py | 4 +- liteyuki/plugins/liteyuki_pacman/common.py | 6 +- liteyuki/plugins/liteyuki_pacman/npm.py | 14 +-- liteyuki/plugins/liteyuki_pacman/rpm.py | 8 +- liteyuki/plugins/liteyuki_sign_status.py | 14 +-- .../plugins/liteyuki_statistics/common.py | 2 +- .../plugins/liteyuki_statistics/stat_api.py | 68 ++++++++++-- .../liteyuki_statistics/stat_matchers.py | 60 +++++++---- .../liteyuki_statistics/stat_monitors.py | 4 +- liteyuki/plugins/liteyuki_status/api.py | 12 +-- liteyuki/plugins/liteyuki_status/status.py | 8 +- .../plugins/liteyuki_user/profile_manager.py | 10 +- liteyuki/plugins/liteyuki_weather/__init__.py | 2 +- liteyuki/plugins/liteyuki_weather/qw_api.py | 8 +- .../plugins/liteyuki_weather/qw_models.py | 2 +- liteyuki/plugins/liteyuki_weather/qweather.py | 12 +-- .../lagrange_sign/templates/js/sign_status.js | 2 +- .../liteyuki_statistics/lang/zh-CN.lang | 1 + .../liteyuki_statistics/metadata.yml | 3 + .../templates/css/stat_msg.css | 4 + .../templates/js/stat_msg.js | 54 ++++++++++ .../templates/stat_msg.html | 22 ++++ liteyuki/{internal => utils}/__init__.py | 6 +- liteyuki/{internal => utils}/base/__init__.py | 0 liteyuki/{internal => utils}/base/config.py | 0 liteyuki/{internal => utils}/base/data.py | 0 .../{internal => utils}/base/data_manager.py | 0 liteyuki/{internal => utils}/base/language.py | 0 liteyuki/{internal => utils}/base/log.py | 0 liteyuki/{internal => utils}/base/ly_api.py | 0 .../{internal => utils}/base/ly_typing.py | 0 .../{internal => utils}/base/permission.py | 0 liteyuki/{internal => utils}/base/reloader.py | 0 liteyuki/{internal => utils}/base/resource.py | 2 +- .../{internal => utils}/canvas/__init__.py | 0 .../{internal => utils}/message/__init__.py | 0 .../{internal => utils}/message/html_tool.py | 5 +- .../{internal => utils}/message/markdown.py | 0 .../{internal => utils}/message/message.py | 0 liteyuki/utils/message/npl.py | 101 ++++++++++++++++++ liteyuki/{internal => utils}/message/tools.py | 0 liteyuki/{internal => utils}/message/union.py | 0 main.py | 10 +- 52 files changed, 371 insertions(+), 160 deletions(-) delete mode 100644 liteyuki/internal/message/npl.py create mode 100644 liteyuki/resources/liteyuki_statistics/lang/zh-CN.lang create mode 100644 liteyuki/resources/liteyuki_statistics/metadata.yml create mode 100644 liteyuki/resources/liteyuki_statistics/templates/css/stat_msg.css create mode 100644 liteyuki/resources/liteyuki_statistics/templates/js/stat_msg.js create mode 100644 liteyuki/resources/liteyuki_statistics/templates/stat_msg.html rename liteyuki/{internal => utils}/__init__.py (92%) rename liteyuki/{internal => utils}/base/__init__.py (100%) rename liteyuki/{internal => utils}/base/config.py (100%) rename liteyuki/{internal => utils}/base/data.py (100%) rename liteyuki/{internal => utils}/base/data_manager.py (100%) rename liteyuki/{internal => utils}/base/language.py (100%) rename liteyuki/{internal => utils}/base/log.py (100%) rename liteyuki/{internal => utils}/base/ly_api.py (100%) rename liteyuki/{internal => utils}/base/ly_typing.py (100%) rename liteyuki/{internal => utils}/base/permission.py (100%) rename liteyuki/{internal => utils}/base/reloader.py (100%) rename liteyuki/{internal => utils}/base/resource.py (99%) rename liteyuki/{internal => utils}/canvas/__init__.py (100%) rename liteyuki/{internal => utils}/message/__init__.py (100%) rename liteyuki/{internal => utils}/message/html_tool.py (95%) rename liteyuki/{internal => utils}/message/markdown.py (100%) rename liteyuki/{internal => utils}/message/message.py (100%) create mode 100644 liteyuki/utils/message/npl.py rename liteyuki/{internal => utils}/message/tools.py (100%) rename liteyuki/{internal => utils}/message/union.py (100%) diff --git a/liteyuki/internal/message/npl.py b/liteyuki/internal/message/npl.py deleted file mode 100644 index ef08dba0..00000000 --- a/liteyuki/internal/message/npl.py +++ /dev/null @@ -1,41 +0,0 @@ -def convert_duration(text: str, default) -> float: - """ - 转换自然语言时间为秒数 - Args: - text: 1d2h3m - default: 出错时返回 - - Returns: - float: 总秒数 - """ - units = { - "d" : 86400, - "h" : 3600, - "m" : 60, - "s" : 1, - "ms": 0.001 - } - - duration = 0 - current_number = '' - current_unit = '' - try: - for char in text: - if char.isdigit(): - current_number += char - else: - if current_number: - duration += int(current_number) * units[current_unit] - current_number = '' - if char in units: - current_unit = char - else: - current_unit = '' - - if current_number: - duration += int(current_number) * units[current_unit] - - return duration - - except: - return default diff --git a/liteyuki/liteyuki_main/__init__.py b/liteyuki/liteyuki_main/__init__.py index 5d8b0f9f..9f04f2db 100644 --- a/liteyuki/liteyuki_main/__init__.py +++ b/liteyuki/liteyuki_main/__init__.py @@ -16,7 +16,7 @@ __plugin_meta__ = PluginMetadata( } ) -from ..internal.base.language import Language, get_default_lang_code +from ..utils.base.language import Language, get_default_lang_code print("\033[34m" + r""" __ ______ ________ ________ __ __ __ __ __ __ ______ diff --git a/liteyuki/liteyuki_main/core.py b/liteyuki/liteyuki_main/core.py index 32063861..d3875450 100644 --- a/liteyuki/liteyuki_main/core.py +++ b/liteyuki/liteyuki_main/core.py @@ -10,12 +10,12 @@ from nonebot.exception import MockApiException from nonebot.internal.matcher import Matcher from nonebot.permission import SUPERUSER -from liteyuki.internal.base.config import get_config, load_from_yaml -from liteyuki.internal.base.data_manager import StoredConfig, TempConfig, common_db -from liteyuki.internal.base.language import get_user_lang -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent -from liteyuki.internal.message.message import MarkdownMessage as md, broadcast_to_superusers -from liteyuki.internal.base.reloader import Reloader +from liteyuki.utils.base.config import get_config, load_from_yaml +from liteyuki.utils.base.data_manager import StoredConfig, TempConfig, common_db +from liteyuki.utils.base.language import get_user_lang +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent +from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_superusers +from liteyuki.utils.base.reloader import Reloader from .api import update_liteyuki require("nonebot_plugin_alconna") diff --git a/liteyuki/liteyuki_main/dev_tools.py b/liteyuki/liteyuki_main/dev_tools.py index a2f8ab5a..fb46dc75 100644 --- a/liteyuki/liteyuki_main/dev_tools.py +++ b/liteyuki/liteyuki_main/dev_tools.py @@ -4,9 +4,9 @@ import nonebot from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler -from liteyuki.internal.base.config import get_config -from liteyuki.internal.base.reloader import Reloader -from liteyuki.internal.base.resource import load_resources +from liteyuki.utils.base.config import get_config +from liteyuki.utils.base.reloader import Reloader +from liteyuki.utils.base.resource import load_resources if get_config("debug", False): nonebot.logger.info("Liteyuki Reload is enable, watching for file changes...") diff --git a/liteyuki/liteyuki_main/loader.py b/liteyuki/liteyuki_main/loader.py index fdfc5446..2b18966c 100644 --- a/liteyuki/liteyuki_main/loader.py +++ b/liteyuki/liteyuki_main/loader.py @@ -1,10 +1,10 @@ import nonebot.plugin -from liteyuki.internal import init_log -from liteyuki.internal.base.config import get_config -from liteyuki.internal.base.data_manager import InstalledPlugin, plugin_db -from liteyuki.internal.base.resource import load_resources -from liteyuki.internal.message.tools import check_for_package +from liteyuki.utils import init_log +from liteyuki.utils.base.config import get_config +from liteyuki.utils.base.data_manager import InstalledPlugin, plugin_db +from liteyuki.utils.base.resource import load_resources +from liteyuki.utils.message.tools import check_for_package load_resources() init_log() diff --git a/liteyuki/plugins/liteyuki_crt_utils/rt_guide.py b/liteyuki/plugins/liteyuki_crt_utils/rt_guide.py index 5e416eca..4167cbf7 100644 --- a/liteyuki/plugins/liteyuki_crt_utils/rt_guide.py +++ b/liteyuki/plugins/liteyuki_crt_utils/rt_guide.py @@ -9,7 +9,7 @@ from nonebot_plugin_alconna import on_alconna, Alconna, Subcommand, Args, MultiV from pydantic import BaseModel from .canvas import * -from ...internal.base.resource import get_path +from ...utils.base.resource import get_path resolution = 256 diff --git a/liteyuki/plugins/liteyuki_eventpush.py b/liteyuki/plugins/liteyuki_eventpush.py index 26873e2a..e8f1688c 100644 --- a/liteyuki/plugins/liteyuki_eventpush.py +++ b/liteyuki/plugins/liteyuki_eventpush.py @@ -2,9 +2,9 @@ import nonebot from nonebot import on_message, require from nonebot.plugin import PluginMetadata -from liteyuki.internal.base.data import Database, LiteModel -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent -from liteyuki.internal.message.message import MarkdownMessage as md +from liteyuki.utils.base.data import Database, LiteModel +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent +from liteyuki.utils.message.message import MarkdownMessage as md require("nonebot_plugin_alconna") from nonebot_plugin_alconna import on_alconna diff --git a/liteyuki/plugins/liteyuki_markdowntest.py b/liteyuki/plugins/liteyuki_markdowntest.py index 2ada59fe..4890ec6f 100644 --- a/liteyuki/plugins/liteyuki_markdowntest.py +++ b/liteyuki/plugins/liteyuki_markdowntest.py @@ -4,9 +4,9 @@ from nonebot.params import CommandArg from nonebot.permission import SUPERUSER from nonebot.plugin import PluginMetadata -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent, v11 -from liteyuki.internal.message.message import MarkdownMessage as md, broadcast_to_superusers -from liteyuki.internal.message.html_tool import * +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent, v11 +from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_superusers +from liteyuki.utils.message.html_tool import * md_test = on_command("mdts", permission=SUPERUSER) btn_test = on_command("btnts", permission=SUPERUSER) diff --git a/liteyuki/plugins/liteyuki_minigame/game.py b/liteyuki/plugins/liteyuki_minigame/game.py index 928e895e..b95ea905 100644 --- a/liteyuki/plugins/liteyuki_minigame/game.py +++ b/liteyuki/plugins/liteyuki_minigame/game.py @@ -1,6 +1,6 @@ import random from pydantic import BaseModel -from liteyuki.internal.message.message import MarkdownMessage as md +from liteyuki.utils.message.message import MarkdownMessage as md class Dot(BaseModel): row: int diff --git a/liteyuki/plugins/liteyuki_minigame/minesweeper.py b/liteyuki/plugins/liteyuki_minigame/minesweeper.py index 03dc0f76..8fdece99 100644 --- a/liteyuki/plugins/liteyuki_minigame/minesweeper.py +++ b/liteyuki/plugins/liteyuki_minigame/minesweeper.py @@ -1,7 +1,7 @@ from nonebot import require -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent -from liteyuki.internal.message.message import MarkdownMessage as md +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent +from liteyuki.utils.message.message import MarkdownMessage as md require("nonebot_plugin_alconna") from .game import Minesweeper diff --git a/liteyuki/plugins/liteyuki_pacman/common.py b/liteyuki/plugins/liteyuki_pacman/common.py index 04889446..1db3b334 100644 --- a/liteyuki/plugins/liteyuki_pacman/common.py +++ b/liteyuki/plugins/liteyuki_pacman/common.py @@ -4,9 +4,9 @@ from typing import Optional import aiofiles import nonebot.plugin -from liteyuki.internal.base.data import LiteModel -from liteyuki.internal.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db -from liteyuki.internal.base.ly_typing import T_MessageEvent +from liteyuki.utils.base.data import LiteModel +from liteyuki.utils.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db +from liteyuki.utils.base.ly_typing import T_MessageEvent __group_data = {} # 群数据缓存, {group_id: Group} __user_data = {} # 用户数据缓存, {user_id: User} diff --git a/liteyuki/plugins/liteyuki_pacman/npm.py b/liteyuki/plugins/liteyuki_pacman/npm.py index 906aedf7..2b2a1af5 100644 --- a/liteyuki/plugins/liteyuki_pacman/npm.py +++ b/liteyuki/plugins/liteyuki_pacman/npm.py @@ -14,13 +14,13 @@ from nonebot.permission import SUPERUSER from nonebot.plugin import Plugin, PluginMetadata from nonebot.utils import run_sync -from liteyuki.internal.base.data_manager import InstalledPlugin -from liteyuki.internal.base.language import get_user_lang -from liteyuki.internal.base.ly_typing import T_Bot -from liteyuki.internal.message.message import MarkdownMessage as md -from liteyuki.internal.message.markdown import MarkdownComponent as mdc, compile_md, escape_md -from liteyuki.internal.base.permission import GROUP_ADMIN, GROUP_OWNER -from liteyuki.internal.message.tools import clamp +from liteyuki.utils.base.data_manager import InstalledPlugin +from liteyuki.utils.base.language import get_user_lang +from liteyuki.utils.base.ly_typing import T_Bot +from liteyuki.utils.message.message import MarkdownMessage as md +from liteyuki.utils.message.markdown import MarkdownComponent as mdc, compile_md, escape_md +from liteyuki.utils.base.permission import GROUP_ADMIN, GROUP_OWNER +from liteyuki.utils.message.tools import clamp from .common import * require("nonebot_plugin_alconna") diff --git a/liteyuki/plugins/liteyuki_pacman/rpm.py b/liteyuki/plugins/liteyuki_pacman/rpm.py index 8de0deef..612345b8 100644 --- a/liteyuki/plugins/liteyuki_pacman/rpm.py +++ b/liteyuki/plugins/liteyuki_pacman/rpm.py @@ -5,10 +5,10 @@ import yaml from nonebot import require from nonebot.permission import SUPERUSER -from liteyuki.internal.base.language import get_user_lang -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent -from liteyuki.internal.message.message import MarkdownMessage as md -from liteyuki.internal.base.resource import (ResourceMetadata, add_resource_pack, change_priority, check_exist, check_status, get_loaded_resource_packs, get_resource_metadata, load_resources, remove_resource_pack) +from liteyuki.utils.base.language import get_user_lang +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent +from liteyuki.utils.message.message import MarkdownMessage as md +from liteyuki.utils.base.resource import (ResourceMetadata, add_resource_pack, change_priority, check_exist, check_status, get_loaded_resource_packs, get_resource_metadata, load_resources, remove_resource_pack) require("nonebot_plugin_alconna") from nonebot_plugin_alconna import Alconna, Args, on_alconna, Arparma, Subcommand diff --git a/liteyuki/plugins/liteyuki_sign_status.py b/liteyuki/plugins/liteyuki_sign_status.py index 6b85be95..b5c448aa 100644 --- a/liteyuki/plugins/liteyuki_sign_status.py +++ b/liteyuki/plugins/liteyuki_sign_status.py @@ -5,10 +5,10 @@ import aiohttp from nonebot import require from nonebot.plugin import PluginMetadata -from liteyuki.internal.base.config import get_config -from liteyuki.internal.base.data import Database, LiteModel -from liteyuki.internal.base.resource import get_path -from liteyuki.internal.message.html_tool import template2image +from liteyuki.utils.base.config import get_config +from liteyuki.utils.base.data import Database, LiteModel +from liteyuki.utils.base.resource import get_path +from liteyuki.utils.message.html_tool import template2image require("nonebot_plugin_alconna") require("nonebot_plugin_apscheduler") @@ -76,7 +76,7 @@ async def _(): async def _(): query_stamp = [1, 5, 10, 15] - reply = "Count from last " + ", ".join([str(i) for i in query_stamp]) + "mins" + reply = "QPS from last " + ", ".join([str(i) for i in query_stamp]) + "mins" for name, url in SIGN_COUNT_URLS.items(): count_data = [] for stamp in query_stamp: @@ -84,8 +84,8 @@ async def _(): if len(count_rows) < 2: count_data.append(-1) else: - count_data.append(count_rows[-1].count - count_rows[0].count) - reply += f"\n{name}: " + ", ".join([str(i) for i in count_data]) + count_data.append((count_rows[-1].count - count_rows[0].count)/(stamp*60)) + reply += f"\n{name}: " + ", ".join([f"{i:.1f}" for i in count_data]) await sign_status.send(reply) diff --git a/liteyuki/plugins/liteyuki_statistics/common.py b/liteyuki/plugins/liteyuki_statistics/common.py index fd7dad31..a893ef99 100644 --- a/liteyuki/plugins/liteyuki_statistics/common.py +++ b/liteyuki/plugins/liteyuki_statistics/common.py @@ -1,4 +1,4 @@ -from liteyuki.internal.base.data import Database, LiteModel +from liteyuki.utils.base.data import Database, LiteModel class MessageEventModel(LiteModel): diff --git a/liteyuki/plugins/liteyuki_statistics/stat_api.py b/liteyuki/plugins/liteyuki_statistics/stat_api.py index d0020002..e6531ce8 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_api.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_api.py @@ -1,12 +1,22 @@ import time from typing import Any + +from liteyuki.utils.message.html_tool import template2image from .common import MessageEventModel, msg_db +from liteyuki.utils.base.language import Language +from liteyuki.utils.base.resource import get_path +from liteyuki.utils.message.npl import convert_seconds_to_time +from contextvars import ContextVar -def get_stat_msg_data(duration, period) -> tuple[list[int,], list[int,]]: +async def get_stat_msg_image(duration: int, period: int, group_id: str = None, bot_id: str = None, ulang: Language = Language()) -> bytes: """ 获取统计消息 Args: + ctx: + ulang: + bot_id: + group_id: duration: 统计时间,单位秒 period: 统计周期,单位秒 @@ -14,20 +24,56 @@ def get_stat_msg_data(duration, period) -> tuple[list[int,], list[int,]]: tuple: [int,], [int,] 两个列表,分别为周期中心时间戳和消息数量 """ now = int(time.time()) + start_time = (now - duration) + + condition = "time > ?" + condition_args = [start_time] + + if group_id: + condition += " AND group_id = ?" + condition_args.append(group_id) + if bot_id: + condition += " AND bot_id = ?" + condition_args.append(bot_id) + msg_rows = msg_db.where_all( MessageEventModel(), - "time > ?", - now - duration + condition, + *condition_args ) timestamps = [] msg_count = [] msg_rows.sort(key=lambda x: x.time) - for msg_row in msg_rows: - period_center_time = msg_row.time - msg_row.time % period + period // 2 - # if not timestamps or period_start_time != timestamps[-1]: - # timestamps.append(period_start_time) - # msg_count.append(1) - # else: - # msg_count[-1] += 1 - # + start_time = max(msg_rows[0].time, start_time) + + for i in range(start_time, now, period): + timestamps.append(i + period // 2) + msg_count.append(0) + + for msg in msg_rows: + period_start_time = start_time + (msg.time - start_time) // period * period + period_center_time = period_start_time + period // 2 + index = timestamps.index(period_center_time) + msg_count[index] += 1 + + templates = { + "data": [ + { + "name" : ulang.get("stat.message") + + f" Period {convert_seconds_to_time(period)}" + f" Duration {convert_seconds_to_time(duration)}" + + (f" Group {group_id}" if group_id else "") + (f" Bot {bot_id}" if bot_id else ""), + "times" : timestamps, + "counts": msg_count + } + ] + } + + return await template2image(get_path("templates/stat_msg.html"), templates, debug=True) + + # if not timestamps or period_start_time != timestamps[-1]: + # timestamps.append(period_start_time) + # msg_count.append(1) + # else: + # msg_count[-1] += 1 + # diff --git a/liteyuki/plugins/liteyuki_statistics/stat_matchers.py b/liteyuki/plugins/liteyuki_statistics/stat_matchers.py index b4e8feca..8ca95177 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_matchers.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_matchers.py @@ -1,31 +1,39 @@ -from nonebot import require -from liteyuki.internal.message.npl import convert_duration +from nonebot import Bot, require +from liteyuki.utils.message.npl import convert_duration, convert_time_to_seconds from .stat_api import * +from ...utils.base.language import Language +from ...utils.base.ly_typing import T_MessageEvent require("nonebot_plugin_alconna") -from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma, Option +from nonebot_plugin_alconna import UniMessage, on_alconna, Alconna, Args, Subcommand, Arparma, Option stat_msg = on_alconna( Alconna( "stat", Subcommand( "message", - Args["duration", str, "1d"], # 默认为1天 + # Args["duration", str, "2d"]["period", str, "60s"], # 默认为1天 + Option( + "-d|--duration", + Args["duration", str, "2d"], + help_text="统计时间", + ), + Option( + "-p|--period", + Args["period", str, "60s"], + help_text="统计周期", + ), Option( "-b|--bot", # 生成图表 - Args["bot_id", str, ""], + Args["bot_id", str, "current"], help_text="是否指定机器人", ), Option( "-g|--group", - Args["group_id", str, ""], + Args["group_id", str, "current"], help_text="指定群组" ), - Option( - "-c|--chart", # 生成图表 - help_text="是否生成图表", - ), alias={"msg", "m"}, help_text="查看统计次数内的消息" ) @@ -34,13 +42,27 @@ stat_msg = on_alconna( @stat_msg.assign("message") -async def _(result: Arparma): - args = result.subcommands.get("message").args - options = result.subcommands.get("message").options - duration = convert_duration(args.get("duration"), 86400) # 秒数 - enable_chart = options.get("chart") +async def _(result: Arparma, event: T_MessageEvent, bot: Bot): + ulang = Language(event.user_id) - if options.get("group"): - group_id = options["group"].args.get("group_id") - else: - msg_rows = get_stat_msg_data(duration) + try: + duration = convert_time_to_seconds(result.other_args.get("duration", "2d")) # 秒数 + period = convert_time_to_seconds(result.other_args.get("period", "1m")) + except BaseException as e: + await stat_msg.send(ulang.get("liteyuki.invalid_command", TEXT=str(e.__str__()))) + return + + group_id = result.other_args.get("group_id") + bot_id = result.other_args.get("bot_id") + + if group_id in ["current", "c"]: + group_id = str(event.group_id) + + if group_id in ["all", "a"]: + group_id = "all" + + if bot_id == ["current", "c"]: + bot_id = str(bot.self_id) + + img = await get_stat_msg_image(duration, period, group_id, bot_id) + await stat_msg.send(UniMessage.image(raw=img)) diff --git a/liteyuki/plugins/liteyuki_statistics/stat_monitors.py b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py index 086c12d5..b6c2720a 100644 --- a/liteyuki/plugins/liteyuki_statistics/stat_monitors.py +++ b/liteyuki/plugins/liteyuki_statistics/stat_monitors.py @@ -3,8 +3,8 @@ import time from nonebot import require from nonebot.message import event_postprocessor -from liteyuki.internal.base.data import Database, LiteModel -from liteyuki.internal.base.ly_typing import v11 +from liteyuki.utils.base.data import Database, LiteModel +from liteyuki.utils.base.ly_typing import v11 from .common import MessageEventModel, msg_db diff --git a/liteyuki/plugins/liteyuki_status/api.py b/liteyuki/plugins/liteyuki_status/api.py index 735d59a8..5222451b 100644 --- a/liteyuki/plugins/liteyuki_status/api.py +++ b/liteyuki/plugins/liteyuki_status/api.py @@ -5,12 +5,12 @@ import nonebot import psutil from cpuinfo import cpuinfo from nonebot import require -from liteyuki.internal import __NAME__, __VERSION__ -from liteyuki.internal.base.config import get_config -from liteyuki.internal.base.data_manager import TempConfig, common_db -from liteyuki.internal.base.language import Language -from liteyuki.internal.base.resource import get_loaded_resource_packs, get_path -from liteyuki.internal.message.html_tool import template2image +from liteyuki.utils import __NAME__, __VERSION__ +from liteyuki.utils.base.config import get_config +from liteyuki.utils.base.data_manager import TempConfig, common_db +from liteyuki.utils.base.language import Language +from liteyuki.utils.base.resource import get_loaded_resource_packs, get_path +from liteyuki.utils.message.html_tool import template2image require("nonebot_plugin_apscheduler") from nonebot_plugin_apscheduler import scheduler diff --git a/liteyuki/plugins/liteyuki_status/status.py b/liteyuki/plugins/liteyuki_status/status.py index 1457d141..13f25006 100644 --- a/liteyuki/plugins/liteyuki_status/status.py +++ b/liteyuki/plugins/liteyuki_status/status.py @@ -1,10 +1,10 @@ from nonebot import require -from liteyuki.internal.base.resource import get_path -from liteyuki.internal.message.html_tool import template2image -from liteyuki.internal.base.language import get_user_lang +from liteyuki.utils.base.resource import get_path +from liteyuki.utils.message.html_tool import template2image +from liteyuki.utils.base.language import get_user_lang from .api import * -from ...internal.base.ly_typing import T_Bot, T_MessageEvent +from ...utils.base.ly_typing import T_Bot, T_MessageEvent require("nonebot_plugin_alconna") from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma, UniMessage diff --git a/liteyuki/plugins/liteyuki_user/profile_manager.py b/liteyuki/plugins/liteyuki_user/profile_manager.py index 93d1f648..1ae69009 100644 --- a/liteyuki/plugins/liteyuki_user/profile_manager.py +++ b/liteyuki/plugins/liteyuki_user/profile_manager.py @@ -3,11 +3,11 @@ from typing import Optional import pytz from nonebot import require -from liteyuki.internal.base.data import LiteModel, Database -from liteyuki.internal.base.data_manager import User, user_db, group_db -from liteyuki.internal.base.language import Language, change_user_lang, get_all_lang, get_user_lang -from liteyuki.internal.base.ly_typing import T_Bot, T_MessageEvent -from liteyuki.internal.message.message import MarkdownMessage as md +from liteyuki.utils.base.data import LiteModel, Database +from liteyuki.utils.base.data_manager import User, user_db, group_db +from liteyuki.utils.base.language import Language, change_user_lang, get_all_lang, get_user_lang +from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent +from liteyuki.utils.message.message import MarkdownMessage as md from .const import representative_timezones_list require("nonebot_plugin_alconna") diff --git a/liteyuki/plugins/liteyuki_weather/__init__.py b/liteyuki/plugins/liteyuki_weather/__init__.py index b5d1ca5c..2127a6ac 100644 --- a/liteyuki/plugins/liteyuki_weather/__init__.py +++ b/liteyuki/plugins/liteyuki_weather/__init__.py @@ -15,7 +15,7 @@ __plugin_meta__ = PluginMetadata( } ) -from ...internal.base.data_manager import set_memory_data +from ...utils.base.data_manager import set_memory_data driver = get_driver() diff --git a/liteyuki/plugins/liteyuki_weather/qw_api.py b/liteyuki/plugins/liteyuki_weather/qw_api.py index c034d1ba..8f28cd91 100644 --- a/liteyuki/plugins/liteyuki_weather/qw_api.py +++ b/liteyuki/plugins/liteyuki_weather/qw_api.py @@ -3,8 +3,8 @@ import aiohttp from .qw_models import * import httpx -from ...internal.base.data_manager import get_memory_data -from ...internal.base.language import Language +from ...utils.base.data_manager import get_memory_data +from ...utils.base.language import Language dev_url = "https://devapi.qweather.com/" # 开发HBa com_url = "https://api.qweather.com/" # 正式环境 @@ -27,9 +27,9 @@ async def check_key_dev(key: str) -> bool: "location": "101010100", "key" : key, } - async with httpx.AsyncClient() as client: + async with aiohttp.ClientSession() as client: resp = await client.get(url, params=params) - return (resp.json()).get("code") != "200" # 查询不到付费数据为开发版 + return (await resp.json()).get("code") != "200" # 查询不到付费数据为开发版 def get_local_data(ulang_code: str) -> dict: diff --git a/liteyuki/plugins/liteyuki_weather/qw_models.py b/liteyuki/plugins/liteyuki_weather/qw_models.py index 63957903..3a5ce04c 100644 --- a/liteyuki/plugins/liteyuki_weather/qw_models.py +++ b/liteyuki/plugins/liteyuki_weather/qw_models.py @@ -1,4 +1,4 @@ -from liteyuki.internal.base.data import LiteModel +from liteyuki.utils.base.data import LiteModel class Location(LiteModel): diff --git a/liteyuki/plugins/liteyuki_weather/qweather.py b/liteyuki/plugins/liteyuki_weather/qweather.py index fd2e28fa..849b8377 100644 --- a/liteyuki/plugins/liteyuki_weather/qweather.py +++ b/liteyuki/plugins/liteyuki_weather/qweather.py @@ -2,14 +2,14 @@ from nonebot import require, on_endswith from nonebot.adapters.onebot.v11 import MessageSegment from nonebot.internal.matcher import Matcher -from liteyuki.internal.base.config import get_config -from liteyuki.internal.base.ly_typing import T_MessageEvent +from liteyuki.utils.base.config import get_config +from liteyuki.utils.base.ly_typing import T_MessageEvent from .qw_api import * -from liteyuki.internal.base.data_manager import User, user_db -from liteyuki.internal.base.language import Language, get_user_lang -from liteyuki.internal.base.resource import get_path -from liteyuki.internal.message.html_tool import template2image +from liteyuki.utils.base.data_manager import User, user_db +from liteyuki.utils.base.language import Language, get_user_lang +from liteyuki.utils.base.resource import get_path +from liteyuki.utils.message.html_tool import template2image require("nonebot_plugin_alconna") from nonebot_plugin_alconna import on_alconna, Alconna, Args, MultiVar, Arparma diff --git a/liteyuki/resources/lagrange_sign/templates/js/sign_status.js b/liteyuki/resources/lagrange_sign/templates/js/sign_status.js index 0f9a7322..06bf3e53 100644 --- a/liteyuki/resources/lagrange_sign/templates/js/sign_status.js +++ b/liteyuki/resources/lagrange_sign/templates/js/sign_status.js @@ -17,7 +17,7 @@ data.forEach((item) => { item["counts"].forEach((count, index) => { // 计算平均值,index - 1的count + index的count + index + 1的count /3 if (index > 0) { - timeCount.push((item["counts"][index] - item["counts"][index - 1]) / (60 * (item["times"][index] - item["times"][index - 1]))) + timeCount.push((item["counts"][index] - item["counts"][index - 1]) / (60*(item["times"][index] - item["times"][index - 1]))) } }) diff --git a/liteyuki/resources/liteyuki_statistics/lang/zh-CN.lang b/liteyuki/resources/liteyuki_statistics/lang/zh-CN.lang new file mode 100644 index 00000000..725ac8fd --- /dev/null +++ b/liteyuki/resources/liteyuki_statistics/lang/zh-CN.lang @@ -0,0 +1 @@ +stat.message=统计消息 \ No newline at end of file diff --git a/liteyuki/resources/liteyuki_statistics/metadata.yml b/liteyuki/resources/liteyuki_statistics/metadata.yml new file mode 100644 index 00000000..64084527 --- /dev/null +++ b/liteyuki/resources/liteyuki_statistics/metadata.yml @@ -0,0 +1,3 @@ +name: 轻雪统计信息附件 +description: For Liteyuki statistic +version: 2024.4.26 \ No newline at end of file diff --git a/liteyuki/resources/liteyuki_statistics/templates/css/stat_msg.css b/liteyuki/resources/liteyuki_statistics/templates/css/stat_msg.css new file mode 100644 index 00000000..7d43a4bb --- /dev/null +++ b/liteyuki/resources/liteyuki_statistics/templates/css/stat_msg.css @@ -0,0 +1,4 @@ +.sign-chart { + height: 400px; + background-color: rgba(255, 255, 255, 0.7); +} \ No newline at end of file diff --git a/liteyuki/resources/liteyuki_statistics/templates/js/stat_msg.js b/liteyuki/resources/liteyuki_statistics/templates/js/stat_msg.js new file mode 100644 index 00000000..a2bc6eb4 --- /dev/null +++ b/liteyuki/resources/liteyuki_statistics/templates/js/stat_msg.js @@ -0,0 +1,54 @@ +// 数据类型声明 +// import * as echarts from 'echarts'; + +let data = JSON.parse(document.getElementById("data").innerText) // object +const signChartDivTemplate = document.importNode(document.getElementById("sign-chart-template").content, true) +data.forEach((item) => { + let signChartDiv = signChartDivTemplate.cloneNode(true) + let chartID = item["name"] + // 初始化ECharts实例 + // 设置id + signChartDiv.querySelector(".sign-chart").id = chartID + document.body.appendChild(signChartDiv) + + let signChart = echarts.init(document.getElementById(chartID)) + + signChart.setOption( + { + animation: false, + title: { + text: item["name"], + textStyle: { + color: '#000000' // 设置标题文本颜色为红色 + } + }, + xAxis: { + type: 'category', + data: item["times"].map(timestampToTime), + }, + yAxis: { + type: 'value', + min: Math.min(...item["counts"]), + }, + + series: [ + { + data: item["counts"], + type: 'line', + } + ] + } + ) +}) + + +function timestampToTime(timestamp) { + let date = new Date(timestamp * 1000) + let Y = date.getFullYear() + '-' + let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-' + let D = date.getDate() + ' ' + let h = date.getHours() + ':' + let m = date.getMinutes() + ':' + let s = date.getSeconds() + return M + D + h + m + s +} \ No newline at end of file diff --git a/liteyuki/resources/liteyuki_statistics/templates/stat_msg.html b/liteyuki/resources/liteyuki_statistics/templates/stat_msg.html new file mode 100644 index 00000000..c667245e --- /dev/null +++ b/liteyuki/resources/liteyuki_statistics/templates/stat_msg.html @@ -0,0 +1,22 @@ + + + + + Liteyuki Stats Message + + + + + + + + +
{{ data | tojson }}
+ + + + + \ No newline at end of file diff --git a/liteyuki/internal/__init__.py b/liteyuki/utils/__init__.py similarity index 92% rename from liteyuki/internal/__init__.py rename to liteyuki/utils/__init__.py index 83009462..ec3b46d9 100644 --- a/liteyuki/internal/__init__.py +++ b/liteyuki/utils/__init__.py @@ -11,9 +11,9 @@ __VERSION__ = "6.3.2" # 60201 import requests -from liteyuki.internal.base.config import load_from_yaml, config -from liteyuki.internal.base.log import init_log -from liteyuki.internal.base.data_manager import TempConfig, auto_migrate, common_db +from liteyuki.utils.base.config import load_from_yaml, config +from liteyuki.utils.base.log import init_log +from liteyuki.utils.base.data_manager import TempConfig, auto_migrate, common_db major, minor, patch = map(int, __VERSION__.split(".")) __VERSION_I__ = major * 10000 + minor * 100 + patch diff --git a/liteyuki/internal/base/__init__.py b/liteyuki/utils/base/__init__.py similarity index 100% rename from liteyuki/internal/base/__init__.py rename to liteyuki/utils/base/__init__.py diff --git a/liteyuki/internal/base/config.py b/liteyuki/utils/base/config.py similarity index 100% rename from liteyuki/internal/base/config.py rename to liteyuki/utils/base/config.py diff --git a/liteyuki/internal/base/data.py b/liteyuki/utils/base/data.py similarity index 100% rename from liteyuki/internal/base/data.py rename to liteyuki/utils/base/data.py diff --git a/liteyuki/internal/base/data_manager.py b/liteyuki/utils/base/data_manager.py similarity index 100% rename from liteyuki/internal/base/data_manager.py rename to liteyuki/utils/base/data_manager.py diff --git a/liteyuki/internal/base/language.py b/liteyuki/utils/base/language.py similarity index 100% rename from liteyuki/internal/base/language.py rename to liteyuki/utils/base/language.py diff --git a/liteyuki/internal/base/log.py b/liteyuki/utils/base/log.py similarity index 100% rename from liteyuki/internal/base/log.py rename to liteyuki/utils/base/log.py diff --git a/liteyuki/internal/base/ly_api.py b/liteyuki/utils/base/ly_api.py similarity index 100% rename from liteyuki/internal/base/ly_api.py rename to liteyuki/utils/base/ly_api.py diff --git a/liteyuki/internal/base/ly_typing.py b/liteyuki/utils/base/ly_typing.py similarity index 100% rename from liteyuki/internal/base/ly_typing.py rename to liteyuki/utils/base/ly_typing.py diff --git a/liteyuki/internal/base/permission.py b/liteyuki/utils/base/permission.py similarity index 100% rename from liteyuki/internal/base/permission.py rename to liteyuki/utils/base/permission.py diff --git a/liteyuki/internal/base/reloader.py b/liteyuki/utils/base/reloader.py similarity index 100% rename from liteyuki/internal/base/reloader.py rename to liteyuki/utils/base/reloader.py diff --git a/liteyuki/internal/base/resource.py b/liteyuki/utils/base/resource.py similarity index 99% rename from liteyuki/internal/base/resource.py rename to liteyuki/utils/base/resource.py index 16f13490..bd3e9772 100644 --- a/liteyuki/internal/base/resource.py +++ b/liteyuki/utils/base/resource.py @@ -42,7 +42,7 @@ def load_resource_from_dir(path: str): metadata["path"] = path metadata["folder"] = os.path.basename(path) if os.path.exists(os.path.join(path, "lang")): - from liteyuki.internal.base.language import load_from_dir + from liteyuki.utils.base.language import load_from_dir load_from_dir(os.path.join(path, "lang")) _loaded_resource_packs.insert(0, ResourceMetadata(**metadata)) diff --git a/liteyuki/internal/canvas/__init__.py b/liteyuki/utils/canvas/__init__.py similarity index 100% rename from liteyuki/internal/canvas/__init__.py rename to liteyuki/utils/canvas/__init__.py diff --git a/liteyuki/internal/message/__init__.py b/liteyuki/utils/message/__init__.py similarity index 100% rename from liteyuki/internal/message/__init__.py rename to liteyuki/utils/message/__init__.py diff --git a/liteyuki/internal/message/html_tool.py b/liteyuki/utils/message/html_tool.py similarity index 95% rename from liteyuki/internal/message/html_tool.py rename to liteyuki/utils/message/html_tool.py index 79969d32..5a1fe689 100644 --- a/liteyuki/internal/message/html_tool.py +++ b/liteyuki/utils/message/html_tool.py @@ -6,11 +6,10 @@ import aiofiles import nonebot from nonebot import require -from liteyuki.internal.base.resource import load_resources - require("nonebot_plugin_htmlrender") from nonebot_plugin_htmlrender import * +from .tools import random_hex_string async def html2image( @@ -76,7 +75,7 @@ async def template2image( ) async with aiofiles.open(os.path.join(template_path, "latest-debug.html"), "w", encoding="utf-8") as f: await f.write(raw_html) - nonebot.logger.info("Debug HTML: %s" % "latest-debug.html") + nonebot.logger.info("Debug HTML: %s" % f"debug-{random_hex_string(6)}.html") return await template_to_pic( template_name=template_name, diff --git a/liteyuki/internal/message/markdown.py b/liteyuki/utils/message/markdown.py similarity index 100% rename from liteyuki/internal/message/markdown.py rename to liteyuki/utils/message/markdown.py diff --git a/liteyuki/internal/message/message.py b/liteyuki/utils/message/message.py similarity index 100% rename from liteyuki/internal/message/message.py rename to liteyuki/utils/message/message.py diff --git a/liteyuki/utils/message/npl.py b/liteyuki/utils/message/npl.py new file mode 100644 index 00000000..32cf9a0a --- /dev/null +++ b/liteyuki/utils/message/npl.py @@ -0,0 +1,101 @@ +import nonebot + + +def convert_duration(text: str, default) -> float: + """ + 转换自然语言时间为秒数 + Args: + text: 1d2h3m + default: 出错时返回 + + Returns: + float: 总秒数 + """ + units = { + "d" : 86400, + "h" : 3600, + "m" : 60, + "s" : 1, + "ms": 0.001 + } + + duration = 0 + current_number = '' + current_unit = '' + try: + for char in text: + if char.isdigit(): + current_number += char + else: + if current_number: + duration += int(current_number) * units[current_unit] + current_number = '' + if char in units: + current_unit = char + else: + current_unit = '' + + if current_number: + duration += int(current_number) * units[current_unit] + + return duration + + except BaseException as e: + nonebot.logger.info(f"convert_duration error: {e}") + return default + + +def convert_time_to_seconds(time_str): + """转换自然语言时长为秒数 + Args: + time_str: 1d2m3s + + Returns: + + """ + seconds = 0 + current_number = '' + + for char in time_str: + if char.isdigit() or char == '.': + current_number += char + elif char == 'd': + seconds += float(current_number) * 24 * 60 * 60 + current_number = '' + elif char == 'h': + seconds += float(current_number) * 60 * 60 + current_number = '' + elif char == 'm': + seconds += float(current_number) * 60 + current_number = '' + elif char == 's': + seconds += float(current_number) + current_number = '' + + return int(seconds) + + +def convert_seconds_to_time(seconds): + """转换秒数为自然语言时长 + Args: + seconds: 10000 + + Returns: + + """ + d = seconds // (24 * 60 * 60) + h = (seconds % (24 * 60 * 60)) // (60 * 60) + m = (seconds % (60 * 60)) // 60 + s = seconds % 60 + + # 若值为0则不显示 + time_str = '' + if d: + time_str += f"{d}d" + if h: + time_str += f"{h}h" + if m: + time_str += f"{m}m" + if not time_str: + time_str = f"{s}s" + return time_str diff --git a/liteyuki/internal/message/tools.py b/liteyuki/utils/message/tools.py similarity index 100% rename from liteyuki/internal/message/tools.py rename to liteyuki/utils/message/tools.py diff --git a/liteyuki/internal/message/union.py b/liteyuki/utils/message/union.py similarity index 100% rename from liteyuki/internal/message/union.py rename to liteyuki/utils/message/union.py diff --git a/main.py b/main.py index fce3ba6a..c78799c0 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,9 @@ import nonebot from nonebot.adapters.onebot import v11, v12 -from liteyuki.internal import init -from liteyuki.internal.base.config import load_from_yaml -from liteyuki.internal.base.data_manager import StoredConfig, common_db -from liteyuki.internal.base.ly_api import liteyuki_api +from liteyuki.utils import init +from liteyuki.utils.base.config import load_from_yaml +from liteyuki.utils.base.data_manager import StoredConfig, common_db +from liteyuki.utils.base.ly_api import liteyuki_api if __name__ == "__mp_main__": init() @@ -25,5 +25,5 @@ if __name__ == "__mp_main__": liteyuki_api.bug_report(str(e.__repr__())) if __name__ == "__main__": - from liteyuki.internal.base.reloader import Reloader + from liteyuki.utils.base.reloader import Reloader nonebot.run()