提供新webui api (#1673)

This commit is contained in:
HibiKier 2024-10-03 23:56:17 +08:00 committed by GitHub
parent 42b6e94564
commit f08114f6c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 368 additions and 67 deletions

View File

@ -1,16 +1,21 @@
import uuid
from datetime import datetime
import nonebot
import ujson as json
from nonebot import require
from nonebot.drivers import Driver
from tortoise import Tortoise
from nonebot.adapters import Bot
from nonebot.drivers import Driver
from tortoise.exceptions import OperationalError
from zhenxun.models.goods_info import GoodsInfo
from zhenxun.models.group_member_info import GroupInfoUser
from zhenxun.models.sign_user import SignUser
from zhenxun.models.user_console import UserConsole
from zhenxun.services.log import logger
from zhenxun.models.sign_user import SignUser
from zhenxun.models.goods_info import GoodsInfo
from zhenxun.models.user_console import UserConsole
from zhenxun.utils.decorator.shop import shop_register
from zhenxun.models.bot_connect_log import BotConnectLog
from zhenxun.models.group_member_info import GroupInfoUser
require("nonebot_plugin_apscheduler")
require("nonebot_plugin_alconna")
@ -19,16 +24,30 @@ require("nonebot_plugin_userinfo")
require("nonebot_plugin_htmlrender")
import nonebot
import ujson as json
driver: Driver = nonebot.get_driver()
@driver.on_bot_connect
async def _(bot: Bot):
logger.debug(f"Bot: {bot.self_id} 建立连接...")
await BotConnectLog.create(
bot_id=bot.self_id, platform=bot.adapter, connect_time=datetime.now(), type=1
)
@driver.on_bot_disconnect
async def _(bot: Bot):
logger.debug(f"Bot: {bot.self_id} 断开连接...")
await BotConnectLog.create(
bot_id=bot.self_id, platform=bot.adapter, connect_time=datetime.now(), type=0
)
SIGN_SQL = """
select distinct on("user_id") t1.user_id, t1.checkin_count, t1.add_probability, t1.specify_probability, t1.impression
select distinct on("user_id") t1.user_id, t1.checkin_count, t1.add_probability,
t1.specify_probability, t1.impression
from public.sign_group_users t1
join (
join (
select user_id, max(t2.impression) as max_impression
from public.sign_group_users t2
group by user_id
@ -38,7 +57,7 @@ from public.sign_group_users t1
BAG_SQL = """
select t1.user_id, t1.gold, t1.property
from public.bag_users t1
join (
join (
select user_id, max(t2.gold) as max_gold
from public.bag_users t2
group by user_id
@ -74,15 +93,12 @@ async def _():
}
create_list = []
sign_id_list = []
max_uid = 0
if user2uid:
max_uid = max(user2uid.values()) + 1
max_uid = max(user2uid.values()) + 1 if user2uid else 0
for old_sign in old_sign_list:
sign_id_list.append(old_sign["user_id"])
old_bag = [
if old_bag := [
b for b in old_bag_list if b["user_id"] == old_sign["user_id"]
]
if old_bag:
]:
old_bag = old_bag[0]
property = json.loads(old_bag["property"])
props = {}
@ -115,9 +131,9 @@ async def _():
create_list.clear()
uc_dict = {u.user_id: u for u in await UserConsole.all()}
for old_sign in old_sign_list:
user_console = uc_dict.get(old_sign["user_id"])
if not user_console:
user_console = await UserConsole.get_user(old_sign["user_id"], "qq")
user_console = uc_dict.get(
old_sign["user_id"]
) or await UserConsole.get_user(old_sign["user_id"], "qq")
create_list.append(
SignUser(
user_id=old_sign["user_id"],

View File

@ -1,16 +1,17 @@
from datetime import datetime
from nonebot.adapters import Bot, Event
from nonebot.adapters.onebot.v11 import PokeNotifyEvent
from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor
from nonebot.adapters import Bot, Event
from nonebot.plugin import PluginMetadata
from nonebot.message import run_postprocessor
from nonebot_plugin_session import EventSession
from nonebot.adapters.onebot.v11 import PokeNotifyEvent
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.models.statistics import Statistics
from zhenxun.configs.utils import PluginExtraData
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.statistics import Statistics
from zhenxun.utils.enum import PluginType
__plugin_meta__ = PluginMetadata(
name="功能调用统计",
@ -36,13 +37,12 @@ async def _(
if session.id1:
plugin = await PluginInfo.get_or_none(module=matcher.module_name)
plugin_type = plugin.plugin_type if plugin else None
if plugin_type == PluginType.NORMAL and matcher.plugin_name not in [
"update_info",
"statistics_handle",
]:
if plugin_type == PluginType.NORMAL:
logger.debug(f"提交调用记录: {matcher.plugin_name}...", session=session)
await Statistics.create(
user_id=session.id1,
group_id=session.id3 or session.id2,
plugin_name=matcher.plugin_name,
create_time=datetime.now(),
bot_id=bot.self_id,
)

View File

@ -1,9 +1,18 @@
from datetime import datetime, timedelta
from nonebot import require
from fastapi import APIRouter
from tortoise.functions import Count
from tortoise.expressions import RawSQL
from zhenxun.models.statistics import Statistics
from zhenxun.models.chat_history import ChatHistory
from zhenxun.models.bot_connect_log import BotConnectLog
from ....base_model import Result
from .data_source import BotManage
from ....utils import authentication
from ....base_model import Result, QueryModel, BaseResultModel
from .model import ChatCallMonthCount, QueryChatCallCount, AllChatAndCallCount
require("plugin_store")
@ -20,3 +29,142 @@ async def _() -> Result:
return Result.ok(await BotManage.get_bot_list(), "拿到信息啦!")
except Exception as e:
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
"/get_chat_and_call_count",
dependencies=[authentication()],
description="获取聊天/调用记录的全部和今日数量",
)
async def _(bot_id: str | None = None) -> Result:
now = datetime.now()
query = ChatHistory
if bot_id:
query = query.filter(bot_id=bot_id)
chat_all_count = await query.annotate().count()
chat_day_count = await query.filter(
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
).count()
query = Statistics
if bot_id:
query = query.filter(bot_id=bot_id)
call_all_count = await query.annotate().count()
call_day_count = await query.filter(
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
).count()
return Result.ok(
QueryChatCallCount(
chat_num=chat_all_count,
chat_day=chat_day_count,
call_num=call_all_count,
call_day=call_day_count,
)
)
@router.get(
"/get_all_chat_and_call_count",
dependencies=[authentication()],
description="获取聊天/调用记录的全部数据次数",
)
async def _(bot_id: str | None = None) -> Result:
now = datetime.now()
query = ChatHistory
if bot_id:
query = query.filter(bot_id=bot_id)
chat_week_count = await query.filter(
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
).count()
chat_month_count = await query.filter(
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
).count()
chat_year_count = await query.filter(
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
).count()
query = Statistics
if bot_id:
query = query.filter(bot_id=bot_id)
call_week_count = await query.filter(
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
).count()
call_month_count = await query.filter(
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
).count()
call_year_count = await query.filter(
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
).count()
return Result.ok(
AllChatAndCallCount(
chat_week=chat_week_count,
chat_month=chat_month_count,
chat_year=chat_year_count,
call_week=call_week_count,
call_month=call_month_count,
call_year=call_year_count,
)
)
@router.get(
"/get_chat_and_call_month",
dependencies=[authentication()],
deprecated="获取聊天/调用记录的一个月数量", # type: ignore
)
async def _() -> Result:
now = datetime.now()
filter_date = now - timedelta(days=30, hours=now.hour, minutes=now.minute)
chat_date_list = (
await ChatHistory.filter(create_time__gte=filter_date)
.annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
.group_by("date")
.values("date", "count")
)
call_date_list = (
await Statistics.filter(create_time__gte=filter_date)
.annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
.group_by("date")
.values("date", "count")
)
date_list = []
chat_count_list = []
call_count_list = []
chat_date2cnt = {str(date["date"]): date["count"] for date in chat_date_list}
call_date2cnt = {str(date["date"]): date["count"] for date in call_date_list}
date = now.date()
for _ in range(30):
if str(date) in chat_date2cnt:
chat_count_list.append(chat_date2cnt[str(date)])
else:
chat_count_list.append(0)
if str(date) in call_date2cnt:
call_count_list.append(call_date2cnt[str(date)])
else:
call_count_list.append(0)
date_list.append(str(date)[5:])
date -= timedelta(days=1)
chat_count_list.reverse()
call_count_list.reverse()
date_list.reverse()
return Result.ok(
ChatCallMonthCount(chat=chat_count_list, call=call_count_list, date=date_list)
)
@router.post(
"/get_connect_log",
dependencies=[authentication()],
deprecated="获取Bot连接记录", # type: ignore
)
async def _(query: QueryModel) -> Result:
total = await BotConnectLog.all().count()
if total % query.size:
total += 1
data = (
await BotConnectLog.all()
.order_by("-id")
.offset((query.index - 1) * query.size)
.limit(query.size)
)
for v in data:
v.connect_time = v.connect_time.replace(tzinfo=None).replace(microsecond=0)
return Result.ok(BaseResultModel(total=total, data=data))

View File

@ -62,10 +62,7 @@ class BotManage:
bot_info.connect_time = bot_live.get(bot.self_id) or 0
if bot_info.connect_time:
connect_date = datetime.fromtimestamp(CONNECT_TIME)
connect_date_str = connect_date.strftime("%Y-%m-%d %H:%M:%S")
bot_info.connect_date = datetime.strptime(
connect_date_str, "%Y-%m-%d %H:%M:%S"
)
bot_info.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
return bot_info
@classmethod

View File

@ -1,5 +1,3 @@
from datetime import datetime
from pydantic import BaseModel
@ -22,5 +20,52 @@ class BotInfo(BaseModel):
"""今日调用插件次数"""
connect_time: int = 0
"""连接时间"""
connect_date: datetime | None = None
connect_date: str | None = None
"""连接日期"""
class QueryChatCallCount(BaseModel):
"""
查询聊天/调用记录次数
"""
chat_num: int
"""聊天记录总数"""
chat_day: int
"""今日消息"""
call_num: int
"""调用记录总数"""
call_day: int
"""今日调用"""
class ChatCallMonthCount(BaseModel):
"""
查询聊天/调用一个月记录次数
"""
chat: list[int]
"""一个月内聊天总数"""
call: list[int]
"""一个月内调用数据"""
date: list[str]
"""日期"""
class AllChatAndCallCount(BaseModel):
"""
查询聊天/调用记录次数
"""
chat_week: int
"""一周内聊天次数"""
chat_month: int
"""一月内聊天次数"""
chat_year: int
"""一年内聊天次数"""
call_week: int
"""一周内调用次数"""
call_month: int
"""一月内调用次数"""
call_year: int
"""一年内调用次数"""

View File

@ -21,8 +21,9 @@ from ....base_model import Result
from .data_source import bot_live
from ....utils import authentication, get_system_status
from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
from .model import BaseInfo, HotPlugin, ActiveGroup, ChatHistoryCount
from .model import BaseInfo, HotPlugin, QueryCount, ActiveGroup, NonebotData
driver = nonebot.get_driver()
run_time = time.time()
ws_router = APIRouter()
@ -39,6 +40,7 @@ async def _(bot_id: str | None = None) -> Result:
返回:
Result: 获取指定bot信息与bot列表
"""
global run_time
bot_list: list[BaseInfo] = []
if bots := nonebot.get_bots():
select_bot: BaseInfo
@ -82,10 +84,7 @@ async def _(bot_id: str | None = 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)
connect_date_str = connect_date.strftime("%Y-%m-%d %H:%M:%S")
select_bot.connect_date = datetime.strptime(
connect_date_str, "%Y-%m-%d %H:%M:%S"
)
select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
version_file = Path() / "__version__"
if version_file.exists():
if text := version_file.open().read():
@ -102,23 +101,58 @@ async def _(bot_id: str | None = None) -> Result:
@router.get(
"/get_all_ch_count", dependencies=[authentication()], description="获取接收消息数量"
)
async def _(bot_id: str) -> Result:
async def _(bot_id: str | None = None) -> 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)
query = ChatHistory
if bot_id:
query = query.filter(bot_id=bot_id)
all_count = await query.annotate().count()
day_count = await query.filter(
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
).count()
week_count = await ChatHistory.filter(
bot_id=bot_id, create_time__gte=now - timedelta(days=7)
week_count = await query.filter(
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
).count()
month_count = await ChatHistory.filter(
bot_id=bot_id, create_time__gte=now - timedelta(days=30)
month_count = await query.filter(
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
).count()
year_count = await ChatHistory.filter(
bot_id=bot_id, create_time__gte=now - timedelta(days=365)
year_count = await query.filter(
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
).count()
return Result.ok(
ChatHistoryCount(
QueryCount(
num=all_count,
day=day_count,
week=week_count,
month=month_count,
year=year_count,
)
)
@router.get(
"/get_all_call_count", dependencies=[authentication()], description="获取调用次数"
)
async def _(bot_id: str | None = None) -> Result:
now = datetime.now()
query = Statistics
# if bot_id:
# query = query.filter(bot_id=bot_id)
all_count = await query.annotate().count()
day_count = await query.filter(
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
).count()
week_count = await query.filter(
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
).count()
month_count = await query.filter(
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
).count()
year_count = await query.filter(
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
).count()
return Result.ok(
QueryCount(
num=all_count,
day=day_count,
week=week_count,
@ -182,11 +216,21 @@ async def _(bot_id: str) -> Result:
return Result.warning_("无Bot连接...")
@router.get("/get_nb_data", dependencies=[authentication()], description="获取nb数据")
async def _() -> Result:
return Result.ok(NonebotData(config=driver.config, run_time=int(run_time)))
@router.get("/get_nb_config", dependencies=[authentication()], description="获取nb配置")
async def _() -> Result:
return Result.ok(driver.config)
@router.get(
"/get_run_time", dependencies=[authentication()], description="获取nb运行时间"
)
async def _() -> Result:
return Result.ok(int(time.time() - run_time))
return Result.ok(int(run_time))
@router.get(

View File

@ -1,8 +1,8 @@
import time
import nonebot
from nonebot.adapters.onebot.v11 import Bot
from nonebot.drivers import Driver
from nonebot.adapters.onebot.v11 import Bot
driver: Driver = nonebot.get_driver()

View File

@ -1,8 +1,6 @@
from datetime import datetime
from pydantic import BaseModel
from nonebot.adapters import Bot
from nonebot.config import Config
from pydantic import BaseModel
class SystemStatus(BaseModel):
@ -36,7 +34,7 @@ class BaseInfo(BaseModel):
"""今日 累计接收消息"""
connect_time: int = 0
"""连接时间"""
connect_date: datetime | None = None
connect_date: str | None = None
"""连接日期"""
plugin_count: int = 0
@ -60,7 +58,7 @@ class BaseInfo(BaseModel):
arbitrary_types_allowed = True
class ChatHistoryCount(BaseModel):
class QueryCount(BaseModel):
"""
聊天记录数量
"""
@ -103,3 +101,10 @@ class HotPlugin(BaseModel):
"""插件名称"""
count: int
"""调用次数"""
class NonebotData(BaseModel):
config: Config
"""nb配置"""
run_time: int
"""运行时间"""

View File

@ -1,6 +1,8 @@
from nonebot import require
from fastapi import APIRouter
from zhenxun.models.plugin_info import PluginInfo
from .model import PluginIr
from ....base_model import Result
from ....utils import authentication
@ -19,7 +21,14 @@ router = APIRouter(prefix="/store")
async def _() -> Result:
try:
data = await ShopManage.get_data()
return Result.ok(data)
plugin_list = [
{**data[name].dict(), "name": name, "id": idx}
for idx, name in enumerate(data)
]
modules = await PluginInfo.filter(load_status=True).values_list(
"module", flat=True
)
return Result.ok({"install_module": modules, "plugin_list": plugin_list})
except Exception as e:
return Result.fail(f"获取插件商店插件信息失败: {type(e)}: {e}")
@ -32,11 +41,24 @@ async def _() -> Result:
async def _(param: PluginIr) -> Result:
try:
result = await ShopManage.add_plugin(param.id) # type: ignore
return Result.ok(result)
return Result.ok(info=result)
except Exception as e:
return Result.fail(f"安装插件失败: {type(e)}: {e}")
@router.post(
"/update_plugin",
dependencies=[authentication()],
deprecated="更新插件", # type: ignore
)
async def _(param: PluginIr) -> Result:
try:
result = await ShopManage.update_plugin(param.id) # type: ignore
return Result.ok(info=result)
except Exception as e:
return Result.fail(f"更新插件失败: {type(e)}: {e}")
@router.post(
"/remove_plugin",
dependencies=[authentication()],
@ -45,6 +67,6 @@ async def _(param: PluginIr) -> Result:
async def _(param: PluginIr) -> Result:
try:
result = await ShopManage.remove_plugin(param.id) # type: ignore
return Result.ok(result)
return Result.ok(info=result)
except Exception as e:
return Result.fail(f"移除插件失败: {type(e)}: {e}")

View File

@ -0,0 +1,22 @@
from tortoise import fields
from zhenxun.services.db_context import Model
class BotConnectLog(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
bot_id = fields.CharField(255, description="Bot id")
"""Bot id"""
platform = fields.CharField(255, null=True, description="平台")
"""平台"""
connect_time = fields.DatetimeField(description="连接时间")
"""日期"""
type = fields.IntField(null=True, description="1: 连接, 0: 断开")
"""1: 连接, 0: 断开"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
class Meta: # type: ignore
table = "bot_connect_log"
table_description = "bot连接表"

View File

@ -4,7 +4,6 @@ from zhenxun.services.db_context import Model
class Statistics(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_id = fields.CharField(255)
@ -15,15 +14,19 @@ class Statistics(Model):
"""插件名称"""
create_time = fields.DatetimeField(auto_now=True)
"""添加日期"""
bot_id = fields.CharField(255, null=True)
"""Bot Id"""
class Meta:
class Meta: # type: ignore
table = "statistics"
table_description = "插件调用统计数据库"
@classmethod
async def _run_script(cls):
return [
"ALTER TABLE statistics RENAME COLUMN user_qq TO user_id;", # 将user_qq改为user_id
"ALTER TABLE statistics RENAME COLUMN user_qq TO user_id;",
# 将user_qq改为user_id
"ALTER TABLE statistics ALTER COLUMN user_id TYPE character varying(255);",
"ALTER TABLE statistics ALTER COLUMN group_id TYPE character varying(255);",
"ALTER TABLE statistics ADD boe_id Text DEFAULT '';",
]

View File

@ -2,7 +2,6 @@ from pydantic import BaseModel
class CommonSql(BaseModel):
sql: str
"""sql语句"""
remark: str