Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion astrbot/core/agent/tool_image_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def __init__(self) -> None:
self._initialized = True
self._cache_dir = os.path.join(get_astrbot_temp_path(), self.CACHE_DIR_NAME)
os.makedirs(self._cache_dir, exist_ok=True)
logger.debug(f"ToolImageCache initialized, cache dir: {self._cache_dir}")

def _get_file_extension(self, mime_type: str) -> str:
"""Get file extension from MIME type."""
Expand Down
11 changes: 8 additions & 3 deletions astrbot/core/config/astrbot_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ def check_config_integrity(self, refer_conf: dict, conf: dict, path=""):
for key, value in refer_conf.items():
if key not in conf:
# 配置项不存在,插入默认值
logger.info("检查到配置项不存在,已插入默认值")
path_ = path + "." + key if path else key
logger.info("Config key missing; added default.")
new_conf[key] = value
has_new = True
elif conf[key] is None:
Expand Down Expand Up @@ -132,12 +133,16 @@ def check_config_integrity(self, refer_conf: dict, conf: dict, path=""):
# 检查是否存在参考配置中没有的配置项
for key in list(conf.keys()):
if key not in refer_conf:
logger.info("检查到未知配置项,将从当前配置中删除")
path_ = path + "." + key if path else key
logger.info("Config key removed: %s", path_)
Comment thread
Soulter marked this conversation as resolved.
Dismissed
has_new = True

# 顺序不一致也算作变更
if list(conf.keys()) != list(new_conf.keys()):
logger.info("检查到配置项顺序不一致,已重新排序")
if path:
logger.info("Config key order fixed: %s", path)
Comment thread
Soulter marked this conversation as resolved.
Dismissed
else:
logger.info("Config key order fixed")
has_new = True

