aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/examples
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2024-06-17 03:52:59 +0800
committer简律纯 <i@jyunko.cn>2024-06-17 03:52:59 +0800
commit525de52d687b44fb14be7da2c46c548eb8a32fbd (patch)
treef696587114334a87bcc672f08b9c161d797abf13 /examples
parent5597a8af382e256951d3813aad1cedf41fcde9ac (diff)
downloadHydroRoll-525de52d687b44fb14be7da2c46c548eb8a32fbd.tar.gz
HydroRoll-525de52d687b44fb14be7da2c46c548eb8a32fbd.zip
refactor(examples): update file tree
Diffstat (limited to 'examples')
-rw-r--r--examples/config.toml12
-rw-r--r--examples/plugins/.gitkeep (renamed from examples/plugins/HydroRoll/command/ROUTES)0
-rw-r--r--examples/plugins/HydroRoll/__init__.py151
-rw-r--r--examples/plugins/HydroRoll/command/__init__.py74
-rw-r--r--examples/plugins/HydroRoll/command/alias_command.py4
-rw-r--r--examples/plugins/HydroRoll/command/get_command.py4
-rw-r--r--examples/plugins/HydroRoll/command/set_command.py4
-rw-r--r--examples/plugins/HydroRoll/command/typing.py4
-rw-r--r--examples/plugins/HydroRoll/config.py110
-rw-r--r--examples/plugins/HydroRoll/exceptions.py0
-rw-r--r--examples/plugins/HydroRoll/models/Transformer.py9
-rw-r--r--examples/plugins/HydroRoll/models/__init__.py0
-rw-r--r--examples/plugins/HydroRoll/models/cos_sim.py100
-rw-r--r--examples/plugins/HydroRoll/models/hola.py62
-rw-r--r--examples/plugins/HydroRoll/utils.py170
-rw-r--r--examples/plugins/cachetool.py2
-rw-r--r--examples/plugins/draftbottles/__init__.py48
-rw-r--r--examples/plugins/draftbottles/config.py52
-rw-r--r--examples/plugins/draftbottles/database.py11
-rw-r--r--examples/plugins/draftbottles/inspector.py128
-rw-r--r--examples/plugins/draftbottles/permission.py10
-rw-r--r--examples/plugins/draftbottles/workroutes.py9
-rw-r--r--examples/plugins/lua.py64
-rw-r--r--examples/plugins/nivis.❄295
-rw-r--r--examples/plugins/snow.nivis44
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")
- )