Skip to content

Commit 212d8cc

Browse files
版本号统一,常量移动至base包 (#3281)
Co-authored-by: 赵天乐(tyler zhao) <189870321+tyler-ztl@users.noreply.github.com>
1 parent 36de3c5 commit 212d8cc

27 files changed

Lines changed: 298 additions & 276 deletions

File tree

.github/copilot-instructions.md

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,63 @@
1-
# AstrBot Development Instructions
2-
3-
AstrBot is a multi-platform LLM chatbot and development framework written in Python with a Vue.js dashboard. It supports multiple messaging platforms (QQ, Telegram, Discord, etc.) and various LLM providers (OpenAI, Anthropic, Google Gemini, etc.).
4-
5-
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
6-
7-
## Working Effectively
8-
9-
### Bootstrap and Install Dependencies
10-
- **Python 3.10+ required** - Check `.python-version` file
11-
- Install UV package manager: `pip install uv`
12-
- Install project dependencies: `uv sync` -- takes 6-7 minutes. NEVER CANCEL. Set timeout to 10+ minutes.
13-
- Create required directories: `mkdir -p data/plugins data/config data/temp`
14-
15-
### Running the Application
16-
- Run main application: `uv run main.py` -- starts in ~3 seconds
17-
- Application creates WebUI on http://localhost:6185 (default credentials: `astrbot`/`astrbot`)
18-
- Application loads plugins automatically from `packages/` and `data/plugins/` directories
19-
20-
### Dashboard Build (Vue.js/Node.js)
21-
- **Prerequisites**: Node.js 20+ and npm 10+ required
22-
- Navigate to dashboard: `cd dashboard`
23-
- Install dashboard dependencies: `npm install` -- takes 2-3 minutes. NEVER CANCEL. Set timeout to 5+ minutes.
24-
- Build dashboard: `npm run build` -- takes 25-30 seconds. NEVER CANCEL.
25-
- Dashboard creates optimized production build in `dashboard/dist/`
26-
27-
### Testing
28-
- Do not generate test files for now.
29-
30-
### Code Quality and Linting
31-
- Install ruff linter: `uv add --dev ruff`
32-
- Check code style: `uv run ruff check .` -- takes <1 second
33-
- Check formatting: `uv run ruff format --check .` -- takes <1 second
34-
- Fix formatting: `uv run ruff format .`
35-
- **ALWAYS** run `uv run ruff check .` and `uv run ruff format .` before committing changes
36-
37-
### Plugin Development
38-
- Plugins load from `packages/` (built-in) and `data/plugins/` (user-installed)
39-
- Plugin system supports function tools and message handlers
40-
- Key plugins: python_interpreter, web_searcher, astrbot, reminder, session_controller
41-
42-
### Common Issues and Workarounds
43-
- **Dashboard download fails**: Known issue with "division by zero" error - application still works
44-
- **Import errors in tests**: Ensure `uv run` is used to run tests in proper environment
45-
=- **Build timeouts**: Always set appropriate timeouts (10+ minutes for uv sync, 5+ minutes for npm install)
46-
47-
## CI/CD Integration
48-
- GitHub Actions workflows in `.github/workflows/`
49-
- Docker builds supported via `Dockerfile`
50-
- Pre-commit hooks enforce ruff formatting and linting
51-
52-
## Docker Support
53-
- Primary deployment method: `docker run soulter/astrbot:latest`
54-
- Compose file available: `compose.yml`
55-
- Exposes ports: 6185 (WebUI), 6195 (WeChat), 6199 (QQ), etc.
56-
- Volume mount required: `./data:/AstrBot/data`
57-
58-
## Multi-language Support
59-
- Documentation in Chinese (README.md), English (README_en.md), Japanese (README_ja.md)
60-
- UI supports internationalization
61-
- Default language is Chinese
62-
63-
Remember: This is a production chatbot framework with real users. Always test thoroughly and ensure changes don't break existing functionality.
1+
# AstrBot 开发指南
2+
3+
AstrBot 是一个使用 Python 编写、配备 Vue.js 仪表盘的多平台 LLM 聊天机器人开发框架。它支持多个消息平台(QQ、TelegramDiscord 等)和多种 LLM 提供商(OpenAIAnthropicGoogle Gemini 等)。
4+
5+
始终优先参考这些指南,仅在遇到与此处信息不符的意外情况时才回退到搜索或 bash 命令。
6+
7+
## 高效工作
8+
9+
### 引导和安装依赖
10+
- **需要 Python 3.10+** - 检查 `.python-version` 文件
11+
- 安装 UV 包管理器:`pip install uv`
12+
- 安装项目依赖:`uv sync` -- 很快几分钟。绝不要取消。设置超时时间为 10+ 分钟。
13+
- 创建必需的目录:`mkdir -p data/plugins data/config data/temp`
14+
15+
### 运行应用程序
16+
- 运行主应用程序:`uv run main.py` -- 约 3 秒启动
17+
- 应用程序在 http://localhost:6185 创建 WebUI(默认凭据:`astrbot`/`astrbot`
18+
- 应用程序自动从 `packages/` `data/plugins/` 目录加载插件
19+
20+
### 仪表盘构建(Vue.js/Node.js
21+
- **前置要求**:需要 Node.js 20+ npm 10+
22+
- 导航到仪表盘:`cd dashboard`
23+
- 安装仪表盘依赖:`npm install` -- 需要 2-3 分钟。绝不要取消。设置超时时间为 5+ 分钟。
24+
- 构建仪表盘:`npm run build` -- 需要 25-30 秒。绝不要取消。
25+
- 仪表盘在 `dashboard/dist/` 创建优化的生产构建
26+
27+
### 测试
28+
- 暂时不要生成测试文件。
29+
30+
### 代码质量和检查
31+
- 安装 ruff 检查器:`uv add --dev ruff`
32+
- 检查代码风格:`uv run ruff check .` -- 耗时 <1
33+
- 检查格式:`uv run ruff format --check .` -- 耗时 <1
34+
- 修复格式:`uv run ruff format .`
35+
- **始终**在提交更改前运行 `uv run ruff check .` `uv run ruff format .`
36+
37+
### 插件开发
38+
- 插件从 `packages/`(内置)和 `data/plugins/`(用户安装)加载
39+
- 插件系统支持函数工具和消息处理器
40+
- 关键插件:python_interpreterweb_searcherastrbotremindersession_controller
41+
42+
### 常见问题和解决方法
43+
- **仪表盘下载失败**:已知的"除以零"错误问题 - 应用程序仍可正常工作
44+
- **测试中的导入错误**:确保使用 `uv run` 在适当的环境中运行测试
45+
- **构建超时**:始终设置适当的超时时间(uv sync 为 10+ 分钟,npm install 为 5+ 分钟)
46+
47+
## CI/CD 集成
48+
- GitHub Actions 工作流在 `.github/workflows/`
49+
- 通过 `Dockerfile` 支持 Docker 构建
50+
- Pre-commit 钩子强制执行 ruff 格式化和检查
51+
52+
## Docker 支持
53+
- 主要部署方法:`docker run soulter/astrbot:latest`
54+
- 可用的 Compose 文件:`compose.yml`
55+
- 暴露端口:6185WebUI)、6195WeChat)、6199(QQ)等
56+
- 需要挂载卷:`./data:/AstrBot/data`
57+
58+
## 多语言支持
59+
- 文档包括中文(README.md)、英文(README_en.md)、日文(README_ja.md
60+
- UI 支持国际化
61+
- 默认语言为中文
62+
63+
请记住:这是一个有真实用户的生产聊天机器人框架。始终进行彻底测试,确保更改不会破坏现有功能。

astrbot/__main__.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import argparse
2+
import asyncio
3+
import mimetypes
4+
import os
5+
import sys
6+
7+
from astrbot.base import LOGO, AstrbotPaths
8+
from astrbot.core import LogBroker, LogManager, db_helper, logger
9+
from astrbot.core.config.default import VERSION
10+
from astrbot.core.initial_loader import InitialLoader
11+
from astrbot.core.utils.io import download_dashboard, get_dashboard_version
12+
13+
14+
def check_env():
15+
if not (sys.version_info.major == 3 and sys.version_info.minor >= 10):
16+
logger.error("请使用 Python3.10+ 运行本项目。")
17+
exit()
18+
19+
# os.makedirs("data/config", exist_ok=True)
20+
# os.makedirs("data/plugins", exist_ok=True)
21+
# os.makedirs("data/temp", exist_ok=True)
22+
23+
# 针对问题 #181 的临时解决方案
24+
mimetypes.add_type("text/javascript", ".js")
25+
mimetypes.add_type("text/javascript", ".mjs")
26+
mimetypes.add_type("application/json", ".json")
27+
28+
29+
async def check_dashboard_files(webui_dir: str | None = None):
30+
"""下载管理面板文件"""
31+
# 指定webui目录
32+
if webui_dir:
33+
if os.path.exists(webui_dir):
34+
logger.info(f"使用指定的 WebUI 目录: {webui_dir}")
35+
return webui_dir
36+
logger.warning(f"指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。")
37+
38+
data_dist_path = str(AstrbotPaths.astrbot_root / "dist")
39+
if os.path.exists(data_dist_path):
40+
v = await get_dashboard_version()
41+
if v is not None:
42+
# 存在文件
43+
if v == f"v{VERSION}":
44+
logger.info("WebUI 版本已是最新。")
45+
else:
46+
logger.warning(
47+
f"检测到 WebUI 版本 ({v}) 与当前 AstrBot 版本 (v{VERSION}) 不符。",
48+
)
49+
return data_dist_path
50+
51+
logger.info(
52+
"开始下载管理面板文件...高峰期(晚上)可能导致较慢的速度。如多次下载失败,请前往 https://github.com/AstrBotDevs/AstrBot/releases/latest 下载 dist.zip,并将其中的 dist 文件夹解压至 data 目录下。",
53+
)
54+
55+
try:
56+
await download_dashboard(version=f"v{VERSION}", latest=False)
57+
except Exception as e:
58+
logger.critical(f"下载管理面板文件失败: {e}。")
59+
return None
60+
61+
logger.info("管理面板下载完成。")
62+
return data_dist_path
63+
64+
65+
def main():
66+
parser = argparse.ArgumentParser(description="AstrBot")
67+
parser.add_argument(
68+
"--webui-dir",
69+
type=str,
70+
help="指定 WebUI 静态文件目录路径",
71+
default=None,
72+
)
73+
args = parser.parse_args()
74+
75+
check_env()
76+
77+
# 启动日志代理
78+
log_broker = LogBroker()
79+
LogManager.set_queue_handler(logger, log_broker)
80+
81+
# 检查仪表板文件
82+
webui_dir = asyncio.run(check_dashboard_files(args.webui_dir))
83+
84+
db = db_helper
85+
86+
# 打印 logo
87+
logger.info(LOGO)
88+
89+
core_lifecycle = InitialLoader(db, log_broker)
90+
core_lifecycle.webui_dir = webui_dir
91+
asyncio.run(core_lifecycle.start())
92+
93+
94+
if __name__ == "__main__":
95+
main()

astrbot/base/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from .abc import IAstrbotPaths
2+
from .const import LOGO
23
from .paths import AstrbotPaths
34

45
__all__ = [
56
"IAstrbotPaths",
67
"AstrbotPaths",
8+
"LOGO",
79
]

astrbot/base/abc.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ def data(self) -> Path:
4343
def log(self) -> Path:
4444
"""获取模块日志目录."""
4545

46+
@property
47+
@abstractmethod
48+
def temp(self) -> Path:
49+
"""获取模块临时目录."""
50+
51+
@property
52+
@abstractmethod
53+
def plugins(self) -> Path:
54+
"""获取插件目录."""
55+
4656
@abstractmethod
4757
def reload(self) -> None:
4858
"""重新加载环境变量."""

astrbot/base/const.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
LOGO = r"""
2+
___ _______.___________..______ .______ ______ .___________.
3+
/ \ / | || _ \ | _ \ / __ \ | |
4+
/ ^ \ | (----`---| |----`| |_) | | |_) | | | | | `---| |----`
5+
/ /_\ \ \ \ | | | / | _ < | | | | | |
6+
/ _____ \ .----) | | | | |\ \----.| |_) | | `--' | | |
7+
/__/ \__\ |_______/ |__| | _| `._____||______/ \______/ |__|
8+
9+
"""

astrbot/base/paths.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020

2121
class AstrbotPaths(IAstrbotPaths):
22-
"""Class to manage and provide paths used by Astrbot Canary."""
22+
"""统一化路径获取."""
2323

2424
load_dotenv()
2525
astrbot_root: ClassVar[Path] = Path(
2626
getenv("ASTRBOT_ROOT", Path.home() / ".astrbot")
2727
).absolute()
2828

29+
_instances: ClassVar[dict[str, AstrbotPaths]] = {}
30+
2931
def __init__(self, name: str) -> None:
3032
self.name: str = name
3133
# 确保根目录存在
@@ -35,8 +37,11 @@ def __init__(self, name: str) -> None:
3537
def getPaths(cls, name: str) -> AstrbotPaths:
3638
"""返回Paths实例,用于访问模块的各类目录."""
3739
normalized_name: NormalizedName = canonicalize_name(name)
40+
if normalized_name in cls._instances:
41+
return cls._instances[normalized_name]
3842
instance: AstrbotPaths = cls(normalized_name)
3943
instance.name = normalized_name
44+
cls._instances[normalized_name] = instance
4045
return instance
4146

4247
@property
@@ -68,7 +73,7 @@ def config(self) -> Path:
6873

6974
@property
7075
def data(self) -> Path:
71-
"""返回模块数据目录."""
76+
"""返回模块/插件数据目录."""
7277
data_path = self.astrbot_root / "data" / self.name
7378
data_path.mkdir(parents=True, exist_ok=True)
7479
return data_path
@@ -80,6 +85,20 @@ def log(self) -> Path:
8085
log_path.mkdir(parents=True, exist_ok=True)
8186
return log_path
8287

88+
@property
89+
def temp(self) -> Path:
90+
"""返回模块临时文件目录."""
91+
temp_path = self.astrbot_root / "temp" / self.name
92+
temp_path.mkdir(parents=True, exist_ok=True)
93+
return temp_path
94+
95+
@property
96+
def plugins(self) -> Path:
97+
"""返回插件目录."""
98+
plugin_path = self.astrbot_root / "plugins" / self.name
99+
plugin_path.mkdir(parents=True, exist_ok=True)
100+
return plugin_path
101+
83102
@classmethod
84103
def is_root(cls, path: Path) -> bool:
85104
"""检查路径是否为 Astrbot 根目录."""

astrbot/cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.5.23"
1+
"""AstrBot CLI入口"""

astrbot/cli/__main__.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
"""AstrBot CLI入口"""
22

33
import sys
4+
from importlib.metadata import version
45

56
import click
67

7-
from . import __version__
8+
from astrbot.base import LOGO
9+
810
from .commands import conf, init, plug, run
911

10-
logo_tmpl = r"""
11-
___ _______.___________..______ .______ ______ .___________.
12-
/ \ / | || _ \ | _ \ / __ \ | |
13-
/ ^ \ | (----`---| |----`| |_) | | |_) | | | | | `---| |----`
14-
/ /_\ \ \ \ | | | / | _ < | | | | | |
15-
/ _____ \ .----) | | | | |\ \----.| |_) | | `--' | | |
16-
/__/ \__\ |_______/ |__| | _| `._____||______/ \______/ |__|
17-
"""
12+
__version__ = version("astrbot")
1813

1914

2015
@click.group()
2116
@click.version_option(__version__, prog_name="AstrBot")
2217
def cli() -> None:
2318
"""The AstrBot CLI"""
24-
click.echo(logo_tmpl)
19+
click.echo(LOGO)
2520
click.echo("Welcome to AstrBot CLI!")
2621
click.echo(f"AstrBot CLI version: {__version__}")
2722

astrbot/cli/commands/cmd_plug.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import click
66

7+
from astrbot.base import AstrbotPaths
8+
79
from ..utils import (
810
PluginStatus,
911
build_plug_list,
@@ -47,8 +49,7 @@ def display_plugins(plugins, title=None, color=None):
4749
@click.argument("name")
4850
def new(name: str):
4951
"""创建新插件"""
50-
base_path = _get_data_path()
51-
plug_path = base_path / "plugins" / name
52+
plug_path = AstrbotPaths.getPaths(name).plugins
5253

5354
if plug_path.exists():
5455
raise click.ClickException(f"插件 {name} 已存在")

astrbot/cli/utils/basic.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99
def check_astrbot_root(path: str | Path) -> bool:
1010
"""检查路径是否为 AstrBot 根目录"""
1111
warnings.warn(
12-
"请使用 AstrbotPaths 类代替本模块中的函数",
13-
DeprecationWarning,
14-
stacklevel=2,
12+
"请使用 AstrbotPaths 类代替本模块中的函数",
13+
DeprecationWarning,
14+
stacklevel=2,
1515
)
1616
return AstrbotPaths.is_root(Path(path))
1717

18+
1819
def get_astrbot_root() -> Path:
1920
"""获取Astrbot根目录路径"""
2021
warnings.warn(
21-
"请使用 AstrbotPaths 类代替本模块中的函数",
22-
DeprecationWarning,
23-
stacklevel=2,
22+
"请使用 AstrbotPaths 类代替本模块中的函数",
23+
DeprecationWarning,
24+
stacklevel=2,
2425
)
2526
return AstrbotPaths.astrbot_root
2627

0 commit comments

Comments
 (0)