# 更新原始配置
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/core_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ async def start(self) -> None:
用load加载事件总线和任务并初始化, 执行启动完成事件钩子
"""
self._load()
logger.info("AstrBot 启动完成。")
logger.info("AstrBot started.")

# 执行启动完成事件钩子
handlers = star_handlers_registry.get_handlers_by_event_type(
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/persona_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, db_helper: BaseDatabase, acm: AstrBotConfigManager) -> None:
async def initialize(self) -> None:
self.personas = await self.get_all_personas()
self.get_v3_persona_data()
logger.info(f"已加载 {len(self.personas)} 个人格。")
logger.info("Loaded %s personas.", len(self.personas))

async def get_persona(self, persona_id: str):
"""获取指定 persona 的信息"""
Expand Down
6 changes: 4 additions & 2 deletions astrbot/core/platform/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ async def load_platform(self, platform_config: dict) -> None:
return

logger.info(
f"载入 {platform_config['type']}({platform_config['id']}) 平台适配器 ...",
"Loading IM platform adapter %s(%s) ...",
platform_config["type"],
platform_config["id"],
)
match platform_config["type"]:
case "aiocqhttp":
Expand Down Expand Up @@ -201,7 +203,7 @@ async def load_platform(self, platform_config: dict) -> None:

if platform_config["type"] not in platform_cls_map:
logger.error(
f"未找到适用于 {platform_config['type']}({platform_config['id']}) 平台适配器,请检查是否已经安装或者名称填写错误",
f"Platform adapter not found: {platform_config['type']}({platform_config['id']}).",
)
return
cls_type = platform_cls_map[platform_config["type"]]
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/platform/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def decorator(cls):
)
platform_registry.append(pm)
platform_cls_map[adapter_name] = cls
logger.debug(f"平台适配器 {adapter_name} 已注册")
logger.debug("Platform adapter registered: %s", adapter_name)
return cls

return decorator
Expand Down
12 changes: 7 additions & 5 deletions astrbot/core/provider/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,9 @@ async def load_provider(self, provider_config: dict) -> None:
return

logger.info(
f"载入 {provider_config['type']}({provider_config['id']}) 服务提供商 ...",
"Loading model %s(%s) ...",
provider_config["type"],
provider_config["id"],
)

# 动态导入
Expand All @@ -591,7 +593,7 @@ async def load_provider(self, provider_config: dict) -> None:

if provider_config["type"] not in provider_cls_map:
logger.error(
f"未找到适用于 {provider_config['type']}({provider_config['id']}) 的提供商适配器,请检查是否已经安装或者名称填写错误。已跳过。",
f"Provider adapter not found: {provider_config['type']}({provider_config['id']}). Skipped.",
exc_info=True,
)
return
Expand Down Expand Up @@ -625,7 +627,7 @@ async def load_provider(self, provider_config: dict) -> None:
):
self.curr_stt_provider_inst = inst
logger.info(
f"已选择 {provider_config['type']}({provider_config['id']}) 作为当前语音转文本提供商适配器。",
f"Selected {provider_config['type']}({provider_config['id']}) as default STT provider",
)
if not self.curr_stt_provider_inst:
self.curr_stt_provider_inst = inst
Expand All @@ -648,7 +650,7 @@ async def load_provider(self, provider_config: dict) -> None:
):
self.curr_tts_provider_inst = inst
logger.info(
f"已选择 {provider_config['type']}({provider_config['id']}) 作为当前文本转语音提供商适配器。",
f"Selected {provider_config['type']}({provider_config['id']}) as default TTS provider",
)
if not self.curr_tts_provider_inst:
self.curr_tts_provider_inst = inst
Expand All @@ -674,7 +676,7 @@ async def load_provider(self, provider_config: dict) -> None:
):
self.curr_provider_inst = inst
logger.info(
f"已选择 {provider_config['type']}({provider_config['id']}) 作为当前提供商适配器。",
f"Selected {provider_config['type']}({provider_config['id']}) as default chat model provider",
)
if not self.curr_provider_inst:
self.curr_provider_inst = inst
Expand Down
2 changes: 1 addition & 1 deletion astrbot/core/provider/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def decorator(cls):
)
provider_registry.append(pm)
provider_cls_map[provider_type_name] = pm
logger.debug(f"服务提供商 Provider {provider_type_name} 已注册")
logger.debug("Model provider registered: %s", provider_type_name)
return cls

return decorator
10 changes: 5 additions & 5 deletions astrbot/core/star/star_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,21 +570,21 @@ def _validate_astrbot_version_specifier(
except InvalidSpecifier:
return (
False,
"astrbot_version 格式无效,请使用 PEP 440 版本范围格式,例如 >=4.16,<5",
"Invalid astrbot_version. Use a PEP 440 range, e.g. >=4.16,<5.",
)

try:
current_version = Version(VERSION)
except InvalidVersion:
return (
False,
f"AstrBot 当前版本 {VERSION} 无法被解析,无法校验插件版本范围。",
f"Invalid current AstrBot version: {VERSION}. Cannot check plugin version range.",
)

if not specifier.contains(current_version, prereleases=True):
return (
False,
f"当前 AstrBot 版本为 {VERSION},不满足插件要求的 astrbot_version: {normalized_spec}",
f"AstrBot {VERSION} does not satisfy plugin astrbot_version: {normalized_spec}",
)
return True, None

Expand Down Expand Up @@ -874,7 +874,7 @@ async def load(
if specified_dir_name and root_dir_name != specified_dir_name:
continue

logger.info(f"正在载入插件 {root_dir_name} ...")
logger.info("Loading plugin %s ...", root_dir_name)

# 尝试导入模块
try:
Expand Down Expand Up @@ -993,7 +993,7 @@ async def load(
setattr(metadata.star_cls, "author", p_author)
setattr(metadata.star_cls, "plugin_id", plugin_id)
else:
logger.info(f"插件 {metadata.name} 已被禁用。")
logger.info("Plugin %s is disabled.", metadata.name)

metadata.module = module
metadata.root_dir_name = root_dir_name
Expand Down
19 changes: 11 additions & 8 deletions astrbot/core/utils/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,14 @@ async def download_file(url: str, path: str, show_progress: bool = False) -> Non
) as session:
async with session.get(url, timeout=1800) as resp:
if resp.status != 200:
raise Exception(f"下载文件失败: {resp.status}")
logger.error(
f"Failed to download file from {url}. HTTP status code: {resp.status}"
)
total_size = int(resp.headers.get("content-length", 0))
downloaded_size = 0
start_time = time.time()
if show_progress:
print(f"文件大小: {total_size / 1024:.2f} KB | 文件地址: {url}")
print(f"Downloading: {url} | Size: {total_size / 1024:.2f} KB")
with open(path, "wb") as f:
while True:
chunk = await resp.content.read(8192)
Expand All @@ -157,13 +159,14 @@ async def download_file(url: str, path: str, show_progress: bool = False) -> Non
)
speed = downloaded_size / 1024 / elapsed_time # KB/s
print(
f"\r下载进度: {downloaded_size / total_size:.2%} 速度: {speed:.2f} KB/s",
f"\rProgress: {downloaded_size / total_size:.2%} Speed: {speed:.2f} KB/s",
end="",
)
except (aiohttp.ClientConnectorSSLError, aiohttp.ClientConnectorCertificateError):
# 关闭SSL验证(仅在证书验证失败时作为fallback)
logger.warning(
"SSL 证书验证失败,已关闭 SSL 验证(不安全,仅用于临时下载)。请检查目标服务器的证书配置。"
f"SSL certificate verification failed for {url}. "
"Falling back to unverified connection (CERT_NONE). "
)
logger.warning(
f"SSL certificate verification failed for {url}. "
Expand All @@ -180,7 +183,7 @@ async def download_file(url: str, path: str, show_progress: bool = False) -> Non
downloaded_size = 0
start_time = time.time()
if show_progress:
print(f"文件大小: {total_size / 1024:.2f} KB | 文件地址: {url}")
print(f"Size: {total_size / 1024:.2f} KB | URL: {url}")
with open(path, "wb") as f:
while True:
chunk = await resp.content.read(8192)
Expand All @@ -192,7 +195,7 @@ async def download_file(url: str, path: str, show_progress: bool = False) -> Non
elapsed_time = time.time() - start_time
speed = downloaded_size / 1024 / elapsed_time # KB/s
print(
f"\r下载进度: {downloaded_size / total_size:.2%} 速度: {speed:.2f} KB/s",
f"\rProgress: {downloaded_size / total_size:.2%} Speed: {speed:.2f} KB/s",
end="",
)
if show_progress:
Expand Down Expand Up @@ -252,7 +255,7 @@ async def download_dashboard(
ver_name = "latest" if latest else version
dashboard_release_url = f"https://astrbot-registry.soulter.top/download/astrbot-dashboard/{ver_name}/dist.zip"
logger.info(
f"准备下载指定发行版本的 AstrBot WebUI 文件: {dashboard_release_url}",
f"Downloading AstrBot WebUI from {dashboard_release_url}",
)
try:
await download_file(
Expand All @@ -274,7 +277,7 @@ async def download_dashboard(
)
else:
url = f"https://github.com/AstrBotDevs/astrbot-release-harbour/releases/download/release-{version}/dist.zip"
logger.info(f"准备下载指定版本的 AstrBot WebUI: {url}")
logger.info(f"Downloading AstrBot WebUI from {url}")
if proxy:
url = f"{proxy}/{url}"
await download_file(url, str(zip_path), show_progress=True)
Expand Down
24 changes: 12 additions & 12 deletions astrbot/dashboard/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,20 +322,20 @@ def _resolve_dashboard_ssl_config(

if not cert_file or not key_file:
logger.warning(
"dashboard.ssl.enable 已启用,但未同时配置 cert_file key_fileSSL 配置将不会生效。",
"dashboard.ssl.enable is set, but cert_file or key_file is missing. SSL disabled.",
)
return False, {}

cert_path = Path(cert_file).expanduser()
key_path = Path(key_file).expanduser()
if not cert_path.is_file():
logger.warning(
f"dashboard.ssl.enable 已启用,但 SSL 证书文件不存在: {cert_path}SSL 配置将不会生效。",
f"dashboard.ssl.enable is set, but cert file is missing: {cert_path}. SSL disabled.",
)
return False, {}
if not key_path.is_file():
logger.warning(
f"dashboard.ssl.enable 已启用,但 SSL 私钥文件不存在: {key_path}SSL 配置将不会生效。",
f"dashboard.ssl.enable is set, but key file is missing: {key_path}. SSL disabled.",
)
return False, {}

Expand All @@ -348,7 +348,7 @@ def _resolve_dashboard_ssl_config(
ca_path = Path(ca_certs).expanduser()
if not ca_path.is_file():
logger.warning(
f"dashboard.ssl.enable 已启用,但 SSL CA 证书文件不存在: {ca_path}SSL 配置将不会生效。",
f"dashboard.ssl.enable is set, but CA cert file is missing: {ca_path}. SSL disabled.",
)
return False, {}
resolved_ssl_config["ca_certs"] = str(ca_path.resolve())
Expand Down Expand Up @@ -385,13 +385,13 @@ def run(self):
scheme = "https" if ssl_enable else "http"

if not enable:
logger.info("WebUI 已被禁用")
logger.info("WebUI disabled.")
return None

logger.info(f"正在启动 WebUI, 监听地址: {scheme}://{host}:{port}")
logger.info("Starting WebUI at %s://%s:%s", scheme, host, port)
if host == "0.0.0.0":
logger.info(
"提示: WebUI 将监听所有网络接口,请注意安全。(可在 data/cmd_config.json 中配置 dashboard.host 以修改 host)",
"WebUI listens on all interfaces. Check security. Set dashboard.host in data/cmd_config.json to change it.",
)

if host not in ["localhost", "127.0.0.1"]:
Expand All @@ -415,16 +415,16 @@ def run(self):

raise Exception(f"端口 {port} 已被占用")

parts = [f"\n ✨✨✨\n AstrBot v{VERSION} WebUI 已启动,可访问\n\n"]
parts.append(f" ➜ 本地: {scheme}://localhost:{port}\n")
parts = [f"\n ✨✨✨\n AstrBot v{VERSION} WebUI is ready\n\n"]
parts.append(f" ➜ Local: {scheme}://localhost:{port}\n")
for ip in ip_addr:
parts.append(f" ➜ 网络: {scheme}://{ip}:{port}\n")
parts.append(" ➜ 默认用户名和密码: astrbot\n ✨✨✨\n")
parts.append(f" ➜ Network: {scheme}://{ip}:{port}\n")
parts.append(" ➜ Default username/password: astrbot / astrbot\n ✨✨✨\n")
display = "".join(parts)

if not ip_addr:
display += (
"可在 data/cmd_config.json 中配置 dashboard.host 以便远程访问。\n"
"Set dashboard.host in data/cmd_config.json to enable remote access.\n"
)

logger.info(display)
Expand Down
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ venv/
node_modules/
.vitepress/cache
*dist
scripts/deploy-cli.sh
scripts/deploy-cli.ps1
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"scripts": {
"docs:dev": "vitepress dev --host",
"docs:build": "vitepress build",
"docs:build": "node scripts/copy-deploy-cli.mjs && vitepress build",
"docs:preview": "vitepress preview"
},
"devDependencies": {
Expand Down
21 changes: 21 additions & 0 deletions docs/scripts/copy-deploy-cli.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { chmod, copyFile, mkdir } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const scriptDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(scriptDir, "../..");

const files = [
{ name: "deploy-cli.sh", mode: 0o755 },
{ name: "deploy-cli.ps1", mode: 0o644 },
];

await mkdir(scriptDir, { recursive: true });

for (const file of files) {
const source = resolve(repoRoot, "scripts", file.name);
const target = resolve(scriptDir, file.name);
await copyFile(source, target);
await chmod(target, file.mode);
console.log(`Copied ${file.name} to docs/scripts/`);
}
3 changes: 1 addition & 2 deletions docs/zh/deploy/astrbot/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
>
> 以下教程默认您的设备上已经安装 Python,并且版本 `>=3.10`


## 下载/克隆仓库

如果你的电脑上安装了 `git`,你可以通过以下命令来下载源码:

```bash
git clone https://github.com/AstrBotDevs/AstrBot.git
git clone https://github.com/AstrBotDevs/AstrBot
# 上面的代码默认会拉取最新的提交的源码,如果你需要拉取最新稳定发行版本的源码,可以使用以下命令:
# git clone --depth=1 --branch $(git ls-remote --tags --sort='-v:refname' https://github.com/AstrBotDevs/AstrBot.git | head -n1 | awk -F/ '{print $3}') https://github.com/AstrBotDevs/AstrBot.git
cd AstrBot
Expand Down
Loading
Loading