Files
zhenxun_bot/zhenxun/services/help_service.py
T

141 lines
4.5 KiB
Python
Raw Normal View History

from collections import defaultdict
import nonebot
from nonebot.plugin import PluginMetadata
from pydantic import BaseModel
from zhenxun import ui
from zhenxun.configs.config import BotConfig, Config
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.task_info import TaskInfo
from zhenxun.services.renderer.result_cache import RenderResultMemoryCache
from zhenxun.ui.models import HelpCategory, HelpItem, PluginHelpPageData
from zhenxun.utils.common_utils import format_usage_for_markdown
from zhenxun.utils.enum import PluginType
_PLUGIN_HELP_IMAGE_CACHE = RenderResultMemoryCache(
ttl_seconds=300,
max_items=48,
max_total_bytes=48 * 1024 * 1024,
)
class PluginData(BaseModel):
plugin: PluginInfo
metadata: PluginMetadata
class Config:
arbitrary_types_allowed = True
async def _get_plugins_by_types(plugin_types: list[PluginType]) -> list[PluginData]:
"""根据指定的插件类型列表获取插件数据"""
plugin_list = await PluginInfo.filter(plugin_type__in=plugin_types).all()
data_list = []
for plugin in plugin_list:
if _plugin := nonebot.get_plugin_by_module_name(plugin.module_path):
if _plugin.metadata:
data_list.append(PluginData(plugin=plugin, metadata=_plugin.metadata))
return data_list
async def _get_task_category() -> dict:
"""获取被动技能帮助类别"""
task_items = []
if task_list := await TaskInfo.all():
task_names = "\n".join([task.name for task in task_list])
task_items.append(
{
"name": "被动技能",
"description": "控制群组中的被动技能状态",
"usage": "通过 开启/关闭群被动 来控制群被动\n"
+ " 示例:开启/关闭群被动早晚安\n 示例:开启/关闭全部群被动"
+ " \n ---------- \n "
+ task_names,
}
)
return {
"title": "被动技能管理",
"icon_svg_path": "M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z",
"items": task_items,
}
async def create_plugin_help_image(
plugin_types: list[PluginType], page_title: str
) -> bytes:
"""
一个通用的函数,用于创建插件帮助图片。
参数:
plugin_types: 要包含在帮助中的插件类型列表。
page_title: 生成图片的标题。
返回:
bytes: 生成的图片字节流。
"""
plugins_data = await _get_plugins_by_types(plugin_types)
grouped_plugins = defaultdict(list)
for data in plugins_data:
menu_type = data.plugin.menu_type or "功能"
grouped_plugins[menu_type].append(
HelpItem(
name=data.plugin.name,
description=format_usage_for_markdown(data.metadata.description),
usage=format_usage_for_markdown(data.metadata.usage),
)
)
# 直接构建 HelpCategory 列表
categories = []
for menu_type, items in grouped_plugins.items():
categories.append(
HelpCategory(
title=menu_type,
icon_svg_path="M12,2L15.09,8.26L22,9.27L17,14.14L18.18,21.02L12,17.77L5.82,21.02L7,14.14L2,9.27L8.91,8.26L12,2Z",
items=sorted(items, key=lambda x: x.name),
)
)
task_category_data = await _get_task_category()
if task_category_data["items"]:
task_items = [HelpItem(**item) for item in task_category_data["items"]]
categories.append(
HelpCategory(
title=task_category_data["title"],
icon_svg_path=task_category_data["icon_svg_path"],
items=task_items,
)
)
# 直接实例化 Data Model
page_data = PluginHelpPageData(
bot_nickname=BotConfig.self_nickname,
page_title=page_title,
categories=categories,
)
cache_payload = {
"plugin_types": sorted([plugin_type.value for plugin_type in plugin_types]),
"page_title": page_title,
"theme": Config.get_config("UI", "THEME", "default"),
"page_data": page_data,
}
cache_key = RenderResultMemoryCache.build_key(cache_payload)
if cached_image := await _PLUGIN_HELP_IMAGE_CACHE.get(cache_key):
return cached_image
image_bytes = await ui.render(
page_data,
use_cache=True,
clip_selector=".container",
clip_padding=20,
disable_animations=True,
)
await _PLUGIN_HELP_IMAGE_CACHE.set(cache_key, image_bytes)
return image_bytes