fix(onebot): 解决了跨容器路径访问难题: 由于您的 AstrBot 和 NapCat 可能运行在不同的容器或环境中,NapCat 无法直接访问 AstrBot 生成的本地临时文件(如 //AstrBot/data/temp/...),导致报错 ENOENT: no such file or directory。 现在,插件在调用 OneBot 发送图片或上传文件前,会自动将本地文件转为 Base64 编码数据。这样,图片数据将直接通过协议传输,彻底摆脱了对物理磁盘路径共享的依赖。

This commit is contained in:
SXP-Simon
2026-02-21 19:30:51 +08:00
committed by Helian Nuits
parent 7f46a6d797
commit 750470d677
@@ -6,6 +6,7 @@ OneBot v11 平台适配器
import asyncio import asyncio
import base64 import base64
import os
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any from typing import Any
@@ -453,7 +454,18 @@ class OneBotAdapter(PlatformAdapter):
elif image_path.startswith("base64://"): elif image_path.startswith("base64://"):
file_str = image_path file_str = image_path
else: else:
file_str = f"file:///{image_path}" # 尝试转换为 Base64,解决跨容器路径不一致导致的 1200 错误
b64_str = await self._get_base64_from_file(image_path)
if b64_str:
logger.debug(
f"已将本地图片转换为 Base64 发送: {image_path[:50]}..."
)
file_str = b64_str
else:
logger.warning(
f"无法读取本地图片,将尝试使用原始路径回退: {image_path}"
)
file_str = f"file:///{image_path}"
message.append({"type": "image", "data": {"file": file_str}}) message.append({"type": "image", "data": {"file": file_str}})
@@ -485,11 +497,17 @@ class OneBotAdapter(PlatformAdapter):
bool: 上传任务启动是否成功 bool: 上传任务启动是否成功
""" """
try: try:
# 同样优先使用 Base64 发送文件,适配跨容器环境
file_str = await self._get_base64_from_file(file_path)
if not file_str:
logger.warning(f"无法读取本地文件进行 Base64 编码: {file_path}")
file_str = file_path # 回退
await self.bot.call_action( await self.bot.call_action(
"upload_group_file", "upload_group_file",
group_id=int(group_id), group_id=int(group_id),
file=file_path, file=file_str,
name=filename or file_path.replace("\\", "/").split("/")[-1], name=filename or os.path.basename(file_path),
) )
return True return True
except Exception as e: except Exception as e:
@@ -612,6 +630,31 @@ class OneBotAdapter(PlatformAdapter):
except Exception: except Exception:
return None return None
async def _get_base64_from_file(self, file_path: str) -> str | None:
"""
读取本地文件并返回 Base64 编码字符串。
Args:
file_path: 本地文件绝对路径
Returns:
str | None: base64://... 格式的字符串,读取失败返回 None
"""
try:
import os
if not os.path.exists(file_path):
logger.error(f"文件不存在,无法读取 Base64: {file_path}")
return None
with open(file_path, "rb") as f:
data = f.read()
b64 = base64.b64encode(data).decode("utf-8")
return f"base64://{b64}"
except Exception as e:
logger.error(f"读取文件并转换 Base64 失败: {e}")
return None
# ==================== IAvatarRepository 实现 ==================== # ==================== IAvatarRepository 实现 ====================
async def get_user_avatar_url( async def get_user_avatar_url(
@@ -863,7 +906,7 @@ class OneBotAdapter(PlatformAdapter):
""" """
try: try:
# 如果没有 album_id,尝试获取该群的第一个相册作为默认目标 # 如果没有 album_id,尝试获取该群的第一个相册作为默认目标
# 注意:某些 API (如 upload_image_to_qun_album) 强制要求 album_id # 注意:某些 API (如 upload_image_to_qun_album) 强制要求 album_id 且不能为空
if not album_id: if not album_id:
albums = await self.get_group_album_list(group_id) albums = await self.get_group_album_list(group_id)
if albums: if albums:
@@ -875,12 +918,22 @@ class OneBotAdapter(PlatformAdapter):
f"未指定有效的相册,自动选择默认相册 ID: {album_id}" f"未指定有效的相册,自动选择默认相册 ID: {album_id}"
) )
if not album_id:
logger.info(
f"{group_id} 未找到任何有效相册,且未指定相册名,跳过相册上传以防止后端错误。"
)
return False
# 尝试转换为 Base64 以保证跨容器成功率 (兼容性取决于 OneBot 实现)
b64_file = await self._get_base64_from_file(image_path)
upload_path = b64_file if b64_file else image_path
# 策略 1: 尝试 upload_image_to_qun_album (参考 astrbot_plugin_qun_album) # 策略 1: 尝试 upload_image_to_qun_album (参考 astrbot_plugin_qun_album)
try: try:
# 注意:NapCat 的某些实现强制要求 album_id 字段存在 # 注意:NapCat 的某些实现强制要求 album_id 字段存在
params = { params = {
"group_id": int(group_id), "group_id": int(group_id),
"file": image_path, "file": upload_path,
"album_id": str(album_id or ""), # 保证字段存在 "album_id": str(album_id or ""), # 保证字段存在
} }
if album_name: if album_name:
@@ -902,7 +955,7 @@ class OneBotAdapter(PlatformAdapter):
params = { params = {
"group_id": int(group_id), "group_id": int(group_id),
"file": image_path, "file": upload_path,
"album_id": str(album_id or ""), "album_id": str(album_id or ""),
} }