diff --git a/plugins/statistics/_model.py b/models/statistics.py similarity index 100% rename from plugins/statistics/_model.py rename to models/statistics.py diff --git a/plugins/statistics/_config.py b/plugins/statistics/_config.py new file mode 100644 index 00000000..edee1069 --- /dev/null +++ b/plugins/statistics/_config.py @@ -0,0 +1,26 @@ +from enum import Enum +from typing import NamedTuple + + +class SearchType(Enum): + + """ + 查询类型 + """ + + DAY = "day_statistics" + """天""" + WEEK = "week_statistics" + """周""" + MONTH = "month_statistics" + """月""" + TOTAL = "total_statistics" + """总数""" + + +class ParseData(NamedTuple): + + global_search: bool + """是否全局搜索""" + search_type: SearchType + """搜索类型""" diff --git a/plugins/statistics/statistics_handle.py b/plugins/statistics/statistics_handle.py index 706ff10c..f0515a4b 100755 --- a/plugins/statistics/statistics_handle.py +++ b/plugins/statistics/statistics_handle.py @@ -1,13 +1,13 @@ import asyncio import os -from typing import Tuple from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent -from nonebot.params import Command, CommandArg +from nonebot.params import CommandArg from configs.path_config import DATA_PATH, IMAGE_PATH from models.group_info import GroupInfo +from utils.depends import OneCommand from utils.image_utils import BuildMat from utils.manager import plugins2settings_manager from utils.message_builder import image @@ -91,7 +91,7 @@ statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" @statistics.handle() -async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): +async def _(bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()): msg = arg.extract_plain_text().strip() if cmd[0][:2] == "全局": if str(event.user_id) in bot.config.superusers: diff --git a/plugins/statistics/statistics_hook.py b/plugins/statistics/statistics_hook.py index 2de3a1f1..9fea8b2c 100755 --- a/plugins/statistics/statistics_hook.py +++ b/plugins/statistics/statistics_hook.py @@ -6,11 +6,10 @@ from nonebot.message import run_postprocessor from nonebot.typing import Optional, T_State from configs.path_config import DATA_PATH +from models.statistics import Statistics from utils.manager import plugins2settings_manager from utils.utils import scheduler -from ._model import Statistics - try: import ujson as json except ModuleNotFoundError: @@ -21,69 +20,69 @@ __zx_plugin_name__ = "功能调用统计 [Hidden]" __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" -statistics_group_file = DATA_PATH / "statistics" / "_prefix_count.json" -statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" +# statistics_group_file = DATA_PATH / "statistics" / "_prefix_count.json" +# statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" -try: - with open(statistics_group_file, "r", encoding="utf8") as f: - _prefix_count_dict = json.load(f) -except (FileNotFoundError, ValueError): - _prefix_count_dict = { - "total_statistics": { - "total": {}, - }, - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": str(datetime.now().date()), - "day_index": 0, - } +# try: +# with open(statistics_group_file, "r", encoding="utf8") as f: +# _prefix_count_dict = json.load(f) +# except (FileNotFoundError, ValueError): +# _prefix_count_dict = { +# "total_statistics": { +# "total": {}, +# }, +# "day_statistics": { +# "total": {}, +# }, +# "week_statistics": { +# "total": {}, +# }, +# "month_statistics": { +# "total": {}, +# }, +# "start_time": str(datetime.now().date()), +# "day_index": 0, +# } -try: - with open(statistics_user_file, "r", encoding="utf8") as f: - _prefix_user_count_dict = json.load(f) -except (FileNotFoundError, ValueError): - _prefix_user_count_dict = { - "total_statistics": { - "total": {}, - }, - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": str(datetime.now().date()), - "day_index": 0, - } +# try: +# with open(statistics_user_file, "r", encoding="utf8") as f: +# _prefix_user_count_dict = json.load(f) +# except (FileNotFoundError, ValueError): +# _prefix_user_count_dict = { +# "total_statistics": { +# "total": {}, +# }, +# "day_statistics": { +# "total": {}, +# }, +# "week_statistics": { +# "total": {}, +# }, +# "month_statistics": { +# "total": {}, +# }, +# "start_time": str(datetime.now().date()), +# "day_index": 0, +# } -# 以前版本转换 -if _prefix_count_dict.get("day_index") is None: - tmp = _prefix_count_dict.copy() - _prefix_count_dict = { - "total_statistics": tmp["total_statistics"], - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": tmp["start_time"], - "day_index": 0, - } +# # 以前版本转换 +# if _prefix_count_dict.get("day_index") is None: +# tmp = _prefix_count_dict.copy() +# _prefix_count_dict = { +# "total_statistics": tmp["total_statistics"], +# "day_statistics": { +# "total": {}, +# }, +# "week_statistics": { +# "total": {}, +# }, +# "month_statistics": { +# "total": {}, +# }, +# "start_time": tmp["start_time"], +# "day_index": 0, +# } # 添加命令次数 @@ -95,7 +94,7 @@ async def _( event: MessageEvent, state: T_State, ): - global _prefix_count_dict + # global _prefix_count_dict if ( matcher.type == "message" and matcher.priority not in [1, 999] @@ -107,112 +106,112 @@ async def _( plugin_name=matcher.plugin_name, create_time=datetime.now(), ) - module = matcher.plugin_name - day_index = _prefix_count_dict["day_index"] - try: - group_id = str(event.group_id) - except AttributeError: - group_id = "total" - user_id = str(event.user_id) - plugin_name = plugins2settings_manager.get_plugin_data(module) - if plugin_name and plugin_name.cmd: - plugin_name = plugin_name.cmd[0] - check_exists_key(group_id, user_id, plugin_name) - for data in [_prefix_count_dict, _prefix_user_count_dict]: - data["total_statistics"]["total"][plugin_name] += 1 - data["day_statistics"]["total"][plugin_name] += 1 - data["week_statistics"]["total"][plugin_name] += 1 - data["month_statistics"]["total"][plugin_name] += 1 - # print(_prefix_count_dict) - if group_id != "total": - for data in [_prefix_count_dict, _prefix_user_count_dict]: - if data == _prefix_count_dict: - key = group_id - else: - key = user_id - data["total_statistics"][key][plugin_name] += 1 - data["day_statistics"][key][plugin_name] += 1 - data["week_statistics"][key][str(day_index % 7)][plugin_name] += 1 - data["month_statistics"][key][str(day_index % 30)][plugin_name] += 1 - with open(statistics_group_file, "w", encoding="utf8") as f: - json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) - with open(statistics_user_file, "w", encoding="utf8") as f: - json.dump(_prefix_user_count_dict, f, ensure_ascii=False, indent=4) + # module = matcher.plugin_name + # day_index = _prefix_count_dict["day_index"] + # try: + # group_id = str(event.group_id) + # except AttributeError: + # group_id = "total" + # user_id = str(event.user_id) + # plugin_name = plugins2settings_manager.get_plugin_data(module) + # if plugin_name and plugin_name.cmd: + # plugin_name = plugin_name.cmd[0] + # check_exists_key(group_id, user_id, plugin_name) + # for data in [_prefix_count_dict, _prefix_user_count_dict]: + # data["total_statistics"]["total"][plugin_name] += 1 + # data["day_statistics"]["total"][plugin_name] += 1 + # data["week_statistics"]["total"][plugin_name] += 1 + # data["month_statistics"]["total"][plugin_name] += 1 + # # print(_prefix_count_dict) + # if group_id != "total": + # for data in [_prefix_count_dict, _prefix_user_count_dict]: + # if data == _prefix_count_dict: + # key = group_id + # else: + # key = user_id + # data["total_statistics"][key][plugin_name] += 1 + # data["day_statistics"][key][plugin_name] += 1 + # data["week_statistics"][key][str(day_index % 7)][plugin_name] += 1 + # data["month_statistics"][key][str(day_index % 30)][plugin_name] += 1 + # with open(statistics_group_file, "w", encoding="utf8") as f: + # json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) + # with open(statistics_user_file, "w", encoding="utf8") as f: + # json.dump(_prefix_user_count_dict, f, ensure_ascii=False, indent=4) -def check_exists_key(group_id: str, user_id: str, plugin_name: str): - global _prefix_count_dict, _prefix_user_count_dict - for data in [_prefix_count_dict, _prefix_user_count_dict]: - if data == _prefix_count_dict: - key = group_id - else: - key = user_id - if not data["total_statistics"]["total"].get(plugin_name): - data["total_statistics"]["total"][plugin_name] = 0 - if not data["day_statistics"]["total"].get(plugin_name): - data["day_statistics"]["total"][plugin_name] = 0 - if not data["week_statistics"]["total"].get(plugin_name): - data["week_statistics"]["total"][plugin_name] = 0 - if not data["month_statistics"]["total"].get(plugin_name): - data["month_statistics"]["total"][plugin_name] = 0 +# def check_exists_key(group_id: str, user_id: str, plugin_name: str): +# global _prefix_count_dict, _prefix_user_count_dict +# for data in [_prefix_count_dict, _prefix_user_count_dict]: +# if data == _prefix_count_dict: +# key = group_id +# else: +# key = user_id +# if not data["total_statistics"]["total"].get(plugin_name): +# data["total_statistics"]["total"][plugin_name] = 0 +# if not data["day_statistics"]["total"].get(plugin_name): +# data["day_statistics"]["total"][plugin_name] = 0 +# if not data["week_statistics"]["total"].get(plugin_name): +# data["week_statistics"]["total"][plugin_name] = 0 +# if not data["month_statistics"]["total"].get(plugin_name): +# data["month_statistics"]["total"][plugin_name] = 0 - if not data["total_statistics"].get(key): - data["total_statistics"][key] = {} - if not data["total_statistics"][key].get(plugin_name): - data["total_statistics"][key][plugin_name] = 0 - if not data["day_statistics"].get(key): - data["day_statistics"][key] = {} - if not data["day_statistics"][key].get(plugin_name): - data["day_statistics"][key][plugin_name] = 0 +# if not data["total_statistics"].get(key): +# data["total_statistics"][key] = {} +# if not data["total_statistics"][key].get(plugin_name): +# data["total_statistics"][key][plugin_name] = 0 +# if not data["day_statistics"].get(key): +# data["day_statistics"][key] = {} +# if not data["day_statistics"][key].get(plugin_name): +# data["day_statistics"][key][plugin_name] = 0 - if key != "total": - if not data["week_statistics"].get(key): - data["week_statistics"][key] = {} - if data["week_statistics"][key].get("0") is None: - for i in range(7): - data["week_statistics"][key][str(i)] = {} - if data["week_statistics"][key]["0"].get(plugin_name) is None: - for i in range(7): - data["week_statistics"][key][str(i)][plugin_name] = 0 +# if key != "total": +# if not data["week_statistics"].get(key): +# data["week_statistics"][key] = {} +# if data["week_statistics"][key].get("0") is None: +# for i in range(7): +# data["week_statistics"][key][str(i)] = {} +# if data["week_statistics"][key]["0"].get(plugin_name) is None: +# for i in range(7): +# data["week_statistics"][key][str(i)][plugin_name] = 0 - if not data["month_statistics"].get(key): - data["month_statistics"][key] = {} - if data["month_statistics"][key].get("0") is None: - for i in range(30): - data["month_statistics"][key][str(i)] = {} - if data["month_statistics"][key]["0"].get(plugin_name) is None: - for i in range(30): - data["month_statistics"][key][str(i)][plugin_name] = 0 +# if not data["month_statistics"].get(key): +# data["month_statistics"][key] = {} +# if data["month_statistics"][key].get("0") is None: +# for i in range(30): +# data["month_statistics"][key][str(i)] = {} +# if data["month_statistics"][key]["0"].get(plugin_name) is None: +# for i in range(30): +# data["month_statistics"][key][str(i)][plugin_name] = 0 # 天 -@scheduler.scheduled_job( - "cron", - hour=0, - minute=1, -) -async def _(): - for data in [_prefix_count_dict, _prefix_user_count_dict]: - data["day_index"] += 1 - for x in data["day_statistics"].keys(): - for key in data["day_statistics"][x].keys(): - try: - data["day_statistics"][x][key] = 0 - except KeyError: - pass - for type_ in ["week_statistics", "month_statistics"]: - index = str( - data["day_index"] % 7 - if type_ == "week_statistics" - else data["day_index"] % 30 - ) - for x in data[type_].keys(): - try: - for key in data[type_][x][index].keys(): - data[type_][x][index][key] = 0 - except KeyError: - pass - with open(statistics_group_file, "w", encoding="utf8") as f: - json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) - with open(statistics_user_file, "w", encoding="utf8") as f: - json.dump(_prefix_user_count_dict, f, indent=4, ensure_ascii=False) +# @scheduler.scheduled_job( +# "cron", +# hour=0, +# minute=1, +# ) +# async def _(): +# for data in [_prefix_count_dict, _prefix_user_count_dict]: +# data["day_index"] += 1 +# for x in data["day_statistics"].keys(): +# for key in data["day_statistics"][x].keys(): +# try: +# data["day_statistics"][x][key] = 0 +# except KeyError: +# pass +# for type_ in ["week_statistics", "month_statistics"]: +# index = str( +# data["day_index"] % 7 +# if type_ == "week_statistics" +# else data["day_index"] % 30 +# ) +# for x in data[type_].keys(): +# try: +# for key in data[type_][x][index].keys(): +# data[type_][x][index][key] = 0 +# except KeyError: +# pass +# with open(statistics_group_file, "w", encoding="utf8") as f: +# json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) +# with open(statistics_user_file, "w", encoding="utf8") as f: +# json.dump(_prefix_user_count_dict, f, indent=4, ensure_ascii=False) diff --git a/plugins/statistics/utils.py b/plugins/statistics/utils.py new file mode 100644 index 00000000..c35b5672 --- /dev/null +++ b/plugins/statistics/utils.py @@ -0,0 +1,16 @@ +from typing import List +from nonebot.adapters.onebot.v11 import MessageEvent +from ._config import SearchType + + +def parse_data(cmd: str, event: MessageEvent, superusers: List[str]): + search_type = SearchType.TOTAL + if cmd[:2] == "全局": + if str(event.user_id) in superusers: + if cmd[2] == '日': + search_type = SearchType.DAY + elif cmd[2] == '周': + _type = SearchType.WEEK + elif cmd[2] == '月': + _type = SearchType.MONTH + diff --git a/plugins/web_ui/__init__.py b/plugins/web_ui/__init__.py index 4e03feda..fddfe793 100644 --- a/plugins/web_ui/__init__.py +++ b/plugins/web_ui/__init__.py @@ -12,24 +12,15 @@ from configs.config import Config as gConfig from services.log import logger, logger_ from utils.manager import plugins2settings_manager -# from .api.base_info import router as base_info_routes -# from .api.group import router as group_routes from .api.logs import router as ws_log_routes from .api.logs.log_manager import LOG_STORAGE from .api.tabs.database import router as database_router - -# from .api.system import router as system_routes from .api.tabs.main import router as main_router from .api.tabs.main import ws_router as status_routes from .api.tabs.manage import router as manage_router - -# from .api.g import * +from .api.tabs.plugin_manage import router as plugin_router from .auth import router as auth_router -# from .api.plugins import router as plugin_routes -# from .api.request import router as request_routes - - driver = nonebot.get_driver() gConfig.add_plugin_config("web-ui", "username", "admin", name="web-ui", help_="前端管理用户名") @@ -40,13 +31,10 @@ gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前 BaseApiRouter = APIRouter(prefix="/zhenxun/api") BaseApiRouter.include_router(auth_router) -# BaseApiRouter.include_router(plugin_routes) -# BaseApiRouter.include_router(group_routes) -# BaseApiRouter.include_router(request_routes) -# BaseApiRouter.include_router(system_routes) BaseApiRouter.include_router(main_router) BaseApiRouter.include_router(manage_router) BaseApiRouter.include_router(database_router) +BaseApiRouter.include_router(plugin_router) @driver.on_startup diff --git a/plugins/web_ui/api/__init__.py b/plugins/web_ui/api/__init__.py index 92af2280..32d31b27 100644 --- a/plugins/web_ui/api/__init__.py +++ b/plugins/web_ui/api/__init__.py @@ -1,5 +1 @@ -# from .group import * -# from .plugins import * -# from .request import * -# from .system import * from .tabs import * diff --git a/plugins/web_ui/api/base_info.py b/plugins/web_ui/api/base_info.py deleted file mode 100644 index 3b9a7db3..00000000 --- a/plugins/web_ui/api/base_info.py +++ /dev/null @@ -1,75 +0,0 @@ -# from datetime import datetime, timedelta -# from typing import List, Optional - -# import nonebot -# from fastapi import APIRouter - -# from configs.config import Config -# from models.chat_history import ChatHistory -# from services.log import logger -# from utils.manager import plugin_data_manager, plugins2settings_manager, plugins_manager -# from utils.manager.models import PluginData, PluginType - -# from ..base_model import BotInfo, Result -# from ..models.params import UpdateConfig, UpdatePlugin -# from ..utils import authentication - -# AVA_URL = "http://q1.qlogo.cn/g?b=qq&nk={}&s=160" - -# router = APIRouter() - - -# @router.get("/get_bot_info", dependencies=[authentication()]) -# async def _(self_id: Optional[str] = None) -> Result: -# """ -# 获取Bot基础信息 - -# Args: -# qq (Optional[str], optional): qq号. Defaults to None. - -# Returns: -# Result: 获取指定bot信息与bot列表 -# """ -# bot_list: List[BotInfo] = [] -# if bots := nonebot.get_bots(): -# select_bot: BotInfo -# for key, bot in bots.items(): -# bot_list.append( -# BotInfo( -# bot=bot, # type: ignore -# self_id=bot.self_id, -# nickname="可爱的小真寻", -# ava_url=AVA_URL.format(bot.self_id), -# ) -# ) -# if _bl := [b for b in bot_list if b.self_id == self_id]: -# select_bot = _bl[0] -# else: -# select_bot = bot_list[0] -# select_bot.is_select = True -# now = datetime.now() -# select_bot.received_messages = await ChatHistory.filter( -# bot_id=int(select_bot.self_id) -# ).count() -# select_bot.received_messages_day = await ChatHistory.filter( -# bot_id=int(select_bot.self_id), -# create_time__gte=now - timedelta(hours=now.hour), -# ).count() -# select_bot.received_messages_week = await ChatHistory.filter( -# bot_id=int(select_bot.self_id), -# create_time__gte=now - timedelta(days=7), -# ).count() -# select_bot.group_count = len(await select_bot.bot.get_group_list()) -# select_bot.friend_count = len(await select_bot.bot.get_friend_list()) -# for bot in bot_list: -# bot.bot = None # type: ignore -# # 插件加载数量 -# select_bot.plugin_count = len(plugins2settings_manager) -# pm_data = plugins_manager.get_data() -# select_bot.fail_plugin_count = len([pd for pd in pm_data if pm_data[pd].error]) -# select_bot.success_plugin_count = ( -# select_bot.plugin_count - select_bot.fail_plugin_count -# ) - -# return Result.ok(bot_list, "已获取操作列表") -# return Result.fail("无Bot连接") diff --git a/plugins/web_ui/api/group.py b/plugins/web_ui/api/group.py deleted file mode 100644 index 76f1a4d0..00000000 --- a/plugins/web_ui/api/group.py +++ /dev/null @@ -1,69 +0,0 @@ -# from fastapi import APIRouter -# from pydantic.error_wrappers import ValidationError - -# from services.log import logger -# from utils.manager import group_manager -# from utils.utils import get_bot - -# from ..base_model import Group, GroupResult, Result, Task -# from ..models.params import UpdateGroup -# from ..utils import authentication - -# router = APIRouter() - - -# @router.get("/get_group", dependencies=[authentication()]) -# async def _() -> Result: -# """ -# 获取群信息 -# """ -# group_list_result = [] -# try: -# group_info = {} -# if bot := get_bot(): -# group_list = await bot.get_group_list() -# for g in group_list: -# group_info[g["group_id"]] = Group(**g) -# group_data = group_manager.get_data() -# for group_id in group_data.group_manager: -# task_list = [] -# data = group_manager[group_id].dict() -# for tn, status in data["group_task_status"].items(): -# task_list.append( -# Task( -# **{ -# "name": tn, -# "nameZh": group_manager.get_task_data().get(tn) or tn, -# "status": status, -# } -# ) -# ) -# data["task"] = task_list -# if x := group_info.get(int(group_id)): -# data["group"] = x -# else: -# continue -# group_list_result.append(GroupResult(**data)) -# except Exception as e: -# logger.error("调用API错误", "/get_group", e=e) -# return Result.fail(f"{type(e)}: {e}") -# return Result.ok(group_list_result, "拿到了新鲜出炉的数据!") - - -# @router.post("/update_group", dependencies=[authentication()]) -# async def _(group: UpdateGroup) -> Result: -# """ -# 修改群信息 -# """ -# try: -# group_id = group.group_id -# group_manager.set_group_level(group_id, group.level) -# if group.status: -# group_manager.turn_on_group_bot_status(group_id) -# else: -# group_manager.shutdown_group_bot_status(group_id) -# group_manager.save() -# except Exception as e: -# logger.error("调用API错误", "/get_group", e=e) -# return Result.fail(f"{type(e)}: {e}") -# return Result.ok(info="已完成记录!") diff --git a/plugins/web_ui/api/logs/log_manager.py b/plugins/web_ui/api/logs/log_manager.py index 0257f9cf..c7c8140e 100644 --- a/plugins/web_ui/api/logs/log_manager.py +++ b/plugins/web_ui/api/logs/log_manager.py @@ -21,18 +21,18 @@ class LogStorage(Generic[_T]): self.listeners: Set[LogListener[str]] = set() async def add(self, log: str): - log = re.sub(PATTERN, "", log) - log_split = log.split() - time = log_split[0] + " " + log_split[1] - level = log_split[2] - main = log_split[3] - type_ = None - log_ = " ".join(log_split[3:]) - if "Calling API" in log_: - sp = log_.split("|") - type_ = sp[1] - log_ = "|".join(log_[1:]) - data = {"time": time, "level": level, "main": main, "type": type_, "log": log_} + # log = re.sub(PATTERN, "", log) + # log_split = log.split() + # time = log_split[0] + " " + log_split[1] + # level = log_split[2] + # main = log_split[3] + # type_ = None + # log_ = " ".join(log_split[3:]) + # if "Calling API" in log_: + # sp = log_.split("|") + # type_ = sp[1] + # log_ = "|".join(log_[1:]) + # data = {"time": time, "level": level, "main": main, "type": type_, "log": log_} seq = self.count = self.count + 1 self.logs[seq] = log asyncio.get_running_loop().call_later(self.rotation, self.remove, seq) diff --git a/plugins/web_ui/api/plugins.py b/plugins/web_ui/api/plugins.py deleted file mode 100644 index 8262a0bd..00000000 --- a/plugins/web_ui/api/plugins.py +++ /dev/null @@ -1,115 +0,0 @@ -# from typing import Optional - -# import cattrs -# from fastapi import APIRouter - -# from configs.config import Config -# from services.log import logger -# from utils.manager import plugin_data_manager, plugins2settings_manager, plugins_manager -# from utils.manager.models import PluginData, PluginType - -# from ..config import * -# from ..base_model import Plugin, PluginConfig, Result -# from ..models.params import UpdateConfig, UpdatePlugin -# from ..utils import authentication - -# router = APIRouter() - - -# @router.get("/get_plugins", dependencies=[authentication()]) -# def _( -# plugin_type: PluginType, -# ) -> Result: -# """ -# 获取插件列表 -# :param plugin_type: 类型 normal, superuser, hidden, admin -# """ -# try: -# plugin_list = [] -# for module in plugin_data_manager.keys(): -# plugin_data: Optional[PluginData] = plugin_data_manager[module] -# if plugin_data and plugin_data.plugin_type == plugin_type: -# plugin_config = None -# if plugin_data.plugin_configs: -# plugin_config = {} -# for key in plugin_data.plugin_configs: -# plugin_config[key] = PluginConfig( -# key=key, -# module=module, -# has_type=bool(plugin_data.plugin_configs[key].type), -# **plugin_data.plugin_configs[key].dict(), -# ) -# plugin_list.append( -# Plugin( -# model=module, -# plugin_settings=plugin_data.plugin_setting, -# plugin_manager=plugin_data.plugin_status, -# plugin_config=plugin_config, -# cd_limit=plugin_data.plugin_cd, -# block_limit=plugin_data.plugin_block, -# count_limit=plugin_data.plugin_count, -# ) -# ) -# except Exception as e: -# logger.error("调用API错误", "/get_plugins", e=e) -# return Result.fail(f"{type(e)}: {e}") -# return Result.ok(plugin_list, "拿到了新鲜出炉的数据!") - - -# @router.post("/update_plugins", dependencies=[authentication()]) -# def _(plugin: UpdatePlugin) -> Result: -# """ -# 修改插件信息 -# :param plugin: 插件内容 -# """ -# try: -# module = plugin.module -# if p2s := plugins2settings_manager.get(module): -# p2s.default_status = plugin.default_status -# p2s.limit_superuser = plugin.limit_superuser -# p2s.cost_gold = plugin.cost_gold -# p2s.cmd = plugin.cmd -# p2s.level = plugin.group_level -# if pd := plugin_data_manager.get(module): -# menu_lin = None -# if len(pd.menu_type) > 1: -# menu_lin = pd.menu_type[1] -# if menu_lin is not None: -# pd.menu_type = (plugin.menu_type, menu_lin) -# else: -# pd.menu_type = (plugin.menu_type,) -# if pm := plugins_manager.get(module): -# if plugin.block_type: -# pm.block_type = plugin.block_type -# pm.status = False -# else: -# pm.block_type = None -# pm.status = True -# plugins2settings_manager.save() -# plugins_manager.save() -# except Exception as e: -# logger.error("调用API错误", "/update_plugins", e=e) -# return Result.fail(f"{type(e)}: {e}") -# return Result.ok(info="已经帮你写好啦!") - - -# @router.post("/update_config", dependencies=[authentication()]) -# def _(config_list: List[UpdateConfig]) -> Result: -# try: -# for config in config_list: -# if cg := Config.get(config.module): -# if c := cg.configs.get(config.key): -# if isinstance(c.value, (list, tuple)) or isinstance( -# c.default_value, (list, tuple) -# ): -# value = config.value.split(",") -# else: -# value = config.value -# if c.type and value is not None: -# value = cattrs.structure(value, c.type) -# Config.set_config(config.module, config.key, value) -# except Exception as e: -# logger.error("调用API错误", "/update_config", e=e) -# return Result.fail(f"{type(e)}: {e}") -# Config.save(save_simple_data=True) -# return Result.ok(info="写入配置项了哦!") diff --git a/plugins/web_ui/api/request.py b/plugins/web_ui/api/request.py deleted file mode 100644 index 83a878dd..00000000 --- a/plugins/web_ui/api/request.py +++ /dev/null @@ -1,87 +0,0 @@ -from typing import Optional - -from fastapi import APIRouter - -from configs.config import NICKNAME -from models.group_info import GroupInfo -from services.log import logger -from utils.manager import requests_manager -from utils.utils import get_bot - -from ..base_model import RequestResult, Result -from ..models.params import HandleRequest -from ..utils import authentication - -router = APIRouter() - - -@router.get("/get_request", dependencies=[authentication()]) -def _(request_type: Optional[str]) -> Result: - try: - req_data = requests_manager.get_data() - req_list = [] - if request_type in ["group", "private"]: - req_data = req_data[request_type] - for x in req_data: - req_data[x]["oid"] = x - req_list.append(RequestResult(**req_data[x])) - req_list.reverse() - except Exception as e: - logger.error("调用API错误", "/get_request", e=e) - return Result.fail(f"{type(e)}: {e}") - return Result.ok(req_list, f"{NICKNAME}带来了最新的数据!") - - -@router.delete("/clear_request", dependencies=[authentication()]) -def _(request_type: Optional[str]) -> Result: - """ - 清空请求 - :param type_: 类型 - """ - requests_manager.clear(request_type) - return Result.ok(info="成功清除了数据") - - -# @router.post("/handle_request", dependencies=[authentication()]) -# async def _(parma: HandleRequest) -> Result: -# """ -# 操作请求 -# :param parma: 参数 -# """ -# try: -# result = "操作成功!" -# flag = 3 -# if bot := get_bot(): -# if parma.handle == "approve": -# if parma.type == "group": -# if rid := requests_manager.get_group_id(parma.id): -# # await GroupInfo.update_or_create(defaults={"group_flag": 1}, ) -# if group := await GroupInfo.get_or_none(group_id=str(rid)): -# await group.update_or_create(group_flag=1) -# else: -# group_info = await bot.get_group_info(group_id=rid) -# await GroupInfo.update_or_create( -# group_id=str(group_info["group_id"]), -# defaults={ -# "group_name": group_info["group_name"], -# "max_member_count": group_info["max_member_count"], -# "member_count": group_info["member_count"], -# "group_flag": 1, -# }, -# ) -# flag = await requests_manager.approve(bot, parma.id, parma.type) -# elif parma.handle == "refuse": -# flag = await requests_manager.refused(bot, parma.id, parma.type) -# elif parma.handle == "delete": -# requests_manager.delete_request(parma.id, parma.type) -# if parma.handle != "delete": -# if flag == 1: -# result = "该请求已失效" -# requests_manager.delete_request(parma.id, parma.type) -# elif flag == 2: -# result = "未找到此Id" -# return Result.ok(result, "成功处理了请求!") -# return Result.fail("Bot未连接") -# except Exception as e: -# logger.error("调用API错误", "/get_group", e=e) -# return Result.fail(f"{type(e)}: {e}") diff --git a/plugins/web_ui/api/tabs/__init__.py b/plugins/web_ui/api/tabs/__init__.py index 97abef9c..c2758a6a 100644 --- a/plugins/web_ui/api/tabs/__init__.py +++ b/plugins/web_ui/api/tabs/__init__.py @@ -1,3 +1,4 @@ from .database import * from .main import * from .manage import * +from .plugin_manage import * diff --git a/plugins/web_ui/api/tabs/main/__init__.py b/plugins/web_ui/api/tabs/main/__init__.py index 7daa0ddc..125cb587 100644 --- a/plugins/web_ui/api/tabs/main/__init__.py +++ b/plugins/web_ui/api/tabs/main/__init__.py @@ -7,21 +7,26 @@ import nonebot from fastapi import APIRouter, WebSocket from nonebot.utils import escape_tag from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState +from tortoise.functions import Count +from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK from configs.config import NICKNAME from models.chat_history import ChatHistory +from models.group_info import GroupInfo +from models.statistics import Statistics from services.log import logger from utils.manager import plugin_data_manager, plugins2settings_manager, plugins_manager -from utils.manager.models import PluginData, PluginType -from ....config import QueryDateType from ....base_model import Result +from ....config import QueryDateType from ....utils import authentication, get_system_status from .data_source import bot_live -from .model import BaseInfo +from .model import ActiveGroup, BaseInfo, ChatHistoryCount, HotPlugin AVA_URL = "http://q1.qlogo.cn/g?b=qq&nk={}&s=160" +GROUP_AVA_URL = "http://p.qlogo.cn/gh/{}/{}/640/" + run_time = time.time() ws_router = APIRouter() @@ -34,7 +39,7 @@ async def _(bot_id: Optional[str] = None) -> Result: 获取Bot基础信息 Args: - qq (Optional[str], optional): qq号. Defaults to None. + bot_id (Optional[str], optional): bot_id. Defaults to None. Returns: Result: 获取指定bot信息与bot列表 @@ -43,20 +48,22 @@ async def _(bot_id: Optional[str] = None) -> Result: if bots := nonebot.get_bots(): select_bot: BaseInfo for key, bot in bots.items(): + login_info = await bot.get_login_info() bot_list.append( BaseInfo( bot=bot, # type: ignore self_id=bot.self_id, - nickname=NICKNAME, + nickname=login_info["nickname"], ava_url=AVA_URL.format(bot.self_id), ) ) - # 获取指定qq号的bot信息,若无指定则获取第一个 + # 获取指定qq号的bot信息,若无指定 则获取第一个 if _bl := [b for b in bot_list if b.self_id == bot_id]: select_bot = _bl[0] else: select_bot = bot_list[0] select_bot.is_select = True + select_bot.config = select_bot.bot.config now = datetime.now() # 今日累计接收消息 select_bot.received_messages = await ChatHistory.filter( @@ -78,11 +85,43 @@ async def _(bot_id: Optional[str] = None) -> Result: ) # 连接时间 select_bot.connect_time = bot_live.get(select_bot.self_id) or 0 + if select_bot.connect_time: + connect_date = datetime.fromtimestamp(select_bot.connect_time) + select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S") - return Result.ok(bot_list, "已获取操作列表") + return Result.ok(bot_list, "拿到信息啦!") return Result.warning_("无Bot连接...") +@router.get( + "/get_all_ch_count", dependencies=[authentication()], description="获取接收消息数量" +) +async def _(bot_id: str) -> Result: + now = datetime.now() + all_count = await ChatHistory.filter(bot_id=bot_id).count() + day_count = await ChatHistory.filter( + bot_id=bot_id, create_time__gte=now - timedelta(hours=now.hour) + ).count() + week_count = await ChatHistory.filter( + bot_id=bot_id, create_time__gte=now - timedelta(days=7) + ).count() + month_count = await ChatHistory.filter( + bot_id=bot_id, create_time__gte=now - timedelta(days=30) + ).count() + year_count = await ChatHistory.filter( + bot_id=bot_id, create_time__gte=now - timedelta(days=365) + ).count() + return Result.ok( + ChatHistoryCount( + num=all_count, + day=day_count, + week=week_count, + month=month_count, + year=year_count, + ) + ) + + @router.get("/get_ch_count", dependencies=[authentication()], description="获取接收消息数量") async def _(bot_id: str, query_type: Optional[QueryDateType] = None) -> Result: if bots := nonebot.get_bots(): @@ -135,6 +174,81 @@ async def _() -> Result: return Result.ok(int(time.time() - run_time)) +@router.get("/get_active_group", dependencies=[authentication()], description="获取活跃群聊") +async def _(date_type: Optional[QueryDateType] = None) -> Result: + query = ChatHistory + now = datetime.now() + if date_type == QueryDateType.DAY: + query = ChatHistory.filter(create_time__gte=now - timedelta(hours=now.hour)) + if date_type == QueryDateType.WEEK: + query = ChatHistory.filter(create_time__gte=now - timedelta(days=7)) + if date_type == QueryDateType.MONTH: + query = ChatHistory.filter(create_time__gte=now - timedelta(days=30)) + if date_type == QueryDateType.YEAR: + query = ChatHistory.filter(create_time__gte=now - timedelta(days=365)) + data_list = ( + await query.annotate(count=Count("id")) + .group_by("group_id").order_by("-count").limit(5) + .values_list("group_id", "count") + ) + active_group_list = [] + id2name = {} + if data_list: + if info_list := await GroupInfo.filter(group_id__in=[x[0] for x in data_list]).all(): + for group_info in info_list: + id2name[group_info.group_id] = group_info.group_name + for data in data_list: + active_group_list.append( + ActiveGroup( + group_id=data[0], + name=id2name.get(data[0]) or data[0], + chat_num=data[1], + ava_img=GROUP_AVA_URL.format(data[0], data[0]), + ) + ) + active_group_list = sorted( + active_group_list, key=lambda x: x.chat_num, reverse=True + ) + if len(active_group_list) > 5: + active_group_list = active_group_list[:5] + return Result.ok(active_group_list) + + +@router.get("/get_hot_plugin", dependencies=[authentication()], description="获取热门插件") +async def _(date_type: Optional[QueryDateType] = None) -> Result: + query = Statistics + now = datetime.now() + if date_type == QueryDateType.DAY: + query = Statistics.filter(create_time__gte=now - timedelta(hours=now.hour)) + if date_type == QueryDateType.WEEK: + query = Statistics.filter(create_time__gte=now - timedelta(days=7)) + if date_type == QueryDateType.MONTH: + query = Statistics.filter(create_time__gte=now - timedelta(days=30)) + if date_type == QueryDateType.YEAR: + query = Statistics.filter(create_time__gte=now - timedelta(days=365)) + data_list = ( + await query.annotate(count=Count("id")) + .group_by("plugin_name").order_by("-count").limit(5) + .values_list("plugin_name", "count") + ) + hot_plugin_list = [] + for data in data_list: + name = data[0] + if plugin_data := plugin_data_manager.get(data[0]): + name = plugin_data.name + hot_plugin_list.append( + HotPlugin( + module=data[0], + name=name, + count=data[1], + ) + ) + hot_plugin_list = sorted(hot_plugin_list, key=lambda x: x.count, reverse=True) + if len(hot_plugin_list) > 5: + hot_plugin_list = hot_plugin_list[:5] + return Result.ok(hot_plugin_list) + + @ws_router.websocket("/system_status") async def system_logs_realtime(websocket: WebSocket): await websocket.accept() @@ -144,6 +258,6 @@ async def system_logs_realtime(websocket: WebSocket): system_status = await get_system_status() await websocket.send_text(system_status.json()) await asyncio.sleep(5) - except WebSocketDisconnect: + except (WebSocketDisconnect, ConnectionClosedError, ConnectionClosedOK): pass return diff --git a/plugins/web_ui/api/tabs/main/data_source.py b/plugins/web_ui/api/tabs/main/data_source.py index e164383c..42a3df42 100644 --- a/plugins/web_ui/api/tabs/main/data_source.py +++ b/plugins/web_ui/api/tabs/main/data_source.py @@ -3,7 +3,7 @@ from typing import Optional import nonebot from nonebot import Driver -from nonebot.adapters.onebot.v12 import Bot +from nonebot.adapters.onebot.v11 import Bot driver: Driver = nonebot.get_driver() diff --git a/plugins/web_ui/api/tabs/main/model.py b/plugins/web_ui/api/tabs/main/model.py index decb2aea..bced1817 100644 --- a/plugins/web_ui/api/tabs/main/model.py +++ b/plugins/web_ui/api/tabs/main/model.py @@ -1,4 +1,8 @@ +from datetime import datetime +from typing import Optional, Union + from nonebot.adapters.onebot.v11 import Bot +from nonebot.config import Config from pydantic import BaseModel @@ -41,6 +45,8 @@ class BaseInfo(BaseModel): # """一年内累计接受消息""" connect_time: int = 0 """连接时间""" + connect_date: Optional[datetime] = None + """连接日期""" plugin_count: int = 0 """加载插件数量""" @@ -52,5 +58,53 @@ class BaseInfo(BaseModel): is_select: bool = False """当前选择""" + config: Optional[Config] = None + """nb配置""" + class Config: arbitrary_types_allowed = True + + +class ChatHistoryCount(BaseModel): + """ + 聊天记录数量 + """ + + num: int + """总数""" + day: int + """一天内""" + week: int + """一周内""" + month: int + """一月内""" + year: int + """一年内""" + + +class ActiveGroup(BaseModel): + """ + 活跃群聊数据 + """ + + group_id: Union[str, int] + """群组id""" + name: str + """群组名称""" + chat_num: int + """发言数量""" + ava_img: str + """群组头像""" + + +class HotPlugin(BaseModel): + """ + 热门插件 + """ + + module: str + """模块名""" + name: str + """插件名称""" + count: int + """调用次数""" diff --git a/plugins/web_ui/api/tabs/plugin_manage/__init__.py b/plugins/web_ui/api/tabs/plugin_manage/__init__.py new file mode 100644 index 00000000..4201a528 --- /dev/null +++ b/plugins/web_ui/api/tabs/plugin_manage/__init__.py @@ -0,0 +1,149 @@ +from typing import List, Optional + +import cattrs +from fastapi import APIRouter + +from configs.config import Config +from services.log import logger +from utils.manager import plugin_data_manager, plugins2settings_manager, plugins_manager +from utils.manager.models import PluginData, PluginSetting, PluginType + +from ....base_model import Result +from ....utils import authentication +from .model import PluginCount, PluginInfo, PluginSwitch, UpdateConfig, UpdatePlugin + +router = APIRouter() + + +@router.get("/get_plugin_list", dependencies=[authentication()], deprecated="获取插件列表") +def _( + plugin_type: PluginType, menu_type: Optional[str] = None +) -> Result: + """ + 获取插件列表 + :param plugin_type: 类型 normal, superuser, hidden, admin + """ + try: + plugin_list: List[PluginInfo] = [] + for module in plugin_data_manager.keys(): + plugin_data: Optional[PluginData] = plugin_data_manager[module] + if plugin_data and plugin_data.plugin_type == plugin_type: + setting = plugin_data.plugin_setting or PluginSetting() + plugin = plugin_data.plugin_status + menu_type_ = getattr(setting, "plugin_type", ["无"])[0] + if menu_type and menu_type != menu_type_: + continue + plugin_info = PluginInfo( + module=module, + plugin_name=plugin_data.name, + default_switch=getattr(setting, "default_status", False), + limit_superuser=getattr(setting, "limit_superuser", False), + cost_gold=getattr(setting, "cost_gold", 0), + menu_type=menu_type_, + version=(plugin.version or 0) if plugin else 0, + level=getattr(setting, "level", 5), + status=plugin.status if plugin else False, + author=plugin.author if plugin else None + ) + plugin_info.version = (plugin.version or 0) if plugin else 0 + plugin_list.append(plugin_info) + except Exception as e: + logger.error("调用API错误", "/get_plugins", e=e) + return Result.fail(f"{type(e)}: {e}") + return Result.ok(plugin_list, "拿到了新鲜出炉的数据!") + +@router.get("/get_plugin_count", dependencies=[authentication()], deprecated="获取插件数量") +def _() -> Result: + plugin_count = PluginCount() + for module in plugin_data_manager.keys(): + plugin_data: Optional[PluginData] = plugin_data_manager[module] + if plugin_data and plugin_data.plugin_type == PluginType.NORMAL: + plugin_count.normal += 1 + elif plugin_data and plugin_data.plugin_type == PluginType.ADMIN: + plugin_count.admin += 1 + elif plugin_data and plugin_data.plugin_type == PluginType.SUPERUSER: + plugin_count.superuser += 1 + else: + plugin_count.other += 1 + return Result.ok(plugin_count) + +@router.post("/update_plugins", dependencies=[authentication()], description="更新插件参数") +def _(plugin: UpdatePlugin) -> Result: + """ + 修改插件信息 + :param plugin: 插件内容 + """ + try: + module = plugin.module + if p2s := plugins2settings_manager.get(module): + p2s.default_status = plugin.default_status + p2s.limit_superuser = plugin.limit_superuser + p2s.cost_gold = plugin.cost_gold + p2s.cmd = plugin.cmd.split(",") if plugin.cmd else [] + p2s.level = plugin.level + if pd := plugin_data_manager.get(module): + menu_lin = None + if len(pd.menu_type) > 1: + menu_lin = pd.menu_type[1] + if menu_lin is not None: + pd.menu_type = (plugin.menu_type, menu_lin) + else: + pd.menu_type = (plugin.menu_type,) + if pm := plugins_manager.get(module): + if plugin.block_type: + pm.block_type = plugin.block_type + pm.status = False + else: + pm.block_type = None + pm.status = True + plugins2settings_manager.save() + plugins_manager.save() + except Exception as e: + logger.error("调用API错误", "/update_plugins", e=e) + return Result.fail(f"{type(e)}: {e}") + return Result.ok(info="已经帮你写好啦!") + + +@router.post("/update_config", dependencies=[authentication()], description="更新配置") +def _(config_list: List[UpdateConfig]) -> Result: + try: + for config in config_list: + if cg := Config.get(config.module): + if c := cg.configs.get(config.key): + if isinstance(c.value, (list, tuple)) or isinstance( + c.default_value, (list, tuple) + ): + value = config.value.split(",") + else: + value = config.value + if c.type and value is not None: + value = cattrs.structure(value, c.type) + Config.set_config(config.module, config.key, value) + except Exception as e: + logger.error("调用API错误", "/update_config", e=e) + return Result.fail(f"{type(e)}: {e}") + Config.save(save_simple_data=True) + return Result.ok(info="写入配置项了哦!") + + +@router.post("/change_switch", dependencies=[authentication()], description="开关插件") +def _(param: PluginSwitch) -> Result: + if pm := plugins_manager.get(param.module): + pm.block_type = None if param.status else 'all' + pm.status = param.status + plugins_manager.save() + return Result.ok(info="成功改变了开关状态!") + return Result.warning_("未获取该插件的配置!") + + +@router.get("/get_plugin_menu_type", dependencies=[authentication()], description="获取插件类型") +def _() -> Result: + menu_type_list = [] + for module in plugin_data_manager.keys(): + plugin_data: Optional[PluginData] = plugin_data_manager[module] + if plugin_data: + setting = plugin_data.plugin_setting or PluginSetting() + menu_type = getattr(setting, "plugin_type", ["无"])[0] + if menu_type not in menu_type_list: + menu_type_list.append(menu_type) + return Result.ok(menu_type_list) \ No newline at end of file diff --git a/plugins/web_ui/api/tabs/plugin_manage/model.py b/plugins/web_ui/api/tabs/plugin_manage/model.py new file mode 100644 index 00000000..869bd594 --- /dev/null +++ b/plugins/web_ui/api/tabs/plugin_manage/model.py @@ -0,0 +1,135 @@ +from typing import Any, Dict, List, Optional, Union + +from pydantic import BaseModel + +from utils.manager.models import Plugin as PluginManager +from utils.manager.models import ( + PluginBlock, + PluginCd, + PluginCount, + PluginSetting, + PluginType, +) +from utils.typing import BLOCK_TYPE + + +class PluginSwitch(BaseModel): + """ + 插件开关 + """ + + module: str + """模块""" + status: bool + """开关状态""" + + +class UpdateConfig(BaseModel): + """ + 配置项修改参数 + """ + + module: str + """模块""" + key: str + """配置项key""" + value: Any + """配置项值""" + + +class UpdatePlugin(BaseModel): + """ + 插件修改参数 + """ + + module: str + """模块""" + default_status: bool + """默认开关""" + limit_superuser: bool + """限制超级用户""" + cost_gold: int + """金币花费""" + cmd: str + """插件别名""" + menu_type: str + """插件菜单类型""" + level: int + """插件所需群权限""" + block_type: BLOCK_TYPE + """禁用类型""" + + +class PluginInfo(BaseModel): + """ + 基本插件信息 + """ + + module: str + """插件名称""" + plugin_name: str + """插件中文名称""" + default_switch: bool + """默认开关""" + limit_superuser: bool + """限制超级用户""" + cost_gold: int + """花费金币""" + menu_type: str + """插件菜单类型""" + version: Union[int, str, float] + """插件版本""" + level: int + """群权限""" + status: bool + """当前状态""" + author: Optional[str] = None + """作者""" + + +class PluginConfig(BaseModel): + """ + 插件配置项 + """ + + module: str + key: str + value: Any + help: Optional[str] + default_value: Any + has_type: bool + + +class Plugin(BaseModel): + """ + 插件 + """ + + module: str + """模块名称""" + plugin_settings: Optional[PluginSetting] + """settings""" + plugin_manager: Optional[PluginManager] + """manager""" + plugin_config: Optional[Dict[str, PluginConfig]] + """配置项""" + cd_limit: Optional[PluginCd] + """cd限制""" + block_limit: Optional[PluginBlock] + """阻断限制""" + count_limit: Optional[PluginCount] + """次数限制""" + +class PluginCount(BaseModel): + """ + 插件数量 + """ + + normal: int = 0 + """普通插件""" + admin: int = 0 + """管理员插件""" + superuser: int = 0 + """超级用户插件""" + other: int = 0 + """其他插件""" \ No newline at end of file diff --git a/plugins/web_ui/base_model.py b/plugins/web_ui/base_model.py index d9f76531..2ce1a82f 100644 --- a/plugins/web_ui/base_model.py +++ b/plugins/web_ui/base_model.py @@ -76,38 +76,38 @@ class QueryModel(BaseModel, Generic[T]): return size -# class PluginConfig(BaseModel): -# """ -# 插件配置项 -# """ +class PluginConfig(BaseModel): + """ + 插件配置项 + """ -# module: str -# key: str -# value: Optional[Any] -# help: Optional[str] -# default_value: Optional[Any] -# has_type: bool + module: str + key: str + value: Optional[Any] + help: Optional[str] + default_value: Optional[Any] + has_type: bool -# class Plugin(BaseModel): -# """ -# 插件 -# """ +class Plugin(BaseModel): + """ + 插件 + """ -# model: str -# """模块名称""" -# plugin_settings: Optional[PluginSetting] -# """settings""" -# plugin_manager: Optional[PluginManager] -# """manager""" -# plugin_config: Optional[Dict[str, PluginConfig]] -# """配置项""" -# cd_limit: Optional[PluginCd] -# """cd限制""" -# block_limit: Optional[PluginBlock] -# """阻断限制""" -# count_limit: Optional[PluginCount] -# """次数限制""" + model: str + """模块名称""" + plugin_settings: Optional[PluginSetting] + """settings""" + plugin_manager: Optional[PluginManager] + """manager""" + plugin_config: Optional[Dict[str, PluginConfig]] + """配置项""" + cd_limit: Optional[PluginCd] + """cd限制""" + block_limit: Optional[PluginBlock] + """阻断限制""" + count_limit: Optional[PluginCount] + """次数限制""" class SystemStatus(BaseModel):