message 统计

This commit is contained in:
2024-05-12 02:47:14 +08:00
parent c6f2a29320
commit 041ceb81d8
52 changed files with 371 additions and 160 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -1,4 +1,4 @@
from liteyuki.internal.base.data import Database, LiteModel
from liteyuki.utils.base.data import Database, LiteModel
class MessageEventModel(LiteModel):

View File

@ -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
#

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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()

View File

@ -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:

View File

@ -1,4 +1,4 @@
from liteyuki.internal.base.data import LiteModel
from liteyuki.utils.base.data import LiteModel
class Location(LiteModel):

View File

@ -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