Add HeXi bot codebase: custom plugins, web frontends, tests
- hexi core: message handling, rate limiting, cooldown, plugin manager - Custom plugins: BF stats, daily check-in, quotes, persona cards, etc. - Community plugins vendored under hexi/plugins with local fixes - Web admin frontends (learning-chat, persona-admin), unified hexi/web - Tests for rate_limit/cooldown/memes/persona; poetry.lock Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import importlib
|
||||
from collections.abc import Awaitable
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, TypedDict
|
||||
from typing_extensions import Protocol, Unpack
|
||||
|
||||
from nonebot import logger
|
||||
|
||||
from ..config import config
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bg_provider import BgBytesData
|
||||
|
||||
|
||||
class TemplateRendererKwargs(TypedDict):
|
||||
collected: dict[str, Any]
|
||||
bg: "BgBytesData"
|
||||
|
||||
|
||||
class TemplateRenderer(Protocol):
|
||||
__name__: str
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
**kwargs: Unpack[TemplateRendererKwargs],
|
||||
) -> Awaitable[bytes]: ...
|
||||
|
||||
|
||||
@dataclass()
|
||||
class TemplateInfo:
|
||||
renderer: TemplateRenderer
|
||||
collectors: set[str] | None = None
|
||||
|
||||
|
||||
loaded_templates: dict[str, TemplateInfo] = {}
|
||||
|
||||
|
||||
def pic_template(
|
||||
name: str | None = None,
|
||||
collecting: set[str] | None = None,
|
||||
):
|
||||
def deco(func: TemplateRenderer):
|
||||
template_name = name or func.__name__
|
||||
if template_name in loaded_templates:
|
||||
raise ValueError(f"Template {template_name} already exists")
|
||||
loaded_templates[template_name] = TemplateInfo(
|
||||
renderer=func,
|
||||
collectors=collecting,
|
||||
)
|
||||
logger.debug(f"Registered template {template_name}")
|
||||
|
||||
return deco
|
||||
|
||||
|
||||
def load_builtin_templates():
|
||||
for module in Path(__file__).parent.iterdir():
|
||||
name = module.name
|
||||
if (not module.is_dir()) or name.startswith("_"):
|
||||
continue
|
||||
assert importlib.import_module(f".{name}", __package__)
|
||||
|
||||
|
||||
async def render_current_template(**kwargs: Unpack[TemplateRendererKwargs]):
|
||||
return await loaded_templates[config.ps_template].renderer(**kwargs)
|
||||
Reference in New Issue
Block a user