mirror of
https://github.com/AstrBotDevs/AstrBot.git
synced 2026-09-24 16:39:52 +08:00
feat: enhance CLI prompts and fix frontend 401 handling
- cmd_conf: show password rules before setting, display length after input - cmd_init/cmd_run: add Chinese prompts and HTTPS security warnings - openai_source/gemini_source: add missing provider adapter import - ConsoleDisplayer: add missing resolveApiUrl import for SSE - WelcomePage: show user-friendly message for 401 unauthorized errors
This commit is contained in:
@@ -164,7 +164,17 @@ def _get_nested_item(obj: dict[str, Any], path: str) -> Any:
|
||||
|
||||
|
||||
def prompt_dashboard_password(prompt: str = "Dashboard password") -> str:
|
||||
# 显示密码规则提示
|
||||
click.echo()
|
||||
click.echo("密码规则:")
|
||||
click.echo(" - 至少 12 个字符")
|
||||
click.echo(" - 必须包含至少一个大写字母")
|
||||
click.echo(" - 必须包含至少一个小写字母")
|
||||
click.echo(" - 必须包含至少一个数字")
|
||||
click.echo()
|
||||
|
||||
password = click.prompt(prompt, hide_input=True, confirmation_prompt=True, type=str)
|
||||
click.echo(f"密码长度: {len(password)} 字符")
|
||||
return _validate_dashboard_password(password)
|
||||
|
||||
|
||||
|
||||
@@ -23,15 +23,20 @@ async def initialize_astrbot(
|
||||
admin_password: str | None,
|
||||
) -> None:
|
||||
"""Execute AstrBot initialization logic"""
|
||||
click.echo("=" * 60)
|
||||
click.echo("AstrBot 初始化向导")
|
||||
click.echo("=" * 60)
|
||||
click.echo()
|
||||
|
||||
dot_astrbot = astrbot_root / ".astrbot"
|
||||
if not dot_astrbot.exists():
|
||||
if yes or click.confirm(
|
||||
f"Install AstrBot to this directory? {astrbot_root}",
|
||||
f"确定要将 AstrBot 安装到以下目录吗?\n {astrbot_root}",
|
||||
default=True,
|
||||
abort=True,
|
||||
):
|
||||
dot_astrbot.touch()
|
||||
click.echo(f"Created {dot_astrbot}")
|
||||
click.echo(f"[OK] 已创建: {dot_astrbot}")
|
||||
paths = {
|
||||
"data": astrbot_root / "data",
|
||||
"config": astrbot_root / "data" / "config",
|
||||
@@ -41,16 +46,15 @@ async def initialize_astrbot(
|
||||
}
|
||||
for name, path in paths.items():
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
click.echo(
|
||||
f"{('Created' if not path.exists() else f'{name} Directory exists')}: {path}",
|
||||
)
|
||||
status = "Created" if not path.exists() else "Exists"
|
||||
click.echo(f" [{status}] {name.title()}: {path}")
|
||||
config_path = astrbot_root / "data" / "cmd_config.json"
|
||||
if not config_path.exists():
|
||||
config_path.write_text(
|
||||
json.dumps(DEFAULT_CONFIG, ensure_ascii=False, indent=2),
|
||||
encoding="utf-8-sig",
|
||||
)
|
||||
click.echo(f"Created config file: {config_path}")
|
||||
click.echo(f"[OK] 配置文件已创建: {config_path}")
|
||||
ASTRBOT_ROOT = astrbot_root
|
||||
env_file = ASTRBOT_ROOT / ".env"
|
||||
if not env_file.exists():
|
||||
@@ -80,11 +84,11 @@ async def initialize_astrbot(
|
||||
header = f"# Generated from config.template by astrbot init for instance: {instance_name}\n# This file will be auto-loaded by 'astrbot run'\n\n"
|
||||
env_file.write_text(header + txt, encoding="utf-8")
|
||||
env_file.chmod(420)
|
||||
click.echo(f"Created environment file from template: {env_file}")
|
||||
click.echo(f"[OK] 环境变量文件已创建: {env_file}")
|
||||
except Exception as e:
|
||||
click.echo(f"Warning: failed to generate .env from template: {e!s}")
|
||||
click.echo(f"[警告] 无法从模板生成 .env 文件: {e!s}")
|
||||
else:
|
||||
click.echo("No config.template found; skipping .env generation")
|
||||
click.echo("[提示] 未找到 config.template 文件,跳过 .env 生成")
|
||||
if admin_password is not None:
|
||||
raise click.ClickException(
|
||||
"--admin-password is no longer supported during init. Run 'astrbot conf admin' after initialization.",
|
||||
@@ -105,20 +109,36 @@ async def initialize_astrbot(
|
||||
json.dumps(config, ensure_ascii=False, indent=2),
|
||||
encoding="utf-8-sig",
|
||||
)
|
||||
click.echo(f"Configured dashboard admin username: {effective_admin_username}")
|
||||
click.echo(
|
||||
"Dashboard password is not initialized for interactive use. Run 'astrbot conf admin' before the first login.",
|
||||
)
|
||||
click.echo(f"[OK] Dashboard admin 用户名已设置为: {effective_admin_username}")
|
||||
click.echo()
|
||||
click.echo("!" * 60)
|
||||
click.echo("重要提示:")
|
||||
click.echo(" 1. Dashboard 密码尚未设置!首次登录前必须先设置密码")
|
||||
click.echo(" 2. 设置命令: astrbot conf admin")
|
||||
click.echo(" 3. 登录地址: http://localhost:6185 或 http://服务器IP:6185")
|
||||
click.echo("!" * 60)
|
||||
click.echo()
|
||||
if not backend_only and (
|
||||
yes
|
||||
or click.confirm(
|
||||
"是否需要集成式 WebUI?(个人电脑推荐,服务器不推荐)",
|
||||
"是否需要集成式 WebUI?(个人电脑推荐,服务器推荐使用后端模式)",
|
||||
default=True,
|
||||
)
|
||||
):
|
||||
await DashboardManager().ensure_installed(astrbot_root)
|
||||
else:
|
||||
click.echo("你可以使用在线面版(需支持配置后端)来控制。")
|
||||
click.echo()
|
||||
click.echo("[提示] 你选择了后端模式,可以使用以下方式管理 AstrBot:")
|
||||
click.echo(" - 使用在线 Dashboard: 在浏览器中访问远程服务器的 WebUI")
|
||||
click.echo(" - 使用 CLI 命令: astrbot conf / astrbot plug 等")
|
||||
click.echo()
|
||||
click.echo("!" * 60)
|
||||
click.echo("安全提示:")
|
||||
click.echo(" HTTPS 前端只能安全连接 localhost 的 HTTP 后端")
|
||||
click.echo(" 不支持远程 + HTTP 后端(不安全)")
|
||||
click.echo(" 如需远程访问,请使用 HTTPS 后端或通过反向代理")
|
||||
click.echo("!" * 60)
|
||||
click.echo()
|
||||
|
||||
|
||||
@click.command()
|
||||
@@ -179,7 +199,18 @@ def init(
|
||||
backup_file=backup,
|
||||
yes=True,
|
||||
)
|
||||
click.echo("Done! You can now run 'astrbot run' to start AstrBot")
|
||||
click.echo()
|
||||
click.echo("=" * 60)
|
||||
click.echo("初始化完成!")
|
||||
click.echo("=" * 60)
|
||||
click.echo()
|
||||
click.echo("启动 AstrBot:")
|
||||
click.echo(" 完整模式(含 Dashboard): astrbot run")
|
||||
click.echo(" 仅后端模式: astrbot run --backend-only")
|
||||
click.echo()
|
||||
click.echo("首次使用前请先设置管理员密码:")
|
||||
click.echo(" astrbot conf admin")
|
||||
click.echo()
|
||||
except Timeout:
|
||||
raise click.ClickException(
|
||||
"Cannot acquire lock file. Please check if another instance is running",
|
||||
|
||||
@@ -378,10 +378,34 @@ def run(
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
click.echo("AstrBot is running... (streaming logs)")
|
||||
click.echo()
|
||||
click.echo("=" * 60)
|
||||
click.echo("AstrBot 启动中...")
|
||||
click.echo("=" * 60)
|
||||
click.echo()
|
||||
|
||||
if backend_only:
|
||||
click.echo("Dashboard: https://dash.astrbot.men/")
|
||||
click.echo("Backend: localhost or based on https")
|
||||
click.echo("[模式] 仅后端模式(无本地 Dashboard)")
|
||||
click.echo()
|
||||
click.echo("[提示] 可以通过以下方式访问 WebUI:")
|
||||
click.echo(" - 使用远程服务器的在线 Dashboard")
|
||||
click.echo(" - 地址: http://服务器IP:6185")
|
||||
click.echo()
|
||||
else:
|
||||
dashboard_url = f"http://{host or 'localhost'}:{port or '6185'}"
|
||||
click.echo(f"[模式] 完整模式(含本地 Dashboard)")
|
||||
click.echo()
|
||||
click.echo(f"[Dashboard] 请访问: {dashboard_url}")
|
||||
click.echo()
|
||||
click.echo("!" * 60)
|
||||
click.echo("安全提示:")
|
||||
click.echo(" HTTPS 前端只能安全连接 localhost 的 HTTP 后端")
|
||||
click.echo(" 不支持远程 + HTTP 后端(不安全)")
|
||||
click.echo("!" * 60)
|
||||
click.echo()
|
||||
|
||||
click.echo("正在启动服务...(日志输出中)")
|
||||
click.echo()
|
||||
|
||||
asyncio.run(run_with_logging())
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -26,6 +26,7 @@ from astrbot.core.utils.astrbot_path import get_astrbot_temp_path
|
||||
from astrbot.core.utils.io import download_file, download_image_by_url
|
||||
from astrbot.core.utils.media_utils import ensure_wav
|
||||
from astrbot.core.utils.network_utils import is_connection_error, log_connection_failure
|
||||
from astrbot.core.provider.register import register_provider_adapter
|
||||
|
||||
|
||||
class SuppressNonTextPartsWarning(logging.Filter):
|
||||
|
||||
@@ -45,6 +45,7 @@ from astrbot.core.utils.network_utils import (
|
||||
log_connection_failure,
|
||||
)
|
||||
from astrbot.core.utils.string_utils import normalize_and_dedupe_strings
|
||||
from astrbot.core.provider.register import register_provider_adapter
|
||||
|
||||
|
||||
@register_provider_adapter(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { useCommonStore } from "@/stores/common";
|
||||
import axios from "@/utils/request";
|
||||
import axios, { resolveApiUrl } from "@/utils/request";
|
||||
import { EventSourcePolyfill } from "event-source-polyfill";
|
||||
</script>
|
||||
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
this.eventSource = new EventSourcePolyfill("/api/live-log", {
|
||||
this.eventSource = new EventSourcePolyfill(resolveApiUrl("/api/live-log"), {
|
||||
headers: {
|
||||
Authorization: token ? `Bearer ${token}` : "",
|
||||
},
|
||||
|
||||
@@ -446,10 +446,14 @@ async function checkAndSaveBackend() {
|
||||
if ((platformConfigData.value.platform || []).length > 0) {
|
||||
platformStepState.value = "completed";
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
setApiBaseUrl(originalBase);
|
||||
backendStepState.value = "pending";
|
||||
showError(`Failed to connect to backend: ${error}`);
|
||||
if (error?.response?.status === 401) {
|
||||
showError("无访问权限!请点击右上角退出登录!");
|
||||
} else {
|
||||
showError(`Failed to connect to backend: ${error}`);
|
||||
}
|
||||
} finally {
|
||||
checkingBackend.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user