Compare commits

...
24 Commits
Author SHA1 Message Date
HibiKier 6cb4099a2e Update README.md 2022-04-10 22:57:36 +08:00
HibiKier e75a4966b2 Update __init__.py 2022-04-10 22:57:05 +08:00
HibiKier d55cba49bd Update data_source.py 2022-04-10 22:31:07 +08:00
HibiKier 0215abac30 update v0.1.4.7 2022-04-10 22:19:50 +08:00
HibiKier 2dcac5f009 Update README.md 2022-04-09 18:09:22 +08:00
HibiKier 0d8c64f7d1 Merge pull request #144 from AkashiCoin/main
fix: 更新问题,戳一戳图片路径问题
2022-04-09 18:08:49 +08:00
AkashiCoin 55626645fb fix: 更新问题,戳一戳图片路径问题 2022-04-09 14:56:30 +08:00
HibiKier f7925fa259 update genshin.query_role 2022-04-08 01:09:29 +08:00
HibiKier c814ae08b1 Update README.md 2022-04-06 18:52:01 +08:00
HibiKier 24666368f7 Merge pull request #143 from yajiwa/main
update search_type
2022-04-06 18:50:59 +08:00
yajiwa a77e85b62d fix bug 2022-04-06 13:17:08 +08:00
yajiwa 6319c7fce1 fix 2022-04-05 22:38:43 +08:00
yajiwa a45b95d5d4 update search_type 2022-04-05 22:15:47 +08:00
HibiKier 188f6f0f99 Update README.md 2022-04-05 19:42:20 +08:00
HibiKier a72f126d8f fix web_ui api 2022-04-05 13:14:29 +08:00
HibiKier 33eb1b83a8 Update README.md 2022-04-04 23:52:24 +08:00
HibiKier 2d9ebe2e6d Merge pull request #141 from yajiwa/main
Update word_bank plus
2022-04-04 23:50:34 +08:00
yajiwa 262b098dec Merge branch 'HibiKier:main' into main 2022-04-04 22:04:27 +08:00
HibiKier 79d88065aa Update README.md 2022-04-04 20:56:02 +08:00
yajiwa 610d588e34 Merge branch 'zhenxun_yajiwa' 2022-04-03 20:17:08 +08:00
yajiwa f99abb2f98 fix config 2022-04-03 20:11:00 +08:00
yajiwa b2b7560d05 Update word_bank_plus 2022-04-03 20:05:18 +08:00
yajiwa 07c16e5238 Merge pull request #1 from yajiwa/zhenxun_yajiwa
Update Modify the entry
2022-04-01 23:56:57 +08:00
yajiwa 1741ea7d26 Update Modify the entry 2022-04-01 23:54:40 +08:00
25 changed files with 903 additions and 393 deletions
+34 -5
View File
@@ -32,6 +32,12 @@
## 普通帮助图片 ## 普通帮助图片
![x](https://github.com/HibiKier/zhenxun_bot/blob/0.0.8.2/docs_image/3238573864-836268675-E2FFBB2AC143EAF4DDDF150438508721.png) ![x](https://github.com/HibiKier/zhenxun_bot/blob/0.0.8.2/docs_image/3238573864-836268675-E2FFBB2AC143EAF4DDDF150438508721.png)
## Web UI
[zhenxun_bot_webui](https://github.com/HibiKier/zhenxun_bot_webui)
## 一键安装脚本
[zhenxun_bot-deploy](https://github.com/AkashiCoin/zhenxun_bot-deploy)
## 提供符合真寻标准的插件仓库 ## 提供符合真寻标准的插件仓库
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot) [AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
@@ -236,6 +242,29 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
## 更新 ## 更新
### 2022/4/10 \[v0.1.4.7]
* 新增消息记录模块
* 丰富处理请求操作提示
* web ui新增配置项修改
* 修复chat_history阻断消息
### 2022/4/9
* fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
### 2022/4/8
* 修复原神玩家查询
### 2022/4/6
* update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
### 2022/4/5 \[v0.1.4.6]
* 修复web修改插件后帮助图片生成错误
### 2022/4/4 \[v0.1.4.5] ### 2022/4/4 \[v0.1.4.5]
* 替换了bt搜索URL * 替换了bt搜索URL
@@ -328,15 +357,15 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119) * epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122) * fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
### 2021/2/11 ### 2022/2/11
* 修复pix不使用反代无法下载图片 * 修复pix不使用反代无法下载图片
### 2021/2/10 \[v0.1.1] ### 2022/2/10 \[v0.1.1]
* 修复购买道具出错 * 修复购买道具出错
### 2021/2/9 \[v0.1] ### 2022/2/9 \[v0.1]
* 新增原神自动签到和手动签到 * 新增原神自动签到和手动签到
* 新增原神树脂提醒 * 新增原神树脂提醒
@@ -346,7 +375,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* 修复修改商品时限制时间出错 * 修复修改商品时限制时间出错
* 修复超时商品依旧可以被购买 * 修复超时商品依旧可以被购买
### 2021/1/16 \[v0.0.9.0] ### 2022/1/16 \[v0.0.9.0]
* Ai提供文本敏感词过滤器 * Ai提供文本敏感词过滤器
* 疫情插件适配新版腾讯API * 疫情插件适配新版腾讯API
@@ -365,7 +394,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功) * “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
* “_max_num_limit”(该道具单次使用的最多个数,默认1) * “_max_num_limit”(该道具单次使用的最多个数,默认1)
### 2021/1/5 \[v0.0.8.2] ### 2022/1/5 \[v0.0.8.2]
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币 * 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
* 商店插件将作为内置插件移动至basic_plugins * 商店插件将作为内置插件移动至basic_plugins
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.4.5 __version__: v0.1.4.7
+41
View File
@@ -0,0 +1,41 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from models.chat_history import ChatHistory
from ._rule import rule
from configs.config import Config
from nonebot import on_message
__zx_plugin_name__ = "消息存储 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
Config.add_plugin_config(
"chat_history",
"FLAG",
True,
help_="是否开启消息自从存储",
name="消息存储",
default_value=True
)
chat_history = on_message(rule=rule, priority=1, block=False)
# test = on_command("aa")
@chat_history.handle()
async def _(event: MessageEvent):
if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg(event.user_id, event.group_id, str(event.get_message()))
else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()))
# @test.handle()
# async def _(event: MessageEvent):
# print(await ChatHistory.get_user_msg(event.user_id, "private"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
# print(await ChatHistory.get_user_msg(event.user_id, "group"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
# print(await ChatHistory.get_group_msg(event.group_id))
# print(await ChatHistory.get_group_msg_count(event.group_id))
+6
View File
@@ -0,0 +1,6 @@
from nonebot.adapters.onebot.v11 import Event, MessageEvent
from configs.config import Config
def rule(event: Event) -> bool:
return Config.get_config("chat_history", "FLAG") and isinstance(event, MessageEvent)
+20 -15
View File
@@ -82,15 +82,16 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
if is_number(id_): if is_number(id_):
id_ = int(id_) id_ = int(id_)
if cmd[:2] == "同意": if cmd[:2] == "同意":
if await requests_manager.approve(bot, id_, "private"): flag = await requests_manager.approve(bot, id_, "private")
await friend_handle.send("同意好友请求成功..")
else:
await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..")
else: else:
if await requests_manager.refused(bot, id_, "private"): flag = await requests_manager.refused(bot, id_, "private")
await friend_handle.send("拒绝好友请求成功..") if flag == 1:
else: await friend_handle.send(f"{cmd[:2]}好友请求失败,该请求已失效..")
await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..") requests_manager.delete_request(id_, "private")
elif flag == 2:
await friend_handle.send(f"{cmd[:2]}好友请求失败,未找到此id的请求..")
else:
await friend_handle.send(f"{cmd[:2]}好友请求成功!")
else: else:
await friend_handle.send("id必须为纯数字!") await friend_handle.send("id必须为纯数字!")
@@ -99,12 +100,12 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0] cmd = cmd[0]
id_ = arg.extract_plain_text().strip() id_ = arg.extract_plain_text().strip()
flag = None
if is_number(id_): if is_number(id_):
id_ = int(id_) id_ = int(id_)
if cmd[:2] == "同意": if cmd[:2] == "同意":
rid = requests_manager.get_group_id(id_) rid = requests_manager.get_group_id(id_)
if rid: if rid:
await friend_handle.send("同意群聊请求成功..")
if await GroupInfo.get_group_info(rid): if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1) await GroupInfo.set_group_flag(rid, 1)
else: else:
@@ -116,14 +117,18 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
group_info["member_count"], group_info["member_count"],
1 1
) )
await requests_manager.approve(bot, id_, "group") flag = await requests_manager.approve(bot, id_, "group")
else: else:
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..") await friend_handle.send("同意群聊请求失败,未找到此id的请求..")
else: else:
if await requests_manager.refused(bot, id_, "group"): flag = await requests_manager.refused(bot, id_, "group")
await friend_handle.send("拒绝群聊请求成功..") if flag == 1:
else: await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..") requests_manager.delete_request(id_, "group")
elif flag == 2:
await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
else:
await friend_handle.send(f"{cmd[:2]}群聊请求成功!")
else: else:
await friend_handle.send("id必须为纯数字!") await friend_handle.send("id必须为纯数字!")
+19 -3
View File
@@ -11,14 +11,19 @@ class ConfigsManager:
def __init__(self, file: Path): def __init__(self, file: Path):
self._data: dict = {} self._data: dict = {}
self._simple_data: dict = {}
self._admin_level_data = [] self._admin_level_data = []
self._simple_file = Path() / "configs" / "config.yaml"
if file: if file:
file.parent.mkdir(exist_ok=True, parents=True) file.parent.mkdir(exist_ok=True, parents=True)
self.file = file self.file = file
_yaml = YAML()
if file.exists(): if file.exists():
_yaml = YAML()
with open(file, "r", encoding="utf8") as f: with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f) self._data = _yaml.load(f)
if self._simple_file.exists():
with open(self._simple_file, "r", encoding="utf8") as f:
self._simple_data = _yaml.load(f)
def add_plugin_config( def add_plugin_config(
self, self,
@@ -71,6 +76,7 @@ class ConfigsManager:
""" """
if module in self._data.keys(): if module in self._data.keys():
del self._data[module] del self._data[module]
self.save()
def set_config(self, module: str, key: str, value: str): def set_config(self, module: str, key: str, value: str):
""" """
@@ -80,8 +86,10 @@ class ConfigsManager:
:param value: 值 :param value: 值
""" """
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None and self._data[module][key] != value:
self._data[module][key]["value"] = value self._data[module][key]["value"] = value
self._simple_data[module][key] = value
self.save()
def set_help(self, module: str, key: str, help_: str): def set_help(self, module: str, key: str, help_: str):
""" """
@@ -93,6 +101,7 @@ class ConfigsManager:
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None:
self._data[module][key]["help"] = help_ self._data[module][key]["help"] = help_
self.save()
def set_default_value(self, module: str, key: str, value: str): def set_default_value(self, module: str, key: str, value: str):
""" """
@@ -104,6 +113,7 @@ class ConfigsManager:
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None:
self._data[module][key]["default_value"] = value self._data[module][key]["default_value"] = value
self.save()
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]: def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
""" """
@@ -142,11 +152,17 @@ class ConfigsManager:
if key in self._data.keys(): if key in self._data.keys():
return self._data[key] return self._data[key]
def save(self, path: Union[str, Path] = None): def save(self, path: Union[str, Path] = None, save_simple_data: bool = False):
""" """
保存数据 保存数据
:param path: 路径 :param path: 路径
:param save_simple_data: 同时保存至config.yaml
""" """
if save_simple_data:
with open(self._simple_file, "w", encoding="utf8") as f:
yaml.dump(
self._simple_data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
path = path if path else self.file path = path if path else self.file
with open(path, "w", encoding="utf8") as f: with open(path, "w", encoding="utf8") as f:
yaml.dump( yaml.dump(
+123
View File
@@ -0,0 +1,123 @@
from datetime import datetime, timedelta
from typing import List, Literal, Optional
from services.db_context import db
class ChatHistory(db.Model):
__tablename__ = "chat_history"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger())
text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str):
await cls.create(
user_qq=user_qq, group_id=group_id, text=text, create_time=datetime.now()
)
@classmethod
async def get_user_msg(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取用户消息
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return await cls._get_msg(uid, None, "user", msg_type, days).gino.all()
@classmethod
async def get_user_msg_count(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> int:
"""
说明:
获取用户消息数量
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return (await cls._get_msg(uid, None, "user", msg_type, days, True).gino.first())[0]
@classmethod
async def get_group_msg(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return await cls._get_msg(None, gid, "group", None, days).gino.all()
@classmethod
async def get_group_msg_count(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息数量
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return (await cls._get_msg(None, gid, "group", None, days, True).gino.first())[0]
@classmethod
def _get_msg(
cls,
uid: Optional[int],
gid: Optional[int],
type_: Literal["user", "group"],
msg_type: Optional[Literal["private", "group"]],
days: Optional[int],
is_select_count: bool = False
):
"""
说明:
获取消息查询query
参数:
:param uid: 用户qq
:param gid: 群号
:param type_: 类型,私聊或群聊
:param msg_type: 消息类型,用户或群聊
:param days: 限制日期
"""
if is_select_count:
setattr(ChatHistory, 'count', db.func.count(cls.id).label('count'))
query = cls.select('count')
else:
query = cls.query
if type_ == "user":
query = query.where(cls.user_qq == uid)
if msg_type == "private":
query = query.where(cls.group_id == None)
elif msg_type == "group":
query = query.where(cls.group_id != None)
else:
query = query.where(cls.group_id == gid)
if days:
query = query.where(
cls.create_time >= datetime.now() - timedelta(days=days)
)
return query
+1
View File
@@ -76,6 +76,7 @@ async def _(bot: Bot, event: MessageEvent):
f"问题:{msg} ---- 回答:{result}" f"问题:{msg} ---- 回答:{result}"
) )
if result: if result:
result = str(result)
for t in Config.get_config("ai", "TEXT_FILTER"): for t in Config.get_config("ai", "TEXT_FILTER"):
result = result.replace(t, "*") result = result.replace(t, "*")
await ai.finish(Message(result)) await ai.finish(Message(result))
@@ -73,6 +73,7 @@ async def check_update(bot: Bot) -> 'int, str':
message=f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}\n" f"开始更新.....", message=f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}\n" f"开始更新.....",
) )
logger.info(f"开始下载真寻最新版文件....") logger.info(f"开始下载真寻最新版文件....")
tar_gz_url = (await AsyncHttpx.get(tar_gz_url)).headers.get('Location')
if await AsyncHttpx.download_file(tar_gz_url, zhenxun_latest_tar_gz): if await AsyncHttpx.download_file(tar_gz_url, zhenxun_latest_tar_gz):
logger.info("下载真寻最新版文件完成....") logger.info("下载真寻最新版文件完成....")
error = await asyncio.get_event_loop().run_in_executor( error = await asyncio.get_event_loop().run_in_executor(
@@ -299,8 +299,8 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
# 层岩巨渊 和 地下矿区 算一个 # 层岩巨渊 和 地下矿区 算一个
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2") region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
height = 0 height = 0
print(world_data_dict)
for country in ["蒙德", "龙脊雪山", "璃月", "璃月层岩巨渊", "稻妻", "渊下宫"]: for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
x = BuildImage(790, 250, color="#3A4467") x = BuildImage(790, 250, color="#3A4467")
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png") logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
tmp_bk = BuildImage(770, 230, color="#606779") tmp_bk = BuildImage(770, 230, color="#606779")
@@ -322,23 +322,23 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
f"Lv.{world_data_dict[country]['level']}", f"Lv.{world_data_dict[country]['level']}",
fill=(255, 255, 255), fill=(255, 255, 255),
) )
elif country in ["璃月层岩巨渊"]: elif country in ["层岩巨渊"]:
content_bk.text((300, 20), "层岩巨渊探索", fill=(239, 211, 114)) content_bk.text((300, 20), "层岩巨渊探索", fill=(239, 211, 114))
content_bk.text( content_bk.text(
(570, 20), (570, 20),
f"{world_data_dict['璃月层岩巨渊']['exploration_percentage'] / 10}%", f"{world_data_dict['层岩巨渊']['exploration_percentage'] / 10}%",
fill=(255, 255, 255), fill=(255, 255, 255),
) )
content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114)) content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114))
content_bk.text( content_bk.text(
(570, 85), (570, 85),
f"{world_data_dict['璃月层岩巨渊·地下矿区']['exploration_percentage'] / 10}%", f"{world_data_dict['层岩巨渊·地下矿区']['exploration_percentage'] / 10}%",
fill=(255, 255, 255), fill=(255, 255, 255),
) )
content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114)) content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114))
content_bk.text( content_bk.text(
(570, 150), (570, 150),
f"LV.{world_data_dict['璃月层岩巨渊·地下矿区']['offerings'][0]['level']}", f"LV.{world_data_dict['层岩巨渊·地下矿区']['offerings'][0]['level']}",
fill=(255, 255, 255), fill=(255, 255, 255),
) )
elif country in ["龙脊雪山"]: elif country in ["龙脊雪山"]:
+2 -2
View File
@@ -64,8 +64,8 @@ async def _poke_event(event: PokeNotifyEvent):
rand = random.random() rand = random.random()
if rand <= 0.3: if rand <= 0.3:
path = random.choice(["luoli", "meitu"]) path = random.choice(["luoli", "meitu"])
index = random.randint(0, len(os.listdir(IMAGE_PATH / path))) index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)))
result = f"id:{index}" + image(f"{index}.jpg", path) result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
await poke_.send(result) await poke_.send(result)
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} \n {result}") logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} \n {result}")
elif 0.3 < rand < 0.6: elif 0.3 < rand < 0.6:
@@ -139,7 +139,7 @@ async def update_setu_img(flag: bool = False):
f"--> /{path}/{image.local_id}.jpg" f"--> /{path}/{image.local_id}.jpg"
) )
os.rename( os.rename(
TEMP_PATH / f"/{image.local_id}.jpg", TEMP_PATH / f"{image.local_id}.jpg",
path / f"{image.local_id}.jpg", path / f"{image.local_id}.jpg",
) )
except FileNotFoundError: except FileNotFoundError:
+1 -1
View File
@@ -1,5 +1,5 @@
from configs.config import Config as gConfig from configs.config import Config as gConfig
from .manager import * from .api import *
from .auth import * from .auth import *
+3
View File
@@ -0,0 +1,3 @@
from .group import *
from .plugins import *
from .request import *
+61
View File
@@ -0,0 +1,61 @@
from pydantic.error_wrappers import ValidationError
from services.log import logger
from utils.manager import group_manager
from utils.utils import get_bot
from ..auth import Depends, User, token_to_user
from ..config import *
@app.get("/webui/group")
async def _(user: User = Depends(token_to_user)) -> Result:
"""
获取群信息
"""
group_list_result = []
group_info = {}
if bot := get_bot():
group_list = await bot.get_group_list()
for g in group_list:
group_info[g["group_id"]] = Group(**g)
group_data = group_manager.get_data()
for group_id in group_data["group_manager"]:
try:
task_list = []
data = group_data["group_manager"][group_id]
for tn, status in data["group_task_status"].items():
task_list.append(
Task(
**{
"name": tn,
"nameZh": group_manager.get_task_data().get(tn) or tn,
"status": status,
}
)
)
data["task"] = task_list
if x := group_info.get(int(group_id)):
data["group"] = x
else:
continue
try:
group_list_result.append(GroupResult(**data))
except ValidationError:
pass
except Exception as e:
logger.error(f"WEB_UI /webui/group 发生错误 {type(e)}:{e}")
return Result(code=200, data=group_list_result)
@app.post("/webui/group")
async def _(group: GroupResult, user: User = Depends(token_to_user)) -> Result:
"""
修改群信息
"""
group_id = group.group.group_id
group_manager.set_group_level(group_id, group.level)
if group.status:
group_manager.turn_on_group_bot_status(group_id)
else:
group_manager.shutdown_group_bot_status(group_id)
return Result(code=200)
+142
View File
@@ -0,0 +1,142 @@
from configs.config import Config
from services.log import logger
from utils.manager import (plugins2block_manager, plugins2cd_manager,
plugins2count_manager, plugins2settings_manager,
plugins_manager)
from utils.utils import get_matchers
from ..auth import Depends, User, token_to_user
from ..config import *
plugin_name_list = None
@app.get("/webui/plugins")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
"""
获取插件列表
:param type_: 类型 normal, superuser, hidden, admin
"""
global plugin_name_list
if not plugin_name_list:
plugin_name_list = [x.plugin_name for x in get_matchers()]
plugin_list = []
plugin_data = plugins_manager.get_data()
for model in plugin_data:
if model in plugin_name_list:
try:
data = plugin_data.get(model)
data["model"] = model
plugin_name = data.get("plugin_name")
if (
(type_ == "hidden" and "[hidden]" not in plugin_name.lower())
or (type_ == "admin" and "[admin]" not in plugin_name.lower())
or (
type_ == "superuser"
and "[superuser]" not in plugin_name.lower()
)
):
continue
if type_ == "normal" and (
"[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower()
):
continue
data = {"model": model}
if x := plugin_data.get(model):
if not x.get("status") and x.get("block_type") in [
"group",
"private",
"all",
]:
x["block_type"] = (
"群聊"
if x["block_type"] == "group"
else "私聊"
if x["block_type"] == "private"
else "全部"
)
data["plugin_manager"] = PluginManager(**x)
if x := plugins2settings_manager.get(model):
if x.get("cmd") and isinstance(x.get("cmd"), list):
x["cmd"] = ",".join(x["cmd"])
data["plugin_settings"] = PluginSettings(**x)
if x := plugins2cd_manager.get(model):
data["cd_limit"] = CdLimit(**x)
if x := plugins2block_manager.get(model):
data["block_limit"] = BlockLimit(**x)
if x := plugins2count_manager.get(model):
data["count_limit"] = CountLimit(**x)
if x := Config.get(model):
id_ = 0
tmp = []
for key in x.keys():
tmp.append(
PluginConfig(
**{
"key": key,
"help_": x[key].get("help"),
"id": id_,
**x[key],
}
)
)
id_ += 1
data["plugin_config"] = tmp
plugin_list.append(Plugin(**data))
except Exception as e:
logger.error(
f"WEB_UI GET /webui/plugins model:{model} 发生错误 {type(e)}:{e}"
)
return Result(
code=500,
data=f"WEB_UI GET /webui/plugins model:{model} 发生错误 {type(e)}:{e}",
)
return Result(code=200, data=plugin_list)
@app.post("/webui/plugins")
def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
"""
修改插件信息
:param plugin: 插件内容
"""
try:
if plugin.plugin_config:
for c in plugin.plugin_config:
if str(c.value).lower() in ["true", "false"] and (
c.default_value is None or isinstance(c.default_value, bool)
):
c.value = True if str(c.value).lower() == "true" else False
elif isinstance(
Config.get_config(plugin.model, c.key, c.value), int
) or isinstance(c.default_value, int):
c.value = int(c.value)
elif isinstance(
Config.get_config(plugin.model, c.key, c.value), float
) or isinstance(c.default_value, float):
c.value = float(c.value)
elif isinstance(c.value, str) and (
isinstance(Config.get_config(plugin.model, c.key, c.value), list)
or isinstance(c.default_value, list)
):
c.value = c.value.split(",")
Config.set_config(plugin.model, c.key, c.value)
Config.save(None, True)
else:
if plugin.plugin_settings:
for key, value in plugin.plugin_settings:
plugins2settings_manager.set_module_data(plugin.model, key, value)
if plugin.plugin_manager:
for key, value in plugin.plugin_manager:
plugins_manager.set_module_data(plugin.model, key, value)
except Exception as e:
logger.error(
f"WEB_UI POST /webui/plugins model:{plugin.model} 发生错误 {type(e)}:{e}"
)
return Result(
code=500,
data=f"WEB_UI POST /webui/plugins model:{plugin.model} 发生错误 {type(e)}:{e}",
)
return Result(code=200)
+65
View File
@@ -0,0 +1,65 @@
from utils.manager import requests_manager
from ..auth import token_to_user, Depends, User
from utils.utils import get_bot
from models.group_info import GroupInfo
from ..config import *
@app.get("/webui/request")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
req_data = requests_manager.get_data()
req_list = []
if type_ in ["group", "private"]:
req_data = req_data[type_]
for x in req_data:
req_data[x]["oid"] = x
req_list.append(RequestResult(**req_data[x]))
req_list.reverse()
return Result(code=200, data=req_list)
@app.delete("/webui/request")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
"""
清空请求
:param type_: 类型
"""
requests_manager.clear(type_)
return Result(code=200)
@app.post("/webui/request")
async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result:
"""
操作请求
:param parma: 参数
"""
result = "ok"
flag = 3
if bot := get_bot():
if parma.handle == "approve":
if parma.type == "group":
rid = requests_manager.get_group_id(parma.id)
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
flag = await requests_manager.approve(bot, parma.id, parma.type)
elif parma.handle == "refuse":
flag = await requests_manager.refused(bot, parma.id, parma.type)
elif parma.handle == "delete":
requests_manager.delete_request(parma.id, parma.type)
if parma.handle != "delete":
if flag == 1:
result = "该请求已失效"
requests_manager.delete_request(parma.id, parma.type)
elif flag == 2:
result = "未找到此Id"
return Result(code=200, data=result)
+11 -2
View File
@@ -1,4 +1,4 @@
from typing import Optional, List, Any from typing import Optional, List, Any, Union
from pydantic import BaseModel from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
import nonebot import nonebot
@@ -54,13 +54,22 @@ class PluginSettings(BaseModel):
limit_superuser: Optional[bool] # 是否限制超级用户 limit_superuser: Optional[bool] # 是否限制超级用户
cmd: Optional[str] # cmd别名 cmd: Optional[str] # cmd别名
cost_gold: Optional[int] # 花费金币限制 cost_gold: Optional[int] # 花费金币限制
plugin_type: Optional[str] # 帮助类型 plugin_type: Optional[List[Union[str, int]]] # 帮助类型
class PluginConfig(BaseModel):
id: int
key: str
value: Optional[Any]
help_: Optional[str]
default_value: Optional[Any]
class Plugin(BaseModel): class Plugin(BaseModel):
model: str # 模块 model: str # 模块
plugin_settings: Optional[PluginSettings] plugin_settings: Optional[PluginSettings]
plugin_manager: Optional[PluginManager] plugin_manager: Optional[PluginManager]
plugin_config: Optional[List[PluginConfig]]
cd_limit: Optional[CdLimit] cd_limit: Optional[CdLimit]
block_limit: Optional[BlockLimit] block_limit: Optional[BlockLimit]
count_limit: Optional[CountLimit] count_limit: Optional[CountLimit]
-209
View File
@@ -1,209 +0,0 @@
from utils.manager import (
plugins_manager,
group_manager,
plugins2settings_manager,
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
requests_manager,
)
from ..auth import token_to_user, Depends, User
from utils.utils import get_matchers, get_bot
from models.group_info import GroupInfo
from pydantic.error_wrappers import ValidationError
from services.log import logger
from ..config import *
import nonebot
app = nonebot.get_app()
plugin_name_list = None
@app.get("/webui/plugins")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
"""
获取插件列表
:param type_: 类型 normal, superuser, hidden, admin
"""
global plugin_name_list
if not plugin_name_list:
plugin_name_list = [x.plugin_name for x in get_matchers()]
plugin_list = []
plugin_data = plugins_manager.get_data()
for model in plugin_data:
if model in plugin_name_list:
data = plugin_data.get(model)
data["model"] = model
plugin_name = data.get("plugin_name")
if (
(type_ == "hidden" and "[hidden]" not in plugin_name.lower())
or (type_ == "admin" and "[admin]" not in plugin_name.lower())
or (type_ == "superuser" and "[superuser]" not in plugin_name.lower())
):
continue
if type_ == "normal" and (
"[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower()
):
continue
data = {"model": model}
if x := plugin_data.get(model):
if not x.get("status") and x.get("block_type") in [
"group",
"private",
"all",
]:
x["block_type"] = (
"群聊"
if x["block_type"] == "group"
else "私聊"
if x["block_type"] == "private"
else "全部"
)
data["plugin_manager"] = PluginManager(**x)
if x := plugins2settings_manager.get(model):
if x.get("cmd") and isinstance(x.get("cmd"), list):
x["cmd"] = ",".join(x["cmd"])
if isinstance(x["plugin_type"], list):
x["plugin_type"] = x["plugin_type"][0]
data["plugin_settings"] = PluginSettings(**x)
if x := plugins2cd_manager.get(model):
data["cd_limit"] = CdLimit(**x)
if x := plugins2block_manager.get(model):
data["block_limit"] = BlockLimit(**x)
if x := plugins2count_manager.get(model):
data["count_limit"] = CountLimit(**x)
# if x := resources_manager.get(model):
# data = dict(data, **x)
plugin_list.append(Plugin(**data))
return Result(code=200, data=plugin_list)
@app.post("/webui/plugins")
def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
"""
修改插件信息
:param plugin: 插件内容
"""
print(plugin)
if plugin.plugin_settings:
for key, value in plugin.plugin_settings:
plugins2settings_manager.set_module_data(plugin.model, key, value)
if plugin.plugin_manager:
for key, value in plugin.plugin_manager:
print(key, value)
plugins_manager.set_module_data(plugin.model, key, value)
return Result(code=200)
@app.get("/webui/group")
async def _(user: User = Depends(token_to_user)) -> Result:
"""
获取群信息
"""
group_list_result = []
group_info = {}
if bot := get_bot():
group_list = await bot.get_group_list()
for g in group_list:
group_info[g["group_id"]] = Group(**g)
group_data = group_manager.get_data()
for group_id in group_data["group_manager"]:
try:
task_list = []
data = group_data["group_manager"][group_id]
for tn, status in data["group_task_status"].items():
task_list.append(
Task(
**{
"name": tn,
"nameZh": group_manager.get_task_data().get(tn) or tn,
"status": status,
}
)
)
data["task"] = task_list
if x := group_info.get(int(group_id)):
data["group"] = x
else:
continue
try:
group_list_result.append(GroupResult(**data))
except ValidationError:
pass
except Exception as e:
logger.error(f"WEB_UI /webui/group 发生错误 {type(e)}:{e}")
return Result(code=200, data=group_list_result)
@app.post("/webui/group")
async def _(group: GroupResult, user: User = Depends(token_to_user)) -> Result:
"""
修改群信息
"""
group_id = group.group.group_id
group_manager.set_group_level(group_id, group.level)
if group.status:
group_manager.turn_on_group_bot_status(group_id)
else:
group_manager.shutdown_group_bot_status(group_id)
return Result(code=200)
@app.get("/webui/request")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
req_data = requests_manager.get_data()
req_list = []
if type_ in ["group", "private"]:
req_data = req_data[type_]
for x in req_data:
req_data[x]["oid"] = x
req_list.append(RequestResult(**req_data[x]))
return Result(code=200, data=req_list)
@app.delete("/webui/request")
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
"""
清空请求
:param type_: 类型
"""
requests_manager.clear(type_)
return Result(code=200)
@app.post("/webui/request")
async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result:
"""
操作请求
:param parma: 参数
"""
result = "error"
if bot := get_bot():
if parma.handle == "approve":
if parma.type == "group":
rid = requests_manager.get_group_id(parma.id)
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
if await requests_manager.approve(bot, parma.id, parma.type):
result = "ok"
elif parma.handle == "refuse":
if await requests_manager.refused(bot, parma.id, parma.type):
result = "ok"
elif parma.handle == "delete":
requests_manager.delete_request(parma.id, parma.type)
result = "ok"
return Result(code=200, data=result)
+21 -3
View File
@@ -1,7 +1,6 @@
from configs.config import Config from configs.config import Config
import nonebot import nonebot
Config.add_plugin_config( Config.add_plugin_config(
"word_bank", "word_bank",
"WORD_BANK_LEVEL [LEVEL]", "WORD_BANK_LEVEL [LEVEL]",
@@ -11,6 +10,25 @@ Config.add_plugin_config(
default_value=5 default_value=5
) )
Config.add_plugin_config(
"word_bank",
"WORD_BANK_FUZZY",
False,
help_="模糊匹配",
default_value=False
)
Config.add_plugin_config(
"word_bank",
"WORD_BANK_KEY",
True,
help_="关键字匹配",
default_value=True
)
Config.add_plugin_config(
"word_bank",
"WORD_BANK_MIX",
25,
help_="查看词条时图片内最多显示条数",
default_value=25
)
nonebot.load_plugins("plugins/word_bank") nonebot.load_plugins("plugins/word_bank")
+10 -14
View File
@@ -5,7 +5,6 @@ from typing import Union
class WordBankBuilder: class WordBankBuilder:
def __init__(self, user_id: int, group_id: int, problem: str): def __init__(self, user_id: int, group_id: int, problem: str):
self._data = { self._data = {
"user_id": user_id, "user_id": user_id,
"group_id": group_id, "group_id": group_id,
@@ -29,24 +28,21 @@ class WordBankBuilder:
""" """
self._data["answer"] = answer self._data["answer"] = answer
async def save(self): async def save(self,search_type):
user_id = self._data["user_id"] user_id = self._data["user_id"]
group_id = self._data["group_id"] group_id = self._data["group_id"]
problem = self._data["problem"] problem = self._data["problem"]
answer = self._data["answer"] answer = self._data["answer"]
placeholder = self._data.get("placeholder") placeholder = self._data.get("placeholder")
await WordBank.add_problem_answer(user_id, group_id, problem, answer, placeholder) return await WordBank.add_problem_answer(user_id, group_id, search_type,problem, answer, placeholder)
async def update(self, index):
user_id = self._data["user_id"]
group_id = self._data["group_id"]
problem = self._data["problem"]
answer = self._data["answer"]
placeholder = self._data.get("placeholder")
return await WordBank.update_problem_answer(user_id, group_id, problem, answer, index, placeholder)
def __str__(self): def __str__(self):
return str(self._data) return str(self._data)
+20 -11
View File
@@ -5,36 +5,40 @@ from configs.path_config import DATA_PATH
from nonebot.adapters.onebot.v11 import GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.utils import get_message_text from utils.utils import get_message_text
from nonebot import on_message from nonebot import on_message
from models.group_member_info import GroupInfoUser
__zx_plugin_name__ = "词库问答回复操作 [Hidden]" __zx_plugin_name__ = "词库问答回复操作 [Hidden]"
data_dir = DATA_PATH / "word_bank" data_dir = DATA_PATH / "word_bank"
data_dir.mkdir(parents=True, exist_ok=True) data_dir.mkdir(parents=True, exist_ok=True)
message_handle = on_message(priority=6, block=True, rule=check)
message_handle = on_message(priority=5, block=True, rule=check)
@message_handle.handle() @message_handle.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
path = data_dir / f"{event.group_id}"
q = await WordBank.check( q = await WordBank.check(
event.group_id, get_message_text(event.json()), event.is_tome() event.group_id, get_message_text(event.json()), event.is_tome()
) )
await message_handle.send(await get_one_answer(event, q.format, q.answer))
# 处理单条回答
async def get_one_answer(event, format, _answer, all=1):
path = data_dir / f"{event.group_id}"
placeholder_list = ( placeholder_list = (
[ [
(x.split("<_s>")[0], x.split("<_s>")[1]) (x.split("<_s>")[0], x.split("<_s>")[1])
for x in q.format.split("<format>")[:-1] for x in format.split("<format>")[:-1]
] ]
if q.format if format
else [] else []
) )
answer = "" answer = ""
_a = q.answer _a = _answer
if not placeholder_list: if not placeholder_list:
answer = _a answer = _a
return answer
else: else:
for idx, placeholder in placeholder_list: for idx, placeholder in placeholder_list:
if placeholder.endswith("jpg"): if placeholder.endswith("jpg"):
@@ -42,6 +46,11 @@ async def _(event: GroupMessageEvent):
path / placeholder path / placeholder
) )
else: else:
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(placeholder) if all == 1:
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]") :] answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(placeholder)
await message_handle.send(answer) else:
q = await GroupInfoUser.get_member_info(
int(placeholder), event.group_id)
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
return answer + _a
+121 -39
View File
@@ -5,6 +5,7 @@ from pathlib import Path
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
import re import re
import random import random
from configs.config import Config
class WordBank(db.Model): class WordBank(db.Model):
@@ -21,17 +22,19 @@ class WordBank(db.Model):
@classmethod @classmethod
async def add_problem_answer( async def add_problem_answer(
cls, cls,
user_id: int, user_id: int,
group_id: Optional[int], group_id: Optional[int],
problem: str, search_type: [int],
answer: str, problem: str,
format_: Optional[List[Tuple[int, Union[int, str]]]], answer: str,
format_: Optional[List[Tuple[int, Union[int, str]]]],
) -> bool: ) -> bool:
""" """
添加或新增一个问答 添加或新增一个问答
:param user_id: 用户id :param user_id: 用户id
:param group_id: 群号 :param group_id: 群号
:search_type: 问题类型,
:param problem: 问题 :param problem: 问题
:param answer: 回答 :param answer: 回答
:param format_: 格式化数据 :param format_: 格式化数据
@@ -42,12 +45,12 @@ class WordBank(db.Model):
for x, y in format_: for x, y in format_:
_str += f"{x}<_s>{y}<format>" _str += f"{x}<_s>{y}<format>"
return await cls._problem_answer_handle( return await cls._problem_answer_handle(
user_id, group_id, problem, "add", answer=answer, format_=_str user_id, group_id, problem, "add", search_type=search_type, answer=answer, format_=_str
) )
@classmethod @classmethod
async def delete_problem_answer( async def delete_problem_answer(
cls, user_id: int, group_id: Optional[int], problem: str, index: Optional[int] cls, user_id: int, group_id: Optional[int], problem: str, index: Optional[int]
) -> str: ) -> str:
""" """
删除某问题一个或全部回答 删除某问题一个或全部回答
@@ -60,9 +63,35 @@ class WordBank(db.Model):
user_id, group_id, problem, "delete", index=index user_id, group_id, problem, "delete", index=index
) )
@classmethod
async def update_problem_answer(
cls,
user_id: int,
group_id: Optional[int],
problem: str,
answer: str,
index: Optional[int],
format_: Optional[List[Tuple[int, Union[int, str]]]],
) -> str:
"""
修改某问题一个或全部回答
:param user_id: 用户id
:param group_id: 群号
:param problem: 问题
:param index: 回答下标
"""
_str = None
if format_:
_str = ""
for x, y in format_:
_str += f"{x}<_s>{y}<format>"
return await cls._problem_answer_handle(
user_id, group_id, problem, "update", answer=answer, index=index, format_=_str
)
@classmethod @classmethod
async def get_problem_answer( async def get_problem_answer(
cls, user_id: int, group_id: Optional[int], problem: str cls, user_id: int, group_id: Optional[int], problem: str
) -> List[str]: ) -> List[str]:
""" """
获取问题的所有回答 获取问题的所有回答
@@ -87,7 +116,8 @@ class WordBank(db.Model):
q = await cls.query.where( q = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem) (cls.group_id == group_id) & (cls.problem == problem)
).gino.all() ).gino.all()
return [x.answer for x in q] if q else None
return [(x.answer, x.format) for x in q] if q else None
@classmethod @classmethod
async def get_group_all_problem(cls, group_id: int) -> List[str]: async def get_group_all_problem(cls, group_id: int) -> List[str]:
@@ -128,22 +158,45 @@ class WordBank(db.Model):
return x return x
return None return None
else: else:
q = await cls.query.where( if problem:
(cls.group_id == group_id) & (cls.problem == problem) FUZZY = Config.get_config("word_bank", "WORD_BANK_FUZZY")
).gino.all() KEY = Config.get_config("word_bank", "WORD_BANK_KEY")
q = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
if KEY and FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_fuzzy + q_key
elif FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q += q_fuzzy
elif KEY:
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_key
else:
return None
return random.choice(q) if q else None return random.choice(q) if q else None
@classmethod @classmethod
async def _problem_answer_handle( async def _problem_answer_handle(
cls, cls,
user_id: int, user_id: int,
group_id: Optional[int], group_id: Optional[int],
problem: str, problem: str,
type_: str, type_: str,
*, *,
answer: Optional[str] = None, search_type: [int] = 0,
index: Optional[int] = None, answer: Optional[str] = None,
format_: Optional[str] = None, index: Optional[int] = None,
format_: Optional[str] = None,
) -> Union[List[Union[str, Tuple[str, str]]], bool, str]: ) -> Union[List[Union[str, Tuple[str, str]]], bool, str]:
""" """
添加或新增一个问答 添加或新增一个问答
@@ -166,27 +219,27 @@ class WordBank(db.Model):
else: else:
q = cls.query.where((cls.user_qq == user_id) & (cls.problem == problem)) q = cls.query.where((cls.user_qq == user_id) & (cls.problem == problem))
if type_ == "add": if type_ == "add":
q = await q.where(cls.answer == answer).gino.all() q = await q.where((cls.answer == answer) & (cls.search_type == search_type)).gino.all()
if not q or ".jpg" in format_: try:
await cls.create( if not q or ".jpg" in format_:
user_qq=user_id, await cls.create(
group_id=group_id, user_qq=user_id,
problem=problem, group_id=group_id,
answer=answer, search_type=search_type,
format=format_, problem=problem,
create_time=datetime.now().date(), answer=answer,
update_time=datetime.now().date(), format=format_,
) create_time=datetime.now().replace(microsecond=0),
update_time=datetime.now().replace(microsecond=0),
)
except:
return False
return True return True
elif type_ == "delete": elif type_ == "delete":
q = await q.with_for_update().gino.all() q = await q.with_for_update().gino.all()
if q: if q:
path = DATA_PATH / "word_bank" / f"{group_id}" path = DATA_PATH / "word_bank" / f"{group_id}"
if index is not None: if index is not None:
_q = [x.problem for x in q]
_q.sort()
prob = _q[index]
index = [x.problem for x in q].index(prob)
q = [q[index]] q = [q[index]]
answer = "\n".join([x.answer for x in q]) answer = "\n".join([x.answer for x in q])
for x in q: for x in q:
@@ -199,14 +252,43 @@ class WordBank(db.Model):
if _path.exists(): if _path.exists():
_path.unlink() _path.unlink()
await cls.delete.where( await cls.delete.where(
(cls.problem == problem) (cls.update_time == x.update_time)
& (cls.problem == problem)
& (cls.answer == x.answer) & (cls.answer == x.answer)
& (cls.group_id == group_id) & (cls.group_id == group_id)
).gino.status() ).gino.status()
return answer return answer
elif type_ == "update":
new_format = format_
new_answer = answer
q = await q.with_for_update().gino.all()
if q:
path = DATA_PATH / "word_bank" / f"{group_id}"
if index is not None:
q = [q[index]]
else:
q = [q[0]]
for x in q:
format_ = x.format
if format_:
for sp in format_.split("<format>")[:-1]:
_, image_name = sp.split("<_s>")
if image_name.endswith("jpg"):
_path = path / image_name
if _path.exists():
_path.unlink()
await cls.update.values(answer=new_answer,
format=new_format,
update_time=datetime.now().replace(microsecond=0), ).where(
(cls.problem == problem)
& (cls.answer == x.answer)
& (cls.group_id == group_id)
& (cls.group_id == group_id)
& (cls.update_time == x.update_time)
).gino.status()
return True
elif type_ == "get": elif type_ == "get":
q = await q.gino.all() q = await q.gino.all()
if q: if q:
return [(x.answer, x.format.split("<format>")[:-1]) for x in q] return [(x.answer, x.format.split("<format>")[:-1]) for x in q]
return False return False
+184 -73
View File
@@ -4,9 +4,9 @@ from services.log import logger
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from ._data_source import WordBankBuilder from ._data_source import WordBankBuilder
from configs.config import Config
from utils.message_builder import image from utils.message_builder import image
from utils.image_utils import text2image from utils.image_utils import text2image
from .message_handle import get_one_answer
from .model import WordBank from .model import WordBank
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
@@ -18,6 +18,7 @@ from nonebot import on_command
import random import random
import os import os
import re import re
from configs.config import NICKNAME, Config
__zx_plugin_name__ = "词库问答 [Admin]" __zx_plugin_name__ = "词库问答 [Admin]"
__plugin_usage__ = """ __plugin_usage__ = """
@@ -25,45 +26,51 @@ usage:
对指定问题的随机回答,对相同问题可以设置多个不同回答 对指定问题的随机回答,对相同问题可以设置多个不同回答
删除词条后每个词条的id可能会变化,请查看后再删除 删除词条后每个词条的id可能会变化,请查看后再删除
指令: 指令:
添加词条问...答...:添加问答词条,可重复添加相同问题的不同回答 添加词条 ?[模糊/关键字]...答...:添加问答词条,可重复添加相同问题的不同回答
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答 删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
查看词条 ?[问题/下标]:查看全部词条或对应词条回答 查看词条 ?[问题/下标]:查看全部词条或对应词条回答
示例:添加词条问谁是萝莉答是我 示例:添加词条问谁是萝莉答是我
示例:删除词条 谁是萝莉 示例:删除词条 谁是萝莉
示例:删除词条 谁是萝莉 0 示例:删除词条 谁是萝莉 0
示例:删除词条 id:0 示例:删除词条 id:0
示例:修改词条 谁是萝莉 是你
示例:修改词条 谁是萝莉 0 是你
示例:修改词条 id:0 是你
示例:查看词条 示例:查看词条
示例:查看词条 谁是萝莉 示例:查看词条 谁是萝莉
示例:查看词条 id:0 示例:查看词条 id:0
""".strip() """.strip()
__plugin_des__ = "自定义词条内容随机回复" __plugin_des__ = "自定义词条内容随机回复"
__plugin_cmd__ = [ __plugin_cmd__ = [
"添加词条问...答..", "添加词条 ?[模糊/关键字]问...答..",
"删除词条 [问题/下标] ?[下标]", "删除词条 [问题/下标] ?[下标]",
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
"查看词条 ?[问题/下标]", "查看词条 ?[问题/下标]",
] ]
__plugin_version__ = 0.1 __plugin_version__ = 0.2
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
__plugin_settings__ = { __plugin_settings__ = {
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL"), "admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
"cmd": ["词库问答", "添加词条", "删除词条", "查看词条"], "cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
} }
data_dir = DATA_PATH / "word_bank" data_dir = DATA_PATH / "word_bank"
data_dir.mkdir(parents=True, exist_ok=True) data_dir.mkdir(parents=True, exist_ok=True)
add_word = on_command("添加词条", priority=5, block=True) add_word = on_command("添加词条", priority=5, block=True)
delete_word = on_command("删除词条", priority=5, block=True) delete_word = on_command("删除词条", priority=5, block=True)
update_word = on_command("修改词条", priority=5, block=True)
show_word = on_command("显示词条", aliases={"查看词条"}, priority=5, block=True) show_word = on_command("显示词条", aliases={"查看词条"}, priority=5, block=True)
@add_word.handle() @add_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = CommandArg()): async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = CommandArg()):
msg = str(arg) msg = str(arg)
r = re.search(r"^问(.+)\s?答([\s\S]*)", msg) r = re.search(r"问(.+)\s?答([\s\S]*)", msg)
if not r: if not r:
await add_word.finish("未检测到词条问题...") await add_word.finish("未检测到词条问题...")
problem = r.group(1).strip() problem = r.group(1).strip()
@@ -75,10 +82,177 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
idx = 0 idx = 0
for n in bot.config.nickname: for n in bot.config.nickname:
if n and problem.startswith(n): if n and problem.startswith(n):
_problem = f"[_to_me|{n}]" + problem[len(n) :] _problem = f"[_to_me|{n}]" + problem[len(n):]
break break
else: else:
_problem = problem _problem = problem
search_type = 0
if re.search("^关键字(.*)", msg):
search_type = 1
elif re.search("^模糊(.*)", msg):
search_type = 2
_builder = await get__builder(event, _problem, answer, idx)
if await _builder.save(search_type):
logger.info(f"已保存词条 问:{problem} 答:{msg}")
await add_word.send(f"已保存词条:{problem}")
else:
await delete_word.send("保存失败,可能是回答重复")
@delete_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None
_sp_msg = msg.split()
if len(_sp_msg) > 1:
if is_number(_sp_msg[-1]):
index = int(_sp_msg[-1])
msg = " ".join(_sp_msg[:-1])
problem = msg
if problem.startswith("id:"):
x = problem.split(":")[-1]
if not is_number(x) or int(x) < 0:
await delete_word.finish("id必须为数字且符合规范!")
p = await WordBank.get_group_all_problem(event.group_id)
if p:
problem = p[int(x)]
try:
if answer := await WordBank.delete_problem_answer(
event.user_id, event.group_id, problem, index
):
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除词条: {problem}"
)
else:
await delete_word.send(f"删除词条:{problem} 失败,可能该词条不存在")
except IndexError:
await delete_word.send("指定下标错误...请通过查看词条来确定..")
@update_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = str(arg)
if not msg:
await update_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None
new_answer = None
problem = None
_sp_msg = msg.split()
len_msg = len(_sp_msg)
if 1 < len_msg:
problem = "".join(_sp_msg[0])
if len_msg == 3:
if is_number(_sp_msg[1]):
index = int(_sp_msg[1])
new_answer = "".join(_sp_msg[2:])
else:
new_answer = "".join(_sp_msg[1:])
else:
await update_word.finish("此命令之后需要跟随修改内容")
idx = 0
for n in bot.config.nickname:
if n and problem.startswith(n):
_problem = f"[_to_me|{n}]" + problem[len(n):]
break
else:
_problem = problem
_builder = await get__builder(event, _problem, new_answer, idx)
try:
if await _builder.update(index):
await update_word.send(f"修改词条成功:{problem}")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 修改词条: {problem}"
)
else:
await update_word.send(f"修改词条:{problem} 失败,可能该词条不存在")
except IndexError:
await update_word.send("指定下标错误...请通过查看词条来确定..")
@show_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
_problem_list = await WordBank.get_group_all_problem(event.group_id)
if not _problem_list:
await show_word.finish("该群未收录任何词条..")
_problem_list = [f"\t{i}. {x}" for i, x in enumerate(_problem_list)]
long_problem_list = len(_problem_list)
max_line = Config.get_config("word_bank", "WORD_BANK_MIX")
if long_problem_list > max_line:
pic_list = []
mes_list = []
img_nu = long_problem_list // max_line
one_msg = "该群已收录的词条:"
await show_word.send(one_msg)
for i in range(img_nu + 1):
if _problem_list:
one_img = image(
b64=(await text2image("\n".join(_problem_list[:max_line]),
padding=10,
color="#f9f6f2",
)).pic2bs4()
)
if img_nu > 2:
pic_list.append(one_img)
else:
await show_word.send(one_img)
del _problem_list[:max_line]
if pic_list:
for img in pic_list:
data = {
"type": "node",
"data": {"name": f"{NICKNAME}", "uin": f"{bot.self_id}", "content": img},
}
mes_list.append(data)
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
else:
await show_word.send(
image(
b64=(await text2image(
"该群已收录的词条:\n\n" + "\n".join(_problem_list),
padding=10,
color="#f9f6f2",
)).pic2bs4()
)
)
else:
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg)
if not _answer_list:
await show_word.send("未收录该词条...")
else:
# 解析图片和@
_answer_img_nu_list = [await get_one_answer(event, format, answer, 0) for answer, format in _answer_list]
word_nu = len(_answer_img_nu_list)
img_nu = 0
answer = f"词条 {msg} 回答:"
for i, x, in enumerate(_answer_img_nu_list):
r = re.findall(rf"\[CQ:image,file=", str(x))
if r:
img_nu += len(r)
answer += "\n" + f"{i}." + x
if (img_nu > 2 and word_nu > 5) or word_nu > 10 or img_nu > 4:
data = {
"type": "node",
"data": {"name": f"{NICKNAME}", "uin": f"{bot.self_id}", "content": answer},
}
await bot.send_group_forward_msg(group_id=event.group_id, messages=data)
else:
await show_word.send(answer)
# await show_word.send(f"词条 {msg} 回答:\n" + "\n".join(_answer_list))
async def get__builder(event, _problem, answer, idx):
(data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True) (data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True)
_builder = WordBankBuilder(event.user_id, event.group_id, _problem) _builder = WordBankBuilder(event.user_id, event.group_id, _problem)
for at_ in get_message_at(event.json()): for at_ in get_message_at(event.json()):
@@ -108,67 +282,4 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg") _builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
idx += 1 idx += 1
_builder.set_answer(answer) _builder.set_answer(answer)
await _builder.save() return _builder
logger.info(f"已保存词条 问:{problem} 答:{msg}")
await add_word.send(f"已保存词条:{problem}")
@delete_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None
_sp_msg = msg.split()
if len(_sp_msg) > 1:
if is_number(_sp_msg[-1]):
index = int(_sp_msg[-1])
msg = " ".join(_sp_msg[:-1])
problem = msg
if problem.startswith("id:"):
x = problem.split(":")[-1]
if not is_number(x) or int(x) < 0:
await delete_word.finish("id必须为数字且符合规范!")
p = await WordBank.get_group_all_problem(event.group_id)
if p:
problem = p[int(x)]
try:
if answer := await WordBank.delete_problem_answer(
event.user_id, event.group_id, problem, index
):
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除词条: {problem}"
)
else:
await delete_word.send(f"删除词条:{problem} 失败,可能该词条不存在")
except IndexError:
await delete_word.send("指定下标错误...请通过查看词条来确定..")
@show_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
_problem_list = await WordBank.get_group_all_problem(event.group_id)
if not _problem_list:
await show_word.finish("该群未收录任何词条..")
_problem_list = [f"\t{i}. {x}" for i, x in enumerate(_problem_list)]
await show_word.send(
image(
b64=(await text2image(
"该群已收录的词条:\n\n" + "\n".join(_problem_list),
padding=10,
color="#f9f6f2",
)).pic2bs4()
)
)
else:
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg)
if not _answer_list:
await show_word.send("未收录该词条...")
else:
_answer_list = [f"{i}. {x}" for i, x in enumerate(_answer_list)]
await show_word.send(f"词条 {msg} 回答:\n" + "\n".join(_answer_list))
+9 -8
View File
@@ -85,7 +85,7 @@ class RequestManager(StaticData):
return data["invite_group"] return data["invite_group"]
return None return None
async def approve(self, bot: Bot, id_: int, type_: str) -> Optional[int]: async def approve(self, bot: Bot, id_: int, type_: str) -> int:
""" """
同意请求 同意请求
:param bot: Bot :param bot: Bot
@@ -232,7 +232,7 @@ class RequestManager(StaticData):
async def _set_add_request( async def _set_add_request(
self, bot: Bot, id_: int, type_: str, approve: bool self, bot: Bot, id_: int, type_: str, approve: bool
) -> Optional[int]: ) -> int:
""" """
处理请求 处理请求
:param bot: Bot :param bot: Bot
@@ -260,12 +260,13 @@ class RequestManager(StaticData):
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})" f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
f"的{'好友' if type_ == 'private' else '入群'}请求失败了..." f"的{'好友' if type_ == 'private' else '入群'}请求失败了..."
) )
return None return 1 # flag失效
logger.info( else:
f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})" logger.info(
f"的{'好友' if type_ == 'private' else '入群'}请求..." f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
) f"的{'好友' if type_ == 'private' else '入群'}请求..."
)
del self._data[type_][id_] del self._data[type_][id_]
self.save() self.save()
return rid return rid
return None return 2 # 未找到id