Skip to content

Commit b9fd7dc

Browse files
committed
refactor: bundled webui static files into wheel and replace astrbot cli log with English
- Translated and standardized log messages in cmd_conf.py for better clarity. - Updated initialization logic in cmd_init.py to provide clearer user prompts and error handling. - Improved plugin management commands in cmd_plug.py with consistent language and error messages. - Enhanced run command in cmd_run.py with clearer status messages and error handling. - Updated utility functions in basic.py and plugin.py to improve readability and maintainability. - Added version comparison logic in version_comparator.py with clearer comments. - Enhanced logging configuration in log.py to suppress noisy loggers. - Updated the updater logic in updator.py to provide clearer error messages for users. - Improved IO utility functions in io.py to handle dashboard versioning more effectively. - Enhanced dashboard server logic in server.py to prioritize bundled assets and improve user feedback. - Updated pyproject.toml to include bundled dashboard assets and custom build hooks. - Added a custom build script (hatch_build.py) to automate dashboard builds during package creation.
1 parent 0dbe32e commit b9fd7dc

15 files changed

Lines changed: 291 additions & 187 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ dashboard/dist/
3636
package-lock.json
3737
yarn.lock
3838

39+
# Bundled dashboard dist (generated by hatch_build.py during pip wheel build)
40+
astrbot/dashboard/dist/
41+
3942
# Operating System
4043
**/.DS_Store
4144
.DS_Store

astrbot/cli/__main__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""AstrBot CLI入口"""
1+
"""AstrBot CLI entry point"""
22

33
import sys
44

@@ -29,23 +29,23 @@ def cli() -> None:
2929
@click.command()
3030
@click.argument("command_name", required=False, type=str)
3131
def help(command_name: str | None) -> None:
32-
"""显示命令的帮助信息
32+
"""Display help information for commands
3333
34-
如果提供了 COMMAND_NAME,则显示该命令的详细帮助信息。
35-
否则,显示通用帮助信息。
34+
If COMMAND_NAME is provided, display detailed help for that command.
35+
Otherwise, display general help information.
3636
"""
3737
ctx = click.get_current_context()
3838
if command_name:
39-
# 查找指定命令
39+
# Find the specified command
4040
command = cli.get_command(ctx, command_name)
4141
if command:
42-
# 显示特定命令的帮助信息
42+
# Display help for the specific command
4343
click.echo(command.get_help(ctx))
4444
else:
4545
click.echo(f"Unknown command: {command_name}")
4646
sys.exit(1)
4747
else:
48-
# 显示通用帮助信息
48+
# Display general help information
4949
click.echo(cli.get_help(ctx))
5050

5151

astrbot/cli/commands/cmd_conf.py

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,57 +10,57 @@
1010

1111

1212
def _validate_log_level(value: str) -> str:
13-
"""验证日志级别"""
13+
"""Validate log level"""
1414
value = value.upper()
1515
if value not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
1616
raise click.ClickException(
17-
"日志级别必须是 DEBUG/INFO/WARNING/ERROR/CRITICAL 之一",
17+
"Log level must be one of DEBUG/INFO/WARNING/ERROR/CRITICAL",
1818
)
1919
return value
2020

2121

2222
def _validate_dashboard_port(value: str) -> int:
23-
"""验证 Dashboard 端口"""
23+
"""Validate Dashboard port"""
2424
try:
2525
port = int(value)
2626
if port < 1 or port > 65535:
27-
raise click.ClickException("端口必须在 1-65535 范围内")
27+
raise click.ClickException("Port must be in range 1-65535")
2828
return port
2929
except ValueError:
30-
raise click.ClickException("端口必须是数字")
30+
raise click.ClickException("Port must be a number")
3131

3232

3333
def _validate_dashboard_username(value: str) -> str:
34-
"""验证 Dashboard 用户名"""
34+
"""Validate Dashboard username"""
3535
if not value:
36-
raise click.ClickException("用户名不能为空")
36+
raise click.ClickException("Username cannot be empty")
3737
return value
3838

3939

4040
def _validate_dashboard_password(value: str) -> str:
41-
"""验证 Dashboard 密码"""
41+
"""Validate Dashboard password"""
4242
if not value:
43-
raise click.ClickException("密码不能为空")
43+
raise click.ClickException("Password cannot be empty")
4444
return hashlib.md5(value.encode()).hexdigest()
4545

4646

