forked from bot/app
🔥 小型重构
This commit is contained in:
parent
35823be13e
commit
8b01943d14
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,7 +15,7 @@ _config.yml
|
||||
config.yml
|
||||
config.example.yml
|
||||
compile.bat
|
||||
liteyuki/resources/templates/latest-debug.html
|
||||
src/resources/templates/latest-debug.html
|
||||
# vuepress
|
||||
.github
|
||||
pyproject.toml
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {defineClientConfig} from "vuepress/client";
|
||||
import resourceStoreComp from "./components/res_store.vue";
|
||||
import pluginStoreComp from "./components/plugin_store.vue";
|
||||
import resourceStoreComp from "./components/ResStore.vue";
|
||||
import pluginStoreComp from "./components/PluginStore.vue";
|
||||
//导入element-plus
|
||||
import ElementPlus from 'element-plus';
|
||||
|
||||
@ -9,6 +9,5 @@ export default defineClientConfig({
|
||||
app.component("resourceStoreComp", resourceStoreComp);
|
||||
app.component("pluginStoreComp", pluginStoreComp);
|
||||
app.use(ElementPlus);
|
||||
|
||||
},
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import ItemCard from './plugin_item_card.vue'
|
||||
import ItemCard from './PluginItemCard.vue'
|
||||
|
||||
// 插件商店Nonebot
|
||||
let items = ref([])
|
@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import ItemCard from './res_item_card.vue'
|
||||
import ItemCard from './ResItemCard.vue'
|
||||
|
||||
// 从public/assets/resources.json加载插件
|
||||
let items = ref([])
|
||||
fetch('https://bot.liteyuki.icu/assets/resources.json')
|
||||
fetch('/assets/resources.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
items.value = data
|
@ -10,6 +10,7 @@ export default defineUserConfig({
|
||||
description: "LiteyukiBot | 轻雪机器人 | An OneBot Standard ChatBot | 一个OneBot标准的聊天机器人",
|
||||
head: [
|
||||
// 设置 favor.ico,.vuepress/public 下
|
||||
["script", {src: "/js/style.js", "type": "module"}],
|
||||
['link', {rel: 'icon', href: 'https://cdn.liteyuki.icu/favicon.ico'},],
|
||||
|
||||
['link', {rel: 'stylesheet', href: 'https://cdn.bootcdn.net/ajax/libs/firacode/6.2.0/fira_code.min.css'}],
|
||||
|
22
docs/.vuepress/public/js/style.js
Normal file
22
docs/.vuepress/public/js/style.js
Normal file
@ -0,0 +1,22 @@
|
||||
function applyStyle() {
|
||||
let lineNumbers = document.body.querySelectorAll('[class^="language-"].line-numbers-mode')
|
||||
lineNumbers.forEach((item) => {
|
||||
// 插入现成的html文本
|
||||
let title = item.getAttribute('data-title')
|
||||
let tabStr =
|
||||
"<div class='tab' style='display: flex; background-color: #d0e9ff'>" +
|
||||
" <div class='tab-buttons'>" +
|
||||
" <div class='tab-button' style='background-color: #FF5F57'></div>" +
|
||||
" <div class='tab-button' style='background-color: #FFBD2E'></div>" +
|
||||
" <div class='tab-button' style='background-color: #27C93F'></div>" +
|
||||
" </div>" +
|
||||
` <div class='tab-title'>${title}</div>` +
|
||||
" <div style='flex: 1'></div>" +
|
||||
"</div>"
|
||||
// 在代码块前插入选项卡
|
||||
item.insertAdjacentHTML('beforebegin', tabStr);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
applyStyle()
|
@ -1,5 +1,10 @@
|
||||
// place your custom styles here
|
||||
|
||||
:root {
|
||||
--code-window-border-radius: 10px;
|
||||
--button-distance: 8px;
|
||||
}
|
||||
|
||||
#main-title {
|
||||
font-family: ColorTube, "Fira Code", serif;
|
||||
color: #ff0000 !important; /* 你想要的颜色 */
|
||||
@ -23,3 +28,54 @@ code {
|
||||
#main-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-hope-content pre {
|
||||
overflow: auto;
|
||||
margin: 0 0;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
line-height: 1.375;
|
||||
}
|
||||
// 移除该before
|
||||
.theme-hope-content pre::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.theme-hope-content > div[class*=language-] {
|
||||
margin: 0 0 0 0;
|
||||
// 仅下半部分有圆弧
|
||||
border-radius: 0 0 var(--code-window-border-radius) var(--code-window-border-radius);
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
height: 25px;
|
||||
margin-bottom: 0;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-top-left-radius: var(--code-window-border-radius);
|
||||
border-top-right-radius: var(--code-window-border-radius);
|
||||
}
|
||||
|
||||
.tab-buttons {
|
||||
padding: 7px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
height: 60%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
margin-right: var(--button-distance);
|
||||
border-radius: 50%;
|
||||
height: 100%;
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
|
||||
.tab-title{
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.11",
|
||||
"element-plus": "^2.7.0",
|
||||
"element-ui": "^2.15.14"
|
||||
"element-ui": "^2.15.14",
|
||||
"vue-router": "^4.4.0"
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ dependencies:
|
||||
element-ui:
|
||||
specifier: ^2.15.14
|
||||
version: 2.15.14(vue@3.4.21)
|
||||
vue-router:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0(vue@3.4.21)
|
||||
|
||||
devDependencies:
|
||||
'@vuepress/bundler-vite':
|
||||
@ -938,7 +941,6 @@ packages:
|
||||
|
||||
/@vue/devtools-api@6.6.1:
|
||||
resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
|
||||
dev: true
|
||||
|
||||
/@vue/reactivity@3.4.21:
|
||||
resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
|
||||
@ -985,7 +987,7 @@ packages:
|
||||
rollup: 4.13.1
|
||||
vite: 5.2.6
|
||||
vue: 3.4.21
|
||||
vue-router: 4.3.0(vue@3.4.21)
|
||||
vue-router: 4.4.0(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
@ -1021,7 +1023,7 @@ packages:
|
||||
'@vue/devtools-api': 6.6.1
|
||||
'@vuepress/shared': 2.0.0-rc.9
|
||||
vue: 3.4.21
|
||||
vue-router: 4.3.0(vue@3.4.21)
|
||||
vue-router: 4.4.0(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
dev: true
|
||||
@ -2739,14 +2741,13 @@ packages:
|
||||
dependencies:
|
||||
vue: 3.4.21
|
||||
|
||||
/vue-router@4.3.0(vue@3.4.21):
|
||||
resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
|
||||
/vue-router@4.4.0(vue@3.4.21):
|
||||
resolution: {integrity: sha512-HB+t2p611aIZraV2aPSRNXf0Z/oLZFrlygJm+sZbdJaW6lcFqEDQwnzUBXn+DApw+/QzDU/I9TeWx9izEjTmsA==}
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.1
|
||||
vue: 3.4.21
|
||||
dev: true
|
||||
|
||||
/vue@3.4.21:
|
||||
resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
|
||||
|
12
main.py
12
main.py
@ -1,8 +1,8 @@
|
||||
import nonebot
|
||||
from liteyuki.utils import adapter_manager, driver_manager, init
|
||||
from liteyuki.utils.base.config import load_from_yaml
|
||||
from liteyuki.utils.base.data_manager import StoredConfig, common_db
|
||||
from liteyuki.utils.base.ly_api import liteyuki_api
|
||||
from src.utils import adapter_manager, driver_manager, init
|
||||
from src.utils.base.config import load_from_yaml
|
||||
from src.utils.base.data_manager import StoredConfig, common_db
|
||||
from src.utils.base.ly_api import liteyuki_api
|
||||
|
||||
if __name__ == "__mp_main__":
|
||||
# Start as multiprocessing
|
||||
@ -15,7 +15,7 @@ if __name__ == "__mp_main__":
|
||||
nonebot.init(**store_config)
|
||||
adapter_manager.register()
|
||||
try:
|
||||
nonebot.load_plugin("liteyuki.liteyuki_main")
|
||||
nonebot.load_plugin("src.liteyuki_main")
|
||||
nonebot.load_from_toml("pyproject.toml")
|
||||
except BaseException as e:
|
||||
if not isinstance(e, KeyboardInterrupt):
|
||||
@ -24,6 +24,6 @@ if __name__ == "__mp_main__":
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Start as __main__
|
||||
from liteyuki.utils.base.reloader import Reloader
|
||||
from src.utils.base.reloader import Reloader
|
||||
|
||||
nonebot.run()
|
||||
|
@ -10,6 +10,7 @@ nonebot-adapter-onebot~=2.4.3
|
||||
nonebot-plugin-alconna~=0.46.3
|
||||
nonebot_plugin_apscheduler~=0.4.0
|
||||
nonebot-adapter-satori~=0.11.5
|
||||
numpy~=2.0.0
|
||||
packaging~=23.1
|
||||
psutil~=5.9.8
|
||||
py-cpuinfo~=9.0.0
|
||||
|
6
src/liteyuki/bot/__init__.py
Normal file
6
src/liteyuki/bot/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
import abc
|
||||
|
||||
|
||||
class Bot(abc.ABC):
|
||||
def __init__(self):
|
||||
pass
|
10
src/liteyuki/exception.py
Normal file
10
src/liteyuki/exception.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""exception模块包含了liteyuki运行中的所有错误
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
class LiteyukiException(BaseException):
|
||||
"""Liteyuki的异常基类。"""
|
||||
def __str__(self) -> str:
|
||||
return self.__repr__()
|
@ -1,7 +1,7 @@
|
||||
import nonebot
|
||||
from git import Repo
|
||||
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from src.utils.base.config import get_config
|
||||
|
||||
remote_urls = [
|
||||
"https://github.com/snowykami/LiteyukiBot.git",
|
@ -11,13 +11,13 @@ from nonebot.exception import MockApiException
|
||||
from nonebot.internal.matcher import Matcher
|
||||
from nonebot.permission import SUPERUSER
|
||||
|
||||
from liteyuki.utils.base.config import get_config, load_from_yaml
|
||||
from liteyuki.utils.base.data_manager import StoredConfig, TempConfig, common_db
|
||||
from liteyuki.utils.base.language import get_user_lang
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
|
||||
from liteyuki.utils.base.reloader import Reloader
|
||||
from liteyuki.utils import event as event_utils, satori_utils
|
||||
from src.utils.base.config import get_config, load_from_yaml
|
||||
from src.utils.base.data_manager import StoredConfig, TempConfig, common_db
|
||||
from src.utils.base.language import get_user_lang
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
|
||||
from src.utils.base.reloader import Reloader
|
||||
from src.utils import event as event_utils, satori_utils
|
||||
from .api import update_liteyuki
|
||||
from ..utils.base.ly_function import get_function
|
||||
|
@ -2,34 +2,37 @@ import nonebot
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.reloader import Reloader
|
||||
from liteyuki.utils.base.resource import load_resources
|
||||
from src.utils.base.config import get_config
|
||||
from src.utils.base.reloader import Reloader
|
||||
from src.utils.base.resource import load_resources
|
||||
|
||||
if get_config("debug", False):
|
||||
|
||||
src_directories = (
|
||||
"liteyuki/liteyuki_main",
|
||||
"liteyuki/plugins",
|
||||
"liteyuki/utils",
|
||||
"src/liteyuki_main",
|
||||
"src/plugins",
|
||||
"src/utils",
|
||||
)
|
||||
src_excludes_extensions = (
|
||||
"pyc",
|
||||
)
|
||||
|
||||
res_directories = (
|
||||
"liteyuki/resources",
|
||||
"src/resources",
|
||||
"resources",
|
||||
)
|
||||
|
||||
nonebot.logger.info("Liteyuki Reload is enable, watching for file changes...")
|
||||
|
||||
|
||||
class CodeModifiedHandler(FileSystemEventHandler):
|
||||
"""
|
||||
Handler for code file changes
|
||||
"""
|
||||
|
||||
def on_modified(self, event):
|
||||
if event.src_path.endswith(src_excludes_extensions) or event.is_directory or "__pycache__" in event.src_path:
|
||||
if event.src_path.endswith(
|
||||
src_excludes_extensions) or event.is_directory or "__pycache__" in event.src_path:
|
||||
return
|
||||
nonebot.logger.info(f"{event.src_path} modified, reloading bot...")
|
||||
Reloader.reload()
|
||||
@ -39,6 +42,7 @@ if get_config("debug", False):
|
||||
"""
|
||||
Handler for resource file changes
|
||||
"""
|
||||
|
||||
def on_modified(self, event):
|
||||
nonebot.logger.info(f"{event.src_path} modified, reloading resource...")
|
||||
load_resources()
|
@ -1,10 +1,10 @@
|
||||
import nonebot.plugin
|
||||
from nonebot import get_driver
|
||||
from liteyuki.utils import init_log
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.data_manager import InstalledPlugin, plugin_db
|
||||
from liteyuki.utils.base.resource import load_resources
|
||||
from liteyuki.utils.message.tools import check_for_package
|
||||
from src.utils import init_log
|
||||
from src.utils.base.config import get_config
|
||||
from src.utils.base.data_manager import InstalledPlugin, plugin_db
|
||||
from src.utils.base.resource import load_resources
|
||||
from src.utils.message.tools import check_for_package
|
||||
|
||||
load_resources()
|
||||
init_log()
|
@ -3,11 +3,11 @@ from urllib.parse import quote
|
||||
import aiohttp
|
||||
from nonebot import require
|
||||
|
||||
from liteyuki.utils.event import get_user_id
|
||||
from liteyuki.utils.base.language import Language
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from liteyuki.utils.base.resource import get_path
|
||||
from liteyuki.utils.message.html_tool import template2image
|
||||
from src.utils.event import get_user_id
|
||||
from src.utils.base.language import Language
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils.base.resource import get_path
|
||||
from src.utils.message.html_tool import template2image
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
@ -2,9 +2,9 @@ import nonebot
|
||||
from nonebot import on_message, require
|
||||
from nonebot.plugin import PluginMetadata
|
||||
|
||||
from liteyuki.utils.base.data import Database, LiteModel
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.base.data import Database, LiteModel
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import on_alconna
|
@ -4,9 +4,9 @@ from nonebot.params import CommandArg
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.plugin import PluginMetadata
|
||||
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent, v11
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
|
||||
from liteyuki.utils.message.html_tool import *
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent, v11
|
||||
from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
|
||||
from src.utils.message.html_tool import *
|
||||
|
||||
md_test = on_command("mdts", permission=SUPERUSER)
|
||||
btn_test = on_command("btnts", permission=SUPERUSER)
|
@ -1,6 +1,6 @@
|
||||
import random
|
||||
from pydantic import BaseModel
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
|
||||
class Dot(BaseModel):
|
||||
row: int
|
@ -1,7 +1,7 @@
|
||||
from nonebot import require
|
||||
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from .game import Minesweeper
|
@ -5,10 +5,10 @@ import aiofiles
|
||||
import nonebot.plugin
|
||||
from nonebot.adapters import satori
|
||||
|
||||
from liteyuki.utils import event as event_utils
|
||||
from liteyuki.utils.base.data import LiteModel
|
||||
from liteyuki.utils.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils import event as event_utils
|
||||
from src.utils.base.data import LiteModel
|
||||
from src.utils.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
|
||||
__group_data = {} # 群数据缓存, {group_id: Group}
|
||||
__user_data = {} # 用户数据缓存, {user_id: User}
|
@ -14,13 +14,13 @@ from nonebot.permission import SUPERUSER
|
||||
from nonebot.plugin import Plugin, PluginMetadata
|
||||
from nonebot.utils import run_sync
|
||||
|
||||
from liteyuki.utils.base.data_manager import InstalledPlugin
|
||||
from liteyuki.utils.base.language import get_user_lang
|
||||
from liteyuki.utils.base.ly_typing import T_Bot
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from liteyuki.utils.message.markdown import MarkdownComponent as mdc, compile_md, escape_md
|
||||
from liteyuki.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
|
||||
from liteyuki.utils.message.tools import clamp
|
||||
from src.utils.base.data_manager import InstalledPlugin
|
||||
from src.utils.base.language import get_user_lang
|
||||
from src.utils.base.ly_typing import T_Bot
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.message.markdown import MarkdownComponent as mdc, compile_md, escape_md
|
||||
from src.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
|
||||
from src.utils.message.tools import clamp
|
||||
from .common import *
|
||||
|
||||
require("nonebot_plugin_alconna")
|
@ -6,10 +6,10 @@ from nonebot import require
|
||||
from nonebot.internal.matcher import Matcher
|
||||
from nonebot.permission import SUPERUSER
|
||||
|
||||
from liteyuki.utils.base.language import get_user_lang
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from liteyuki.utils.base.resource import (ResourceMetadata, add_resource_pack, change_priority, check_exist, check_status, get_loaded_resource_packs, get_resource_metadata, load_resources, remove_resource_pack)
|
||||
from src.utils.base.language import get_user_lang
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.base.resource import (ResourceMetadata, add_resource_pack, change_priority, check_exist, check_status, get_loaded_resource_packs, get_resource_metadata, load_resources, remove_resource_pack)
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import Alconna, Args, on_alconna, Arparma, Subcommand
|
@ -2,11 +2,11 @@ import nonebot
|
||||
|
||||
from nonebot.message import event_preprocessor
|
||||
# from nonebot_plugin_alconna.typings import Event
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from liteyuki.utils import satori_utils
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils import satori_utils
|
||||
from nonebot.adapters import satori
|
||||
from nonebot_plugin_alconna.typings import Event
|
||||
from liteyuki.plugins.liteyuki_status.counter_for_satori import satori_counter
|
||||
from src.plugins.liteyuki_status.counter_for_satori import satori_counter
|
||||
|
||||
|
||||
@event_preprocessor
|
@ -5,10 +5,10 @@ import aiohttp
|
||||
from nonebot import require
|
||||
from nonebot.plugin import PluginMetadata
|
||||
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.data import Database, LiteModel
|
||||
from liteyuki.utils.base.resource import get_path
|
||||
from liteyuki.utils.message.html_tool import template2image
|
||||
from src.utils.base.config import get_config
|
||||
from src.utils.base.data import Database, LiteModel
|
||||
from src.utils.base.resource import get_path
|
||||
from src.utils.message.html_tool import template2image
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
require("nonebot_plugin_apscheduler")
|
@ -8,12 +8,12 @@ from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
from .utils import get_keywords
|
||||
from liteyuki.utils.base.word_bank import get_reply
|
||||
from liteyuki.utils.event import get_message_type
|
||||
from liteyuki.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
|
||||
from liteyuki.utils.base.data_manager import group_db, Group
|
||||
from src.utils.base.word_bank import get_reply
|
||||
from src.utils.event import get_message_type
|
||||
from src.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
|
||||
from src.utils.base.data_manager import group_db, Group
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
|
@ -1,4 +1,4 @@
|
||||
from liteyuki.utils.base.data import Database, LiteModel
|
||||
from src.utils.base.data import Database, LiteModel
|
||||
|
||||
|
||||
class MessageEventModel(LiteModel):
|
@ -5,11 +5,11 @@ from collections import Counter
|
||||
|
||||
from nonebot import Bot
|
||||
|
||||
from liteyuki.utils.message.html_tool import template2image
|
||||
from src.utils.message.html_tool import template2image
|
||||
from .common import MessageEventModel, msg_db
|
||||
from liteyuki.utils.base.language import Language
|
||||
from liteyuki.utils.base.resource import get_path
|
||||
from liteyuki.utils.message.string_tool import convert_seconds_to_time
|
||||
from src.utils.base.language import Language
|
||||
from src.utils.base.resource import get_path
|
||||
from src.utils.message.string_tool import convert_seconds_to_time
|
||||
from ...utils.external.logo import get_group_icon, get_user_icon
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
from nonebot import Bot, require
|
||||
from liteyuki.utils.message.string_tool import convert_duration, convert_time_to_seconds
|
||||
from .stat_api import *
|
||||
from liteyuki.utils import event as event_utils
|
||||
from liteyuki.utils.base.language import Language
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils.message.string_tool import convert_duration, convert_time_to_seconds
|
||||
from .data_source import *
|
||||
from src.utils import event as event_utils
|
||||
from src.utils.base.language import Language
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
@ -3,13 +3,13 @@ import time
|
||||
from nonebot import require
|
||||
from nonebot.message import event_postprocessor
|
||||
|
||||
from liteyuki.utils.base.data import Database, LiteModel
|
||||
from liteyuki.utils.base.ly_typing import v11, v12, satori
|
||||
from src.utils.base.data import Database, LiteModel
|
||||
from src.utils.base.ly_typing import v11, v12, satori
|
||||
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
|
||||
from .common import MessageEventModel, msg_db
|
||||
from liteyuki.utils import event as event_utils
|
||||
from src.utils import event as event_utils
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
21
src/plugins/liteyuki_statistics/word_cloud/LICENSE
Normal file
21
src/plugins/liteyuki_statistics/word_cloud/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 hemengyang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
107
src/plugins/liteyuki_statistics/word_cloud/data_source.py
Normal file
107
src/plugins/liteyuki_statistics/word_cloud/data_source.py
Normal file
@ -0,0 +1,107 @@
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import contextlib
|
||||
import re
|
||||
from functools import partial
|
||||
from io import BytesIO
|
||||
from random import choice
|
||||
from typing import Optional
|
||||
|
||||
import jieba
|
||||
import jieba.analyse
|
||||
import numpy as np
|
||||
from emoji import replace_emoji
|
||||
from PIL import Image
|
||||
from wordcloud import WordCloud
|
||||
|
||||
from .config import global_config, plugin_config
|
||||
|
||||
|
||||
def pre_precess(msg: str) -> str:
|
||||
"""对消息进行预处理"""
|
||||
# 去除网址
|
||||
# https://stackoverflow.com/a/17773849/9212748
|
||||
url_regex = re.compile(
|
||||
r"(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]"
|
||||
r"+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})"
|
||||
)
|
||||
msg = url_regex.sub("", msg)
|
||||
|
||||
# 去除 \u200b
|
||||
msg = re.sub(r"\u200b", "", msg)
|
||||
|
||||
# 去除 emoji
|
||||
# https://github.com/carpedm20/emoji
|
||||
msg = replace_emoji(msg)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def analyse_message(msg: str) -> dict[str, float]:
|
||||
"""分析消息
|
||||
|
||||
分词,并统计词频
|
||||
"""
|
||||
# 设置停用词表
|
||||
if plugin_config.wordcloud_stopwords_path:
|
||||
jieba.analyse.set_stop_words(plugin_config.wordcloud_stopwords_path)
|
||||
# 加载用户词典
|
||||
if plugin_config.wordcloud_userdict_path:
|
||||
jieba.load_userdict(str(plugin_config.wordcloud_userdict_path))
|
||||
# 基于 TF-IDF 算法的关键词抽取
|
||||
# 返回所有关键词,因为设置了数量其实也只是 tags[:topK],不如交给词云库处理
|
||||
words = jieba.analyse.extract_tags(msg, topK=0, withWeight=True)
|
||||
return dict(words)
|
||||
|
||||
|
||||
def get_mask(key: str):
|
||||
"""获取 mask"""
|
||||
mask_path = plugin_config.get_mask_path(key)
|
||||
if mask_path.exists():
|
||||
return np.array(Image.open(mask_path))
|
||||
# 如果指定 mask 文件不存在,则尝试默认 mask
|
||||
default_mask_path = plugin_config.get_mask_path()
|
||||
if default_mask_path.exists():
|
||||
return np.array(Image.open(default_mask_path))
|
||||
|
||||
|
||||
def _get_wordcloud(messages: list[str], mask_key: str) -> Optional[bytes]:
|
||||
# 过滤掉命令
|
||||
command_start = tuple(i for i in global_config.command_start if i)
|
||||
message = " ".join(m for m in messages if not m.startswith(command_start))
|
||||
# 预处理
|
||||
message = pre_precess(message)
|
||||
# 分析消息。分词,并统计词频
|
||||
frequency = analyse_message(message)
|
||||
# 词云参数
|
||||
wordcloud_options = {}
|
||||
wordcloud_options.update(plugin_config.wordcloud_options)
|
||||
wordcloud_options.setdefault("font_path", str(plugin_config.wordcloud_font_path))
|
||||
wordcloud_options.setdefault("width", plugin_config.wordcloud_width)
|
||||
wordcloud_options.setdefault("height", plugin_config.wordcloud_height)
|
||||
wordcloud_options.setdefault(
|
||||
"background_color", plugin_config.wordcloud_background_color
|
||||
)
|
||||
# 如果 colormap 是列表,则随机选择一个
|
||||
colormap = (
|
||||
plugin_config.wordcloud_colormap
|
||||
if isinstance(plugin_config.wordcloud_colormap, str)
|
||||
else choice(plugin_config.wordcloud_colormap)
|
||||
)
|
||||
wordcloud_options.setdefault("colormap", colormap)
|
||||
wordcloud_options.setdefault("mask", get_mask(mask_key))
|
||||
with contextlib.suppress(ValueError):
|
||||
wordcloud = WordCloud(**wordcloud_options)
|
||||
image = wordcloud.generate_from_frequencies(frequency).to_image()
|
||||
image_bytes = BytesIO()
|
||||
image.save(image_bytes, format="PNG")
|
||||
return image_bytes.getvalue()
|
||||
|
||||
|
||||
async def get_wordcloud(messages: list[str], mask_key: str) -> Optional[bytes]:
|
||||
loop = asyncio.get_running_loop()
|
||||
pfunc = partial(_get_wordcloud, messages, mask_key)
|
||||
# 虽然不知道具体是哪里泄漏了,但是通过每次关闭线程池可以避免这个问题
|
||||
# https://github.com/he0119/nonebot-plugin-wordcloud/issues/99
|
||||
with concurrent.futures.ThreadPoolExecutor() as pool:
|
||||
return await loop.run_in_executor(pool, pfunc)
|
@ -7,13 +7,13 @@ from cpuinfo import cpuinfo
|
||||
from nonebot import require
|
||||
from nonebot.adapters import satori
|
||||
|
||||
from liteyuki.utils import __NAME__, __VERSION__
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.data_manager import TempConfig, common_db
|
||||
from liteyuki.utils.base.language import Language
|
||||
from liteyuki.utils.base.resource import get_loaded_resource_packs, get_path
|
||||
from liteyuki.utils.message.html_tool import template2image
|
||||
from liteyuki.utils import satori_utils
|
||||
from src.utils import __NAME__, __VERSION__
|
||||
from src.utils.base.config import get_config
|
||||
from src.utils.base.data_manager import TempConfig, common_db
|
||||
from src.utils.base.language import Language
|
||||
from src.utils.base.resource import get_loaded_resource_packs, get_path
|
||||
from src.utils.message.html_tool import template2image
|
||||
from src.utils import satori_utils
|
||||
from .counter_for_satori import satori_counter
|
||||
from git import Repo
|
||||
|
@ -1,6 +1,6 @@
|
||||
from liteyuki.utils import event as event_utils
|
||||
from liteyuki.utils.base.language import get_user_lang
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils import event as event_utils
|
||||
from src.utils.base.language import get_user_lang
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from .api import *
|
||||
|
||||
require("nonebot_plugin_alconna")
|
@ -3,13 +3,13 @@ from typing import Optional
|
||||
import pytz
|
||||
from nonebot import require
|
||||
|
||||
from liteyuki.utils.base.data import LiteModel, Database
|
||||
from liteyuki.utils.base.data_manager import User, user_db, group_db
|
||||
from liteyuki.utils.base.language import Language, change_user_lang, get_all_lang, get_user_lang
|
||||
from liteyuki.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from liteyuki.utils.message.message import MarkdownMessage as md
|
||||
from src.utils.base.data import LiteModel, Database
|
||||
from src.utils.base.data_manager import User, user_db, group_db
|
||||
from src.utils.base.language import Language, change_user_lang, get_all_lang, get_user_lang
|
||||
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
|
||||
from src.utils.message.message import MarkdownMessage as md
|
||||
from .const import representative_timezones_list
|
||||
from liteyuki.utils import event as event_utils
|
||||
from src.utils import event as event_utils
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import Alconna, Args, Arparma, Subcommand, on_alconna
|
@ -1,4 +1,4 @@
|
||||
from liteyuki.utils.base.data import LiteModel
|
||||
from src.utils.base.data import LiteModel
|
||||
|
||||
|
||||
class Location(LiteModel):
|
@ -3,15 +3,15 @@ from nonebot.adapters import satori
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
from nonebot.internal.matcher import Matcher
|
||||
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
from src.utils.base.config import get_config
|
||||
from src.utils.base.ly_typing import T_MessageEvent
|
||||
|
||||
from .qw_api import *
|
||||
from liteyuki.utils.base.data_manager import User, user_db
|
||||
from liteyuki.utils.base.language import Language, get_user_lang
|
||||
from liteyuki.utils.base.resource import get_path
|
||||
from liteyuki.utils.message.html_tool import template2image
|
||||
from liteyuki.utils import event as event_utils
|
||||
from src.utils.base.data_manager import User, user_db
|
||||
from src.utils.base.language import Language, get_user_lang
|
||||
from src.utils.base.resource import get_path
|
||||
from src.utils.message.html_tool import template2image
|
||||
from src.utils import event as event_utils
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, MultiVar, Arparma, UniMessage
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user