Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
c9a4683e98 | |||
317e07eb71 | |||
37749ae15e | |||
f94c10de61 | |||
5ccef735be | |||
262002b49a | |||
40c6ba6d9e | |||
60093b562b | |||
30880ec13b | |||
cc1d82312a | |||
efca13d397 | |||
3a8c09d6db | |||
cc1bb8e5e4 | |||
93c17b6026 | |||
fd3f6272f1 | |||
4d87a3c0b7 | |||
86f47ee411 | |||
1d6b8d60f3 | |||
3890704045 | |||
b0761e9873 | |||
291314de93 | |||
fd835e9406 | |||
d681c5645a | |||
d0619f1fe8 | |||
b022a364e3 | |||
df00c61dd8 | |||
94a021bab0 | |||
6b20e9eae0 | |||
0a35a3c6f8 | |||
2e75c7bc65 | |||
3341505715 | |||
bdde9c45fd | |||
7bf94a15c8 | |||
4510477026 | |||
86e50e369b | |||
796fc6f233 | |||
80c6875567 | |||
ab89cd1c72 | |||
5e454bc971 | |||
70bfb0fcee | |||
13b95c2732 | |||
ef5866343d | |||
d5ccd105a2 |
0
.dockerignore
Normal file → Executable file
0
.dockerignore
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/resource_publish_en.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/resource_publish_en.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/resource_publish_zh.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/resource_publish_zh.yml
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/问题反馈.md
vendored
Normal file → Executable file
0
.github/ISSUE_TEMPLATE/问题反馈.md
vendored
Normal file → Executable file
0
.github/dependabot.yml
vendored
Normal file → Executable file
0
.github/dependabot.yml
vendored
Normal file → Executable file
43
.github/workflows/build-image.yml
vendored
Executable file
43
.github/workflows/build-image.yml
vendored
Executable file
@ -0,0 +1,43 @@
|
||||
|
||||
name: Docker Image Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: docker-build
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USERNAME }}
|
||||
password: ${{ secrets.GHCR_PASSWORD }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/liteyukistudio/liteyukibot:latest
|
||||
|
||||
- name: Log out from GitHub Container Registry
|
||||
run: docker logout ghcr.io
|
0
.github/workflows/deploy-docs.yml
vendored
Normal file → Executable file
0
.github/workflows/deploy-docs.yml
vendored
Normal file → Executable file
0
.github/workflows/issue_handler.yml
vendored
Normal file → Executable file
0
.github/workflows/issue_handler.yml
vendored
Normal file → Executable file
30
.github/workflows/pre-commit.yml
vendored
Executable file
30
.github/workflows/pre-commit.yml
vendored
Executable file
@ -0,0 +1,30 @@
|
||||
name: Pre-commit checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13'] # 添加你想要测试的 Python 版本
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }} # 使用矩阵中的 Python 版本
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install pdm
|
||||
python -m pip install pre-commit
|
||||
pdm config python.use_venv false
|
||||
pdm install --no-lock
|
||||
pre-commit install
|
||||
|
||||
- name: Run pre-commit
|
||||
run: pre-commit run --all-files
|
0
.github/workflows/pypi-publish.yml
vendored
Normal file → Executable file
0
.github/workflows/pypi-publish.yml
vendored
Normal file → Executable file
11
.gitignore
vendored
Normal file → Executable file
11
.gitignore
vendored
Normal file → Executable file
@ -24,7 +24,6 @@ config.yml
|
||||
config.example.yml
|
||||
|
||||
# vuepress
|
||||
.github
|
||||
|
||||
# mupy
|
||||
mypy.ini
|
||||
@ -64,4 +63,12 @@ mkdoc.bat
|
||||
# vitepress
|
||||
docs/.vitepress/dist/
|
||||
docs/.vitepress/cache
|
||||
docs/.vitepress/.temp
|
||||
docs/.vitepress/.temp
|
||||
|
||||
# python toolchain
|
||||
.mypy_cache/
|
||||
.pytest_cache/
|
||||
|
||||
# pdm
|
||||
__pypackages__/
|
||||
pdm.lock
|
26
.pre-commit-config.yaml
Executable file
26
.pre-commit-config.yaml
Executable file
@ -0,0 +1,26 @@
|
||||
fail_fast: true
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 24.4.2
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--config=./pyproject.toml]
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
args: ["--profile", "black"]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.13.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
6
Dockerfile
Normal file → Executable file
6
Dockerfile
Normal file → Executable file
@ -2,17 +2,15 @@ FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.10-slim
|
||||
|
||||
ENV TZ Asia/Shanghai
|
||||
|
||||
COPY docker/sources.list /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y git
|
||||
|
||||
WORKDIR /liteyukibot
|
||||
|
||||
COPY . /liteyukibot
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
RUN apt-get install -y libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libasound2
|
||||
RUN apt-get install -y libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libasound2 libpango-1.0-0 libcairo2
|
||||
|
||||
EXPOSE 20216
|
||||
|
||||
|
50
README.md
Normal file → Executable file
50
README.md
Normal file → Executable file
@ -1,15 +1,24 @@
|
||||
<div align="center">
|
||||
|
||||
[//]: # (<img src="https://cdn.liteyuki.icu/static/svg/lylogo-full.svg" style="align-content: center; width: 50%; margin-top:10%;" alt="a">)
|
||||
[![][banner]][lightyuki-link]
|
||||
[![][banner]][liteyuki-link]
|
||||
<h2><a href="https://bot.liteyuki.icu"> <span style="color: #a2d8f4">轻雪</span> <span style="color: #d0e9ff">6</span></a></h2>
|
||||
<h4> <span style="color: #a2d8f4">✨ 轻量,高效,易于扩展✨</span></h4>
|
||||
|
||||
[![][OneBot]][onebot-link]
|
||||
[![][NoneBot2]][nonebot-link]
|
||||
[![][Liteyuki6.0]][lightyuki-link]
|
||||
[![][Liteyuki6.0]][liteyuki-link]
|
||||
[![][Python3.10+]][python-link]
|
||||
[![][Usage]][usage-link]
|
||||
[![][Repo]][repo-link]
|
||||
[![][Github]][github-link]
|
||||
[![][LiteyukiLab]][liteyukilab-link]
|
||||
|
||||
</div>
|
||||
|
||||
## 关于
|
||||
|
||||
访问[轻雪6.0](https://bot.liteyuki.icu)主页获取更多信息
|
||||
|
||||
## 特点及优势
|
||||
|
||||
- 原生支持与任意`Python`Bot框架互联,有良好的生态支持
|
||||
- 开箱即用,无需复杂配置
|
||||
@ -18,36 +27,43 @@
|
||||
- 国际化支持,支持多种语言
|
||||
- 高性能,500插件2s内启动
|
||||
|
||||
<h3>👇更多内容请访问👇</h3>
|
||||
<h2><a href="https://bot.liteyuki.icu">轻雪机器人主页</a></h2>
|
||||
</div>
|
||||
## 服务及支持(敬请期待)
|
||||
- 提供Liteyuki Cloud官方的容器化托管服务,无需担心服务器问题
|
||||
|
||||
### 感谢
|
||||
- 所有贡献者们
|
||||
**👇所有内容请访问👇**: [bot.liteyuki.icu](https://bot.liteyuki.icu)
|
||||
|
||||
### 参考及鸣谢
|
||||
## 参考及鸣谢
|
||||
- [nonebot-plugin-uninfo](https://github.com/RF-Tar-Railt/nonebot-plugin-uninfo)为会话部分用户信息提供了参考
|
||||
- [nonebot-plugin-alconna](https://github.com/nonebot/plugin-alconna/)为消息部分提供了参考
|
||||
|
||||
## 其他
|
||||
- 本仓库是一个monorepo,包含了框架,文档,测试,内置资源包,内置插件,预设配置等
|
||||
|
||||
[OneBot]: https://img.shields.io/badge/OneBot-11/12-blue?style=for-the-badge
|
||||
|
||||
[NoneBot2]: https://img.shields.io/badge/Nonebot-2-red?style=for-the-badge
|
||||
|
||||
[Liteyuki6.0]: https://img.shields.io/badge/Liteyuki-6.0-blue?style=for-the-badge
|
||||
|
||||
[Python3.10+]: https://img.shields.io/badge/Python-3.10+-blue?style=for-the-badge
|
||||
|
||||
[Usage]: https://img.shields.io/badge/文档-页面-blue?style=for-the-badge
|
||||
[Usage]: https://img.shields.io/badge/主页-文档-blue?style=for-the-badge
|
||||
|
||||
[onebot-link]:https://onebot.dev/
|
||||
[Repo]: https://img.shields.io/badge/官方托管-仓库-blue?style=for-the-badge
|
||||
|
||||
[Github]: https://img.shields.io/badge/Github-仓库-blue?style=for-the-badge
|
||||
|
||||
[LiteyukiLab]: https://img.shields.io/badge/轻雪社区-官方-blue?style=for-the-badge
|
||||
|
||||
[nonebot-link]:https://nonebot.dev/
|
||||
|
||||
[lightyuki-link]:/
|
||||
|
||||
[python-link]:https://www.python.org/
|
||||
|
||||
[usage-link]:https://bot.liteyuki.icu/
|
||||
|
||||
[liteyuki-link]:https://bot.liteyuki.icu/
|
||||
|
||||
[repo-link]:https://git.liteyuki.icu/bot/app
|
||||
|
||||
[github-link]:https://github.com/LiteyukiStudio/LiteyukiBot
|
||||
|
||||
[liteyukilab-link]:https://lab.liteyuki.icu/@LiteyukiBot
|
||||
|
||||
[banner]: https://socialify.git.ci/LiteyukiStudio/LiteyukiBot/image?description=1&forks=1&issues=1&Plus&pulls=1&stargazers=1&theme=Auto&logo=https%3a%2f%2fcdn.liteyuki.icu%2fstatic%2fsvg%2flylogo-full.svg
|
||||
|
6
config/default.yml
Normal file → Executable file
6
config/default.yml
Normal file → Executable file
@ -1,8 +1,10 @@
|
||||
nonebot:
|
||||
host: 127.0.0.1
|
||||
host: 0.0.0.0
|
||||
port: 20216
|
||||
command_start: ["", "/"]
|
||||
nickname: [ "liteyuki" ]
|
||||
default_language: zh
|
||||
driver: ~fastapi+~httpx+~websockets
|
||||
alconna_use_command_start: true
|
||||
alconna_use_command_start: true
|
||||
gotify_token: "empty token"
|
||||
|
||||
|
12
docker-compose.yml
Executable file
12
docker-compose.yml
Executable file
@ -0,0 +1,12 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
image: git.liteyuki.icu/bot/app:latest
|
||||
ports:
|
||||
- "20216:20216"
|
||||
environment:
|
||||
- TZ=Asia/Chongqing
|
||||
volumes:
|
||||
- .:/liteyukibot
|
||||
command: [ "python", "main.py" ]
|
0
docker/sources.list
Normal file → Executable file
0
docker/sources.list
Normal file → Executable file
27
docs/.vitepress/config/common.ts
Normal file → Executable file
27
docs/.vitepress/config/common.ts
Normal file → Executable file
@ -1,9 +1,9 @@
|
||||
// 共有配置项,导入index用
|
||||
|
||||
import {defineConfig} from 'vitepress'
|
||||
import {generateSidebar} from 'vitepress-sidebar';
|
||||
import {zh} from "./zh";
|
||||
import {en} from "./en";
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { generateSidebar } from 'vitepress-sidebar';
|
||||
import { zh } from "./zh";
|
||||
import { en } from "./en";
|
||||
|
||||
let defaultLocale = 'zh';
|
||||
const commonSidebarOptions = {
|
||||
@ -48,13 +48,12 @@ function generateSidebarConfig(): any[] {
|
||||
return ret
|
||||
}
|
||||
|
||||
console.log(generateSidebarConfig())
|
||||
|
||||
export const common = defineConfig({
|
||||
head: [
|
||||
// 配置favicon.ico
|
||||
['link', {rel: 'icon', type: 'image/x-icon', href: 'favicon.ico'}],
|
||||
['link', {rel: 'stylesheet', href: 'https://fonts.font.im/css?family=Cousine:400,400i,700,700i|Poppins:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i'}],
|
||||
['link', { rel: 'icon', type: 'image/x-icon', href: 'favicon.ico' }],
|
||||
['link', { rel: 'stylesheet', href: 'https://fonts.font.im/css?family=Cousine:400,400i,700,700i|Poppins:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i' }],
|
||||
],
|
||||
rewrites: {
|
||||
[`${defaultLocale}/:rest*`]: ":rest*",
|
||||
@ -71,12 +70,18 @@ export const common = defineConfig({
|
||||
]
|
||||
),
|
||||
socialLinks: [
|
||||
{icon: 'github', link: 'https://github.com/LiteyukiStudio/LiteyukiBot'},
|
||||
{ icon: 'github', link: 'https://github.com/LiteyukiStudio/LiteyukiBot' },
|
||||
{
|
||||
icon: {
|
||||
svg: '<svg t="1725391346807" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5067" width="256" height="256"><path d="M1004.692673 466.396616l-447.094409-447.073929c-25.743103-25.763582-67.501405-25.763582-93.264987 0l-103.873521 103.873521 78.171378 78.171378c12.533635-6.00058 26.562294-9.359266 41.389666-9.359266 53.02219 0 96.00928 42.98709 96.00928 96.00928 0 14.827372-3.358686 28.856031-9.359266 41.389666l127.97824 127.97824c12.533635-6.00058 26.562294-9.359266 41.389666-9.359266 53.02219 0 96.00928 42.98709 96.00928 96.00928s-42.98709 96.00928-96.00928 96.00928-96.00928-42.98709-96.00928-96.00928c0-14.827372 3.358686-28.856031 9.359266-41.389666l-127.97824-127.97824c-3.051489 1.454065-6.184898 2.744293-9.379746 3.870681l0 266.97461c37.273227 13.188988 63.99936 48.721433 63.99936 90.520695 0 53.02219-42.98709 96.00928-96.00928 96.00928s-96.00928-42.98709-96.00928-96.00928c0-41.799262 26.726133-77.331707 63.99936-90.520695l0-266.97461c-37.273227-13.188988-63.99936-48.721433-63.99936-90.520695 0-14.827372 3.358686-28.856031 9.359266-41.389666l-78.171378-78.171378-295.892081 295.871601c-25.743103 25.784062-25.743103 67.542365 0 93.285467l447.114889 447.073929c25.743103 25.743103 67.480925 25.743103 93.264987 0l445.00547-445.00547c25.763582-25.763582 25.763582-67.542365 0-93.285467z" fill="#a2d8f4" p-id="5068"></path></svg>'
|
||||
},
|
||||
link: "https://git.liteyuki.icu/LiteyukiStudio/LiteyukiBot"
|
||||
link: "https://git.liteyuki.icu/bot/app"
|
||||
},
|
||||
{
|
||||
icon:{
|
||||
svg:'<svg t="1736700504329" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14158" width="200" height="200"><path d="M944.355556 142.222222c-17.066667-22.755556-45.511111-34.133333-79.644445-34.133333-28.444444 0-68.266667 5.688889-108.088889 22.755555h-5.688889c17.066667 11.377778 34.133333 28.444444 51.2 39.822223 56.888889-17.066667 91.022222-11.377778 96.711111 0 11.377778 11.377778 5.688889 45.511111-22.755555 91.022222 11.377778 17.066667 17.066667 34.133333 28.444444 51.2 0 0 0 5.688889 5.688889 5.688889 22.755556-34.133333 34.133333-62.577778 45.511111-91.022222 11.377778-28.444444 5.688889-62.577778-11.377777-85.333334z" p-id="14159" fill="#a2d8f4"></path><path d="M267.377778 512a45.511111 45.511111 0 1 0 91.022222 0 45.511111 45.511111 0 1 0-91.022222 0Z" p-id="14160" fill="#a2d8f4"></path><path d="M625.777778 614.4c-113.777778 85.333333-227.555556 153.6-324.266667 193.422222-11.377778 5.688889-17.066667 5.688889-28.444444 11.377778 22.755556 17.066667 51.2 34.133333 79.644444 45.511111 51.2 22.755556 108.088889 34.133333 164.977778 34.133333s113.777778-11.377778 164.977778-34.133333c51.2-22.755556 96.711111-51.2 136.533333-91.022222 39.822222-39.822222 68.266667-85.333333 91.022222-130.844445 22.755556-51.2 34.133333-108.088889 34.133334-159.288888 0-51.2-11.377778-102.4-28.444445-153.6-5.688889 5.688889-11.377778 17.066667-17.066667 22.755555-68.266667 79.644444-164.977778 176.355556-273.066666 261.688889zM813.511111 187.733333c-5.688889-5.688889-11.377778-5.688889-11.377778-11.377777-17.066667-17.066667-34.133333-28.444444-51.2-39.822223-22.755556-11.377778-45.511111-28.444444-68.266666-34.133333-56.888889-28.444444-108.088889-39.822222-164.977778-39.822222s-113.777778 11.377778-164.977778 34.133333c-51.2 22.755556-96.711111 51.2-136.533333 91.022222-39.822222 34.133333-68.266667 79.644444-91.022222 130.844445-22.755556 51.2-34.133333 108.088889-34.133334 159.288889 0 51.2 11.377778 96.711111 22.755556 142.222222-22.755556 34.133333-39.822222 68.266667-51.2 96.711111-11.377778 39.822222-5.688889 68.266667 11.377778 91.022222 17.066667 22.755556 45.511111 34.133333 79.644444 34.133334h11.377778c28.444444 0 62.577778-11.377778 96.711111-22.755556-17.066667-11.377778-34.133333-28.444444-51.2-39.822222-51.2 11.377778-85.333333 11.377778-96.711111 0 0-17.066667 5.688889-45.511111 34.133333-96.711111 17.066667 34.133333 39.822222 62.577778 68.266667 91.022222h5.688889c17.066667-5.688889 39.822222-11.377778 62.577777-17.066667 91.022222-34.133333 204.8-102.4 307.2-187.733333 108.088889-85.333333 199.111111-170.666667 256-250.311111l34.133334-51.2c-22.755556-28.444444-39.822222-56.888889-68.266667-79.644445z m-500.622222 420.977778c-56.888889 0-102.4-45.511111-102.4-102.4s45.511111-102.4 102.4-102.4S409.6 455.111111 409.6 512c0 51.2-45.511111 96.711111-96.711111 96.711111z" p-id="14161" fill="#a2d8f4"></path></svg>'
|
||||
},
|
||||
link: 'https://lab.liteyuki.icu/@LiteyukiBot'
|
||||
}
|
||||
],
|
||||
search: {
|
||||
@ -124,8 +129,8 @@ export const common = defineConfig({
|
||||
},
|
||||
lastUpdated: true,
|
||||
locales: {
|
||||
root: {label: "简体中文", ...zh},
|
||||
en: {label: "English", ...en},
|
||||
root: { label: "简体中文", ...zh },
|
||||
en: { label: "English", ...en },
|
||||
},
|
||||
|
||||
})
|
2
docs/.vitepress/config/en.ts
Normal file → Executable file
2
docs/.vitepress/config/en.ts
Normal file → Executable file
@ -20,7 +20,7 @@ export const en = defineConfig({
|
||||
'Edit this page on GitHub',
|
||||
),
|
||||
footer: {
|
||||
message: 'Documentation built with <a href="https://vitepress.dev/">VitePress</a> | API references generated by <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a>',
|
||||
message: 'Page accelerated by <a href="https://cdn.liteyuki.icu" target="_blank">Liteyukiflare CDN</a><br>Documentation built with <a href="https://vitepress.dev/">VitePress</a> | API references generated by <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a>',
|
||||
copyright: ThemeConfig.copyright
|
||||
},
|
||||
outline: ThemeConfig.getOutLine("Page Content"),
|
||||
|
0
docs/.vitepress/config/index.ts
Normal file → Executable file
0
docs/.vitepress/config/index.ts
Normal file → Executable file
0
docs/.vitepress/config/utils.ts
Normal file → Executable file
0
docs/.vitepress/config/utils.ts
Normal file → Executable file
2
docs/.vitepress/config/zh.ts
Normal file → Executable file
2
docs/.vitepress/config/zh.ts
Normal file → Executable file
@ -20,7 +20,7 @@ export const zh = defineConfig({
|
||||
'在 GitHub 上编辑此页',
|
||||
),
|
||||
footer: {
|
||||
message: '文档由 <a href="https://vitepress.dev/">VitePress</a> 构建 | API引用由 <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a> 生成',
|
||||
message: '页面由 <a href="https://cdn.liteyuki.icu" target="_blank">Liteyukiflare CDN</a> 提供加速服务<br>文档由 <a href="https://vitepress.dev/">VitePress</a> 构建 | API引用由 <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a> 生成',
|
||||
copyright: ThemeConfig.copyright
|
||||
},
|
||||
outline: ThemeConfig.getOutLine("页面内容"),
|
||||
|
0
docs/.vitepress/theme/index.ts
Normal file → Executable file
0
docs/.vitepress/theme/index.ts
Normal file → Executable file
0
docs/.vitepress/theme/liteyuki.scss
Normal file → Executable file
0
docs/.vitepress/theme/liteyuki.scss
Normal file → Executable file
0
docs/components/ContributorBar.vue
Normal file → Executable file
0
docs/components/ContributorBar.vue
Normal file → Executable file
0
docs/components/Dash.vue
Normal file → Executable file
0
docs/components/Dash.vue
Normal file → Executable file
0
docs/components/Geo.vue
Normal file → Executable file
0
docs/components/Geo.vue
Normal file → Executable file
0
docs/components/Home.vue
Normal file → Executable file
0
docs/components/Home.vue
Normal file → Executable file
0
docs/components/PluginItemCard.vue
Normal file → Executable file
0
docs/components/PluginItemCard.vue
Normal file → Executable file
0
docs/components/PluginStore.vue
Normal file → Executable file
0
docs/components/PluginStore.vue
Normal file → Executable file
0
docs/components/ResItemCard.vue
Normal file → Executable file
0
docs/components/ResItemCard.vue
Normal file → Executable file
0
docs/components/ResPubWindow.vue
Normal file → Executable file
0
docs/components/ResPubWindow.vue
Normal file → Executable file
0
docs/components/ResStore.vue
Normal file → Executable file
0
docs/components/ResStore.vue
Normal file → Executable file
0
docs/components/StatsBar.vue
Normal file → Executable file
0
docs/components/StatsBar.vue
Normal file → Executable file
0
docs/components/Tabs.vue
Normal file → Executable file
0
docs/components/Tabs.vue
Normal file → Executable file
0
docs/components/ToggleSwitch.vue
Normal file → Executable file
0
docs/components/ToggleSwitch.vue
Normal file → Executable file
0
docs/components/TryLiteyukiWindow.vue
Normal file → Executable file
0
docs/components/TryLiteyukiWindow.vue
Normal file → Executable file
0
docs/components/scripts/const.ts
Normal file → Executable file
0
docs/components/scripts/const.ts
Normal file → Executable file
0
docs/components/scripts/i18n.ts
Normal file → Executable file
0
docs/components/scripts/i18n.ts
Normal file → Executable file
0
docs/components/scripts/statsApi.ts
Normal file → Executable file
0
docs/components/scripts/statsApi.ts
Normal file → Executable file
0
docs/en/deploy/config.md
Normal file → Executable file
0
docs/en/deploy/config.md
Normal file → Executable file
34
docs/en/deploy/fandq.md
Normal file → Executable file
34
docs/en/deploy/fandq.md
Normal file → Executable file
@ -10,20 +10,11 @@ order: 3
|
||||
- You can specify which python interpreter to use by using the full path to the python executable, for example, `/path/to/python main.py`
|
||||
- Use virtual environments to avoid conflicts between different python interpreters
|
||||
|
||||
- Why does the bot not respond after I start it?
|
||||
- Please check the configuration file `command_start` or `superusers`, make sure you have permission to use the command and send it correctly
|
||||
- Make sure the command header does not conflict with `nickname{}`, for example, a command is `help`, but the `Bot` nickname has a `help`, then it will be parsed as a nickname instead of a command
|
||||
|
||||
- Update Liteyuki failed, error `InvalidGitRepositoryError`
|
||||
- Please install `Git` correctly and deploy Liteyuki using cloning instead of direct download
|
||||
|
||||
- How to log in to chat platforms such as Telegram?
|
||||
- If you have this question, it means you don't know much about this project.
|
||||
This project does not implement the login function, only the message processing and response.
|
||||
The login function is provided by the implementation side (protocol side). The implementation side itself does not handle response logic.
|
||||
It processes and reports messages to Liteyuki according to the OneBot standard.
|
||||
You need to use an implementation side that complies with the OneBot standard to connect to Liteyuki and report messages to Liteyuki.
|
||||
Some recommended implementation sides have been listed below
|
||||
- How to log in to chat platforms?
|
||||
- Some plugins provide the ability to log in to specific platforms, for example, using the NoneBot plugin to log in to supported adapter platforms
|
||||
|
||||
- `Playwright` installation failed
|
||||
- Enter `playwright install` to install the browser
|
||||
@ -37,24 +28,3 @@ order: 3
|
||||
|
||||
- Join chat group[775840726](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=SzmDYbfR6jY94o9KFNon7AwelRyI6M_u&authKey=ygeBdEmdFNyCWuNR4w0M1M8%2B5oDg7k%2FDfN0tzBkYcnbB%2FGHNnlVEnCIGbdftsnn7&noverify=0&group_code=775840726)
|
||||
- If you don't have a QQ account, you can [submit an issue on GitHub](https://github.com/LiteyukiStudio/LiteyukiBot/issues/new?assignees=&labels=&projects=&template=%E9%97%AE%E9%A2%98%E5%8F%8D%E9%A6%88.md&title=)
|
||||
|
||||
## **Recommended Solution(QQ)**
|
||||
|
||||
1. [Lagrange.OneBot](https://github.com/KonataDev/Lagrange.Core), based on `Lagrange.Core`, a Linux QQ implementation, supports OneBotv11 protocol
|
||||
2. [LLOneBot](https://github.com/LLOneBot/LLOneBot), a plugin for `Liteloader NTQQ`, supports OneBotv11 protocol
|
||||
3. [OpenShamrock](https://github.com/whitechi73/OpenShamrock), based on Lsposed, supports kritor protocol
|
||||
4. [TRSS-Yunzai](https://github.com/TimeRainStarSky/Yunzai), based on `Node.js`, supports OneBotv11 protocol
|
||||
5. [go-cqhttp](https://github.com/Mrs4s/go-cqhttp),A QQ Client based on `go`, supports OneBotv11 protocol
|
||||
6. [Gensokyo](https://github.com/Hoshinonyaruko/Gensokyo), use QQ protocol
|
||||
|
||||
## **Recommended Solution(Minecraft)**
|
||||
|
||||
1. [MinecraftOneBot](https://github.com/snowykami/MinecraftOnebot), We develop a Minecraft server chat bot
|
||||
|
||||
Other project encountered issues, please prioritize the documentation and issues of the project itself, don't ask LiteyukiBot developers
|
||||
|
||||
## **Acknowledgements**
|
||||
|
||||
- [Nonebot2](https://nonebot.dev) provides the underlying framework
|
||||
- [nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna) provides the command parser
|
||||
- [MiSans](https://hyperos.mi.com/font/zh/),[MapleMono](https://gitee.com/mirrors/Maple-Mono) provides the font
|
||||
|
8
docs/en/deploy/install.md
Normal file → Executable file
8
docs/en/deploy/install.md
Normal file → Executable file
@ -37,11 +37,9 @@ python main.py
|
||||
|
||||
## **Run with Docker**
|
||||
|
||||
1. Install [`Docker`](https://docs.docker.com/get-docker/)
|
||||
2. Clone Repo `git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1`
|
||||
3. Change directory `cd LiteyukiBot`
|
||||
4. Build docker image `docker build -t liteyukibot .`
|
||||
5. Run container `docker run -p 20216:20216 -v $(pwd):/liteyukibot -v $(pwd)/.cache:/root/.cache liteyukibot`
|
||||
```bash
|
||||
docker pull ghcr.io/liteyukistudio/liteyukibot:latest # Nightly build
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> If you are using Windows, please use the absolute project directory `/path/to/LiteyukiBot` instead of `$(pwd)` <br>
|
||||
|
0
docs/en/dev/best_practices.md
Normal file → Executable file
0
docs/en/dev/best_practices.md
Normal file → Executable file
0
docs/en/dev/comm.md
Normal file → Executable file
0
docs/en/dev/comm.md
Normal file → Executable file
0
docs/en/dev/guide.md
Normal file → Executable file
0
docs/en/dev/guide.md
Normal file → Executable file
0
docs/en/dev/lyfunc.md
Normal file → Executable file
0
docs/en/dev/lyfunc.md
Normal file → Executable file
4
docs/en/dev/plugin.md
Normal file → Executable file
4
docs/en/dev/plugin.md
Normal file → Executable file
@ -1,11 +1,11 @@
|
||||
---
|
||||
title: Liteyuki Plugin
|
||||
title: Plugin
|
||||
order: 3
|
||||
---
|
||||
|
||||
# 简介
|
||||
|
||||
轻雪插件是轻雪内置的一部分功能,运行在主进程中,可以很高程度地扩展轻雪的功能
|
||||
轻雪插件是轻雪内置的一部分功能,运行在主进程中,可以很高程度地扩展轻雪的功能。
|
||||
|
||||
## 开始
|
||||
|
||||
|
0
docs/en/dev/resource.md
Normal file → Executable file
0
docs/en/dev/resource.md
Normal file → Executable file
0
docs/en/index.md
Normal file → Executable file
0
docs/en/index.md
Normal file → Executable file
0
docs/en/store/plugin.md
Normal file → Executable file
0
docs/en/store/plugin.md
Normal file → Executable file
0
docs/en/store/resource.md
Normal file → Executable file
0
docs/en/store/resource.md
Normal file → Executable file
0
docs/en/usage/agreement.md
Normal file → Executable file
0
docs/en/usage/agreement.md
Normal file → Executable file
0
docs/en/usage/basic.md
Normal file → Executable file
0
docs/en/usage/basic.md
Normal file → Executable file
0
docs/en/usage/extra.md
Normal file → Executable file
0
docs/en/usage/extra.md
Normal file → Executable file
0
docs/package.json
Normal file → Executable file
0
docs/package.json
Normal file → Executable file
0
docs/pnpm-lock.yaml
generated
Normal file → Executable file
0
docs/pnpm-lock.yaml
generated
Normal file → Executable file
0
docs/public/favicon.ico
Normal file → Executable file
0
docs/public/favicon.ico
Normal file → Executable file
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
docs/public/liteyuki-dark.svg
Normal file → Executable file
0
docs/public/liteyuki-dark.svg
Normal file → Executable file
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
0
docs/public/liteyuki.svg
Normal file → Executable file
0
docs/public/liteyuki.svg
Normal file → Executable file
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
0
docs/public/plugins.json
Normal file → Executable file
0
docs/public/plugins.json
Normal file → Executable file
0
docs/public/resources.json
Normal file → Executable file
0
docs/public/resources.json
Normal file → Executable file
0
docs/tsconfig.json
Normal file → Executable file
0
docs/tsconfig.json
Normal file → Executable file
0
docs/zh/deploy/config.md
Normal file → Executable file
0
docs/zh/deploy/config.md
Normal file → Executable file
35
docs/zh/deploy/fandq.md
Normal file → Executable file
35
docs/zh/deploy/fandq.md
Normal file → Executable file
@ -10,43 +10,16 @@ order: 3
|
||||
然后用`/path/to/python main.py`来启动Bot,
|
||||
其中`/path/to/python`是你要用来运行Bot的可执行文件
|
||||
|
||||
- 为什么我启动后机器人没有反应?
|
||||
- 请检查配置文件的`command_start`或`superusers`,确认你有权限使用命令并按照正确的命令发送
|
||||
- 确认命令头没有和`nickname{}`冲突,例如一个命令是`help`,但是`Bot`昵称有一个`help`,那么将会被解析为nickname而不是命令
|
||||
|
||||
- 更新轻雪失败,报错`InvalidGitRepositoryError`
|
||||
- 请正确安装`Git`,并使用克隆而非直接下载的方式部署轻雪
|
||||
|
||||
- 怎么登录聊天平台,例如QQ?
|
||||
- 你有这个问题说明你不是很了解这个项目,本项目不负责实现登录功能,只负责处理和回应消息,登录功能由实现端(协议端)提供,
|
||||
实现端本身不负责处理响应逻辑,将消息按照OneBot标准处理好上报给轻雪
|
||||
你需要使用Onebot标准的实现端来连接到轻雪并将消息上报给轻雪,下面已经列出一些推荐的实现端
|
||||
- 怎么对接聊天平台?
|
||||
- Bot部分插件提供了对接特定平台的能力,例如使用NoneBot插件可对接支持的适配器平台
|
||||
- `Playwright`安装失败
|
||||
- 输入`playwright install`安装浏览器
|
||||
- 有的插件安装后报错无法启动
|
||||
- 请先查阅插件文档,确认插件必要配置项完好后,仍然出现问题,请联系插件作者或在安全模式`safe_mode: true`下启动轻雪,在安全模式下你可以使用`npm uninstall`卸载问题插件
|
||||
- 其他问题
|
||||
|
||||
## 其他问题
|
||||
-
|
||||
加入QQ群[775840726](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=SzmDYbfR6jY94o9KFNon7AwelRyI6M_u&authKey=ygeBdEmdFNyCWuNR4w0M1M8%2B5oDg7k%2FDfN0tzBkYcnbB%2FGHNnlVEnCIGbdftsnn7&noverify=0&group_code=775840726)
|
||||
|
||||
## **推荐方案(QQ)**
|
||||
|
||||
1. [Lagrange.OneBot](https://github.com/KonataDev/Lagrange.Core),基于NTQQ的OneBot实现,目前Markdown消息支持Lagrange
|
||||
2. [LLOneBot](https://github.com/LLOneBot/LLOneBot),NTQQ的OneBot插件,需要安装NTQQ
|
||||
3. [OpenShamrock](https://github.com/whitechi73/OpenShamrock),基于Lsposed的OneBot11实现
|
||||
4. [TRSS-Yunzai](https://github.com/TimeRainStarSky/Yunzai),基于`node.js`,可使用`ws-plugin`进行通信
|
||||
5. [go-cqhttp](https://github.com/Mrs4s/go-cqhttp),`go`语言实现的OneBot11实现端,目前可用性较低
|
||||
6. [Gensokyo](https://github.com/Hoshinonyaruko/Gensokyo),基于 OneBot QQ官方机器人Api Golang 原生实现,需要官方机器人权限
|
||||
7. 人工实现的`Onebot`协议,自己整一个WebSocket客户端,看着QQ的消息,然后给轻雪传输数据
|
||||
|
||||
## **推荐方案(Minecraft)**
|
||||
|
||||
1. [MinecraftOneBot](https://github.com/snowykami/MinecraftOnebot),我们专门为Minecraft开发的服务器Bot,支持OneBotV11标准
|
||||
|
||||
使用其他项目连接请先自行查阅文档,若有困难请联系对应开发者而不是Liteyuki的开发者
|
||||
|
||||
## **鸣谢**
|
||||
|
||||
- [Nonebot2](https://nonebot.dev)提供的框架支持
|
||||
- [nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna)提供的命令解析功能
|
||||
- [MiSans](https://hyperos.mi.com/font/zh/),[MapleMono](https://gitee.com/mirrors/Maple-Mono)提供的字体,且遵守了相关字体开源协议
|
||||
|
10
docs/zh/deploy/install.md
Normal file → Executable file
10
docs/zh/deploy/install.md
Normal file → Executable file
@ -12,7 +12,7 @@ order: 1
|
||||
|
||||
```bash
|
||||
# 克隆项目到本地,轻雪使用Git进行版本管理,该步骤为必要项
|
||||
git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1 # 若你不能访问Github,可以使用Liteyuki镜像:https://git.liteyuki.icu/LiteyukiStudio/LiteyukiBot
|
||||
git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1 # 若你不能访问Github,可以使用Liteyuki镜像:https://git.liteyuki.icu/bot/app
|
||||
|
||||
# 切换到Bot目录下
|
||||
cd LiteyukiBot
|
||||
@ -33,11 +33,9 @@ python main.py
|
||||
|
||||
## **使用Docker构建**
|
||||
|
||||
1. 安装 [`Docker`](https://docs.docker.com/get-docker/)
|
||||
2. 克隆项目 `git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1`
|
||||
3. 进入轻雪目录 `cd LiteyukiBot`
|
||||
4. 构建镜像 `docker build -t liteyukibot .`
|
||||
5. 启动容器 `docker run -p 20216:20216 -v $(pwd):/liteyukibot -v $(pwd)/.cache:/root/.cache liteyukibot`
|
||||
```bash
|
||||
docker pull ghcr.io/liteyukistudio/liteyukibot:latest # 每夜版镜像
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> Windows请使用项目绝对目录`/path/to/LiteyukiBot`代替`$(pwd)` <br>
|
||||
|
0
docs/zh/dev/best_practices.md
Normal file → Executable file
0
docs/zh/dev/best_practices.md
Normal file → Executable file
4
docs/zh/dev/comm.md
Normal file → Executable file
4
docs/zh/dev/comm.md
Normal file → Executable file
@ -7,9 +7,7 @@ order: 4
|
||||
|
||||
### 简介
|
||||
|
||||
轻雪运行在主进程 MainProcess 里,其他插件框架进程是伴随的子进程,因此无法通过内存共享和直接对象传递的方式进行通信,
|
||||
轻雪提供了一个通道[`Channel`](./api/comm/channel#class-channel-generic-t)用于跨进程通信,
|
||||
你可以通过[`Channel`](./api/comm/channel#class-channel-generic-t)发送消息给其他进程,也可以监听其他进程的消息。
|
||||
轻雪运行在主进程 MainProcess 里,有部分实现插件为了一些功能在子进程中运行,这样两个进程上下文是不会互相干扰的,因此无法通过共享内存和直接对象传递进行通信。
|
||||
|
||||
例如子进程接收到用户信息需要重启机器人,这时可以通过通道对主进程发送消息,主进程接收到消息后重启对应子进程。
|
||||
|
||||
|
0
docs/zh/dev/guide.md
Normal file → Executable file
0
docs/zh/dev/guide.md
Normal file → Executable file
0
docs/zh/dev/lyfunc.md
Normal file → Executable file
0
docs/zh/dev/lyfunc.md
Normal file → Executable file
12
docs/zh/dev/plugin.md
Normal file → Executable file
12
docs/zh/dev/plugin.md
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 轻雪插件开发
|
||||
title: 插件开发
|
||||
order: 3
|
||||
---
|
||||
|
||||
@ -7,6 +7,16 @@ order: 3
|
||||
|
||||
轻雪插件是轻雪内置的一部分功能,运行在主进程中,可以很高程度地扩展轻雪的功能
|
||||
|
||||
插件大致可分为应用(Application)、实现(Implementation)及服务(Service)等几种类型,大部分情况下一个插件通常承担着多个责任,可按需调整
|
||||
|
||||
应用:从总线通道接收到消息后进行处理,响应,以实现某些功能,例如`echo`
|
||||
|
||||
实现:对接特定平台,把平台的消息转换为轻雪消息格式传入总线通道
|
||||
|
||||
服务:提供一系列对外的ipc/rpc/http等服务,供其他插件调用
|
||||
|
||||
我们鼓励使用`magicoca`进行对象传递来进行插件间通信而不是依赖关系,这样可以避免很多潜在的问题。
|
||||
|
||||
## 开始
|
||||
|
||||
### 创建插件
|
||||
|
0
docs/zh/dev/resource.md
Normal file → Executable file
0
docs/zh/dev/resource.md
Normal file → Executable file
0
docs/zh/index.md
Normal file → Executable file
0
docs/zh/index.md
Normal file → Executable file
0
docs/zh/store/plugin.md
Normal file → Executable file
0
docs/zh/store/plugin.md
Normal file → Executable file
0
docs/zh/store/resource.md
Normal file → Executable file
0
docs/zh/store/resource.md
Normal file → Executable file
0
docs/zh/usage/agreement.md
Normal file → Executable file
0
docs/zh/usage/agreement.md
Normal file → Executable file
0
docs/zh/usage/basic.md
Normal file → Executable file
0
docs/zh/usage/basic.md
Normal file → Executable file
0
docs/zh/usage/extra.md
Normal file → Executable file
0
docs/zh/usage/extra.md
Normal file → Executable file
0
liteyuki/EN.LICENSE
Normal file → Executable file
0
liteyuki/EN.LICENSE
Normal file → Executable file
0
liteyuki/LICENSE
Normal file → Executable file
0
liteyuki/LICENSE
Normal file → Executable file
0
liteyuki/__init__.py
Normal file → Executable file
0
liteyuki/__init__.py
Normal file → Executable file
0
liteyuki/bot/__init__.py
Normal file → Executable file
0
liteyuki/bot/__init__.py
Normal file → Executable file
0
liteyuki/bot/lifespan.py
Normal file → Executable file
0
liteyuki/bot/lifespan.py
Normal file → Executable file
0
liteyuki/comm/__init__.py
Normal file → Executable file
0
liteyuki/comm/__init__.py
Normal file → Executable file
5
liteyuki/comm/channel.py
Normal file → Executable file
5
liteyuki/comm/channel.py
Normal file → Executable file
@ -75,11 +75,6 @@ class Channel(Generic[T]):
|
||||
if name in _channel:
|
||||
raise ValueError(f"Channel {name} already exists")
|
||||
_channel[name] = self
|
||||
logger.debug(f"Channel {name} initialized in main process")
|
||||
else:
|
||||
logger.debug(
|
||||
f"Channel {name} initialized in sub process, should manually set in main process"
|
||||
)
|
||||
|
||||
def _get_generic_type(self) -> Optional[type]:
|
||||
"""
|
||||
|
0
liteyuki/comm/event.py
Normal file → Executable file
0
liteyuki/comm/event.py
Normal file → Executable file
0
liteyuki/comm/storage.py
Normal file → Executable file
0
liteyuki/comm/storage.py
Normal file → Executable file
51
liteyuki/config.py
Normal file → Executable file
51
liteyuki/config.py
Normal file → Executable file
@ -11,8 +11,8 @@
|
||||
import os
|
||||
import json
|
||||
import copy
|
||||
import toml
|
||||
import yaml
|
||||
import toml # type: ignore
|
||||
import yaml # type: ignore
|
||||
|
||||
from typing import Any
|
||||
|
||||
@ -118,6 +118,8 @@ def load_config_in_default(no_waring: bool = False) -> dict[str, Any]:
|
||||
从一个标准的轻雪项目加载配置文件
|
||||
项目目录下的config.*和config目录下的所有配置文件
|
||||
项目目录下的配置文件优先
|
||||
Args:
|
||||
no_waring: 是否关闭警告
|
||||
"""
|
||||
config = load_configs_from_dirs("config", no_waring=no_waring)
|
||||
config.update(
|
||||
@ -130,3 +132,48 @@ def load_config_in_default(no_waring: bool = False) -> dict[str, Any]:
|
||||
)
|
||||
)
|
||||
return config
|
||||
|
||||
# new config loader
|
||||
class Loader:
|
||||
def __init__(self):
|
||||
self.config = {}
|
||||
|
||||
def load_from_yaml(self, fp: str) -> "Loader":
|
||||
"""从yaml文件加载配置
|
||||
Args:
|
||||
fp
|
||||
"""
|
||||
with open(fp, 'r') as file:
|
||||
self.config.update(yaml.safe_load(file))
|
||||
return self
|
||||
|
||||
def load_from_toml(self, fp: str) -> "Loader":
|
||||
"""从toml文件加载配置"""
|
||||
with open(fp, 'r') as file:
|
||||
self.config.update(toml.load(file))
|
||||
return self
|
||||
|
||||
def load_from_json(self, fp: str) -> "Loader":
|
||||
"""从json文件加载配置"""
|
||||
with open(fp, 'r') as file:
|
||||
self.config.update(json.load(file))
|
||||
return self
|
||||
|
||||
def load_from_env(self, prefix: str = "") -> "Loader":
|
||||
"""从环境变量加载配置"""
|
||||
for key, value in os.environ.items():
|
||||
if key.startswith(prefix):
|
||||
self.config[key[len(prefix):]] = value
|
||||
return self
|
||||
|
||||
def merge(self, loader: "Loader") -> "Loader":
|
||||
"""合并两个Loader键值对树"""
|
||||
self.config.update(loader.config)
|
||||
return self
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
"""获取配置值"""
|
||||
return self.config.get(key, default)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Loader(config={self.config})"
|
0
liteyuki/core/__init__.py
Normal file → Executable file
0
liteyuki/core/__init__.py
Normal file → Executable file
0
liteyuki/core/manager.py
Normal file → Executable file
0
liteyuki/core/manager.py
Normal file → Executable file
0
liteyuki/dev/__init__.py
Normal file → Executable file
0
liteyuki/dev/__init__.py
Normal file → Executable file
0
liteyuki/dev/observer.py
Normal file → Executable file
0
liteyuki/dev/observer.py
Normal file → Executable file
0
liteyuki/dev/plugin.py
Normal file → Executable file
0
liteyuki/dev/plugin.py
Normal file → Executable file
0
liteyuki/exception.py
Normal file → Executable file
0
liteyuki/exception.py
Normal file → Executable file
56
liteyuki/log.py
Normal file → Executable file
56
liteyuki/log.py
Normal file → Executable file
@ -12,26 +12,34 @@ import sys
|
||||
|
||||
import loguru
|
||||
|
||||
logger = loguru.logger
|
||||
logger = loguru.logger.bind()
|
||||
|
||||
# DEBUG日志格式
|
||||
debug_format: str = (
|
||||
"<c>{time:YYYY-MM-DD HH:mm:ss}</c> "
|
||||
"<lvl>[{level.icon}]</lvl> "
|
||||
"<c><{name}.{module}.{function}:{line}></c> "
|
||||
"{message}"
|
||||
"<c>{time:YYYY-MM-DD HH:mm:ss}</c> "
|
||||
"<lvl>[{level.icon}{level}]</lvl> "
|
||||
"<c><{name}.{module}.{function}:{line}></c> "
|
||||
"{message}"
|
||||
)
|
||||
|
||||
# 默认日志格式
|
||||
default_format: str = (
|
||||
"<c>{time:MM-DD HH:mm:ss}</c> "
|
||||
"<lvl>[{level.icon}]</lvl> "
|
||||
"<c><{name}></c> "
|
||||
"{message}"
|
||||
"<c>{time:MM-DD HH:mm:ss}</c> "
|
||||
"<lvl>[{level.icon}{level}]</lvl> "
|
||||
"<c><{name}></c> "
|
||||
"{message}"
|
||||
)
|
||||
|
||||
|
||||
def get_format(level: str) -> str:
|
||||
"""
|
||||
获取日志格式
|
||||
Args:
|
||||
level: 日志等级
|
||||
|
||||
Returns: 日志格式
|
||||
|
||||
"""
|
||||
# DEBUG日志格式
|
||||
|
||||
if level == "DEBUG":
|
||||
return debug_format
|
||||
else:
|
||||
@ -41,23 +49,27 @@ def get_format(level: str) -> str:
|
||||
def init_log(config: dict):
|
||||
"""
|
||||
在语言加载完成后执行
|
||||
Returns:
|
||||
|
||||
Args:
|
||||
config: 配置
|
||||
"""
|
||||
|
||||
global logger
|
||||
level = config.get("log_level", "DEBUG")
|
||||
logger.remove()
|
||||
logger.add(
|
||||
sys.stdout,
|
||||
level=0,
|
||||
level=level,
|
||||
diagnose=False,
|
||||
format=get_format(config.get("log_level", "INFO")),
|
||||
format=get_format(level),
|
||||
)
|
||||
show_icon = config.get("log_icon", True)
|
||||
logger.level("DEBUG", color="<blue>", icon=f"{'🐛' if show_icon else ''}DEBUG")
|
||||
logger.level("INFO", color="<normal>", icon=f"{'ℹ️' if show_icon else ''}INFO")
|
||||
logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}SUCCESS")
|
||||
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}WARNING")
|
||||
logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}ERROR")
|
||||
logger.level("DEBUG", color="<blue>", icon=f"{'🐛' if show_icon else ''}")
|
||||
logger.level("INFO", color="<normal>", icon=f"{'ℹ️' if show_icon else ''}")
|
||||
logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}")
|
||||
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}")
|
||||
logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}")
|
||||
logger.level("CRITICAL", color="<red>", icon=f"{'❌' if show_icon else ''}")
|
||||
logger.level("TRACE", color="<cyan>", icon=f"{'🔍' if show_icon else ''}")
|
||||
|
||||
logger.bind()
|
||||
|
||||
init_log(config={})
|
||||
init_log(config={"log_level": "DEBUG", "log_icon": True})
|
@ -1,357 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/19 上午6:23
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : mkdoc.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
|
||||
import ast
|
||||
import os
|
||||
import shutil
|
||||
from typing import Any
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel
|
||||
|
||||
NO_TYPE_ANY = "Any"
|
||||
NO_TYPE_HINT = "NoTypeHint"
|
||||
|
||||
|
||||
class DefType(Enum):
|
||||
FUNCTION = "function"
|
||||
METHOD = "method"
|
||||
STATIC_METHOD = "staticmethod"
|
||||
CLASS_METHOD = "classmethod"
|
||||
PROPERTY = "property"
|
||||
|
||||
|
||||
class FunctionInfo(BaseModel):
|
||||
name: str
|
||||
args: list[tuple[str, str]]
|
||||
return_type: str
|
||||
docstring: str
|
||||
source_code: str = ""
|
||||
|
||||
type: DefType
|
||||
"""若为类中def,则有"""
|
||||
is_async: bool
|
||||
|
||||
|
||||
class AttributeInfo(BaseModel):
|
||||
name: str
|
||||
type: str
|
||||
value: Any = None
|
||||
docstring: str = ""
|
||||
|
||||
|
||||
class ClassInfo(BaseModel):
|
||||
name: str
|
||||
docstring: str
|
||||
methods: list[FunctionInfo]
|
||||
attributes: list[AttributeInfo]
|
||||
inherit: list[str]
|
||||
|
||||
|
||||
class ModuleInfo(BaseModel):
|
||||
module_path: str
|
||||
"""点分割模块路径 例如 liteyuki.bot"""
|
||||
|
||||
functions: list[FunctionInfo]
|
||||
classes: list[ClassInfo]
|
||||
attributes: list[AttributeInfo]
|
||||
docstring: str
|
||||
|
||||
|
||||
def get_relative_path(base_path: str, target_path: str) -> str:
|
||||
"""
|
||||
获取相对路径
|
||||
Args:
|
||||
base_path: 基础路径
|
||||
target_path: 目标路径
|
||||
"""
|
||||
return os.path.relpath(target_path, base_path)
|
||||
|
||||
|
||||
def write_to_files(file_data: dict[str, str]):
|
||||
"""
|
||||
输出文件
|
||||
Args:
|
||||
file_data: 文件数据 相对路径
|
||||
"""
|
||||
|
||||
for rp, data in file_data.items():
|
||||
|
||||
if not os.path.exists(os.path.dirname(rp)):
|
||||
os.makedirs(os.path.dirname(rp))
|
||||
with open(rp, 'w', encoding='utf-8') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
def get_file_list(module_folder: str):
|
||||
file_list = []
|
||||
for root, dirs, files in os.walk(module_folder):
|
||||
for file in files:
|
||||
if file.endswith((".py", ".pyi")):
|
||||
file_list.append(os.path.join(root, file))
|
||||
return file_list
|
||||
|
||||
|
||||
def get_module_info_normal(file_path: str, ignore_private: bool = True) -> ModuleInfo:
|
||||
"""
|
||||
获取函数和类
|
||||
Args:
|
||||
file_path: Python 文件路径
|
||||
ignore_private: 忽略私有函数和类
|
||||
Returns:
|
||||
模块信息
|
||||
"""
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
file_content = file.read()
|
||||
tree = ast.parse(file_content)
|
||||
|
||||
dot_sep_module_path = file_path.replace(os.sep, '.').replace(".py", "").replace(".pyi", "")
|
||||
module_docstring = ast.get_docstring(tree)
|
||||
|
||||
module_info = ModuleInfo(
|
||||
module_path=dot_sep_module_path,
|
||||
functions=[],
|
||||
classes=[],
|
||||
attributes=[],
|
||||
docstring=module_docstring if module_docstring else ""
|
||||
)
|
||||
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 模块函数 且不在类中 若ignore_private=True则忽略私有函数
|
||||
if not any(isinstance(parent, ast.ClassDef) for parent in ast.iter_child_nodes(node)) and (not ignore_private or not node.name.startswith('_')):
|
||||
|
||||
# 判断第一个参数是否为self或cls,后期用其他办法优化
|
||||
if node.args.args:
|
||||
first_arg = node.args.args[0]
|
||||
if first_arg.arg in ("self", "cls"):
|
||||
continue
|
||||
|
||||
function_docstring = ast.get_docstring(node)
|
||||
|
||||
func_info = FunctionInfo(
|
||||
name=node.name,
|
||||
args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in node.args.args],
|
||||
return_type=ast.unparse(node.returns) if node.returns else "None",
|
||||
docstring=function_docstring if function_docstring else "",
|
||||
type=DefType.FUNCTION,
|
||||
is_async=isinstance(node, ast.AsyncFunctionDef),
|
||||
source_code=ast.unparse(node)
|
||||
)
|
||||
module_info.functions.append(func_info)
|
||||
|
||||
elif isinstance(node, ast.ClassDef):
|
||||
# 模块类
|
||||
class_docstring = ast.get_docstring(node)
|
||||
|
||||
class_info = ClassInfo(
|
||||
name=node.name,
|
||||
docstring=class_docstring if class_docstring else "",
|
||||
methods=[],
|
||||
attributes=[],
|
||||
inherit=[ast.unparse(base) for base in node.bases]
|
||||
)
|
||||
|
||||
for class_node in node.body:
|
||||
# methods [instance, static, class, property],保留__init__方法
|
||||
if isinstance(class_node, ast.FunctionDef) and (not ignore_private or not class_node.name.startswith('_') or class_node.name == "__init__"):
|
||||
method_docstring = ast.get_docstring(class_node)
|
||||
def_type = DefType.METHOD
|
||||
if class_node.decorator_list:
|
||||
if any(isinstance(decorator, ast.Name) and decorator.id == "staticmethod" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.STATIC_METHOD
|
||||
elif any(isinstance(decorator, ast.Name) and decorator.id == "classmethod" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.CLASS_METHOD
|
||||
elif any(isinstance(decorator, ast.Name) and decorator.id == "property" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.PROPERTY
|
||||
class_info.methods.append(FunctionInfo(
|
||||
name=class_node.name,
|
||||
args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in class_node.args.args],
|
||||
return_type=ast.unparse(class_node.returns) if class_node.returns else "None",
|
||||
docstring=method_docstring if method_docstring else "",
|
||||
type=def_type,
|
||||
is_async=isinstance(class_node, ast.AsyncFunctionDef),
|
||||
source_code=ast.unparse(class_node)
|
||||
))
|
||||
# attributes
|
||||
elif isinstance(class_node, ast.Assign):
|
||||
for target in class_node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
class_info.attributes.append(AttributeInfo(
|
||||
name=target.id,
|
||||
type=ast.unparse(class_node.value)
|
||||
))
|
||||
module_info.classes.append(class_info)
|
||||
|
||||
elif isinstance(node, ast.Assign):
|
||||
# 检查是否在类或函数中
|
||||
if not any(isinstance(parent, (ast.ClassDef, ast.FunctionDef)) for parent in ast.iter_child_nodes(node)):
|
||||
# 模块属性变量
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and (not ignore_private or not target.id.startswith('_')):
|
||||
attr_type = NO_TYPE_HINT
|
||||
if isinstance(node.value, ast.AnnAssign) and node.value.annotation:
|
||||
attr_type = ast.unparse(node.value.annotation)
|
||||
module_info.attributes.append(AttributeInfo(
|
||||
name=target.id,
|
||||
type=attr_type,
|
||||
value=ast.unparse(node.value) if node.value else None
|
||||
))
|
||||
|
||||
return module_info
|
||||
|
||||
|
||||
def generate_markdown(module_info: ModuleInfo, front_matter=None, lang: str = "zh-CN") -> str:
|
||||
"""
|
||||
生成模块的Markdown
|
||||
你可在此自定义生成的Markdown格式
|
||||
Args:
|
||||
module_info: 模块信息
|
||||
front_matter: 自定义选项title, index, icon, category
|
||||
lang: 语言
|
||||
Returns:
|
||||
Markdown 字符串
|
||||
"""
|
||||
|
||||
content = ""
|
||||
|
||||
front_matter = "---\n" + "\n".join([f"{k}: {v}" for k, v in front_matter.items()]) + "\n---\n\n"
|
||||
|
||||
content += front_matter
|
||||
|
||||
# 模块函数
|
||||
for func in module_info.functions:
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] else arg[0] for arg in func.args]
|
||||
content += f"### ***{'async ' if func.is_async else ''}def*** `{func.name}({', '.join(args_with_type)}) -> {func.return_type}`\n\n"
|
||||
|
||||
func.docstring = func.docstring.replace("\n", "\n\n")
|
||||
content += f"{func.docstring}\n\n"
|
||||
|
||||
# 函数源代码可展开区域
|
||||
content += f"<details>\n<summary>源代码</summary>\n\n```python\n{func.source_code}\n```\n</details>\n\n"
|
||||
|
||||
# 类
|
||||
for cls in module_info.classes:
|
||||
if cls.inherit:
|
||||
inherit = f"({', '.join(cls.inherit)})" if cls.inherit else ""
|
||||
content += f"### ***class*** `{cls.name}{inherit}`\n\n"
|
||||
else:
|
||||
content += f"### ***class*** `{cls.name}`\n\n"
|
||||
|
||||
cls.docstring = cls.docstring.replace("\n", "\n\n")
|
||||
content += f"{cls.docstring}\n\n"
|
||||
for method in cls.methods:
|
||||
# 类函数
|
||||
|
||||
if method.type != DefType.METHOD:
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] else arg[0] for arg in method.args]
|
||||
content += f"###   ***@{method.type.value}***\n"
|
||||
else:
|
||||
# self不加类型提示
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] and arg[0] != "self" else arg[0] for arg in method.args]
|
||||
content += f"###   ***{'async ' if method.is_async else ''}def*** `{method.name}({', '.join(args_with_type)}) -> {method.return_type}`\n\n"
|
||||
|
||||
method.docstring = method.docstring.replace("\n", "\n\n")
|
||||
content += f" {method.docstring}\n\n"
|
||||
# 函数源代码可展开区域
|
||||
|
||||
if lang == "zh-CN":
|
||||
TEXT_SOURCE_CODE = "源代码"
|
||||
else:
|
||||
TEXT_SOURCE_CODE = "Source Code"
|
||||
|
||||
content += f"<details>\n<summary>{TEXT_SOURCE_CODE}</summary>\n\n```python\n{method.source_code}\n```\n</details>\n\n"
|
||||
for attr in cls.attributes:
|
||||
content += f"###   ***attr*** `{attr.name}: {attr.type}`\n\n"
|
||||
|
||||
# 模块属性
|
||||
for attr in module_info.attributes:
|
||||
if attr.type == NO_TYPE_HINT:
|
||||
content += f"### ***var*** `{attr.name} = {attr.value}`\n\n"
|
||||
else:
|
||||
content += f"### ***var*** `{attr.name}: {attr.type} = {attr.value}`\n\n"
|
||||
|
||||
attr.docstring = attr.docstring.replace("\n", "\n\n")
|
||||
content += f"{attr.docstring}\n\n"
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, lang: str = "zh-CN", ignored_paths=None):
|
||||
"""
|
||||
生成文档
|
||||
Args:
|
||||
module_folder: 模块文件夹
|
||||
output_dir: 输出文件夹
|
||||
with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b, True时例如docs/api/module/module_a.md, docs/api/module/module_b.md
|
||||
ignored_paths: 忽略的路径
|
||||
lang: 语言
|
||||
"""
|
||||
if ignored_paths is None:
|
||||
ignored_paths = []
|
||||
file_data: dict[str, str] = {} # 路径 -> 字串
|
||||
|
||||
file_list = get_file_list(module_folder)
|
||||
|
||||
# 清理输出目录
|
||||
shutil.rmtree(output_dir, ignore_errors=True)
|
||||
os.mkdir(output_dir)
|
||||
|
||||
replace_data = {
|
||||
"__init__": "README",
|
||||
".py" : ".md",
|
||||
}
|
||||
|
||||
for pyfile_path in file_list:
|
||||
if any(ignored_path.replace("\\", "/") in pyfile_path.replace("\\", "/") for ignored_path in ignored_paths):
|
||||
continue
|
||||
|
||||
no_module_name_pyfile_path = get_relative_path(module_folder, pyfile_path) # 去头路径
|
||||
|
||||
# markdown相对路径
|
||||
rel_md_path = pyfile_path if with_top else no_module_name_pyfile_path
|
||||
for rk, rv in replace_data.items():
|
||||
rel_md_path = rel_md_path.replace(rk, rv)
|
||||
|
||||
abs_md_path = os.path.join(output_dir, rel_md_path)
|
||||
|
||||
# 获取模块信息
|
||||
module_info = get_module_info_normal(pyfile_path)
|
||||
|
||||
# 生成markdown
|
||||
|
||||
if "README" in abs_md_path:
|
||||
front_matter = {
|
||||
"title" : module_info.module_path.replace(".__init__", "").replace("_", "\\n"),
|
||||
"index" : "true",
|
||||
"icon" : "laptop-code",
|
||||
"category": "API"
|
||||
}
|
||||
else:
|
||||
front_matter = {
|
||||
"title" : module_info.module_path.replace("_", "\\n"),
|
||||
"order" : "1",
|
||||
"icon" : "laptop-code",
|
||||
"category": "API"
|
||||
}
|
||||
|
||||
md_content = generate_markdown(module_info, front_matter)
|
||||
print(f"Generate {pyfile_path} -> {abs_md_path}")
|
||||
file_data[abs_md_path] = md_content
|
||||
|
||||
write_to_files(file_data)
|
||||
|
||||
|
||||
# 入口脚本
|
||||
if __name__ == '__main__':
|
||||
# 这里填入你的模块路径
|
||||
generate_docs('liteyuki', 'docs/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="zh-CN")
|
||||
generate_docs('liteyuki', 'docs/en/dev/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="en")
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user