4747
def _validate_timezone(value: str) -> str:
48-
"""验证时区"""
48+
"""Validate timezone"""
4949
try:
5050
zoneinfo.ZoneInfo(value)
5151
except Exception:
52-
raise click.ClickException(f"无效的时区: {value},请使用有效的IANA时区名称")
52+
raise click.ClickException(f"Invalid timezone: {value}. Please use a valid IANA timezone name")
5353
return value
5454

5555

5656
def _validate_callback_api_base(value: str) -> str:
57-
"""验证回调接口基址"""
57+
"""Validate callback API base URL"""
5858
if not value.startswith("http://") and not value.startswith("https://"):
59-
raise click.ClickException("回调接口基址必须以 http:// https:// 开头")
59+
raise click.ClickException("Callback API base must start with http:// or https://")
6060
return value
6161

6262

63-
# 可通过CLI设置的配置项,配置键到验证器函数的映射
63+
# Configuration items settable via CLI, mapping config keys to validator functions
6464
CONFIG_VALIDATORS: dict[str, Callable[[str], Any]] = {
6565
"timezone": _validate_timezone,
6666
"log_level": _validate_log_level,
@@ -72,11 +72,11 @@ def _validate_callback_api_base(value: str) -> str:
7272

7373

7474
def _load_config() -> dict[str, Any]:
75-
"""加载或初始化配置文件"""
75+
"""Load or initialize config file"""
7676
root = get_astrbot_root()
7777
if not check_astrbot_root(root):
7878
raise click.ClickException(
79-
f"{root}不是有效的 AstrBot 根目录,如需初始化请使用 astrbot init",
79+
f"{root} is not a valid AstrBot root directory. Use 'astrbot init' to initialize",
8080
)
8181

8282
config_path = root / "data" / "cmd_config.json"
@@ -91,11 +91,11 @@ def _load_config() -> dict[str, Any]:
9191
try:
9292
return json.loads(config_path.read_text(encoding="utf-8-sig"))
9393
except json.JSONDecodeError as e:
94-
raise click.ClickException(f"配置文件解析失败: {e!s}")
94+
raise click.ClickException(f"Failed to parse config file: {e!s}")
9595

9696

9797
def _save_config(config: dict[str, Any]) -> None:
98-
"""保存配置文件"""
98+
"""Save config file"""
9999
config_path = get_astrbot_root() / "data" / "cmd_config.json"
100100

101101
config_path.write_text(
@@ -105,21 +105,21 @@ def _save_config(config: dict[str, Any]) -> None:
105105

106106

107107
def _set_nested_item(obj: dict[str, Any], path: str, value: Any) -> None:
108-
"""设置嵌套字典中的值"""
108+
"""Set a value in a nested dictionary"""
109109
parts = path.split(".")
110110
for part in parts[:-1]:
111111
if part not in obj:
112112
obj[part] = {}
113113
elif not isinstance(obj[part], dict):
114114
raise click.ClickException(
115-
f"配置路径冲突: {'.'.join(parts[: parts.index(part) + 1])} 不是字典",
115+
f"Config path conflict: {'.'.join(parts[: parts.index(part) + 1])} is not a dict",
116116
)
117117
obj = obj[part]
118118
obj[parts[-1]] = value
119119

120120

121121
def _get_nested_item(obj: dict[str, Any], path: str) -> Any:
122-
"""获取嵌套字典中的值"""
122+
"""Get a value from a nested dictionary"""
123123
parts = path.split(".")
124124
for part in parts:
125125
obj = obj[part]
@@ -128,31 +128,31 @@ def _get_nested_item(obj: dict[str, Any], path: str) -> Any:
128128

129129
@click.group(name="conf")
130130
def conf() -> None:
131-
"""配置管理命令
131+
"""Configuration management commands
132132
133-
支持的配置项:
133+
Supported config keys:
134134
135-
- timezone: 时区设置 (例如: Asia/Shanghai)
135+
- timezone: Timezone setting (e.g. Asia/Shanghai)
136136
137-
- log_level: 日志级别 (DEBUG/INFO/WARNING/ERROR/CRITICAL)
137+
- log_level: Log level (DEBUG/INFO/WARNING/ERROR/CRITICAL)
138138
139-
- dashboard.port: Dashboard 端口
139+
- dashboard.port: Dashboard port
140140
141-
- dashboard.username: Dashboard 用户名
141+
- dashboard.username: Dashboard username
142142
143-
- dashboard.password: Dashboard 密码
143+
- dashboard.password: Dashboard password
144144
145-
- callback_api_base: 回调接口基址
145+
- callback_api_base: Callback API base URL
146146
"""
147147

148148

149149
@conf.command(name="set")
150150
@click.argument("key")
151151
@click.argument("value")
152152
def set_config(key: str, value: str) -> None:
153-
"""设置配置项的值"""
153+
"""Set the value of a config item"""
154154
if key not in CONFIG_VALIDATORS:
155-
raise click.ClickException(f"不支持的配置项: {key}")
155+
raise click.ClickException(f"Unsupported config key: {key}")
156156

157157
config = _load_config()
158158

@@ -162,41 +162,41 @@ def set_config(key: str, value: str) -> None:
162162
_set_nested_item(config, key, validated_value)
163163
_save_config(config)
164164

165-
click.echo(f"配置已更新: {key}")
165+
click.echo(f"Config updated: {key}")
166166
if key == "dashboard.password":
167-
click.echo(" 原值: ********")
168-
click.echo(" 新值: ********")
167+
click.echo(" Old value: ********")
168+
click.echo(" New value: ********")
169169
else:
170-
click.echo(f" 原值: {old_value}")
171-
click.echo(f" 新值: {validated_value}")
170+
click.echo(f" Old value: {old_value}")
171+
click.echo(f" New value: {validated_value}")
172172

173173
except KeyError:
174-
raise click.ClickException(f"未知的配置项: {key}")
174+
raise click.ClickException(f"Unknown config key: {key}")
175175
except Exception as e:
176-
raise click.UsageError(f"设置配置失败: {e!s}")
176+
raise click.UsageError(f"Failed to set config: {e!s}")
177177

178178

179179
@conf.command(name="get")
180180
@click.argument("key", required=False)
181181
def get_config(key: str | None = None) -> None:
182-
"""获取配置项的值,不提供key则显示所有可配置项"""
182+
"""Get the value of a config item. If no key is provided, show all configurable items"""
183183
config = _load_config()
184184

185185
if key:
186186
if key not in CONFIG_VALIDATORS:
187-
raise click.ClickException(f"不支持的配置项: {key}")
187+
raise click.ClickException(f"Unsupported config key: {key}")
188188

189189
try:
190190
value = _get_nested_item(config, key)
191191
if key == "dashboard.password":
192192
value = "********"
193193
click.echo(f"{key}: {value}")
194194
except KeyError:
195-
raise click.ClickException(f"未知的配置项: {key}")
195+
raise click.ClickException(f"Unknown config key: {key}")
196196
except Exception as e:
197-
raise click.UsageError(f"获取配置失败: {e!s}")
197+
raise click.UsageError(f"Failed to get config: {e!s}")
198198
else:
199-
click.echo("当前配置:")
199+
click.echo("Current config:")
200200
for key in CONFIG_VALIDATORS:
201201
try:
202202
value = (

astrbot/cli/commands/cmd_init.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@
88

99

1010
async def initialize_astrbot(astrbot_root: Path) -> None:
11-
"""执行 AstrBot 初始化逻辑"""
11+
"""Execute AstrBot initialization logic"""
1212
dot_astrbot = astrbot_root / ".astrbot"
1313

1414
if not dot_astrbot.exists():
15-
click.echo(f"Current Directory: {astrbot_root}")
16-
click.echo(
17-
"如果你确认这是 Astrbot root directory, 你需要在当前目录下创建一个 .astrbot 文件标记该目录为 AstrBot 的数据目录。",
18-
)
1915
if click.confirm(
20-
f"请检查当前目录是否正确,确认正确请回车: {astrbot_root}",
16+
f"Install AstrBot to this directory? {astrbot_root}",
2117
default=True,
2218
abort=True,
2319
):
@@ -40,7 +36,7 @@ async def initialize_astrbot(astrbot_root: Path) -> None:
4036

4137
@click.command()
4238
def init() -> None:
43-
"""初始化 AstrBot"""
39+
"""Initialize AstrBot"""
4440
click.echo("Initializing AstrBot...")
4541
astrbot_root = get_astrbot_root()
4642
lock_file = astrbot_root / "astrbot.lock"
@@ -49,8 +45,9 @@ def init() -> None:
4945
try:
5046
with lock.acquire():
5147
asyncio.run(initialize_astrbot(astrbot_root))
48+
click.echo("Done! You can now run 'astrbot run' to start AstrBot")
5249
except Timeout:
53-
raise click.ClickException("无法获取锁文件,请检查是否有其他实例正在运行")
50+
raise click.ClickException("Cannot acquire lock file. Please check if another instance is running")
5451

5552
except Exception as e:
56-
raise click.ClickException(f"初始化失败: {e!s}")
53+
raise click.ClickException(f"Initialization failed: {e!s}")

0 commit comments

Comments
 (0)