mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-16 01:30:03 +08:00
backup
This commit is contained in:
@@ -10,25 +10,4 @@ Config.add_plugin_config(
|
||||
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("test/word_bank")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
scope2int = {
|
||||
"全局": 0,
|
||||
"群聊": 1,
|
||||
"私聊": 2,
|
||||
}
|
||||
|
||||
type2int = {
|
||||
"精准": 0,
|
||||
"模糊": 1,
|
||||
"正则": 2,
|
||||
"图片": 3,
|
||||
}
|
||||
|
||||
int2type = {
|
||||
0: "精准",
|
||||
1: "模糊",
|
||||
2: "正则",
|
||||
3: "图片",
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +1,208 @@
|
||||
from .model import WordBank
|
||||
from typing import Union
|
||||
from pathlib import Path
|
||||
|
||||
from nonebot.adapters.onebot.v11 import Message, MessageSegment
|
||||
|
||||
from services import logger
|
||||
from utils.image_utils import text2image
|
||||
from utils.message_builder import image
|
||||
from ._model import WordBank
|
||||
from typing import Optional, Tuple, Union, List, Any
|
||||
from utils.utils import is_number
|
||||
import nonebot
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
class WordBankBuilder:
|
||||
async def get_problem_str(
|
||||
id_: Union[str, int], group_id: Optional[int] = None, word_scope: int = 1
|
||||
) -> Tuple[str, int]:
|
||||
"""
|
||||
说明:
|
||||
通过id获取问题字符串
|
||||
参数:
|
||||
:param id_: 下标
|
||||
:param group_id: 群号
|
||||
:param word_scope: 获取类型
|
||||
"""
|
||||
if word_scope in [0, 2]:
|
||||
all_problem = await WordBank.get_problem_by_scope(word_scope)
|
||||
else:
|
||||
all_problem = await WordBank.get_group_all_problem(group_id)
|
||||
if id_.startswith("id:"):
|
||||
id_ = id_.split(":")[-1]
|
||||
if not is_number(id_) or int(id_) < 0 or int(id_) > len(all_problem):
|
||||
return "id必须为数字且在范围内", 999
|
||||
return all_problem[int(id_)][0], 200
|
||||
|
||||
def __init__(self, user_id: int, group_id: int, problem: str):
|
||||
self._data = {
|
||||
"user_id": user_id,
|
||||
"group_id": group_id}
|
||||
self.problem = problem
|
||||
|
||||
def set_placeholder(self, id_: int, placeholder: Union[str, int]):
|
||||
"""
|
||||
设置占位符
|
||||
:param id_: 站位id
|
||||
:param placeholder: 占位符内容
|
||||
"""
|
||||
if self._data.get("placeholder") is None:
|
||||
self._data["placeholder"] = []
|
||||
self._data["placeholder"].append((id_, placeholder))
|
||||
async def update_word(params: str, group_id: Optional[int] = None, word_scope: int = 1) -> str:
|
||||
"""
|
||||
说明:
|
||||
修改群词条
|
||||
参数:
|
||||
:param params: 参数
|
||||
:param group_id: 群号
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
return await word_handle(params, group_id, "update", word_scope)
|
||||
|
||||
|
||||
async def delete_word(params: str, group_id: Optional[int] = None, word_scope: int = 1) -> str:
|
||||
"""
|
||||
说明:
|
||||
删除群词条
|
||||
参数:
|
||||
:param params: 参数
|
||||
:param group_id: 群号
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
return await word_handle(params, group_id, "delete", word_scope)
|
||||
|
||||
|
||||
async def word_handle(params: str, group_id: Optional[int], type_: str, word_scope: int = 0) -> str:
|
||||
"""
|
||||
说明:
|
||||
词条操作
|
||||
参数:
|
||||
:param params: 参数
|
||||
:param group_id: 群号
|
||||
:param type_: 类型
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
params = params.split()
|
||||
problem = params[0]
|
||||
if problem.startswith("id:"):
|
||||
problem, code = await get_problem_str(problem, group_id, word_scope)
|
||||
if code != 200:
|
||||
return problem
|
||||
if type_ == "delete":
|
||||
index = params[1] if len(params) > 1 else None
|
||||
if index:
|
||||
answer_num = len(await WordBank.get_problem_all_answer(problem, group_id))
|
||||
if not is_number(index) or int(index) < 0 or int(index) > answer_num:
|
||||
return "指定回答下标id必须为数字且在范围内"
|
||||
index = int(index)
|
||||
await WordBank.delete_group_problem(problem, group_id, index, word_scope)
|
||||
return "删除词条成功"
|
||||
if type_ == "update":
|
||||
replace_str = params[1]
|
||||
await WordBank.update_group_problem(problem, replace_str, group_id, word_scope=word_scope)
|
||||
return "修改词条成功"
|
||||
|
||||
|
||||
async def show_word(
|
||||
problem: str,
|
||||
id_: Optional[int],
|
||||
gid: Optional[int],
|
||||
group_id: Optional[int] = None,
|
||||
word_scope: Optional[int] = None,
|
||||
) -> Union[str, List[Union[str, Message]]]:
|
||||
if problem:
|
||||
msg_list = []
|
||||
if word_scope is not None:
|
||||
problem = (await WordBank.get_problem_by_scope(word_scope))[id_][0]
|
||||
id_ = None
|
||||
_problem_list = await WordBank.get_problem_all_answer(
|
||||
problem, id_ if id_ is not None else gid, group_id if gid is None else None, word_scope
|
||||
)
|
||||
for index, msg in enumerate(_problem_list):
|
||||
if isinstance(msg, Message):
|
||||
temp = ""
|
||||
for seg in msg:
|
||||
if seg.type == "text":
|
||||
temp += seg
|
||||
elif seg.type == "face":
|
||||
temp += f"[face:{seg.data.id}]"
|
||||
elif seg.type == "at":
|
||||
temp += f'[at:{seg.data["qq"]}]'
|
||||
elif seg.type == "image":
|
||||
temp += f"[image]"
|
||||
msg += temp
|
||||
msg_list.append(f"{index}." + msg if isinstance(msg, str) else msg[1])
|
||||
msg_list = [
|
||||
f'词条:{problem or (f"id: {id_}" if id_ is not None else f"gid: {gid}")} 的回答'
|
||||
] + msg_list
|
||||
return msg_list
|
||||
else:
|
||||
if group_id:
|
||||
_problem_list = await WordBank.get_group_all_problem(group_id)
|
||||
else:
|
||||
_problem_list = await WordBank.get_problem_by_scope(word_scope)
|
||||
global_problem_list = await WordBank.get_problem_by_scope(0)
|
||||
if not _problem_list and not global_problem_list:
|
||||
return "未收录任何词条.."
|
||||
msg_list = await build_message(_problem_list)
|
||||
global_msg_list = await build_message(global_problem_list)
|
||||
if global_msg_list:
|
||||
msg_list.append("###以下为全局词条###")
|
||||
msg_list = msg_list + global_msg_list
|
||||
return msg_list
|
||||
|
||||
|
||||
async def build_message(_problem_list: List[Tuple[Any, Union[MessageSegment, str]]]):
|
||||
index = 0
|
||||
str_temp_list = []
|
||||
msg_list = []
|
||||
temp_str = ""
|
||||
for _, problem in _problem_list:
|
||||
if len(temp_str.split("\n")) > 50:
|
||||
img = await text2image(
|
||||
temp_str,
|
||||
padding=10,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
msg_list.append(image(b64=img.pic2bs4()))
|
||||
temp_str = ""
|
||||
if isinstance(problem, str):
|
||||
if problem not in str_temp_list:
|
||||
str_temp_list.append(problem)
|
||||
temp_str += f"{index}. {problem}\n"
|
||||
else:
|
||||
if temp_str:
|
||||
img = await text2image(
|
||||
temp_str,
|
||||
padding=10,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
msg_list.append(image(b64=img.pic2bs4()))
|
||||
temp_str = ""
|
||||
msg_list.append(f"{index}." + problem)
|
||||
index += 1
|
||||
if temp_str:
|
||||
img = await text2image(
|
||||
temp_str,
|
||||
padding=10,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
msg_list.append(image(b64=img.pic2bs4()))
|
||||
return msg_list
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
try:
|
||||
from ._old_model import WordBank as OldWordBank
|
||||
except ModuleNotFoundError:
|
||||
return
|
||||
if await WordBank.get_group_all_problem(0):
|
||||
return
|
||||
logger.info('开始迁移词条 纯文本 数据')
|
||||
word_list = await OldWordBank.get_all()
|
||||
for word in word_list:
|
||||
problem: str = word.problem
|
||||
user_id = word.user_qq
|
||||
group_id = word.group_id
|
||||
format_ = word.format
|
||||
answer = word.answer
|
||||
# 仅对纯文本做处理
|
||||
if '[CQ' not in problem and '[CQ' not in answer and '[_to_me' not in problem:
|
||||
if not format_:
|
||||
await WordBank.add_problem_answer(user_id, group_id, 1, 0, problem, answer)
|
||||
await WordBank.add_problem_answer(0, 0, 999, 0, '_[OK', '_[OK')
|
||||
logger.info('词条 纯文本 数据迁移完成')
|
||||
(Path() / 'plugins' / 'word_bank' / '_old_model.py').unlink()
|
||||
|
||||
def set_answer(self, answer: str):
|
||||
"""
|
||||
设置回答
|
||||
:param answer: 回答
|
||||
"""
|
||||
self._data["answer"] = answer
|
||||
|
||||
def set_problem(self, problem: str):
|
||||
"""
|
||||
设置问题
|
||||
:param problem: 问题
|
||||
"""
|
||||
self._data["problem"] = problem
|
||||
|
||||
async def save(self, search_type):
|
||||
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.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):
|
||||
return str(self._data)
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
import time
|
||||
from nonebot.internal.adapter.template import MessageTemplate
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Message,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
MessageSegment,
|
||||
)
|
||||
from services.db_context import db
|
||||
from typing import Optional, List, Union, Tuple, Any
|
||||
from datetime import datetime
|
||||
from configs.path_config import DATA_PATH
|
||||
import random
|
||||
from ._config import int2type
|
||||
from utils.image_utils import get_img_hash
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import re
|
||||
|
||||
from utils.message_builder import image, face, at
|
||||
from utils.utils import get_message_img
|
||||
|
||||
path = DATA_PATH / "word_bank"
|
||||
|
||||
|
||||
class WordBank(db.Model):
|
||||
__tablename__ = "word_bank2"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.Integer())
|
||||
word_scope = db.Column(
|
||||
db.Integer(), nullable=False, default=0
|
||||
) # 生效范围 0: 全局 1: 群聊 2: 私聊
|
||||
word_type = db.Column(
|
||||
db.Integer(), nullable=False, default=0
|
||||
) # 词条类型 0: 完全匹配 1: 模糊 2: 正则 3: 图片
|
||||
status = db.Column(db.Boolean(), nullable=False, default=True) # 词条状态
|
||||
problem = db.Column(db.String(), nullable=False) # 问题,为图片时使用图片hash
|
||||
answer = db.Column(db.String(), nullable=False) # 回答
|
||||
placeholder = db.Column(db.String()) # 占位符
|
||||
image_path = db.Column(db.String()) # 使用图片作为问题时图片存储的路径
|
||||
create_time = db.Column(db.DateTime(), nullable=False)
|
||||
update_time = db.Column(db.DateTime(), nullable=False)
|
||||
|
||||
@classmethod
|
||||
async def exists(
|
||||
cls,
|
||||
user_id: Optional[int],
|
||||
group_id: Optional[int],
|
||||
problem: str,
|
||||
word_scope: Optional[int] = None,
|
||||
word_type: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测问题是否存在
|
||||
参数:
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
:param word_scope: 词条范围
|
||||
:param word_type: 词条类型
|
||||
"""
|
||||
query = cls.query.where(cls.problem == problem)
|
||||
if user_id:
|
||||
query = query.where(cls.user_qq == user_id)
|
||||
if group_id:
|
||||
query = query.where(cls.group_id == group_id)
|
||||
if word_type:
|
||||
query = query.where(cls.word_type == word_type)
|
||||
if word_scope:
|
||||
query = query.where(cls.word_scope == word_scope)
|
||||
return bool(await query.gino.first())
|
||||
|
||||
@classmethod
|
||||
async def add_problem_answer(
|
||||
cls,
|
||||
user_id: int,
|
||||
group_id: Optional[int],
|
||||
word_scope: int,
|
||||
word_type: int,
|
||||
problem: Union[str, Message],
|
||||
answer: Union[str, Message],
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加或新增一个问答
|
||||
参数:
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param word_scope: 词条范围,
|
||||
:param word_type: 词条类型,
|
||||
:param problem: 问题
|
||||
:param answer: 回答
|
||||
"""
|
||||
# 对图片做额外处理
|
||||
image_path = None
|
||||
if word_type == 3:
|
||||
url = get_message_img(problem)[0]
|
||||
_file = (
|
||||
path / "problem" / f"{group_id}" / f"{user_id}_{int(time.time())}.jpg"
|
||||
)
|
||||
_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
await AsyncHttpx.download_file(url, _file)
|
||||
problem = str(get_img_hash(_file))
|
||||
image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
|
||||
answer, _list = await cls._answer2format(answer, user_id, group_id)
|
||||
await cls.create(
|
||||
user_qq=user_id,
|
||||
group_id=group_id,
|
||||
word_scope=word_scope,
|
||||
word_type=word_type,
|
||||
status=True,
|
||||
problem=problem,
|
||||
answer=answer,
|
||||
image_path=image_path,
|
||||
placeholder=",".join(_list),
|
||||
create_time=datetime.now().replace(microsecond=0),
|
||||
update_time=datetime.now().replace(microsecond=0),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def _answer2format(
|
||||
cls, answer: Union[str, Message], user_id: int, group_id: int
|
||||
) -> Tuple[str, List[Any]]:
|
||||
"""
|
||||
说明:
|
||||
将CQ码转化为占位符
|
||||
参数:
|
||||
:param answer: 回答内容
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if isinstance(answer, str):
|
||||
return answer, []
|
||||
_list = []
|
||||
text = ""
|
||||
index = 0
|
||||
for seg in answer:
|
||||
if isinstance(seg, str):
|
||||
text += seg
|
||||
elif seg.type == "text":
|
||||
text += seg.data["text"]
|
||||
elif seg.type == "face":
|
||||
text += f"[face:placeholder_{index}]"
|
||||
_list.append(seg.data.id)
|
||||
elif seg.type == "at":
|
||||
text += f"[at:placeholder_{index}]"
|
||||
_list.append(seg.data["qq"])
|
||||
else:
|
||||
text += f"[image:placeholder_{index}]"
|
||||
index += 1
|
||||
t = int(time.time())
|
||||
_file = path / "answer" / f"{group_id}" / f"{user_id}_{t}.jpg"
|
||||
_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
await AsyncHttpx.download_file(seg.data["url"], _file)
|
||||
_list.append(f"answer/{group_id}/{user_id}_{t}.jpg")
|
||||
return text, _list
|
||||
|
||||
@classmethod
|
||||
async def _format2answer(
|
||||
cls,
|
||||
problem: str,
|
||||
answer: Union[str, Message],
|
||||
user_id: int,
|
||||
group_id: int,
|
||||
query: Optional["WordBank"] = None,
|
||||
) -> Union[str, Message]:
|
||||
"""
|
||||
说明:
|
||||
将占位符转换为CQ码
|
||||
参数:
|
||||
:param problem: 问题内容
|
||||
:param answer: 回答内容
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if query:
|
||||
answer = query.answer
|
||||
else:
|
||||
query = await cls.query.where(
|
||||
(cls.problem == problem)
|
||||
& (cls.user_qq == user_id)
|
||||
& (cls.group_id == group_id)
|
||||
& (cls.answer == answer)
|
||||
).gino.first()
|
||||
if query and query.placeholder:
|
||||
type_list = re.findall(rf"\[(.*):placeholder_.*]", answer)
|
||||
temp_answer = re.sub(rf"\[(.*):placeholder_.*]", "{}", answer)
|
||||
seg_list = []
|
||||
for t, p in zip(type_list, query.placeholder.split(",")):
|
||||
if t == "image":
|
||||
seg_list.append(image(path / p))
|
||||
elif t == "face":
|
||||
seg_list.append(face(p))
|
||||
elif t == "at":
|
||||
seg_list.append(at(p))
|
||||
return MessageTemplate(temp_answer, Message).format(*seg_list)
|
||||
return answer
|
||||
|
||||
@classmethod
|
||||
async def check(
|
||||
cls,
|
||||
event: MessageEvent,
|
||||
problem: str,
|
||||
word_scope: Optional[int] = None,
|
||||
word_type: Optional[int] = None,
|
||||
) -> Optional[Any]:
|
||||
"""
|
||||
说明:
|
||||
检测是否包含该问题并获取所有回答
|
||||
参数:
|
||||
:param event: event
|
||||
:param problem: 问题内容
|
||||
:param word_scope: 词条范围
|
||||
:param word_type: 词条类型
|
||||
"""
|
||||
query = cls.query
|
||||
sql_text = "SELECT * FROM public.word_bank where 1 = 1"
|
||||
# 救命!!没找到gino的正则表达式方法,暂时使用sql语句
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if word_scope:
|
||||
query = query.where(cls.word_scope == word_scope)
|
||||
sql_text += f" and word_scope = {word_scope}"
|
||||
else:
|
||||
query = query.where(
|
||||
(cls.group_id == event.group_id) | (cls.word_scope == 0)
|
||||
)
|
||||
sql_text += f" and (group_id = {event.group_id} or word_scope = 0)"
|
||||
else:
|
||||
query = query.where((cls.word_scope == 2) | (cls.word_scope == 0))
|
||||
sql_text += f" and (word_scope = 2 or word_scope = 0)"
|
||||
if word_type:
|
||||
query = query.where(cls.word_scope == word_type)
|
||||
sql_text += f" and word_scope = {word_scope}"
|
||||
# 完全匹配
|
||||
if await query.where(cls.problem == problem).gino.first():
|
||||
return query.where(cls.problem == problem)
|
||||
# 正则匹配
|
||||
if await db.first(
|
||||
db.text(sql_text + f" and word_type = 2 and '{problem}' ~ problem;")
|
||||
):
|
||||
return sql_text + f" and word_type = 2 and '{problem}' ~ problem;"
|
||||
# 模糊匹配
|
||||
if await db.first(
|
||||
db.text(sql_text + f" and word_type = 1 and '{problem}' ~ problem;")
|
||||
):
|
||||
return sql_text + f" and word_type = 1 and '{problem}' ~ problem;"
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def get_answer(
|
||||
cls,
|
||||
event: MessageEvent,
|
||||
problem: str,
|
||||
word_scope: Optional[int] = None,
|
||||
word_type: Optional[int] = None,
|
||||
) -> Optional[Union[str, Message]]:
|
||||
"""
|
||||
说明:
|
||||
根据问题内容获取随机回答
|
||||
参数:
|
||||
:param event: event
|
||||
:param problem: 问题内容
|
||||
:param word_scope: 词条范围
|
||||
:param word_type: 词条类型
|
||||
"""
|
||||
query = await cls.check(event, problem, word_scope, word_type)
|
||||
if query is not None:
|
||||
if isinstance(query, str):
|
||||
answer_list = await db.all(db.text(query))
|
||||
answer = random.choice(answer_list)
|
||||
return (
|
||||
await cls._format2answer(problem, answer[7], answer[1], answer[2])
|
||||
if answer.placeholder
|
||||
else answer.answer
|
||||
)
|
||||
else:
|
||||
answer_list = await query.gino.all()
|
||||
answer = random.choice(answer_list)
|
||||
return (
|
||||
await cls._format2answer(
|
||||
problem, answer.answer, answer.user_qq, answer.group_id
|
||||
)
|
||||
if answer.placeholder
|
||||
else answer.answer
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_problem_all_answer(
|
||||
cls,
|
||||
problem: str,
|
||||
index: Optional[int] = None,
|
||||
group_id: Optional[int] = None,
|
||||
word_scope: Optional[int] = 0,
|
||||
) -> List[Union[str, Message]]:
|
||||
"""
|
||||
说明:
|
||||
获取指定问题所有回答
|
||||
参数:
|
||||
:param problem: 问题
|
||||
:param index: 下标
|
||||
:param group_id: 群号
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
if index is not None:
|
||||
if group_id:
|
||||
problem = (await cls.query.where(cls.group_id == group_id).gino.all())[
|
||||
index
|
||||
]
|
||||
else:
|
||||
problem = (
|
||||
await cls.query.where(
|
||||
cls.word_scope == (word_scope or 0)
|
||||
).gino.all()
|
||||
)[index]
|
||||
problem = problem.problem
|
||||
answer = cls.query.where(cls.problem == problem)
|
||||
if group_id:
|
||||
answer = answer.where(cls.group_id == group_id)
|
||||
return [
|
||||
await cls._format2answer("", "", 0, 0, x) for x in (await answer.gino.all())
|
||||
]
|
||||
|
||||
@classmethod
|
||||
async def delete_group_problem(
|
||||
cls,
|
||||
problem: str,
|
||||
group_id: int,
|
||||
index: Optional[int] = None,
|
||||
word_scope: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
删除指定问题全部或指定回答
|
||||
参数:
|
||||
:param problem: 问题文本
|
||||
:param group_id: 群号
|
||||
:param index: 回答下标
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
if index is not None:
|
||||
if group_id:
|
||||
query = await cls.query.where(
|
||||
(cls.group_id == group_id) & (cls.problem == problem)
|
||||
).gino.all()
|
||||
else:
|
||||
query = await cls.query.where(
|
||||
(cls.word_scope == 0) & (cls.problem == problem)
|
||||
).gino.all()
|
||||
await query[index].delete()
|
||||
else:
|
||||
if group_id:
|
||||
await WordBank.delete.where(
|
||||
(cls.group_id == group_id) & (cls.problem == problem)
|
||||
).gino.status()
|
||||
else:
|
||||
await WordBank.delete.where(
|
||||
(cls.word_scope == word_scope) & (cls.problem == problem)
|
||||
).gino.status()
|
||||
|
||||
@classmethod
|
||||
async def update_group_problem(
|
||||
cls,
|
||||
problem: str,
|
||||
replace_str: str,
|
||||
group_id: int,
|
||||
index: Optional[int] = None,
|
||||
word_scope: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
修改词条问题
|
||||
参数:
|
||||
:param problem: 问题
|
||||
:param replace_str: 替换问题
|
||||
:param group_id: 群号
|
||||
:param index: 下标
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
if index is not None:
|
||||
if group_id:
|
||||
query = await cls.query.where(
|
||||
(cls.group_id == group_id) & (cls.problem == problem)
|
||||
).gino.all()
|
||||
else:
|
||||
query = await cls.query.where(
|
||||
(cls.word_scope == word_scope) & (cls.problem == problem)
|
||||
).gino.all()
|
||||
await query[index].update(problem=replace_str).apply()
|
||||
else:
|
||||
if group_id:
|
||||
await WordBank.update.values(problem=replace_str).where(
|
||||
(cls.group_id == group_id) & (cls.problem == problem)
|
||||
).gino.status()
|
||||
else:
|
||||
await WordBank.update.values(problem=replace_str).where(
|
||||
(cls.word_scope == word_scope) & (cls.problem == problem)
|
||||
).gino.status()
|
||||
|
||||
@classmethod
|
||||
async def get_group_all_problem(
|
||||
cls, group_id: int
|
||||
) -> List[Tuple[Any, Union[MessageSegment, str]]]:
|
||||
"""
|
||||
说明:
|
||||
获取群聊所有词条
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
return cls._handle_problem(
|
||||
await cls.query.where(cls.group_id == group_id).gino.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_problem_by_scope(cls, word_scope: int):
|
||||
"""
|
||||
说明:
|
||||
通过词条范围获取词条
|
||||
参数:
|
||||
:param word_scope: 词条范围
|
||||
"""
|
||||
return cls._handle_problem(
|
||||
await cls.query.where(cls.word_scope == word_scope).gino.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_problem_by_type(cls, word_type: int):
|
||||
"""
|
||||
说明:
|
||||
通过词条类型获取词条
|
||||
参数:
|
||||
:param word_type: 词条类型
|
||||
"""
|
||||
return cls._handle_problem(
|
||||
await cls.query.where(cls.word_type == word_type).gino.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _handle_problem(cls, msg_list: List[Union[str, MessageSegment]]):
|
||||
"""
|
||||
说明:
|
||||
格式化处理问题
|
||||
参数:
|
||||
:param msg_list: 消息列表
|
||||
"""
|
||||
_tmp = []
|
||||
problem_list = []
|
||||
for q in msg_list:
|
||||
if q.problem not in _tmp:
|
||||
problem = (
|
||||
q.problem,
|
||||
image(path / q.image_path)
|
||||
if q.image_path
|
||||
else f"[{int2type[q.word_type]}] " + q.problem,
|
||||
)
|
||||
problem_list.append(problem)
|
||||
_tmp.append(q.problem)
|
||||
return problem_list
|
||||
@@ -0,0 +1,20 @@
|
||||
from services.db_context import db
|
||||
from typing import List
|
||||
|
||||
|
||||
class WordBank(db.Model):
|
||||
__tablename__ = "word_bank"
|
||||
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.Integer())
|
||||
search_type = db.Column(db.Integer(), nullable=False, default=0)
|
||||
problem = db.Column(db.String(), nullable=False)
|
||||
answer = db.Column(db.String(), nullable=False)
|
||||
format = db.Column(db.String())
|
||||
create_time = db.Column(db.DateTime(), nullable=False)
|
||||
update_time = db.Column(db.DateTime(), nullable=False)
|
||||
|
||||
@classmethod
|
||||
async def get_all(cls) -> List['WordBank']:
|
||||
return await cls.query.gino.all()
|
||||
|
||||
+28
-15
@@ -1,18 +1,31 @@
|
||||
import re
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Event
|
||||
from utils.utils import get_message_img_file
|
||||
from .model import WordBank
|
||||
import random
|
||||
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
|
||||
from configs.path_config import TEMP_PATH
|
||||
from utils.image_utils import get_img_hash
|
||||
from utils.utils import get_message_text, get_message_img, get_message_at
|
||||
from ._model import WordBank
|
||||
from utils.http_utils import AsyncHttpx
|
||||
|
||||
|
||||
async def check(event: Event) -> bool:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
msg = event.raw_message
|
||||
list_img = get_message_img_file(event.json())
|
||||
if list_img:
|
||||
for img_file in list_img:
|
||||
strinfo = re.compile(f"{img_file},.*?]")
|
||||
msg = strinfo.sub(f'{img_file}]', msg)
|
||||
strinfo_face = re.compile(f",type=sticker]")
|
||||
msg = strinfo_face.sub(f']', msg)
|
||||
return bool(await WordBank.check(event.group_id, msg,))
|
||||
async def check(event: MessageEvent) -> bool:
|
||||
text = get_message_text(event.message)
|
||||
img = get_message_img(event.message)
|
||||
at = get_message_at(event.message)
|
||||
rand = random.randint(1, 100)
|
||||
problem = text
|
||||
if not text and len(img) == 1:
|
||||
if await AsyncHttpx.download_file(img[0], TEMP_PATH / f"{event.user_id}_{rand}_word_bank_check.jpg"):
|
||||
problem = str(get_img_hash(TEMP_PATH / f"{event.user_id}_{rand}_word_bank_check.jpg"))
|
||||
if at:
|
||||
temp = ''
|
||||
for seg in event.message:
|
||||
if seg.type == 'at':
|
||||
temp += f"[at:{seg.data['qq']}]"
|
||||
else:
|
||||
temp += seg
|
||||
problem = temp
|
||||
if problem:
|
||||
return await WordBank.check(event, problem) is not None
|
||||
return False
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
from utils.message_builder import image, at, face
|
||||
from typing import Tuple
|
||||
import random
|
||||
|
||||
from services import logger
|
||||
from utils.image_utils import get_img_hash
|
||||
from ._rule import check
|
||||
from .model import WordBank
|
||||
from configs.path_config import DATA_PATH
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from utils.utils import get_message_at, get_message_img, change_img_md5
|
||||
from ._model import WordBank
|
||||
from configs.path_config import DATA_PATH, TEMP_PATH
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
||||
from utils.utils import get_message_img, get_message_text, get_message_at
|
||||
from nonebot import on_message
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from utils.utils import get_message_img_file, is_number
|
||||
import re
|
||||
from utils.http_utils import AsyncHttpx
|
||||
|
||||
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
|
||||
|
||||
@@ -19,129 +19,33 @@ message_handle = on_message(priority=6, block=True, rule=check)
|
||||
|
||||
|
||||
@message_handle.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
msg = event.raw_message
|
||||
list_img = get_message_img_file(event.json())
|
||||
if list_img:
|
||||
for img_file in list_img:
|
||||
strinfo = re.compile(f"{img_file},.*?]")
|
||||
msg = strinfo.sub(f'{img_file}]', msg)
|
||||
strinfo_face = re.compile(f",type=sticker]")
|
||||
msg = strinfo_face.sub(f']', msg)
|
||||
q = await WordBank.check(event.group_id, msg, )
|
||||
await message_handle.send(await get_one_answer(event, q.format, q.answer))
|
||||
|
||||
|
||||
# 处理单条回答
|
||||
async def get_one_answer(event, format: str, _answer: str, all: bool = True) -> str:
|
||||
path = data_dir / f"{event.group_id}"
|
||||
placeholder_list = (
|
||||
[
|
||||
(x.split("<_s>")[0], x.split("<_s>")[1])
|
||||
for x in format.split("<format>")[:-1]
|
||||
]
|
||||
if format
|
||||
else []
|
||||
)
|
||||
answer = ""
|
||||
_a = _answer
|
||||
if not placeholder_list:
|
||||
answer = _a
|
||||
return answer
|
||||
else:
|
||||
for idx, placeholder in placeholder_list:
|
||||
if placeholder.endswith("jpg"):
|
||||
change_img_md5(path / placeholder)
|
||||
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + image(
|
||||
path / placeholder
|
||||
)
|
||||
async def _(event: MessageEvent):
|
||||
text = get_message_text(event.message)
|
||||
img = get_message_img(event.message)
|
||||
at = get_message_at(event.message)
|
||||
problem = None
|
||||
if not text and img and len(img) == 1:
|
||||
rand = random.randint(1, 10000)
|
||||
if await AsyncHttpx.download_file(img[0], TEMP_PATH / f"{event.user_id}_{rand}_word_bank.jpg"):
|
||||
problem = str(get_img_hash(TEMP_PATH / f"{event.user_id}_{rand}_word_bank.jpg"))
|
||||
elif at:
|
||||
temp = ''
|
||||
for seg in event.message:
|
||||
if seg.type == 'at':
|
||||
temp += f"[at:{seg.data['qq']}]"
|
||||
else:
|
||||
if all:
|
||||
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(int(placeholder))
|
||||
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
|
||||
|
||||
|
||||
# 处理单条问题
|
||||
async def get_one_problem(event, problem: str, ) -> Tuple[str, str]:
|
||||
strinfo = re.compile(f",subType=\d")
|
||||
problem = strinfo.sub('', problem)
|
||||
_problem = problem
|
||||
_p = problem
|
||||
problem = ''
|
||||
for img in get_message_img(event.json()):
|
||||
_x = img.split("?")[0]
|
||||
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", _p)
|
||||
if r:
|
||||
_problem = _problem.replace(
|
||||
rf",url={img}",
|
||||
f"",
|
||||
temp += seg
|
||||
problem = temp
|
||||
elif text:
|
||||
problem = text
|
||||
if problem:
|
||||
if msg := await WordBank.get_answer(event, problem):
|
||||
await message_handle.send(msg)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 触发词条 {problem}"
|
||||
)
|
||||
problem += _p[: _p.find(f"[CQ:image,file={r.group(1)},url={img}]")] + image(img)
|
||||
_p = _p[
|
||||
_p.find(f"[CQ:image,file={r.group(1)},url={img}]") + len(f"[CQ:image,file={r.group(1)},url={img}]"):]
|
||||
for at_ in get_message_at(event.json()):
|
||||
r = re.search(rf"\[CQ:at,qq={at_}]", problem)
|
||||
if r:
|
||||
q = await GroupInfoUser.get_member_info(
|
||||
int(at_), event.group_id)
|
||||
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
|
||||
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
|
||||
return _problem, problem + _p
|
||||
|
||||
|
||||
# 显示单条数据库问题
|
||||
async def get_one_image_problem(event, problem: str) -> str:
|
||||
path = data_dir / f"{event.group_id}" / "problem"
|
||||
placeholder_list = []
|
||||
idx = 0
|
||||
img_list = re.findall(rf"\[CQ:image,file=(.*?)]", problem)
|
||||
at_list = re.findall(rf"\[CQ:at,qq=(.*?)]", problem)
|
||||
if img_list:
|
||||
for img in img_list:
|
||||
problem = problem.replace(f'[CQ:image,file={img}]', f'[__placeholder_{idx}]', 1)
|
||||
placeholder_list.append([idx, img])
|
||||
idx += 1
|
||||
if at_list:
|
||||
for ats in at_list:
|
||||
problem = problem.replace(f'[CQ:at,qq={ats}]', f'[__placeholder_{idx}]', 1)
|
||||
placeholder_list.append([idx, ats])
|
||||
idx += 1
|
||||
_p = problem
|
||||
problem = ''
|
||||
if not placeholder_list:
|
||||
problem = _p
|
||||
return problem
|
||||
else:
|
||||
for idx, placeholder in placeholder_list:
|
||||
if is_number(placeholder):
|
||||
q = await GroupInfoUser.get_member_info(
|
||||
int(placeholder), event.group_id)
|
||||
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
|
||||
else:
|
||||
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + image(
|
||||
path / f"{placeholder}.jpg"
|
||||
)
|
||||
_p = _p[_p.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
|
||||
|
||||
return problem + _p
|
||||
|
||||
|
||||
# 替换cq码
|
||||
async def replace_cq(group_id, msg: str, is_face: bool = True) -> str:
|
||||
strinfo_img = re.compile(f"\[CQ:image.*?]")
|
||||
msg = strinfo_img.sub('[图片]', msg)
|
||||
at_list = re.findall(rf"\[CQ:at,qq=(.*?)]", msg)
|
||||
if at_list:
|
||||
for ats in at_list:
|
||||
q = await GroupInfoUser.get_member_info(
|
||||
int(ats), group_id)
|
||||
msg = msg.replace(f'[CQ:at,qq={ats}]', "@" + q.user_name)
|
||||
if is_face:
|
||||
strinfo_face = re.compile(f"\[CQ:face,id=.*?]")
|
||||
msg = strinfo_face.sub('[表情]', msg)
|
||||
return msg
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List, Union, Tuple
|
||||
from datetime import datetime
|
||||
from configs.path_config import DATA_PATH
|
||||
import random
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
class WordBank(db.Model):
|
||||
__tablename__ = "word_bank"
|
||||
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.Integer())
|
||||
search_type = db.Column(db.Integer(), nullable=False, default=0)
|
||||
problem = db.Column(db.String(), nullable=False)
|
||||
answer = db.Column(db.String(), nullable=False)
|
||||
format = db.Column(db.String())
|
||||
create_time = db.Column(db.DateTime(), nullable=False)
|
||||
update_time = db.Column(db.DateTime(), nullable=False)
|
||||
|
||||
@classmethod
|
||||
async def add_problem_answer(
|
||||
cls,
|
||||
user_id: int,
|
||||
group_id: Optional[int],
|
||||
search_type: [int],
|
||||
problem: str,
|
||||
answer: str,
|
||||
format_: Optional[List[Tuple[int, Union[int, str]]]],
|
||||
) -> bool:
|
||||
"""
|
||||
添加或新增一个问答
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:search_type: 问题类型,
|
||||
:param problem: 问题
|
||||
:param answer: 回答
|
||||
:param format_: 格式化数据
|
||||
"""
|
||||
_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, "add", search_type=search_type, answer=answer, format_=_str
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def delete_problem_answer(
|
||||
cls, user_id: int, group_id: Optional[int], problem: str, index: Optional[int]
|
||||
) -> str:
|
||||
"""
|
||||
删除某问题一个或全部回答
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
:param index: 回答下标
|
||||
"""
|
||||
return await cls._problem_answer_handle(
|
||||
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
|
||||
async def get_problem_answer(
|
||||
cls, user_id: int, group_id: Optional[int], problem: str
|
||||
) -> List[str]:
|
||||
"""
|
||||
获取问题的所有回答
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
"""
|
||||
return await cls._problem_answer_handle(user_id, group_id, problem, "get")
|
||||
|
||||
@classmethod
|
||||
async def get_group_all_answer(cls, group_id: int, problem: str) -> List[str]:
|
||||
"""
|
||||
获取群聊指定词条所有回答
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
"""
|
||||
q = await cls.query.where(
|
||||
(cls.group_id == group_id) & (cls.problem == problem)
|
||||
).gino.all()
|
||||
|
||||
return [(x.answer, x.format) for x in q] if q else None
|
||||
|
||||
@classmethod
|
||||
async def get_group_all_problem(cls, group_id: int) -> List[str]:
|
||||
"""
|
||||
获取群聊所有词条
|
||||
:param group_id: 群号
|
||||
"""
|
||||
q = await cls.query.where(cls.group_id == group_id).gino.all()
|
||||
q = [x.problem for x in q]
|
||||
q.sort()
|
||||
_tmp = []
|
||||
for problem in q:
|
||||
_tmp.append(problem)
|
||||
return list(set(_tmp))
|
||||
|
||||
@classmethod
|
||||
async def check(cls, group_id: int, problem: str) -> Optional["WordBank"]:
|
||||
"""
|
||||
检测词条并随机返回
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
"""
|
||||
if problem:
|
||||
FUZZY = Config.get_config("word_bank", "WORD_BANK_FUZZY")
|
||||
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
|
||||
|
||||
@classmethod
|
||||
async def _problem_answer_handle(
|
||||
cls,
|
||||
user_id: int,
|
||||
group_id: Optional[int],
|
||||
problem: str,
|
||||
type_: str,
|
||||
*,
|
||||
search_type: [int] = 0,
|
||||
answer: Optional[str] = None,
|
||||
index: Optional[int] = None,
|
||||
format_: Optional[str] = None,
|
||||
) -> Union[List[Union[str, Tuple[str, str]]], bool, str]:
|
||||
"""
|
||||
添加或新增一个问答
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param problem: 问题
|
||||
:param type_: 操作类型
|
||||
:param answer: 回答
|
||||
:param format_: 格式化数据
|
||||
"""
|
||||
if problem.startswith("id:"):
|
||||
problem_index = int(problem.split(":")[-1])
|
||||
q = await cls.get_group_all_problem(group_id)
|
||||
if not q:
|
||||
return []
|
||||
if len(q) > problem_index:
|
||||
problem = q[problem_index]
|
||||
if group_id:
|
||||
q = cls.query.where((cls.group_id == group_id) & (cls.problem == problem))
|
||||
else:
|
||||
q = cls.query.where((cls.user_qq == user_id) & (cls.problem == problem))
|
||||
if type_ == "add":
|
||||
q = await q.where((cls.answer == answer) & (cls.search_type == search_type)).gino.all()
|
||||
try:
|
||||
if not q or ".jpg" in format_:
|
||||
await cls.create(
|
||||
user_qq=user_id,
|
||||
group_id=group_id,
|
||||
search_type=search_type,
|
||||
problem=problem,
|
||||
answer=answer,
|
||||
format=format_,
|
||||
create_time=datetime.now().replace(microsecond=0),
|
||||
update_time=datetime.now().replace(microsecond=0),
|
||||
)
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
elif type_ == "delete":
|
||||
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]]
|
||||
answer = "\n".join([x.answer for x in q])
|
||||
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.delete.where(
|
||||
(cls.update_time == x.update_time)
|
||||
& (cls.problem == problem)
|
||||
& (cls.answer == x.answer)
|
||||
& (cls.group_id == group_id)
|
||||
).gino.status()
|
||||
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":
|
||||
q = await q.gino.all()
|
||||
if q:
|
||||
return [(x.answer, x.format.split("<format>")[:-1]) for x in q]
|
||||
return False
|
||||
@@ -0,0 +1,305 @@
|
||||
from typing import Tuple, Any, Optional
|
||||
|
||||
from nonebot.internal.params import Arg, ArgStr
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from utils.utils import get_message_at, is_number, get_message_img
|
||||
from nonebot.params import CommandArg, RegexGroup, Command
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import custom_forward_msg
|
||||
from ._model import WordBank
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent, PrivateMessageEvent
|
||||
from nonebot import on_command, on_regex
|
||||
from configs.config import Config
|
||||
from ._data_source import delete_word, update_word, show_word
|
||||
from ._config import scope2int, type2int
|
||||
|
||||
__zx_plugin_name__ = "词库问答 [Admin]"
|
||||
__plugin_usage__ = r"""
|
||||
usage:
|
||||
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
||||
删除词条后每个词条的id可能会变化,请查看后再删除
|
||||
更推荐使用id方式删除
|
||||
问题回答支持的CQ:at, face, image
|
||||
查看词条命令:群聊时为 群词条+全局词条,私聊时为 私聊词条+全局词条
|
||||
添加词条正则:添加词条(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*)
|
||||
指令:
|
||||
添加词条 ?[模糊|正则|图片]问...答...:添加问答词条,可重复添加相同问题的不同回答
|
||||
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
||||
修改词条 [问题/下标] [新问题]:修改词条问题
|
||||
查看词条 ?[问题/下标]:查看全部词条或对应词条回答
|
||||
示例:添加词条问图片答嗨嗨嗨
|
||||
[图片]...
|
||||
示例:添加词条@萝莉 我来啦
|
||||
示例:添加词条问谁是萝莉答是我
|
||||
示例:删除词条 谁是萝莉
|
||||
示例:删除词条 谁是萝莉 0
|
||||
示例:删除词条 id:0 1
|
||||
示例:修改词条 谁是萝莉 是你
|
||||
示例:修改词条 id:0 是你
|
||||
示例:查看词条
|
||||
示例:查看词条 谁是萝莉
|
||||
示例:查看词条 id:0 (群/私聊词条)
|
||||
示例:查看词条 gid:0 (全局词条)
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = r"""
|
||||
usage:
|
||||
在私聊中超级用户额外设置
|
||||
指令:
|
||||
(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*):添加问答词条,可重复添加相同问题的不同回答
|
||||
全局添加词条
|
||||
私聊添加词条
|
||||
(私聊情况下)删除词条: 删除私聊词条
|
||||
(私聊情况下)删除全局词条
|
||||
(私聊情况下)修改词条: 修改词条私聊词条
|
||||
(私聊情况下)修改全局词条
|
||||
用法与普通用法相同
|
||||
""".strip()
|
||||
__plugin_des__ = "自定义词条内容随机回复"
|
||||
__plugin_cmd__ = [
|
||||
"添加词条 ?[模糊/关键字]问...答..",
|
||||
"删除词条 [问题/下标] ?[下标]",
|
||||
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
|
||||
"查看词条 ?[问题/下标]",
|
||||
]
|
||||
__plugin_version__ = 0.3
|
||||
__plugin_author__ = "HibiKier & yajiwa"
|
||||
__plugin_settings__ = {
|
||||
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
|
||||
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
|
||||
}
|
||||
|
||||
data_dir = DATA_PATH / "word_bank"
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
add_word = on_regex(
|
||||
r"^(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*)", priority=5, block=True
|
||||
)
|
||||
|
||||
delete_word_matcher = on_command("删除词条", aliases={'删除全局词条'}, priority=5, block=True)
|
||||
|
||||
update_word_matcher = on_command("修改词条", aliases={'修改全局词条'}, priority=5, block=True)
|
||||
|
||||
show_word_matcher = on_command("显示词条", aliases={"查看词条"}, priority=5, block=True)
|
||||
|
||||
|
||||
@add_word.handle()
|
||||
async def _(
|
||||
bot: Bot,
|
||||
event: MessageEvent,
|
||||
state: T_State,
|
||||
reg_group: Tuple[Any, ...] = RegexGroup(),
|
||||
):
|
||||
if str(event.user_id) not in bot.config.superusers:
|
||||
await add_word.finish('权限不足捏')
|
||||
word_scope, word_type, problem, answer = reg_group
|
||||
if (
|
||||
word_scope
|
||||
and word_scope in ["全局", "私聊"]
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await add_word.finish("权限不足,无法添加该范围词条")
|
||||
if (not problem or not problem.strip()) and word_type != "图片":
|
||||
await add_word.finish("词条问题不能为空!")
|
||||
if (not answer or not answer.strip()) and not len(get_message_img(event.message)):
|
||||
await add_word.finish("词条回答不能为空!")
|
||||
if word_type != "图片":
|
||||
state["problem_image"] = "YES"
|
||||
answer = event.message
|
||||
# 对at问题对额外处理
|
||||
if get_message_at(event.message):
|
||||
for index, seg in enumerate(event.message):
|
||||
if seg.type == 'text' and '答' in str(seg):
|
||||
_problem = event.message[:index]
|
||||
answer = event.message[index:]
|
||||
answer[0] = str(answer[0])[str(answer).index('答')+1:]
|
||||
_problem[0] = str(_problem[0])[str(_problem).index('问')+1:]
|
||||
temp = ''
|
||||
for g in _problem:
|
||||
if isinstance(g, str) or g.type == 'text':
|
||||
temp += g
|
||||
elif g.type == 'at':
|
||||
temp += f"[at:{g.data['qq']}]"
|
||||
problem = temp
|
||||
break
|
||||
index = len((word_scope or "") + "添加词条" + (word_type or "") + problem) + 1
|
||||
event.message[0] = event.message[0].data["text"][index + 1 :].strip()
|
||||
state["word_scope"] = word_scope
|
||||
state["word_type"] = word_type
|
||||
state["problem"] = problem
|
||||
state["answer"] = answer
|
||||
|
||||
|
||||
@add_word.got("problem_image", prompt="请发送该回答设置的问题图片")
|
||||
async def _(
|
||||
event: MessageEvent,
|
||||
word_scope: Optional[str] = ArgStr("word_scope"),
|
||||
word_type: Optional[str] = ArgStr("word_type"),
|
||||
problem: Optional[str] = ArgStr("problem"),
|
||||
answer: Message = Arg("answer"),
|
||||
problem_image: Message = Arg("problem_image"),
|
||||
):
|
||||
try:
|
||||
await WordBank.add_problem_answer(
|
||||
event.user_id,
|
||||
event.group_id if isinstance(event, GroupMessageEvent) and (not word_scope or word_scope == '1') else 0,
|
||||
scope2int[word_scope] if word_scope else 1,
|
||||
type2int[word_type] if word_type else 0,
|
||||
problem or problem_image,
|
||||
answer,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 添加词条 {problem} 发生错误 {type(e)}: {e} "
|
||||
)
|
||||
await add_word.finish(f"添加词条 {problem} 发生错误!")
|
||||
await add_word.send("添加词条 " + (problem or problem_image) + " 成功!")
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 添加词条 {problem} 成功!"
|
||||
)
|
||||
|
||||
|
||||
@delete_word_matcher.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
if not (msg := arg.extract_plain_text().strip()):
|
||||
await delete_word_matcher.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
||||
result = await delete_word(msg, event.group_id)
|
||||
await delete_word_matcher.send(result)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id})"
|
||||
f" 删除词条:" + msg
|
||||
)
|
||||
|
||||
|
||||
@delete_word_matcher.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, arg: Message = CommandArg(), cmd: Tuple[str, ...] = Command()):
|
||||
if str(event.user_id) not in bot.config.superusers:
|
||||
await delete_word_matcher.finish("权限不足捏!")
|
||||
if not (msg := arg.extract_plain_text().strip()):
|
||||
await delete_word_matcher.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
||||
result = await delete_word(msg, word_scope=2 if cmd[0] == '删除词条' else 0)
|
||||
await delete_word_matcher.send(result)
|
||||
logger.info(
|
||||
f"(USER {event.user_id})"
|
||||
f" 删除词条:" + msg
|
||||
)
|
||||
|
||||
|
||||
@update_word_matcher.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
if not (msg := arg.extract_plain_text().strip()):
|
||||
await update_word_matcher.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
||||
if len(msg.split()) < 2:
|
||||
await update_word_matcher.finish("此命令需要两个参数,请查看帮助")
|
||||
result = await update_word(msg, event.group_id)
|
||||
await update_word_matcher.send(result)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id})"
|
||||
f" 更新词条词条:" + msg
|
||||
)
|
||||
|
||||
|
||||
@update_word_matcher.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, arg: Message = CommandArg(), cmd: Tuple[str, ...] = Command()):
|
||||
if str(event.user_id) not in bot.config.superusers:
|
||||
await delete_word_matcher.finish("权限不足捏!")
|
||||
if not (msg := arg.extract_plain_text().strip()):
|
||||
await update_word_matcher.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
||||
if len(msg.split()) < 2:
|
||||
await update_word_matcher.finish("此命令需要两个参数,请查看帮助")
|
||||
result = await update_word(msg, word_scope=2 if cmd[0] == '修改词条' else 0)
|
||||
await update_word_matcher.send(result)
|
||||
logger.info(
|
||||
f"(USER {event.user_id})"
|
||||
f" 更新词条词条:" + msg
|
||||
)
|
||||
|
||||
|
||||
@show_word_matcher.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
if problem := arg.extract_plain_text().strip():
|
||||
id_ = None
|
||||
gid = None
|
||||
if problem.startswith("id:"):
|
||||
id_ = problem.split(":")[-1]
|
||||
if (
|
||||
not is_number(id_)
|
||||
or int(id_) < 0
|
||||
or int(id_)
|
||||
> len(await WordBank.get_group_all_problem(event.group_id))
|
||||
):
|
||||
await show_word_matcher.finish("id必须为数字且在范围内")
|
||||
id_ = int(id_)
|
||||
if problem.startswith("gid:"):
|
||||
gid = problem.split(":")[-1]
|
||||
if (
|
||||
not is_number(gid)
|
||||
or int(gid) < 0
|
||||
or int(gid)
|
||||
> len(await WordBank.get_problem_by_scope(0))
|
||||
):
|
||||
await show_word_matcher.finish("gid必须为数字且在范围内")
|
||||
gid = int(gid)
|
||||
msg_list = await show_word(problem, id_, gid, None if gid else event.group_id)
|
||||
else:
|
||||
msg_list = await show_word(problem, None, None, event.group_id)
|
||||
if isinstance(msg_list, str):
|
||||
await show_word_matcher.send(msg_list)
|
||||
else:
|
||||
await bot.send_group_forward_msg(
|
||||
group_id=event.group_id, messages=custom_forward_msg(msg_list, bot.self_id)
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 发送查看词条回答:" + problem
|
||||
)
|
||||
|
||||
|
||||
@show_word_matcher.handle()
|
||||
async def _(event: PrivateMessageEvent, arg: Message = CommandArg()):
|
||||
if problem := arg.extract_plain_text().strip():
|
||||
id_ = None
|
||||
gid = None
|
||||
if problem.startswith("id:"):
|
||||
id_ = problem.split(":")[-1]
|
||||
if (
|
||||
not is_number(id_)
|
||||
or int(id_) < 0
|
||||
or int(id_)
|
||||
> len(await WordBank.get_problem_by_scope(2))
|
||||
):
|
||||
await show_word_matcher.finish("id必须为数字且在范围内")
|
||||
id_ = int(id_)
|
||||
if problem.startswith("gid:"):
|
||||
gid = problem.split(":")[-1]
|
||||
if (
|
||||
not is_number(gid)
|
||||
or int(gid) < 0
|
||||
or int(gid)
|
||||
> len(await WordBank.get_problem_by_scope(0))
|
||||
):
|
||||
await show_word_matcher.finish("gid必须为数字且在范围内")
|
||||
gid = int(gid)
|
||||
msg_list = await show_word(problem, id_, gid, word_scope=2 if id_ is not None else None)
|
||||
else:
|
||||
msg_list = await show_word(problem, None, None, word_scope=2)
|
||||
if isinstance(msg_list, str):
|
||||
await show_word_matcher.send(msg_list)
|
||||
else:
|
||||
t = ""
|
||||
for msg in msg_list:
|
||||
t += msg + '\n'
|
||||
await show_word_matcher.send(t[:-1])
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"private)"
|
||||
f" 发送查看词条回答:" + problem
|
||||
)
|
||||
@@ -1,311 +0,0 @@
|
||||
from utils.utils import get_message_at, is_number, get_message_img
|
||||
from nonebot.params import CommandArg
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from ._data_source import WordBankBuilder
|
||||
from utils.message_builder import image
|
||||
from utils.image_utils import text2image
|
||||
from .message_handle import get_one_answer, get_one_problem, get_one_image_problem, replace_cq
|
||||
from .model import WordBank
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupMessageEvent,
|
||||
Message
|
||||
)
|
||||
from nonebot import on_command
|
||||
import random
|
||||
import os
|
||||
import re
|
||||
from configs.config import NICKNAME, Config
|
||||
from models.group_member_info import GroupInfoUser
|
||||
|
||||
__zx_plugin_name__ = "词库问答 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
||||
删除词条后每个词条的id可能会变化,请查看后再删除
|
||||
指令:
|
||||
添加词条 ?[模糊/关键字|词]...答...:添加问答词条,可重复添加相同问题的不同回答
|
||||
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
||||
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
|
||||
查看词条 ?[问题/下标]:查看全部词条或对应词条回答
|
||||
示例:添加词条问谁是萝莉答是我
|
||||
示例:删除词条 谁是萝莉
|
||||
示例:删除词条 谁是萝莉 0
|
||||
示例:删除词条 id:0
|
||||
示例:修改词条 谁是萝莉 是你
|
||||
示例:修改词条 谁是萝莉 0 是你
|
||||
示例:修改词条 id:0 是你
|
||||
示例:查看词条
|
||||
示例:查看词条 谁是萝莉
|
||||
示例:查看词条 id:0
|
||||
""".strip()
|
||||
__plugin_des__ = "自定义词条内容随机回复"
|
||||
__plugin_cmd__ = [
|
||||
"添加词条 ?[模糊/关键字]问...答..",
|
||||
"删除词条 [问题/下标] ?[下标]",
|
||||
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
|
||||
"查看词条 ?[问题/下标]",
|
||||
]
|
||||
__plugin_version__ = 0.3
|
||||
__plugin_author__ = "HibiKier & yajiwa"
|
||||
__plugin_settings__ = {
|
||||
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
|
||||
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
|
||||
}
|
||||
|
||||
data_dir = DATA_PATH / "word_bank"
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
add_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)
|
||||
|
||||
|
||||
@add_word.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = str(arg)
|
||||
r = re.search(r"问(.+)\s?答([\s\S]*)", msg)
|
||||
if not r:
|
||||
await add_word.finish("未检测到词条问题...")
|
||||
problem = r.group(1).strip()
|
||||
if not problem:
|
||||
await add_word.finish("未检测到词条问题...")
|
||||
answer = msg.split("答", maxsplit=1)[-1]
|
||||
if not answer:
|
||||
await add_word.finish("未检测到词条回答...")
|
||||
idx = 0
|
||||
_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"已保存词条 问:{_builder.problem} 答:{answer}")
|
||||
await add_word.send("已保存词条:" + _builder.problem)
|
||||
else:
|
||||
await delete_word.send("保存失败,可能是回答重复")
|
||||
|
||||
|
||||
@delete_word.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = str(arg)
|
||||
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:
|
||||
_problem, problem = await get_one_problem(event, problem)
|
||||
if answer := await WordBank.delete_problem_answer(
|
||||
event.user_id, event.group_id, _problem, index
|
||||
):
|
||||
|
||||
await delete_word.send(Message(
|
||||
"删除词条成功:\n问" + await replace_cq(event.group_id, problem, False) + f"\n回答:\n" + await replace_cq(
|
||||
event.group_id, answer, False) + "\n"))
|
||||
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("删除词条:" + problem + "失败,可能该词条不存在")
|
||||
except IndexError:
|
||||
await delete_word.send("指定下标错误...请通过查看词条来确定..")
|
||||
|
||||
|
||||
@update_word.handle()
|
||||
async def _(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
|
||||
_problem = problem
|
||||
_builder = await get__builder(event, _problem, new_answer, idx)
|
||||
|
||||
try:
|
||||
if await _builder.update(index):
|
||||
await update_word.send(f"修改词条成功:" + _builder.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"修改词条:" + _builder.problem + f"失败,可能该词条不存在")
|
||||
except IndexError:
|
||||
await update_word.send("指定下标错误...请通过查看词条来确定..")
|
||||
|
||||
|
||||
@show_word.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = str(arg).strip()
|
||||
if not msg:
|
||||
_problem_list = await WordBank.get_group_all_problem(event.group_id)
|
||||
if not _problem_list:
|
||||
await show_word.finish("该群未收录任replace_cq何词条..")
|
||||
_problem_list = [f"\t{i}. {await replace_cq(event.group_id, 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 = []
|
||||
if msg.startswith("id:"):
|
||||
x = msg.split(":")[-1]
|
||||
if not is_number(x) or int(x) < 0:
|
||||
return await delete_word.finish("id必须为数字且符合规范!")
|
||||
p = await WordBank.get_group_all_problem(event.group_id)
|
||||
if p:
|
||||
_problem = p[int(x)]
|
||||
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
|
||||
msg += '问' + await get_one_image_problem(event, _problem)
|
||||
else:
|
||||
_problem, msg = await get_one_problem(event, msg)
|
||||
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
|
||||
if not _answer_list:
|
||||
await show_word.send("未收录该词条...")
|
||||
|
||||
else:
|
||||
# 解析图片和@
|
||||
_answer_img_nu_list = [await get_one_answer(event, format, answer, False) for answer, format in
|
||||
_answer_list]
|
||||
word_nu = len(_answer_img_nu_list)
|
||||
img_nu = 0
|
||||
answer = "词条" + msg + "\n回答:"
|
||||
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: str, answer: str, idx: int):
|
||||
(data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True)
|
||||
(data_dir / f"{event.group_id}" / "problem").mkdir(exist_ok=True, parents=True)
|
||||
_builder = WordBankBuilder(event.user_id, event.group_id, _problem)
|
||||
problem = ''
|
||||
_p = _problem
|
||||
for at_ in get_message_at(event.json()):
|
||||
r = re.search(rf"\[CQ:at,qq={at_}]", answer)
|
||||
if r:
|
||||
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
|
||||
_builder.set_placeholder(idx, at_)
|
||||
idx += 1
|
||||
r_problem = re.search(rf"\[CQ:at,qq={at_}]", _problem)
|
||||
if r_problem:
|
||||
q = await GroupInfoUser.get_member_info(
|
||||
int(at_), event.group_id)
|
||||
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
|
||||
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
|
||||
for img in get_message_img(event.json()):
|
||||
_x = img.split("?")[0]
|
||||
_x_list = img.split("?")
|
||||
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
|
||||
if r:
|
||||
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
||||
for _ in range(10):
|
||||
if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"):
|
||||
break
|
||||
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
||||
strinfo = re.compile(f"\[CQ:image,file={r.group(1)},.*url={_x_list[0]}\?{_x_list[1]}.*?]")
|
||||
answer = strinfo.sub(f"[__placeholder_{idx}]", answer)
|
||||
await AsyncHttpx.download_file(
|
||||
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
|
||||
)
|
||||
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
|
||||
idx += 1
|
||||
r_problem = re.search(rf"\[CQ:image,file=(.*?)(,subType=\d)?,url={_x}.*?]", _p)
|
||||
if r_problem:
|
||||
strinfo = re.compile(f"(,subType=\d)?,url={_x_list[0]}\?{_x_list[1]}.*?]")
|
||||
_problem = strinfo.sub(f"]", _problem)
|
||||
_p = strinfo.sub(f"]", _p)
|
||||
problem += _p[: _p.find(f"[CQ:image,file={r_problem.group(1)}]")] + image(img)
|
||||
_p = _p[_p.find(f"[CQ:image,file={r_problem.group(1)}]") + len(f"[CQ:image,file={r_problem.group(1)}]"):]
|
||||
problem_img = r_problem.group(1)
|
||||
if f"{problem_img}.jpg" not in os.listdir(data_dir / f"{event.group_id}" / f"problem"):
|
||||
await AsyncHttpx.download_file(
|
||||
img, data_dir / f"{event.group_id}" / f"problem" / f"{problem_img}.jpg"
|
||||
)
|
||||
_builder.set_answer(answer)
|
||||
_builder.set_problem(_problem)
|
||||
_builder.problem = problem + _p
|
||||
return _builder
|
||||
Reference in New Issue
Block a user