mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 06:12:53 +08:00
🎨代码优化
This commit is contained in:
parent
f70b07e5a3
commit
61ab7ef3d3
@ -1,9 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
from pathlib import Path
|
import subprocess
|
||||||
|
|
||||||
from nonebot.adapters import Bot
|
from nonebot.adapters import Bot
|
||||||
from nonebot.utils import run_sync
|
from nonebot.utils import run_sync
|
||||||
@ -13,24 +12,28 @@ from zhenxun.utils.http_utils import AsyncHttpx
|
|||||||
from zhenxun.utils.platform import PlatformUtils
|
from zhenxun.utils.platform import PlatformUtils
|
||||||
|
|
||||||
from .config import (
|
from .config import (
|
||||||
BACKUP_PATH,
|
|
||||||
BASE_PATH,
|
|
||||||
DEV_URL,
|
DEV_URL,
|
||||||
|
MAIN_URL,
|
||||||
|
TMP_PATH,
|
||||||
|
BASE_PATH,
|
||||||
|
BACKUP_PATH,
|
||||||
|
RELEASE_URL,
|
||||||
|
REQ_TXT_FILE,
|
||||||
|
VERSION_FILE,
|
||||||
|
PYPROJECT_FILE,
|
||||||
|
REPLACE_FOLDERS,
|
||||||
|
BASE_PATH_STRING,
|
||||||
DOWNLOAD_GZ_FILE,
|
DOWNLOAD_GZ_FILE,
|
||||||
DOWNLOAD_ZIP_FILE,
|
DOWNLOAD_ZIP_FILE,
|
||||||
MAIN_URL,
|
|
||||||
PYPROJECT_FILE,
|
|
||||||
PYPROJECT_LOCK_FILE,
|
PYPROJECT_LOCK_FILE,
|
||||||
RELEASE_URL,
|
REQ_TXT_FILE_STRING,
|
||||||
REPLACE_FOLDERS,
|
PYPROJECT_FILE_STRING,
|
||||||
REQ_TXT_FILE,
|
PYPROJECT_LOCK_FILE_STRING,
|
||||||
TMP_PATH,
|
|
||||||
VERSION_FILE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_requirement():
|
def install_requirement():
|
||||||
requirement_path = (Path() / "requirements.txt").absolute()
|
requirement_path = (REQ_TXT_FILE).absolute()
|
||||||
|
|
||||||
if not requirement_path.exists():
|
if not requirement_path.exists():
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@ -41,8 +44,7 @@ def install_requirement():
|
|||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["pip", "install", "-r", str(requirement_path)],
|
["pip", "install", "-r", str(requirement_path)],
|
||||||
check=True,
|
check=True,
|
||||||
stdout=subprocess.PIPE,
|
capture_output=True,
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", "插件管理")
|
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", "插件管理")
|
||||||
@ -67,32 +69,32 @@ def _file_handle(latest_version: str | None):
|
|||||||
tf = zipfile.ZipFile(DOWNLOAD_ZIP_FILE)
|
tf = zipfile.ZipFile(DOWNLOAD_ZIP_FILE)
|
||||||
tf.extractall(TMP_PATH)
|
tf.extractall(TMP_PATH)
|
||||||
logger.debug("解压文件压缩包完成...", "检查更新")
|
logger.debug("解压文件压缩包完成...", "检查更新")
|
||||||
download_file_path = (
|
download_file_path = TMP_PATH / next(
|
||||||
TMP_PATH / [x for x in os.listdir(TMP_PATH) if (TMP_PATH / x).is_dir()][0]
|
x for x in os.listdir(TMP_PATH) if (TMP_PATH / x).is_dir()
|
||||||
)
|
)
|
||||||
_pyproject = download_file_path / "pyproject.toml"
|
_pyproject = download_file_path / PYPROJECT_FILE_STRING
|
||||||
_lock_file = download_file_path / "poetry.lock"
|
_lock_file = download_file_path / PYPROJECT_LOCK_FILE_STRING
|
||||||
_req_file = download_file_path / "requirements.txt"
|
_req_file = download_file_path / REQ_TXT_FILE_STRING
|
||||||
extract_path = download_file_path / "zhenxun"
|
extract_path = download_file_path / BASE_PATH_STRING
|
||||||
target_path = BASE_PATH
|
target_path = BASE_PATH
|
||||||
if PYPROJECT_FILE.exists():
|
if PYPROJECT_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", "检查更新")
|
||||||
shutil.move(PYPROJECT_FILE, BACKUP_PATH / "pyproject.toml")
|
shutil.move(PYPROJECT_FILE, BACKUP_PATH / PYPROJECT_FILE_STRING)
|
||||||
if PYPROJECT_LOCK_FILE.exists():
|
if PYPROJECT_LOCK_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", "检查更新")
|
||||||
shutil.move(PYPROJECT_LOCK_FILE, BACKUP_PATH / "poetry.lock")
|
shutil.move(PYPROJECT_LOCK_FILE, BACKUP_PATH / PYPROJECT_LOCK_FILE_STRING)
|
||||||
if REQ_TXT_FILE.exists():
|
if REQ_TXT_FILE.exists():
|
||||||
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", "检查更新")
|
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", "检查更新")
|
||||||
shutil.move(REQ_TXT_FILE, BACKUP_PATH / "requirements.txt")
|
shutil.move(REQ_TXT_FILE, BACKUP_PATH / REQ_TXT_FILE_STRING)
|
||||||
if _pyproject.exists():
|
if _pyproject.exists():
|
||||||
logger.debug("移动文件: pyproject.toml", "检查更新")
|
logger.debug("移动文件: pyproject.toml", "检查更新")
|
||||||
shutil.move(_pyproject, Path() / "pyproject.toml")
|
shutil.move(_pyproject, PYPROJECT_FILE)
|
||||||
if _lock_file.exists():
|
if _lock_file.exists():
|
||||||
logger.debug("移动文件: poetry.lock", "检查更新")
|
logger.debug("移动文件: poetry.lock", "检查更新")
|
||||||
shutil.move(_lock_file, Path() / "poetry.lock")
|
shutil.move(_lock_file, PYPROJECT_LOCK_FILE)
|
||||||
if _req_file.exists():
|
if _req_file.exists():
|
||||||
logger.debug("移动文件: requirements.txt", "检查更新")
|
logger.debug("移动文件: requirements.txt", "检查更新")
|
||||||
shutil.move(_req_file, Path() / "requirements.txt")
|
shutil.move(_req_file, REQ_TXT_FILE)
|
||||||
for folder in REPLACE_FOLDERS:
|
for folder in REPLACE_FOLDERS:
|
||||||
"""移动指定文件夹"""
|
"""移动指定文件夹"""
|
||||||
_dir = BASE_PATH / folder
|
_dir = BASE_PATH / folder
|
||||||
@ -132,7 +134,6 @@ def _file_handle(latest_version: str | None):
|
|||||||
|
|
||||||
|
|
||||||
class UpdateManage:
|
class UpdateManage:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_version(cls) -> str:
|
async def check_version(cls) -> str:
|
||||||
"""检查更新版本
|
"""检查更新版本
|
||||||
@ -144,7 +145,13 @@ class UpdateManage:
|
|||||||
data = await cls.__get_latest_data()
|
data = await cls.__get_latest_data()
|
||||||
if not data:
|
if not data:
|
||||||
return "检查更新获取版本失败..."
|
return "检查更新获取版本失败..."
|
||||||
return f"检测到当前版本更新\n当前版本:{cur_version}\n最新版本:{data.get('name')}\n创建日期:{data.get('created_at')}\n更新内容:\n{data.get('body')}"
|
return (
|
||||||
|
"检测到当前版本更新\n"
|
||||||
|
f"当前版本:{cur_version}\n"
|
||||||
|
f"最新版本:{data.get('name')}\n"
|
||||||
|
f"创建日期:{data.get('created_at')}\n"
|
||||||
|
f"更新内容:\n{data.get('body')}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update(cls, bot: Bot, user_id: str, version_type: str) -> str | None:
|
async def update(cls, bot: Bot, user_id: str, version_type: str) -> str | None:
|
||||||
@ -158,8 +165,10 @@ class UpdateManage:
|
|||||||
返回:
|
返回:
|
||||||
str | None: 返回消息
|
str | None: 返回消息
|
||||||
"""
|
"""
|
||||||
logger.info(f"开始下载真寻最新版文件....", "检查更新")
|
logger.info("开始下载真寻最新版文件....", "检查更新")
|
||||||
cur_version = cls.__get_version()
|
cur_version = cls.__get_version()
|
||||||
|
url = None
|
||||||
|
new_version = None
|
||||||
if version_type == "dev":
|
if version_type == "dev":
|
||||||
url = DEV_URL
|
url = DEV_URL
|
||||||
new_version = await cls.__get_version_from_branch("dev")
|
new_version = await cls.__get_version_from_branch("dev")
|
||||||
@ -197,7 +206,11 @@ class UpdateManage:
|
|||||||
if await AsyncHttpx.download_file(url, download_file):
|
if await AsyncHttpx.download_file(url, download_file):
|
||||||
logger.debug("下载真寻最新版文件完成...", "检查更新")
|
logger.debug("下载真寻最新版文件完成...", "检查更新")
|
||||||
await _file_handle(new_version)
|
await _file_handle(new_version)
|
||||||
return f"版本更新完成\n版本: {cur_version} -> {new_version}\n请重新启动真寻以完成更新!"
|
return (
|
||||||
|
f"版本更新完成\n"
|
||||||
|
f"版本: {cur_version} -> {new_version}\n"
|
||||||
|
"请重新启动真寻以完成更新!"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
logger.debug("下载真寻最新版文件失败...", "检查更新")
|
logger.debug("下载真寻最新版文件失败...", "检查更新")
|
||||||
return None
|
return None
|
||||||
@ -211,8 +224,7 @@ class UpdateManage:
|
|||||||
"""
|
"""
|
||||||
_version = "v0.0.0"
|
_version = "v0.0.0"
|
||||||
if VERSION_FILE.exists():
|
if VERSION_FILE.exists():
|
||||||
text = VERSION_FILE.open(encoding="utf8").readline()
|
if text := VERSION_FILE.open(encoding="utf8").readline():
|
||||||
if text:
|
|
||||||
_version = text.split(":")[-1].strip()
|
_version = text.split(":")[-1].strip()
|
||||||
return _version
|
return _version
|
||||||
|
|
||||||
@ -231,7 +243,7 @@ class UpdateManage:
|
|||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"检查更新真寻获取版本失败", e=e)
|
logger.error("检查更新真寻获取版本失败", e=e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -6,14 +6,18 @@ DEV_URL = "https://ghproxy.cc/https://github.com/HibiKier/zhenxun_bot/archive/re
|
|||||||
MAIN_URL = "https://ghproxy.cc/https://github.com/HibiKier/zhenxun_bot/archive/refs/heads/main.zip"
|
MAIN_URL = "https://ghproxy.cc/https://github.com/HibiKier/zhenxun_bot/archive/refs/heads/main.zip"
|
||||||
RELEASE_URL = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest"
|
RELEASE_URL = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest"
|
||||||
|
|
||||||
|
VERSION_FILE_STRING = "__version__"
|
||||||
|
VERSION_FILE = Path() / VERSION_FILE_STRING
|
||||||
|
|
||||||
VERSION_FILE = Path() / "__version__"
|
PYPROJECT_FILE_STRING = "pyproject.toml"
|
||||||
|
PYPROJECT_FILE = Path() / PYPROJECT_FILE_STRING
|
||||||
|
PYPROJECT_LOCK_FILE_STRING = "poetry.lock"
|
||||||
|
PYPROJECT_LOCK_FILE = Path() / PYPROJECT_LOCK_FILE_STRING
|
||||||
|
REQ_TXT_FILE_STRING = "requirements.txt"
|
||||||
|
REQ_TXT_FILE = Path() / REQ_TXT_FILE_STRING
|
||||||
|
|
||||||
PYPROJECT_FILE = Path() / "pyproject.toml"
|
BASE_PATH_STRING = "zhenxun"
|
||||||
PYPROJECT_LOCK_FILE = Path() / "poetry.lock"
|
BASE_PATH = Path() / BASE_PATH_STRING
|
||||||
REQ_TXT_FILE = Path() / "requirements.txt"
|
|
||||||
|
|
||||||
BASE_PATH = Path() / "zhenxun"
|
|
||||||
|
|
||||||
TMP_PATH = TEMP_PATH / "auto_update"
|
TMP_PATH = TEMP_PATH / "auto_update"
|
||||||
|
|
||||||
|
|||||||
@ -2,26 +2,26 @@ import asyncio
|
|||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
from fastapi import APIRouter, FastAPI
|
from fastapi import FastAPI, APIRouter
|
||||||
from nonebot.log import default_filter, default_format
|
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot.log import default_filter, default_format
|
||||||
|
|
||||||
from zhenxun.configs.config import Config as gConfig
|
|
||||||
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
|
|
||||||
from zhenxun.services.log import logger, logger_
|
|
||||||
from zhenxun.utils.enum import PluginType
|
from zhenxun.utils.enum import PluginType
|
||||||
|
from zhenxun.services.log import logger, logger_
|
||||||
|
from zhenxun.configs.config import Config as gConfig
|
||||||
|
from zhenxun.configs.utils import RegisterConfig, PluginExtraData
|
||||||
|
|
||||||
|
from .public import init_public
|
||||||
|
from .auth import router as auth_router
|
||||||
from .api.logs import router as ws_log_routes
|
from .api.logs import router as ws_log_routes
|
||||||
from .api.logs.log_manager import LOG_STORAGE
|
from .api.logs.log_manager import LOG_STORAGE
|
||||||
from .api.tabs.database import router as database_router
|
|
||||||
from .api.tabs.main import router as main_router
|
from .api.tabs.main import router as main_router
|
||||||
from .api.tabs.main import ws_router as status_routes
|
|
||||||
from .api.tabs.manage import router as manage_router
|
from .api.tabs.manage import router as manage_router
|
||||||
|
from .api.tabs.system import router as system_router
|
||||||
|
from .api.tabs.main import ws_router as status_routes
|
||||||
|
from .api.tabs.database import router as database_router
|
||||||
from .api.tabs.manage.chat import ws_router as chat_routes
|
from .api.tabs.manage.chat import ws_router as chat_routes
|
||||||
from .api.tabs.plugin_manage import router as plugin_router
|
from .api.tabs.plugin_manage import router as plugin_router
|
||||||
from .api.tabs.system import router as system_router
|
|
||||||
from .auth import router as auth_router
|
|
||||||
from .public import init_public
|
|
||||||
|
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
name="WebUi",
|
name="WebUi",
|
||||||
@ -32,7 +32,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.HIDDEN,
|
||||||
Configs=[
|
configs=[
|
||||||
RegisterConfig(
|
RegisterConfig(
|
||||||
module="web-ui",
|
module="web-ui",
|
||||||
key="username",
|
key="username",
|
||||||
@ -57,7 +57,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
type=str,
|
type=str,
|
||||||
default_value=None,
|
default_value=None,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ async def _():
|
|||||||
logger.warning("Web Ui log_sink", e=e)
|
logger.warning("Web Ui log_sink", e=e)
|
||||||
if not loop:
|
if not loop:
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
loop.create_task(LOG_STORAGE.add(message.rstrip("\n")))
|
loop.create_task(LOG_STORAGE.add(message.rstrip("\n"))) # noqa: RUF006
|
||||||
|
|
||||||
logger_.add(
|
logger_.add(
|
||||||
log_sink, colorize=True, filter=default_filter, format=default_format
|
log_sink, colorize=True, filter=default_filter, format=default_format
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
from nonebot_plugin_alconna import At
|
from nonebot_plugin_alconna import At
|
||||||
from nonebot_plugin_alconna import At as alcAt
|
|
||||||
from nonebot_plugin_alconna import Image
|
from nonebot_plugin_alconna import Image
|
||||||
from nonebot_plugin_alconna import Image as alcImage
|
from nonebot_plugin_alconna import At as alcAt
|
||||||
from nonebot_plugin_alconna import Text as alcText
|
from nonebot_plugin_alconna import Text as alcText
|
||||||
from nonebot_plugin_alconna import UniMessage, UniMsg
|
from nonebot_plugin_alconna import Image as alcImage
|
||||||
|
from nonebot_plugin_alconna import UniMsg, UniMessage
|
||||||
|
|
||||||
from zhenxun.plugins.word_bank._config import ScopeType
|
|
||||||
from zhenxun.utils.image_utils import ImageTemplate
|
|
||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
from zhenxun.utils.image_utils import ImageTemplate
|
||||||
|
from zhenxun.plugins.word_bank._config import ScopeType
|
||||||
|
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
|
|
||||||
@ -42,9 +42,9 @@ def get_problem(message: UniMsg) -> str:
|
|||||||
problem = ""
|
problem = ""
|
||||||
a, b = True, True
|
a, b = True, True
|
||||||
for msg in message:
|
for msg in message:
|
||||||
if isinstance(msg, alcText) or isinstance(msg, str):
|
if isinstance(msg, alcText | str):
|
||||||
msg = str(msg)
|
msg = str(msg)
|
||||||
if "问" in str(msg) and a:
|
if "问" in msg and a:
|
||||||
a = False
|
a = False
|
||||||
split_text = msg.split("问")
|
split_text = msg.split("问")
|
||||||
if len(split_text) > 1:
|
if len(split_text) > 1:
|
||||||
@ -53,7 +53,7 @@ def get_problem(message: UniMsg) -> str:
|
|||||||
if "答" in problem:
|
if "答" in problem:
|
||||||
b = False
|
b = False
|
||||||
problem = problem.split("答")[0]
|
problem = problem.split("答")[0]
|
||||||
elif "答" in msg and b:
|
elif "答" in msg:
|
||||||
b = False
|
b = False
|
||||||
# problem += "答".join(msg.split("答")[:-1])
|
# problem += "答".join(msg.split("答")[:-1])
|
||||||
problem += msg.split("答")[0]
|
problem += msg.split("答")[0]
|
||||||
@ -78,7 +78,7 @@ def get_answer(message: UniMsg) -> UniMessage | None:
|
|||||||
index = 0
|
index = 0
|
||||||
for msg in message:
|
for msg in message:
|
||||||
index += 1
|
index += 1
|
||||||
if isinstance(msg, alcText) or isinstance(msg, str):
|
if isinstance(msg, alcText | str):
|
||||||
msg = str(msg)
|
msg = str(msg)
|
||||||
if "答" in msg:
|
if "答" in msg:
|
||||||
answer += "答".join(msg.split("答")[1:])
|
answer += "答".join(msg.split("答")[1:])
|
||||||
@ -90,7 +90,6 @@ def get_answer(message: UniMsg) -> UniMessage | None:
|
|||||||
|
|
||||||
|
|
||||||
class WordBankManage:
|
class WordBankManage:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_word(
|
async def update_word(
|
||||||
cls,
|
cls,
|
||||||
@ -175,10 +174,14 @@ class WordBankManage:
|
|||||||
)
|
)
|
||||||
if not _problem_list:
|
if not _problem_list:
|
||||||
return problem, ""
|
return problem, ""
|
||||||
if await WordBank.delete_group_problem(problem, group_id, aid, word_scope): # type: ignore
|
return (
|
||||||
return "删除词条成功!", ""
|
("删除词条成功!", "")
|
||||||
return "词条不存在", ""
|
if await WordBank.delete_group_problem(
|
||||||
if handle_type == "update":
|
problem, group_id, aid, word_scope
|
||||||
|
)
|
||||||
|
else ("词条不存在", "")
|
||||||
|
)
|
||||||
|
elif handle_type == "update":
|
||||||
old_problem = await WordBank.update_group_problem(
|
old_problem = await WordBank.update_group_problem(
|
||||||
problem, replace_problem, group_id, word_scope=word_scope
|
problem, replace_problem, group_id, word_scope=word_scope
|
||||||
)
|
)
|
||||||
@ -187,7 +190,10 @@ class WordBankManage:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def __get_problem_str(
|
async def __get_problem_str(
|
||||||
cls, idx: int, group_id: str | None = None, word_scope: ScopeType = ScopeType.GROUP
|
cls,
|
||||||
|
idx: int,
|
||||||
|
group_id: str | None = None,
|
||||||
|
word_scope: ScopeType = ScopeType.GROUP,
|
||||||
) -> tuple[str, int]:
|
) -> tuple[str, int]:
|
||||||
"""通过id获取问题字符串
|
"""通过id获取问题字符串
|
||||||
|
|
||||||
@ -222,7 +228,7 @@ class WordBankManage:
|
|||||||
word_scope: 词条范围
|
word_scope: 词条范围
|
||||||
index: 指定回答下标
|
index: 指定回答下标
|
||||||
"""
|
"""
|
||||||
if problem or index != None:
|
if problem or index is not None:
|
||||||
msg_list = []
|
msg_list = []
|
||||||
problem, _problem_list = await WordBank.get_problem_all_answer(
|
problem, _problem_list = await WordBank.get_problem_all_answer(
|
||||||
problem, # type: ignore
|
problem, # type: ignore
|
||||||
|
|||||||
@ -1,31 +1,29 @@
|
|||||||
import random
|
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
import random
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from datetime import datetime
|
||||||
from nonebot_plugin_alconna import At as alcAt
|
|
||||||
from nonebot_plugin_alconna import Image as alcImage
|
|
||||||
from nonebot_plugin_alconna import Text as alcText
|
|
||||||
from nonebot_plugin_alconna import UniMessage
|
|
||||||
from tortoise import Tortoise, fields
|
|
||||||
from tortoise.expressions import Q
|
|
||||||
from typing_extensions import Self
|
from typing_extensions import Self
|
||||||
|
|
||||||
from zhenxun.configs.path_config import DATA_PATH
|
from tortoise.expressions import Q
|
||||||
from zhenxun.services.db_context import Model
|
from tortoise import Tortoise, fields
|
||||||
from zhenxun.utils.http_utils import AsyncHttpx
|
from nonebot_plugin_alconna import UniMessage
|
||||||
from zhenxun.utils.image_utils import get_img_hash
|
from nonebot_plugin_alconna import At as alcAt
|
||||||
from zhenxun.utils.message import MessageUtils
|
from nonebot_plugin_alconna import Text as alcText
|
||||||
|
from nonebot_plugin_alconna import Image as alcImage
|
||||||
|
|
||||||
from ._config import ScopeType, WordType, int2type
|
from zhenxun.services.db_context import Model
|
||||||
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
from zhenxun.utils.http_utils import AsyncHttpx
|
||||||
|
from zhenxun.configs.path_config import DATA_PATH
|
||||||
|
from zhenxun.utils.image_utils import get_img_hash
|
||||||
|
|
||||||
|
from ._config import WordType, ScopeType, int2type
|
||||||
|
|
||||||
path = DATA_PATH / "word_bank"
|
path = DATA_PATH / "word_bank"
|
||||||
|
|
||||||
|
|
||||||
class WordBank(Model):
|
class WordBank(Model):
|
||||||
|
|
||||||
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||||
"""自增id"""
|
"""自增id"""
|
||||||
user_id = fields.CharField(255)
|
user_id = fields.CharField(255)
|
||||||
@ -57,12 +55,12 @@ class WordBank(Model):
|
|||||||
author = fields.CharField(255, null=True, default="")
|
author = fields.CharField(255, null=True, default="")
|
||||||
"""收录人"""
|
"""收录人"""
|
||||||
|
|
||||||
class Meta:
|
class Meta: # type: ignore
|
||||||
table = "word_bank2"
|
table = "word_bank2"
|
||||||
table_description = "词条数据库"
|
table_description = "词条数据库"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def exists(
|
async def exists( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
user_id: str | None,
|
user_id: str | None,
|
||||||
group_id: str | None,
|
group_id: str | None,
|
||||||
@ -217,7 +215,6 @@ class WordBank(Model):
|
|||||||
user_id: 用户id
|
user_id: 用户id
|
||||||
group_id: 群组id
|
group_id: 群组id
|
||||||
"""
|
"""
|
||||||
result_list = []
|
|
||||||
if not query:
|
if not query:
|
||||||
query = await cls.get_or_none(
|
query = await cls.get_or_none(
|
||||||
problem=problem,
|
problem=problem,
|
||||||
@ -228,18 +225,19 @@ class WordBank(Model):
|
|||||||
if not answer:
|
if not answer:
|
||||||
answer = str(query.answer) # type: ignore
|
answer = str(query.answer) # type: ignore
|
||||||
if query and query.placeholder:
|
if query and query.placeholder:
|
||||||
type_list = re.findall(rf"\[(.*?):placeholder_.*?]", answer)
|
type_list = re.findall(r"\[(.*?):placeholder_.*?]", answer)
|
||||||
answer_split = re.split(rf"\[.*:placeholder_.*?]", answer)
|
answer_split = re.split(r"\[.*:placeholder_.*?]", answer)
|
||||||
placeholder_split = query.placeholder.split(",")
|
placeholder_split = query.placeholder.split(",")
|
||||||
|
result_list = []
|
||||||
for index, ans in enumerate(answer_split):
|
for index, ans in enumerate(answer_split):
|
||||||
result_list.append(ans)
|
result_list.append(ans)
|
||||||
if index < len(type_list):
|
if index < len(type_list):
|
||||||
t = type_list[index]
|
t = type_list[index]
|
||||||
p = placeholder_split[index]
|
p = placeholder_split[index]
|
||||||
if t == "image":
|
if t == "at":
|
||||||
result_list.append(path / p)
|
|
||||||
elif t == "at":
|
|
||||||
result_list.append(alcAt(flag="user", target=p))
|
result_list.append(alcAt(flag="user", target=p))
|
||||||
|
elif t == "image":
|
||||||
|
result_list.append(path / p)
|
||||||
return MessageUtils.build_message(result_list)
|
return MessageUtils.build_message(result_list)
|
||||||
return MessageUtils.build_message(answer)
|
return MessageUtils.build_message(answer)
|
||||||
|
|
||||||
@ -282,7 +280,10 @@ class WordBank(Model):
|
|||||||
return data_list
|
return data_list
|
||||||
db = Tortoise.get_connection("default")
|
db = Tortoise.get_connection("default")
|
||||||
# 模糊匹配
|
# 模糊匹配
|
||||||
sql = query.filter(word_type=1).sql() + " and POSITION(problem in $1) > 0"
|
sql = (
|
||||||
|
query.filter(word_type=WordType.FUZZY.value).sql()
|
||||||
|
+ " and POSITION(problem in $1) > 0"
|
||||||
|
)
|
||||||
data_list = await db.execute_query_dict(sql, [problem])
|
data_list = await db.execute_query_dict(sql, [problem])
|
||||||
if data_list:
|
if data_list:
|
||||||
return [cls(**data) for data in data_list]
|
return [cls(**data) for data in data_list]
|
||||||
@ -292,9 +293,7 @@ class WordBank(Model):
|
|||||||
+ " and $1 ~ problem;"
|
+ " and $1 ~ problem;"
|
||||||
)
|
)
|
||||||
data_list = await db.execute_query_dict(sql, [problem])
|
data_list = await db.execute_query_dict(sql, [problem])
|
||||||
if data_list:
|
return [cls(**data) for data in data_list] if data_list else None
|
||||||
return [cls(**data) for data in data_list]
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_answer(
|
async def get_answer(
|
||||||
@ -318,7 +317,7 @@ class WordBank(Model):
|
|||||||
random_answer = random.choice(data_list)
|
random_answer = random.choice(data_list)
|
||||||
if random_answer.word_type == WordType.REGEX:
|
if random_answer.word_type == WordType.REGEX:
|
||||||
r = re.search(random_answer.problem, problem)
|
r = re.search(random_answer.problem, problem)
|
||||||
has_placeholder = re.search(rf"\$(\d)", random_answer.answer)
|
has_placeholder = re.search(r"\$(\d)", random_answer.answer)
|
||||||
if r and r.groups() and has_placeholder:
|
if r and r.groups() and has_placeholder:
|
||||||
pats = re.sub(r"\$(\d)", r"\\\1", random_answer.answer)
|
pats = re.sub(r"\$(\d)", r"\\\1", random_answer.answer)
|
||||||
random_answer.answer = re.sub(random_answer.problem, pats, problem)
|
random_answer.answer = re.sub(random_answer.problem, pats, problem)
|
||||||
@ -575,9 +574,16 @@ class WordBank(Model):
|
|||||||
async def _run_script(cls):
|
async def _run_script(cls):
|
||||||
return [
|
return [
|
||||||
"ALTER TABLE word_bank2 ADD to_me varchar(255);", # 添加 to_me 字段
|
"ALTER TABLE word_bank2 ADD to_me varchar(255);", # 添加 to_me 字段
|
||||||
"ALTER TABLE word_bank2 ALTER COLUMN create_time TYPE timestamp with time zone USING create_time::timestamp with time zone;",
|
(
|
||||||
"ALTER TABLE word_bank2 ALTER COLUMN update_time TYPE timestamp with time zone USING update_time::timestamp with time zone;",
|
"ALTER TABLE word_bank2 ALTER COLUMN create_time TYPE timestamp"
|
||||||
"ALTER TABLE word_bank2 RENAME COLUMN user_qq TO user_id;", # 将user_qq改为user_id
|
" with time zone USING create_time::timestamp with time zone;"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ALTER TABLE word_bank2 ALTER COLUMN update_time TYPE timestamp"
|
||||||
|
" with time zone USING update_time::timestamp with time zone;"
|
||||||
|
),
|
||||||
|
"ALTER TABLE word_bank2 RENAME COLUMN user_qq TO user_id;",
|
||||||
|
# 将user_qq改为user_id
|
||||||
"ALTER TABLE word_bank2 ALTER COLUMN user_id TYPE character varying(255);",
|
"ALTER TABLE word_bank2 ALTER COLUMN user_id TYPE character varying(255);",
|
||||||
"ALTER TABLE word_bank2 ALTER COLUMN group_id TYPE character varying(255);",
|
"ALTER TABLE word_bank2 ALTER COLUMN group_id TYPE character varying(255);",
|
||||||
"ALTER TABLE word_bank2 ADD platform varchar(255) DEFAULT 'qq';",
|
"ALTER TABLE word_bank2 ADD platform varchar(255) DEFAULT 'qq';",
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import imagehash
|
import imagehash
|
||||||
from nonebot.adapters import Bot, Event
|
|
||||||
from nonebot.typing import T_State
|
|
||||||
from nonebot_plugin_alconna import At as alcAt
|
|
||||||
from nonebot_plugin_alconna import Text as alcText
|
|
||||||
from nonebot_plugin_alconna import UniMsg
|
|
||||||
from nonebot_plugin_session import EventSession
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from nonebot.adapters import Bot, Event
|
||||||
|
from nonebot_plugin_alconna import UniMsg
|
||||||
|
from nonebot_plugin_alconna import At as alcAt
|
||||||
|
from nonebot_plugin_session import EventSession
|
||||||
|
from nonebot_plugin_alconna import Text as alcText
|
||||||
|
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
from zhenxun.utils.http_utils import AsyncHttpx
|
from zhenxun.utils.http_utils import AsyncHttpx
|
||||||
|
|
||||||
from ._data_source import get_img_and_at_list
|
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
|
from ._data_source import get_img_and_at_list
|
||||||
|
|
||||||
|
|
||||||
async def check(
|
async def check(
|
||||||
@ -31,7 +31,7 @@ async def check(
|
|||||||
r = await AsyncHttpx.get(img_list[0])
|
r = await AsyncHttpx.get(img_list[0])
|
||||||
problem = str(imagehash.average_hash(Image.open(BytesIO(r.content))))
|
problem = str(imagehash.average_hash(Image.open(BytesIO(r.content))))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"获取图片失败", "词条检测", session=session, e=e)
|
logger.warning("获取图片失败", "词条检测", session=session, e=e)
|
||||||
if at_list:
|
if at_list:
|
||||||
temp = ""
|
temp = ""
|
||||||
# TODO: 支持更多消息类型
|
# TODO: 支持更多消息类型
|
||||||
|
|||||||
@ -2,27 +2,26 @@ import re
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from nonebot.adapters import Bot
|
from nonebot.adapters import Bot
|
||||||
from nonebot.adapters.onebot.v11 import unescape
|
from nonebot.typing import T_State
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
from nonebot_plugin_alconna import Image
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
from nonebot.exception import FinishedException
|
from nonebot.exception import FinishedException
|
||||||
from nonebot.internal.params import Arg, ArgStr
|
from nonebot.internal.params import Arg, ArgStr
|
||||||
from nonebot.params import RegexGroup
|
|
||||||
from nonebot.plugin import PluginMetadata
|
|
||||||
from nonebot.typing import T_State
|
|
||||||
from nonebot_plugin_alconna import AlconnaQuery, Arparma
|
|
||||||
from nonebot_plugin_alconna import Image
|
|
||||||
from nonebot_plugin_alconna import Image as alcImage
|
|
||||||
from nonebot_plugin_alconna import Match, Query, UniMsg
|
|
||||||
from nonebot_plugin_session import EventSession
|
from nonebot_plugin_session import EventSession
|
||||||
|
from nonebot.adapters.onebot.v11 import unescape
|
||||||
|
from nonebot_plugin_alconna import Image as alcImage
|
||||||
|
from nonebot_plugin_alconna import Match, Query, UniMsg, Arparma, AlconnaQuery
|
||||||
|
|
||||||
from zhenxun.configs.config import Config
|
|
||||||
from zhenxun.configs.utils import PluginExtraData
|
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
|
from zhenxun.configs.config import Config
|
||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
|
||||||
from ._config import ScopeType, WordType, scope2int, type2int
|
|
||||||
from ._data_source import WordBankManage, get_answer, get_img_and_at_list, get_problem
|
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
|
from ._config import WordType, ScopeType, type2int, scope2int
|
||||||
from .command import _add_matcher, _del_matcher, _show_matcher, _update_matcher
|
from .command import _add_matcher, _del_matcher, _show_matcher, _update_matcher
|
||||||
|
from ._data_source import WordBankManage, get_answer, get_problem, get_img_and_at_list
|
||||||
|
|
||||||
base_config = Config.get("word_bank")
|
base_config = Config.get("word_bank")
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ base_config = Config.get("word_bank")
|
|||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
name="词库问答",
|
name="词库问答",
|
||||||
description="自定义词条内容随机回复",
|
description="自定义词条内容随机回复",
|
||||||
usage="""
|
usage=r"""
|
||||||
usage:
|
usage:
|
||||||
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
||||||
删除词条后每个词条的id可能会变化,请查看后再删除
|
删除词条后每个词条的id可能会变化,请查看后再删除
|
||||||
@ -63,11 +62,11 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
查看词条 --id 2 : 查看词条序号为2的全部回答
|
查看词条 --id 2 : 查看词条序号为2的全部回答
|
||||||
查看词条 谁是萝莉 --all: 查看全局词条 谁是萝莉 的全部回答
|
查看词条 谁是萝莉 --all: 查看全局词条 谁是萝莉 的全部回答
|
||||||
查看词条 --id 2 --all: 查看全局词条序号为2的全部回答
|
查看词条 --id 2 --all: 查看全局词条序号为2的全部回答
|
||||||
""".strip(),
|
""".strip(), # noqa: E501
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier & yajiwa",
|
author="HibiKier & yajiwa",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
superuser_help="""
|
superuser_help=r"""
|
||||||
在私聊中超级用户额外设置
|
在私聊中超级用户额外设置
|
||||||
指令:
|
指令:
|
||||||
(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*\s?\S*)\s*?答\s?(\S*):添加问答词条,可重复添加相同问题的不同回答
|
(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*\s?\S*)\s*?答\s?(\S*):添加问答词条,可重复添加相同问题的不同回答
|
||||||
@ -149,7 +148,7 @@ async def _(
|
|||||||
group_id = session.id3 or session.id2
|
group_id = session.id3 or session.id2
|
||||||
try:
|
try:
|
||||||
if word_type == "图片":
|
if word_type == "图片":
|
||||||
problem = [m for m in message if isinstance(m, alcImage)][0].url
|
problem = next(m for m in message if isinstance(m, alcImage)).url
|
||||||
elif word_type == "正则" and problem:
|
elif word_type == "正则" and problem:
|
||||||
problem = unescape(problem)
|
problem = unescape(problem)
|
||||||
try:
|
try:
|
||||||
@ -158,7 +157,9 @@ async def _(
|
|||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
f"添加词条失败,正则表达式 {problem} 非法!"
|
f"添加词条失败,正则表达式 {problem} 非法!"
|
||||||
).finish(reply_to=True)
|
).finish(reply_to=True)
|
||||||
# if str(event.user_id) in bot.config.superusers and isinstance(event, PrivateMessageEvent):
|
# if str(event.user_id) in bot.config.superusers and isinstance(
|
||||||
|
# event, PrivateMessageEvent
|
||||||
|
# ):
|
||||||
# word_scope = "私聊"
|
# word_scope = "私聊"
|
||||||
nickname = None
|
nickname = None
|
||||||
if problem and bot.config.nickname:
|
if problem and bot.config.nickname:
|
||||||
@ -300,17 +301,15 @@ async def _(
|
|||||||
word_scope = ScopeType.GROUP if session.id3 or session.id2 else ScopeType.PRIVATE
|
word_scope = ScopeType.GROUP if session.id3 or session.id2 else ScopeType.PRIVATE
|
||||||
group_id = session.id3 or session.id2
|
group_id = session.id3 or session.id2
|
||||||
if all.result:
|
if all.result:
|
||||||
word_scope = 0
|
word_scope = ScopeType.GLOBAL
|
||||||
if gid.available:
|
if gid.available:
|
||||||
group_id = gid.result
|
group_id = gid.result
|
||||||
if problem.available:
|
if problem.available:
|
||||||
if index.available:
|
if index.available and (
|
||||||
if index.result < 0 or index.result > len(
|
index.result < 0
|
||||||
await WordBank.get_problem_by_scope(word_scope)
|
or index.result > len(await WordBank.get_problem_by_scope(word_scope))
|
||||||
):
|
):
|
||||||
await MessageUtils.build_message("id必须在范围内...").finish(
|
await MessageUtils.build_message("id必须在范围内...").finish(reply_to=True)
|
||||||
reply_to=True
|
|
||||||
)
|
|
||||||
result = await WordBankManage.show_word(
|
result = await WordBankManage.show_word(
|
||||||
problem.result,
|
problem.result,
|
||||||
index.result if index.available else None,
|
index.result if index.available else None,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user