diff options
| author | 2024-06-17 03:52:59 +0800 | |
|---|---|---|
| committer | 2024-06-17 03:52:59 +0800 | |
| commit | 525de52d687b44fb14be7da2c46c548eb8a32fbd (patch) | |
| tree | f696587114334a87bcc672f08b9c161d797abf13 /examples | |
| parent | 5597a8af382e256951d3813aad1cedf41fcde9ac (diff) | |
| download | HydroRoll-525de52d687b44fb14be7da2c46c548eb8a32fbd.tar.gz HydroRoll-525de52d687b44fb14be7da2c46c548eb8a32fbd.zip | |
refactor(examples): update file tree
Diffstat (limited to 'examples')
25 files changed, 7 insertions, 1360 deletions
diff --git a/examples/config.toml b/examples/config.toml index debfa20..e1f9f37 100644 --- a/examples/config.toml +++ b/examples/config.toml @@ -6,20 +6,20 @@ rule_dirs = ["rules"] adapters = [ "iamai.adapter.onebot11", # "iamai.adapter.gensokyo", - # "iamai.adapter.apscheduler", + "iamai.adapter.apscheduler", # "iamai.adapter.dingtalk" -] +] [bot.log] level = "INFO" verbose_exception = true [adapter.onebot11] -adapter_type = "reverse-ws" +adapter_type = "ws" host = "127.0.0.1" -port = 8080 -url = "/cqhttp/ws" -show_raw = true +port = 3002 +# url = "/onebot" +# show_raw = true [adapter.gensokyo] adapter_type = "reverse-ws" diff --git a/examples/plugins/HydroRoll/command/ROUTES b/examples/plugins/.gitkeep index e69de29..e69de29 100644 --- a/examples/plugins/HydroRoll/command/ROUTES +++ b/examples/plugins/.gitkeep diff --git a/examples/plugins/HydroRoll/__init__.py b/examples/plugins/HydroRoll/__init__.py deleted file mode 100644 index 8a5cd74..0000000 --- a/examples/plugins/HydroRoll/__init__.py +++ /dev/null @@ -1,151 +0,0 @@ -"""中间件""" -import re -import json -import joblib -import os -import shutil - -import oneroll -from iamai import ConfigModel, Plugin -from iamai.log import logger -from iamai.exceptions import GetEventTimeout -from iamai.event import MessageEvent, Event -from iamai.typing import StateT - -from .config import Directory, GlobalConfig, Models -from .utils import * -from .models.Transformer import query - -from .config import ( - BasePluginConfig, - CommandPluginConfig, - RegexPluginConfig, - GlobalConfig, -) - -from ast import literal_eval -from os.path import dirname, join, abspath -from abc import ABC, abstractmethod -from typing import Any, Generic, TypeVar -from typing_extensions import Annotated - -ConfigT = TypeVar("ConfigT", bound=BasePluginConfig) -RegexPluginConfigT = TypeVar("RegexPluginConfigT", bound=RegexPluginConfig) -CommandPluginConfigT = TypeVar("CommandPluginConfigT", bound=CommandPluginConfig) - - -BASE_DIR = dirname(abspath("__file__")) -HYDRO_DIR = dirname(abspath(__file__)) -APP_DIR = join(BASE_DIR, "HydroRoll") - -# logger.info(GlobalConfig._copyright) - - -class Dice(Plugin[MessageEvent, Annotated[dict, {}], RegexPluginConfig]): - """中间件""" - - priority = 0 - - # TODO: infini should be able to handle all signals and tokens from Psi. - logger.info("Loading infini...") - - def __post_init__(self): - self.state = {} - self.model_path_list = [] - self.bot.global_state["HydroRoll"] = {} - self.model_dict = Models().get_models_dict() - - self.model_path_list.append(join(BASE_DIR, "models")) - self.model_path_list.append(join(HYDRO_DIR, "models")) - self.model_path_list.append(join(BASE_DIR, "HydroRoll", "models")) - - self.load_models() - - async def handle(self) -> None: - """ - @TODO: infini should be able to handle all signals and tokens from Psi. - @BODY: infini actives the rule-packages. - """ - global flag - - args = self.event.get_plain_text().split(" ") - command_list = ["/r", ".root", ".roots", ".core", ".set", ".get", ".test"] - current_cmd = args[0] - text = ( - self.event.get_plain_text()[2:] - if len(self.event.get_plain_text()) >= 2 - else None - ) - flag = True in [cmd.startswith(current_cmd) for cmd in command_list] - # logger.info(f"Command {current_cmd} not found with flag {flag}") - logger.info(f"text: {text}") - if text and self.event.get_plain_text().startswith("/r"): - logger.info(text) - try: - await self.event.reply(f"{oneroll.roll(text)}") - except Exception as e: - await self.event.reply(f"{e!r}") - if args[0] in [".root", ".roots"]: - try: - import aiohttp - - async with aiohttp.ClientSession() as session: - async with session.get( - "https://api.hydroroll.team/api/roots" - ) as response: - data = await response.json() - await self.event.reply(data["line"]) - except Exception as e: - await self.event.reply(f"{e!r}") - elif args[0] == ".core": - await self.event.reply(f"{self.state}") - # if args[0].startswith(".set"): - # resolve = Set(args[1:]) # TODO: handle multiple sets - # elif args[0].startswith(".get"): - # resolve = Get(args[1:]) # TODO: handle multiple gets - elif args[0].startswith(".test"): - try: - result = eval(self.event.message.get_plain_text()[5:]) - await self.event.reply(str(result)) - except Exception as error: - await self.event.reply(f"{error!r}") - - async def rule(self) -> bool: - """ - @TODO: Psi should be able to handle all message first. - @BODY: lexer module will return a list of tokens, parser module will parse the tokens into a tree, and executor module will execute the tokens with a stack with a bool return value. - """ - logger.info("loading psi...") - return isinstance(self.event, MessageEvent) - - def _init_directory(self, _prefix: str = ""): - """初始化水系目录""" - for _ in Directory(BASE_DIR).get_dice_dir_list(_prefix): - if not os.path.exists(_): - os.makedirs(_) - - def _init_file(self, _prefix: str = ""): - """初始化文件""" - - def init_directory(self, _prefix: str = "HydroRoll"): - """在指定目录生成水系文件结构""" - self._init_directory(_prefix=_prefix) - - def _load_model(self, path: str, model_file: str): - if model_file is None: - model_file = "" - return joblib.load(join(path, f"{model_file}")) - - def _load_models(self, model_path_list: list, model_dict: dict) -> dict: - """加载指定模型, 当然也可能是数据集""" - models = {} - for path in model_path_list: - for model_name, model_file in model_dict.items(): - if os.path.exists(join(path, model_file)): - models[model_name] = self._load_model(path, model_file) - logger.success(f'Succeeded to load model "{model_name}"') - return models - - def load_models(self): - """我想睡觉, 但我失眠了。""" - self.models = self._load_models(self.model_path_list, self.model_dict) diff --git a/examples/plugins/HydroRoll/command/__init__.py b/examples/plugins/HydroRoll/command/__init__.py deleted file mode 100644 index ec4be24..0000000 --- a/examples/plugins/HydroRoll/command/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -SET, GET, ALIAS = ("SET", "GET", "ALIAS") -INTEGER = "INTEGER" -EOF = "EOF" - -class Token(object): - def __init__(self, type, value): - self.type = type - self.value = value - - def __str__(self): - return f"Token({self.type}, {self.value}" - - def __repr__(self) -> str: - return self.__str__() - - -class Lexer(object): - def __init__(self, text): - self.text = text - self.pos = 0 - self.current_char = self.text[self.pos] - - def error(self): - raise Exception("Invalid Character") - - def advance(self): - """Advance the `pos` pointer and set the `current_char` variable.""" - self.pos += 1 - if self.pos > len(self.text) - 1: - self.current_char = None # Indicates end of input - else: - self.current_char = self.text[self.pos] - - def skip_whitespace(self): - while self.current_char is not None and self.current_char.isspace(): - self.advance() - - def integer(self): - """Return a (multidigit) integer consumed from the input.""" - result = "" - while self.current_char is not None and self.current_char.isdigit(): - result += self.current_char - self.advance() - return int(result) - - def get_next_token(self): - """Lexical analyzer (also known as scanner or tokenizer) - - This method is responsible for breaking a sentence - apart into tokens. One token at a time. - """ - while self.current_char is not None: - if self.current_char.isspace(): - self.skip_whitespace() - continue - - if self.current_char.isdigit(): - return Token(INTEGER, self.integer()) - - if self.current_char == "get": - self.advance() - return Token(GET, "get") - - if self.current_char == "set": - self.advance() - return Token(SET, "set") - - if self.current_char == "Alias": - self.advance() - return Token(ALIAS, "Alias") - - self.error() - - return Token(EOF, None) diff --git a/examples/plugins/HydroRoll/command/alias_command.py b/examples/plugins/HydroRoll/command/alias_command.py deleted file mode 100644 index 462c062..0000000 --- a/examples/plugins/HydroRoll/command/alias_command.py +++ /dev/null @@ -1,4 +0,0 @@ -from .typing import CommandBase - -class AliasCommand(CommandBase): - ...
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/command/get_command.py b/examples/plugins/HydroRoll/command/get_command.py deleted file mode 100644 index b8a8a96..0000000 --- a/examples/plugins/HydroRoll/command/get_command.py +++ /dev/null @@ -1,4 +0,0 @@ -from .typing import CommandBase - -class GetCommand(CommandBase): - ...
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/command/set_command.py b/examples/plugins/HydroRoll/command/set_command.py deleted file mode 100644 index 1f1d4dd..0000000 --- a/examples/plugins/HydroRoll/command/set_command.py +++ /dev/null @@ -1,4 +0,0 @@ -from .typing import CommandBase - -class SetCommand(CommandBase): - ...
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/command/typing.py b/examples/plugins/HydroRoll/command/typing.py deleted file mode 100644 index b52d4a6..0000000 --- a/examples/plugins/HydroRoll/command/typing.py +++ /dev/null @@ -1,4 +0,0 @@ -from pydantic import BaseModel - -class CommandBase(BaseModel): - ...
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/config.py b/examples/plugins/HydroRoll/config.py deleted file mode 100644 index c380a01..0000000 --- a/examples/plugins/HydroRoll/config.py +++ /dev/null @@ -1,110 +0,0 @@ -from randomgen import AESCounter -from numpy.random import Generator -import argparse -import sys -from os.path import dirname, dirname, join, abspath -import platform -from importlib.metadata import version -import os -from typing import Set, Optional -from iamai import ConfigModel -import datetime - -from typing import Set - -from pydantic import Field - - -class BasePluginConfig(ConfigModel): - message_str: str = "{message}" - """最终发送消息的格式。""" - - -class RegexPluginConfig(BasePluginConfig): - pass - - -class CommandPluginConfig(RegexPluginConfig): - __config_name__ = "HydroRoll" - command_prefix: Set[str] = Field(default_factory=lambda: {".", "。"}) - """命令前缀。""" - command: Set[str] = Field(default_factory=set) - """命令文本。""" - ignore_case: bool = True - """忽略大小写。""" - - -class Color: - # 定义ANSI转义序列 - RESET = "\033[0m" - BLUE_BASE = "\033[36m" - BLUE_DARK = "\033[34m" - BLUE_DARKER = "\033[32m" - BLUE_DARKEST = "\033[30m" - - -# 定义全局配置类 -class GlobalConfig: - _name = "HydroRoll[水系]" - _version = "0.1.0" - _svn = "2" - _author = "简律纯" - _iamai_version = version("iamai") - _python_ver = sys.version - _python_ver_raw = ".".join(map(str, platform.python_version_tuple()[:3])) - _base_dir = dirname(abspath("__file__")) - _hydro_dir = dirname(abspath(__file__)) - _copyright = f"""\033[36m - _ __ _ _ - /\ /\_ _ __| |_ __ ___ /__\ ___ | | | - / /_/ / | | |/ _` | '__/ _ \ / \/// _ \| | | -/ __ /| |_| | (_| | | | (_) / _ \ (_) | | | -\/ /_/ \__, |\__,_|_| \___/\/ \_/\___/|_|_| - |___/ - -\033[4m{_name} [版本 {_version}]\033[0m\033[36m -(c) HydroRoll-Team contributors, {_author}。 -Github: https://github.com/HydroRoll-Team -Under the MIT License, see LICENSE for more details. -""" - - -class Directory(object): - def __init__(self, _path: str) -> None: - self.current_path = _path - - def get_dice_dir_list(self, _prefix: str) -> list: - return [ - os.path.join(self.current_path, f"{_prefix}", *dirs) - for dirs in [ - ["config"], - ["data"], - ["rules"], - ["scripts", "lua"], - ["scripts", "js"], - ["scripts", "psi"], - ["web", "frontend"], - ["web", "backend"], - ] - ] - - -class FileManager(object): - def __init__(self, _path: str) -> None: - self.current_path = _path - - def get_file_list(self, _dir: str): - return { - "web;frontend": "index.html", - "data": "censor.json", - } - - -class Models: - """模型管理类""" - - def __init__(self) -> None: - self.builtin_models = {"hola": "hola.pkl"} - - def get_models_dict(self) -> dict: - return self.builtin_models diff --git a/examples/plugins/HydroRoll/exceptions.py b/examples/plugins/HydroRoll/exceptions.py deleted file mode 100644 index e69de29..0000000 --- a/examples/plugins/HydroRoll/exceptions.py +++ /dev/null diff --git a/examples/plugins/HydroRoll/models/Transformer.py b/examples/plugins/HydroRoll/models/Transformer.py deleted file mode 100644 index b52422e..0000000 --- a/examples/plugins/HydroRoll/models/Transformer.py +++ /dev/null @@ -1,9 +0,0 @@ -import requests - -API_URL = "https://api-inference.huggingface.co/models/sentence-transformers/all-MiniLM-L6-v2" -headers = {"Authorization": "Bearer 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"} - -def query(payload): - response = requests.post(API_URL, headers=headers, json=payload) - return response.json() - diff --git a/examples/plugins/HydroRoll/models/__init__.py b/examples/plugins/HydroRoll/models/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/examples/plugins/HydroRoll/models/__init__.py +++ /dev/null diff --git a/examples/plugins/HydroRoll/models/cos_sim.py b/examples/plugins/HydroRoll/models/cos_sim.py deleted file mode 100644 index 24b743d..0000000 --- a/examples/plugins/HydroRoll/models/cos_sim.py +++ /dev/null @@ -1,100 +0,0 @@ -"""余弦相似度比较""" - - -import joblib -import jieba -import numpy as np - -from sklearn.feature_extraction.text import TfidfTransformer -from sklearn.feature_extraction.text import CountVectorizer -from sklearn.metrics.pairwise import cosine_similarity - - -class cosSim: - def __init__(self, simple: list = [], test_data: list = []): - self.simple = simple - self.inputs = test_data - self.texts = self.simple - self.texts.extend(self.inputs) - - @property - def corpuss(self): - return [" ".join(jieba.cut(text)) for text in self.simple] - - @property - def vocabulary(self): - return self.getVocabulary(self.corpuss) - - @property - def vectors(self): - return self.getVectors(self.corpuss, self.vocabulary) - - @property - def input_corpuss(self): - return [" ".join(jieba.cut(text)) for text in self.inputs] - - @property - def input_vocabulary(self): - return self.getVocabulary(self.input_corpuss) - - @property - def input_vector(self): - return self.getVectors(self.input_corpuss, self.input_vocabulary) - - def append(self, add_test_data: list = []): - self.inputs.extend(add_test_data) - - @property - def similarities(self): - similarities = [] - corpuss = [" ".join(jieba.cut(text)) for text in self.texts] - vocabulary = self.getVocabulary(corpuss) - vector = self.getVectors(corpuss, vocabulary) - for v in vector[len(self.texts)-1:]: - sim = [] - for v1 in vector[:len(self.simple)+1]: - sim.append(self.cos_sim(v1, v)) - print('sim', sim) - similarities.append(max(sim)) - - return similarities - - @staticmethod - def cos_sim(vector_a, vector_b): - """ - 计算两个向量之间的余弦相似度 - :param vector_a: 向量 a - :param vector_b: 向量 b - :return: sim - """ - vector_a = np.array(vector_a).reshape(1, -1) - vector_b = np.array(vector_b).reshape(1, -1) - return cosine_similarity(vector_a, vector_b)[0][0] - - @staticmethod - def getVocabulary(corpuss): - vectorizer = CountVectorizer(max_features=500) - transformer = TfidfTransformer() - tfidf = transformer.fit_transform(vectorizer.fit_transform(corpuss)) - words = vectorizer.get_feature_names_out() - return words - - @staticmethod - def getVectors(corpus, vocabulary): - vectorizer = CountVectorizer(vocabulary=vocabulary) - transformer = TfidfTransformer() - tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus)) - vectors = tfidf.toarray() - return vectors - - def save(self, filename): - joblib.dump(self, filename) - - @staticmethod - def load(filename): - return joblib.load(filename) - - def reload(self): - self.texts = self.simple - self.texts.extend(self.inputs) - self.similarities
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/models/hola.py b/examples/plugins/HydroRoll/models/hola.py deleted file mode 100644 index 255f5dd..0000000 --- a/examples/plugins/HydroRoll/models/hola.py +++ /dev/null @@ -1,62 +0,0 @@ -from cos_sim import cosSim -import numpy as np - -texts = [ - "你好 HydroRoll", - "你好 水系", - "水系你好", - "HydroRoll hi~", - "水系, hola" - "你好呀 水系", - "hi 水系", - "hi HydroRoll", - "hello 水系", - "hello HydroRoll", - "hola 水系", - "hola HydroRoll", -] - -# print(model.corpuss) - -# print(model.vocabulary) - - - -model = cosSim( - simple=texts, - test_data=[ - # 'Hi! HydroRoll is a roll system.', - # 'Hello, this is a system which named HydroRoll', - # '短文本匹配技术应用是很广泛的,包括搜索、问答、推荐、计算广告等领域,相关技术也沉淀多年,从无监督方法到有监督方法层出不穷,工业界也是都有应用,短文本匹配算是自然语言处理领域的重要技术了,虽然任务简单,但是想要做好并不是那么容易的事情。', - # '短文本匹配技术在搜索、问答、推荐和计算广告等领域有广泛的应用。这项技术已经发展多年,从无监督方法到有监督方法层出不穷。在工业界,短文本匹配技术已经得到了广泛的应用。虽然短文本匹配任务看起来简单,但要做好并不容易。', - # '你好~水系。', - # 'hola~~~~~~~hola水系!' - ] -) - -# print(model.vectors) - -# print(model.input_vector) - -# print(model.input_vocabulary) - -# print(cosSim.cos_sim(vector_a=model.input_vector[4], vector_b=model.input_vector[5])) - - -print(model.similarities) - -print(model.inputs) - -# model.append(['你好水']) - -# model.append(['你好']) - -print(model.inputs) - -print(model.similarities) - -model.reload() - -print(model.input_corpuss) - -print(model.similarities)
\ No newline at end of file diff --git a/examples/plugins/HydroRoll/utils.py b/examples/plugins/HydroRoll/utils.py deleted file mode 100644 index 4c9405c..0000000 --- a/examples/plugins/HydroRoll/utils.py +++ /dev/null @@ -1,170 +0,0 @@ -import difflib -import re -import time -import random -from abc import ABC, abstractmethod -from typing import Type, Union, Generic, TypeVar -from iamai import Plugin - -import re -from abc import ABC, abstractmethod -from typing import Any, Generic, TypeVar - -from iamai import MessageEvent, Plugin -from iamai.typing import StateT - -from .config import BasePluginConfig, CommandPluginConfig, RegexPluginConfig - -ConfigT = TypeVar("ConfigT", bound=BasePluginConfig) -RegexPluginConfigT = TypeVar("RegexPluginConfigT", bound=RegexPluginConfig) -CommandPluginConfigT = TypeVar("CommandPluginConfigT", bound=CommandPluginConfig) - - -class BasePlugin( - Plugin[MessageEvent[Any], StateT, ConfigT], - ABC, - Generic[StateT, ConfigT], -): - def format_str(self, format_str: str, message_str: str = "") -> str: - return format_str.format( - message=message_str, - user_name=self.get_event_sender_name(), - user_id=self.get_event_sender_id(), - ) - - def get_event_sender_name(self) -> str: - from iamai.adapter.gensokyo.event import MessageEvent as OneBotMessageEvent - - if isinstance(self.event, OneBotMessageEvent): - return self.event.sender.nickname or "" - return "" - - def get_event_sender_id(self) -> str: - from iamai.adapter.gensokyo.event import MessageEvent as OneBotMessageEvent - - if isinstance(self.event, OneBotMessageEvent): - if self.event.sender.user_id is not None: - return str(self.event.sender.user_id) - return "" - return "" - - async def rule(self) -> bool: - return isinstance(self.event, MessageEvent) and self.str_match( - self.event.get_plain_text() - ) - - @abstractmethod - def str_match(self, msg_str: str) -> bool: - raise NotImplementedError - - -class RegexPluginBase(BasePlugin[StateT, RegexPluginConfigT], ABC): - msg_match: re.Match[str] - re_pattern: re.Pattern[str] - - def str_match(self, msg_str: str) -> bool: - msg_str = msg_str.strip() - msg_match = self.re_pattern.fullmatch(msg_str) - if msg_match is None: - return False - self.msg_match = msg_match - return bool(self.msg_match) - - -class CommandPluginBase(RegexPluginBase[StateT, CommandPluginConfigT], ABC): - command_match: re.Match[str] - command_re_pattern: re.Pattern[str] - - def str_match(self, msg_str: str) -> bool: - if not hasattr(self, "re_pattern"): - self.re_pattern = re.compile( - f'[{"".join(self.config.command_prefix)}]' - f'({"|".join(self.config.command)})' - r"\s*(?P<command_args>.*)", - flags=re.I if self.config.ignore_case else 0, - ) - msg_str = msg_str.strip() - msg_match = self.re_pattern.fullmatch(msg_str) - if not msg_match: - return False - self.msg_match = msg_match - command_match = self.re_pattern.fullmatch(self.msg_match.group("command_args")) - if not command_match: - return False - self.command_match = command_match - return True - - -class PseudoRandomGenerator: - """线性同余法随机数生成器""" - - def __init__(self, seed): - self.seed = seed - - def generate(self): - while True: - self.seed = (self.seed * 1103515245 + 12345) % (2**31) - yield self.seed - - -class HydroDice: - """水系掷骰组件 - - 一些 API 相关的工具函数 - - """ - - def __init__(self, seed): - self.generator = PseudoRandomGenerator(seed) - - def roll_dice( - self, - _counts: int | str, - _sides: int | str, - is_reversed: bool = False, - streamline: bool = False, - threshold: int | str = 5, - ) -> str: - """普通掷骰 - Args: - _counts (int | str): 掷骰个数. - _sides (int | str): 每个骰子的面数. - is_reversed (bool, optional): 倒序输出. Defaults to False. - streamline (bool, optional): 忽略过程. Defaults to False. - threshold (int | str, optional): streamline 的阈值. Defaults to 5. - - Returns: - str: 表达式结果. - """ - rolls = [] - for _ in range(int(_counts)): - roll = next(self.generator.generate()) % _sides + 1 - rolls.append(roll) - total = sum(rolls) - - if streamline: - return str(total) - if len(rolls) > int(threshold): - return str(total) - rolls_str = " + ".join(str(r) for r in rolls) - return f"{total} = {rolls_str}" if is_reversed else f"{rolls_str} = {total}" - - -def find_max_similarity(input_string, string_list): - """寻找最大的相似度""" - max_similarity = 0 - max_string = "" - - for string in string_list: - similarity = difflib.SequenceMatcher(None, input_string, string).quick_ratio() - if similarity > max_similarity: - max_similarity = similarity - max_string = string - - return max_string, max_similarity - - -def check_file(filename: str) -> bool: - """根据给定参数校验文件夹内文件完整性""" - - return False diff --git a/examples/plugins/cachetool.py b/examples/plugins/cachetool.py index 77885d2..3955891 100644 --- a/examples/plugins/cachetool.py +++ b/examples/plugins/cachetool.py @@ -29,5 +29,5 @@ class CachedPlugin(Plugin): async def rule(self) -> bool: return ( isinstance(self.event, MessageEvent) - and self.event.get_plain_text() == ".cachetools" + and self.event.get_plain_text() == "/cachetools" ) diff --git a/examples/plugins/draftbottles/__init__.py b/examples/plugins/draftbottles/__init__.py deleted file mode 100644 index 1a71f1d..0000000 --- a/examples/plugins/draftbottles/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import Union -from iamai import Plugin, Event, Depends -from iamai.log import logger -from .config import Config -from iamai.event import MessageEvent -from .database import Database -from .permission import Permission -from .workroutes import WorkRoutes -from .inspector import Inspector - - -class Bottles(Plugin, config=Config): - database: Database = Depends() - permission: Permission = Depends() - workroutes: WorkRoutes = Depends() - inspector: Inspector = Depends() - - def __init__(self): - self.text = None - self.prefix = None - self.suffix = None - - async def handle(self) -> None: - self.namespace = next( - ( - key - for key, value in self.config.command_list.items() - if value == self.prefix - ), - "", - ) - if method := getattr(self.inspector, self.namespace, None): - result = await method(self.suffix, self.config) - if result: - await self.event.reply(result) - - async def rule(self) -> bool: - if not isinstance(self.event, MessageEvent): - return False - if not self.permission.is_admin(): - return False - self.text = self.event.get_plain_text() - for prefix in list(self.config.command_list.values()): - if self.text.startswith(prefix): - self.prefix = prefix - self.suffix = self.text[len(self.prefix) + 1 :] - return True - return False diff --git a/examples/plugins/draftbottles/config.py b/examples/plugins/draftbottles/config.py deleted file mode 100644 index f5aaa72..0000000 --- a/examples/plugins/draftbottles/config.py +++ /dev/null @@ -1,52 +0,0 @@ -from iamai import ConfigModel - - -class Config(ConfigModel): - __config_name__ = "draft_bottles" - - usage: str = """\ - 指令: - 扔漂流瓶 [文本/图片] - 捡漂流瓶 - 查看漂流瓶 [漂流瓶编号] - 点赞漂流瓶 [漂流瓶编号] - 评论漂流瓶 [漂流瓶编号] [文本] - 举报漂流瓶 [漂流瓶编号] - 删除漂流瓶 [漂流瓶编号] - 我的漂流瓶 - SUPERUSER指令: - 清空漂流瓶 - 恢复漂流瓶 [漂流瓶编号] - 删除漂流瓶评论 [漂流瓶编号] [QQ号] - 漂流瓶白名单 [QQ / 群聊 / 举报] [QQ号 / 群号] - 漂流瓶黑名单 [QQ / 群聊] [QQ号 / 群号] - 漂流瓶详情 [漂流瓶编号] - """.strip() - - command_list: dict = { - "test": "/dfb", - "throw": "扔漂流瓶", - "get": "捡漂流瓶", - "report": "举报漂流瓶", - "comment": "评论漂流瓶", - "check": "查看漂流瓶", - "remove": "删除漂流瓶", - "listb": "我的漂流瓶", - "like": "点赞漂流瓶", - "resume": "恢复漂流瓶", - "clear": "清空漂流瓶", - "delete": "删除漂流瓶评论", - "details": "漂流瓶详情", - } - - ban_list: dict = { - "groups": [], - "users": [], - } - - white_list: dict = { - "groups": [], - "users": [], - } - - max_content_length: int = 1024 diff --git a/examples/plugins/draftbottles/database.py b/examples/plugins/draftbottles/database.py deleted file mode 100644 index dededac..0000000 --- a/examples/plugins/draftbottles/database.py +++ /dev/null @@ -1,11 +0,0 @@ -class Database: - admin_list: list = [2753364619] - - def __init__(self) -> None: - ... - - def connect(self): - ... - - def close(self): - ... diff --git a/examples/plugins/draftbottles/inspector.py b/examples/plugins/draftbottles/inspector.py deleted file mode 100644 index de757b2..0000000 --- a/examples/plugins/draftbottles/inspector.py +++ /dev/null @@ -1,128 +0,0 @@ -from iamai import Event, Depends, Bot -from .database import Database -from .permission import Permission -from .workroutes import WorkRoutes -from .config import Config -from iamai.exceptions import GetEventTimeout -from iamai.adapter.onebot11.message import CQHTTPMessageSegment as ms -import oneroll - -class Inspector: - event: Event = Depends() - bot: Bot = Depends() - database: Database = Depends() - permission: Permission = Depends() - workroutes: WorkRoutes = Depends() - - async def test(self, *args): - suffix = list(args)[0] - a = "1" - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def throw(self, *args): - suffix = list(args)[0] - config = list(args)[1] - if len(suffix) == 0: - """没有内容,则进入输入流""" - try: - content_event = await self.event.ask( - "在漂流瓶中要写下什么呢?(输入“取消”来取消扔漂流瓶操作。)", timeout=10 - ) # type: ignore - except GetEventTimeout: - return "超时。" - except Exception as e: - return f"{e!r}" - else: - if content_event.message.get_plain_text().lower() in ["取消", "cancel"]: - return ms.reply(content_event.message_id) + ms.text("已取消扔漂流瓶操作。") - """有内容,进行审核""" - content = content_event.message.get_plain_text() - self._throw(content=content, event=content_event) - else: - """有内容,进行审核""" - self._throw(content=suffix, event=self.event) - - async def get(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def report(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def comment(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def check(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def remove(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def listb(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def like(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def resume(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def clear(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def delete(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - async def details(self, *args): - suffix = list(args)[0] - try: - return f"{eval(suffix)}" - except Exception as e: - return f"{e!r}" - - @staticmethod - def _throw(content: str, **kwargs): - """扔出漂流瓶""" - event = kwargs.pop('event', None) diff --git a/examples/plugins/draftbottles/permission.py b/examples/plugins/draftbottles/permission.py deleted file mode 100644 index 456dc8b..0000000 --- a/examples/plugins/draftbottles/permission.py +++ /dev/null @@ -1,10 +0,0 @@ -from iamai import Event, Depends -from .database import Database - - -class Permission: - event: Event = Depends() - database: Database = Depends() - - def is_admin(self): - return self.event.user_id in self.database.admin_list diff --git a/examples/plugins/draftbottles/workroutes.py b/examples/plugins/draftbottles/workroutes.py deleted file mode 100644 index f539780..0000000 --- a/examples/plugins/draftbottles/workroutes.py +++ /dev/null @@ -1,9 +0,0 @@ -from iamai import Event, Depends -from .permission import Permission -from .database import Database - - -class WorkRoutes: - event: Event = Depends() - database: Database = Depends() - permission: Permission = Depends() diff --git a/examples/plugins/lua.py b/examples/plugins/lua.py deleted file mode 100644 index 6a36827..0000000 --- a/examples/plugins/lua.py +++ /dev/null @@ -1,64 +0,0 @@ -from iamai import Plugin -from iamai.exceptions import GetEventTimeout -from numpy.random import Generator -from iamai.adapter.onebot11.message import CQHTTPMessage, CQHTTPMessageSegment -from iamai.log import logger -from lupa import LuaRuntime -from iamai.utils import sync_func_wrapper -import asyncio - -lua = LuaRuntime(unpack_returned_tuples=True) -ms = CQHTTPMessageSegment - - -class Lua(Plugin): - priority = 1 - prefix = "/lua" - - async def handle(self) -> None: - try: - self.suffix = self.event.message.get_plain_text()[len(self.prefix) + 1 :] - - class msg: - priority = self.priority - prefix = self.prefix - fromMsg = self.event.message - suffix = self.suffix - event = self.event - - def echo(self, message=None): - if not message: - return self.__str__ - - loop = asyncio.get_event_loop() - coro = self.event.reply(message) - asyncio.run_coroutine_threadsafe(coro, loop) - - def ask(self, message=None, timeout=10, **kwargs): - if not message: - return self.__str__ - - loop = asyncio.get_event_loop() - try: - coro = self.event.ask(message, timeout=timeout) - asyncio.run_coroutine_threadsafe(coro, loop) - except GetEventTimeout: - return self.__str__ - else: - coro = self.event.reply(**kwargs) - asyncio.run_coroutine_threadsafe(coro, loop) - - lua.globals().msg = msg - lua.globals().event = self.event - # logger.info(lua.eval(self.suffix)) - if result := lua.eval(self.suffix): - await self.event.reply(result) - except Exception as e: - await self.event.reply(f"ERROR!{e!r}") - logger.info(f"ERROR with message: {e}") - - async def rule(self) -> bool: - return ( - self.event.type == "message" - and self.event.message.get_plain_text().startswith(self.prefix) - ) diff --git a/examples/plugins/nivis.❄ b/examples/plugins/nivis.❄ deleted file mode 100644 index 783fdb1..0000000 --- a/examples/plugins/nivis.❄ +++ /dev/null @@ -1,295 +0,0 @@ -""" SPI - Simple Pascal Interpreter """ - -############################################################################### -# # -# LEXER # -# # -############################################################################### - -# Token types -# -# EOF (end-of-file) token is used to indicate that -# there is no more input left for lexical analysis -from iamai import Plugin -from HydroRoll.utils import HydroDice - -INTEGER, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, EOF = ( - "INTEGER", - "PLUS", - "MINUS", - "MUL", - "DIV", - "(", - ")", - "EOF", -) - -DICE = "DICE" - - -class Token(object): - """A single token from the lexer.""" - - def __init__(self, _type, _value): - self.type = _type - self.value = _value - - def __str__(self): - """String representation of the class instance. - - Examples: - Token(INTEGER, 3) - Token(PLUS, '+') - Token(MUL, '*') - """ - return f"Token({self.type}, {repr(self.value)})" - - def __repr__(self): - return self.__str__() - - -class Lexer(object): - """A lexer for the Psi language.""" - - def __init__(self, text): - # client string input, e.g. "4 + 2 * 3 - 6 / 2" - self.text = text - # self.pos is an index into self.text - self.pos = 0 - self.current_char = self.text[self.pos] - - def error(self): - """Raise an exception at the current position.""" - raise ValueError("Invalid character") - - def advance(self): - """Advance the `pos` pointer and set the `current_char` variable.""" - self.pos += 1 - if self.pos > len(self.text) - 1: - self.current_char = None # Indicates end of input - else: - self.current_char = self.text[self.pos] - - def skip_whitespace(self): - while self.current_char is not None and self.current_char.isspace(): - self.advance() - - def integer(self): - """Return a (multidigit) integer consumed from the input.""" - result = "" - while self.current_char is not None and self.current_char.isdigit(): - result += self.current_char - self.advance() - return int(result) - - def get_next_token(self): - """Lexical analyzer (also known as scanner or tokenizer)""" - while self.current_char is not None: - if self.current_char.isspace(): - self.skip_whitespace() - continue - - token_type = { - "+": PLUS, - "-": MINUS, - "d": DICE, - "*": MUL, - "/": DIV, - "(": LPAREN, - ")": RPAREN, - }.get(self.current_char) - - if token_type: - self.advance() - return Token(token_type, self.current_char) - - if self.current_char.isdigit(): - return Token(INTEGER, self.integer()) - - self.error() - - return Token(EOF, None) - - -############################################################################### -# # -# PARSER # -# # -############################################################################### - - -class AST(object): - pass - - -class BinOp(AST): - def __init__(self, left, op, right): - self.left = left - self.token = self.op = op - self.right = right - - -class Num(AST): - def __init__(self, token): - self.token = token - self.value = token.value - - -class UnaryOp(AST): - def __init__(self, op, expr): - self.token = self.op = op - self.expr = expr - - -class Parser(object): - def __init__(self, lexer): - self.lexer = lexer - # set current token to the first token taken from the input - self.current_token = self.lexer.get_next_token() - - def error(self): - raise Exception("Invalid syntax") - - def eat(self, token_type): - # compare the current token type with the passed token - # type and if they match then "eat" the current token - # and assign the next token to the self.current_token, - # otherwise raise an exception. - if self.current_token.type == token_type: - self.current_token = self.lexer.get_next_token() - else: - self.error() - - def factor(self): - """factor : (PLUS | MINUS | DICE) factor | INTEGER | LPAREN expr RPAREN""" - token = self.current_token - if token.type == PLUS: - self.eat(PLUS) - node = UnaryOp(token, self.factor()) - return node - elif token.type == MINUS: - self.eat(MINUS) - node = UnaryOp(token, self.factor()) - return node - elif token.type == DICE: - self.eat(DICE) - left = Num(Token(INTEGER, 1)) # 默认骰子个数为1 - right = self.factor() - node = BinOp(left, token, right) - return node - elif token.type == INTEGER: - self.eat(INTEGER) - return Num(token) - elif token.type == LPAREN: - self.eat(LPAREN) - node = self.expr() - self.eat(RPAREN) - return node - - def term(self): - """term : factor ((MUL | DIV) factor)*""" - node = self.factor() - - while self.current_token.type in (MUL, DIV): - token = self.current_token - if token.type == MUL: - self.eat(MUL) - elif token.type == DIV: - self.eat(DIV) - - node = BinOp(left=node, op=token, right=self.factor()) - - return node - - def expr(self): - """ - expr : term ((PLUS | MINUS) term)* - term : factor ((MUL | DIV) factor)* - factor : (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN - """ - node = self.term() - - while self.current_token.type in (PLUS, MINUS): - token = self.current_token - if token.type == PLUS: - self.eat(PLUS) - elif token.type == MINUS: - self.eat(MINUS) - - node = BinOp(left=node, op=token, right=self.term()) - - return node - - def parse(self): - node = self.expr() - if self.current_token.type != EOF: - self.error() - return node - - -############################################################################### -# # -# INTERPRETER # -# # -############################################################################### - - -class NodeVisitor(object): - def visit(self, node): - method_name = "visit_" + type(node).__name__ - visitor = getattr(self, method_name, self.generic_visit) - return visitor(node) - - def generic_visit(self, node): - raise Exception("No visit_{} method".format(type(node).__name__)) - - -class Interpreter(NodeVisitor): - def __init__(self, parser): - self.parser = parser - - def visit_BinOp(self, node): - if node.op.type == PLUS: - return self.visit(node.left) + self.visit(node.right) - elif node.op.type == MINUS: - return self.visit(node.left) - self.visit(node.right) - elif node.op.type == DICE: - return int( - HydroDice(1).roll_dice( - _counts=self.visit(node.left), - _sides=self.visit(node.right), - streamline=True, - ) - ) - elif node.op.type == MUL: - return self.visit(node.left) * self.visit(node.right) - elif node.op.type == DIV: - return self.visit(node.left) // self.visit(node.right) - - def visit_Num(self, node): - return node.value - - def visit_UnaryOp(self, node): - op = node.op.type - if op == PLUS: - return +self.visit(node.expr) - elif op == MINUS: - return -self.visit(node.expr) - - def interpret(self): - tree = self.parser.parse() - if tree is None: - return "" - return self.visit(tree) - - -class Psi(Plugin): - async def handle(self) -> None: - lexer = Lexer(self.event.message.get_plain_text()[4:]) - parser = Parser(lexer) - interpreter = Interpreter(parser) - result = interpreter.interpret() - await self.event.reply(str(result)) - - async def rule(self) -> bool: - return self.event.type == "message" and self.event.message.startswith(".psi") diff --git a/examples/plugins/snow.nivis b/examples/plugins/snow.nivis deleted file mode 100644 index 4b31630..0000000 --- a/examples/plugins/snow.nivis +++ /dev/null @@ -1,44 +0,0 @@ -from iamai import Plugin -from numpy.random import Generator -from iamai.adapter.onebot11.message import CQHTTPMessage, CQHTTPMessageSegment - -ms = CQHTTPMessageSegment - - -class Exec(Plugin): - priority = 1 - - async def handle(self) -> None: - try: - content = [ - { - "type": "node", - "data": { - "name": f"{self.event.sender.nickname}", - "uin": f"{self.event.sender.user_id}", - "content": [ - { - "type": "text", - "data": { - "text": f"{eval(self.event.message.get_plain_text()[6:])}" - }, - }, - # eval(self.event.message.get_plain_text()[6:]) - ], - }, - } - ] - res = await self.event.adapter.send_group_forward_msg( - group_id=int(self.event.group_id), messages=content - ) - except Exception as e: - # await self.event.reply(f"ERROR!{e!r}") - await self.bot.get_adapter("onebot11").send_guild_channel_msg( - f"{eval(self.event.message.get_plain_text()[6:])}" - ) - - async def rule(self) -> bool: - return ( - self.event.type == "message" - and self.event.message.get_plain_text().startswith(".show") - ) |
