From 26d6d1b36ff967fba14e62579b2a1a5b8310e9cb Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Wed, 18 Mar 2026 17:38:27 +0800 Subject: [PATCH] fix: resolve ruff check issues --- astrbot/core/backup/importer.py | 51 ++++++++++++------- astrbot/core/computer/booters/boxlite.py | 5 +- astrbot/core/computer/booters/shipyard_neo.py | 22 ++++---- .../sources/webchat/message_parts_helper.py | 9 ++-- .../core/provider/sources/volcengine_tts.py | 9 ++-- astrbot/core/utils/media_utils.py | 31 +++++------ astrbot/core/utils/tencent_record_helper.py | 27 ++++++---- astrbot/dashboard/routes/backup.py | 48 ++++++++--------- astrbot/dashboard/routes/knowledge_base.py | 5 +- astrbot/dashboard/routes/live_chat.py | 7 +-- astrbot/dashboard/routes/plugin.py | 18 +++---- astrbot/dashboard/routes/skills.py | 9 ++-- 12 files changed, 134 insertions(+), 107 deletions(-) diff --git a/astrbot/core/backup/importer.py b/astrbot/core/backup/importer.py index b51c7d956..53fb00248 100644 --- a/astrbot/core/backup/importer.py +++ b/astrbot/core/backup/importer.py @@ -16,6 +16,7 @@ from datetime import datetime, timezone from pathlib import Path from typing import TYPE_CHECKING, Any +import anyio from sqlalchemy import delete from astrbot.core import logger @@ -364,7 +365,7 @@ class AstrBotImporter: """ result = ImportResult() - if not os.path.exists(zip_path): + if not await anyio.Path(zip_path).exists(): result.add_error(f"备份文件不存在: {zip_path}") return result @@ -446,12 +447,12 @@ class AstrBotImporter: try: config_content = zf.read("config/cmd_config.json") # 备份现有配置 - if os.path.exists(self.config_path): + if await anyio.Path(self.config_path).exists(): backup_path = f"{self.config_path}.bak" shutil.copy2(self.config_path, backup_path) - with open(self.config_path, "wb") as f: - f.write(config_content) + async with await anyio.open_file(self.config_path, "wb") as f: + await f.write(config_content) result.imported_files["config"] = 1 except Exception as e: result.add_warning(f"导入配置文件失败: {e}") @@ -753,8 +754,10 @@ class AstrBotImporter: if faiss_path in zf.namelist(): try: target_path = kb_dir / "index.faiss" - with zf.open(faiss_path) as src, open(target_path, "wb") as dst: - dst.write(src.read()) + with zf.open(faiss_path) as src: + content = src.read() + async with await anyio.open_file(target_path, "wb") as dst: + await dst.write(content) except Exception as e: result.add_warning(f"导入知识库 {kb_id} 的 FAISS 索引失败: {e}") @@ -765,9 +768,13 @@ class AstrBotImporter: try: rel_path = name[len(media_prefix) :] target_path = kb_dir / rel_path - target_path.parent.mkdir(parents=True, exist_ok=True) - with zf.open(name) as src, open(target_path, "wb") as dst: - dst.write(src.read()) + await anyio.Path(target_path.parent).mkdir( + parents=True, exist_ok=True + ) + with zf.open(name) as src: + content = src.read() + async with await anyio.open_file(target_path, "wb") as dst: + await dst.write(content) except Exception as e: result.add_warning(f"导入媒体文件 {name} 失败: {e}") @@ -827,9 +834,13 @@ class AstrBotImporter: else: target_path = attachments_dir / os.path.basename(name) - target_path.parent.mkdir(parents=True, exist_ok=True) - with zf.open(name) as src, open(target_path, "wb") as dst: - dst.write(src.read()) + await anyio.Path(target_path.parent).mkdir( + parents=True, exist_ok=True + ) + with zf.open(name) as src: + content = src.read() + async with await anyio.open_file(target_path, "wb") as dst: + await dst.write(content) count += 1 except Exception as e: logger.warning(f"导入附件 {name} 失败: {e}") @@ -885,15 +896,15 @@ class AstrBotImporter: continue # 备份现有目录(如果存在) - if target_dir.exists(): + if await anyio.Path(target_dir).exists(): backup_path = Path(f"{target_dir}.bak") - if backup_path.exists(): + if await anyio.Path(backup_path).exists(): shutil.rmtree(backup_path) shutil.move(str(target_dir), str(backup_path)) logger.debug(f"已备份现有目录 {target_dir} 到 {backup_path}") # 创建目标目录 - target_dir.mkdir(parents=True, exist_ok=True) + await anyio.Path(target_dir).mkdir(parents=True, exist_ok=True) # 解压文件 for name in dir_files: @@ -904,10 +915,14 @@ class AstrBotImporter: continue target_path = target_dir / rel_path - target_path.parent.mkdir(parents=True, exist_ok=True) + await anyio.Path(target_path.parent).mkdir( + parents=True, exist_ok=True + ) - with zf.open(name) as src, open(target_path, "wb") as dst: - dst.write(src.read()) + with zf.open(name) as src: + content = src.read() + async with await anyio.open_file(target_path, "wb") as dst: + await dst.write(content) file_count += 1 except Exception as e: result.add_warning(f"导入文件 {name} 失败: {e}") diff --git a/astrbot/core/computer/booters/boxlite.py b/astrbot/core/computer/booters/boxlite.py index 01a29fa8c..f1e17d261 100644 --- a/astrbot/core/computer/booters/boxlite.py +++ b/astrbot/core/computer/booters/boxlite.py @@ -6,6 +6,7 @@ import random from typing import TYPE_CHECKING, Any import aiohttp +import anyio import boxlite from shipyard.filesystem import FileSystemComponent as ShipyardFileSystemComponent from shipyard.python import PythonComponent as ShipyardPythonComponent @@ -52,8 +53,8 @@ class MockShipyardSandboxClient: try: # Read file content - with open(path, "rb") as f: - file_content = f.read() + async with await anyio.open_file(path, "rb") as f: + file_content = await f.read() # Create multipart form data data = aiohttp.FormData() diff --git a/astrbot/core/computer/booters/shipyard_neo.py b/astrbot/core/computer/booters/shipyard_neo.py index 9db855430..ac9f0b26a 100644 --- a/astrbot/core/computer/booters/shipyard_neo.py +++ b/astrbot/core/computer/booters/shipyard_neo.py @@ -5,6 +5,8 @@ import os import shlex from typing import TYPE_CHECKING, Any, cast +import anyio + from astrbot.api import logger if TYPE_CHECKING: @@ -37,7 +39,7 @@ class NeoPythonComponent(PythonComponent): self, code: str, kernel_id: str | None = None, - timeout: int = 30, + timeout: int = 30, # noqa: ASYNC109 silent: bool = False, ) -> dict[str, Any]: _ = kernel_id # Bay runtime does not expose kernel_id in current SDK. @@ -79,7 +81,7 @@ class NeoShellComponent(ShellComponent): command: str, cwd: str | None = None, env: dict[str, str] | None = None, - timeout: int | None = 30, + timeout: int | None = 30, # noqa: ASYNC109 shell: bool = True, background: bool = False, ) -> dict[str, Any]: @@ -196,7 +198,7 @@ class NeoBrowserComponent(BrowserComponent): async def exec( self, cmd: str, - timeout: int = 30, + timeout: int = 30, # noqa: ASYNC109 description: str | None = None, tags: str | None = None, learn: bool = False, @@ -215,7 +217,7 @@ class NeoBrowserComponent(BrowserComponent): async def exec_batch( self, commands: list[str], - timeout: int = 60, + timeout: int = 60, # noqa: ASYNC109 stop_on_error: bool = True, description: str | None = None, tags: str | None = None, @@ -236,7 +238,7 @@ class NeoBrowserComponent(BrowserComponent): async def run_skill( self, skill_key: str, - timeout: int = 60, + timeout: int = 60, # noqa: ASYNC109 stop_on_error: bool = True, include_trace: bool = False, description: str | None = None, @@ -480,8 +482,8 @@ class ShipyardNeoBooter(ComputerBooter): async def upload_file(self, path: str, file_name: str) -> dict: if self._sandbox is None: raise RuntimeError("ShipyardNeoBooter is not initialized.") - with open(path, "rb") as f: - content = f.read() + async with await anyio.open_file(path, "rb") as f: + content = await f.read() remote_path = file_name.lstrip("/") await self._sandbox.filesystem.upload(remote_path, content) logger.info( @@ -500,9 +502,9 @@ class ShipyardNeoBooter(ComputerBooter): content = await self._sandbox.filesystem.download(remote_path.lstrip("/")) local_dir = os.path.dirname(local_path) if local_dir: - os.makedirs(local_dir, exist_ok=True) - with open(local_path, "wb") as f: - f.write(cast(bytes, content)) + await anyio.Path(local_dir).mkdir(parents=True, exist_ok=True) + async with await anyio.open_file(local_path, "wb") as f: + await f.write(cast(bytes, content)) logger.info( "[Computer] file_download booter=shipyard_neo remote_path=%s local_path=%s", remote_path, diff --git a/astrbot/core/platform/sources/webchat/message_parts_helper.py b/astrbot/core/platform/sources/webchat/message_parts_helper.py index 9c65f9e6a..07b90de0a 100644 --- a/astrbot/core/platform/sources/webchat/message_parts_helper.py +++ b/astrbot/core/platform/sources/webchat/message_parts_helper.py @@ -141,14 +141,15 @@ async def parse_webchat_message_parts( continue file_path = Path(str(path)) - if verify_media_path_exists and not file_path.exists(): + if verify_media_path_exists and not await anyio.Path(file_path).exists(): if strict: raise ValueError(f"file not found: {file_path!s}") continue - file_path_str = ( - str(file_path.resolve()) if verify_media_path_exists else str(file_path) - ) + if verify_media_path_exists: + file_path_str = str(await anyio.Path(file_path).resolve()) + else: + file_path_str = str(file_path) has_content = True if part_type == "image": components.append(Image.fromFileSystem(file_path_str)) diff --git a/astrbot/core/provider/sources/volcengine_tts.py b/astrbot/core/provider/sources/volcengine_tts.py index 349815907..6125e4b87 100644 --- a/astrbot/core/provider/sources/volcengine_tts.py +++ b/astrbot/core/provider/sources/volcengine_tts.py @@ -1,4 +1,3 @@ -import asyncio import base64 import json import os @@ -6,6 +5,7 @@ import traceback import uuid import aiohttp +import anyio from astrbot import logger from astrbot.core.utils.astrbot_path import get_astrbot_temp_path @@ -100,11 +100,8 @@ class ProviderVolcengineTTS(TTSProvider): f"volcengine_tts_{uuid.uuid4()}.mp3", ) - loop = asyncio.get_running_loop() - await loop.run_in_executor( - None, - lambda: open(file_path, "wb").write(audio_data), - ) + async with await anyio.open_file(file_path, "wb") as audio_file: + await audio_file.write(audio_data) return file_path error_msg = resp_data.get("message", "未知错误") diff --git a/astrbot/core/utils/media_utils.py b/astrbot/core/utils/media_utils.py index 8d833514f..66ec110ad 100644 --- a/astrbot/core/utils/media_utils.py +++ b/astrbot/core/utils/media_utils.py @@ -7,7 +7,8 @@ import asyncio import os import subprocess import uuid -from pathlib import Path + +import anyio from astrbot import logger from astrbot.core.utils.astrbot_path import get_astrbot_temp_path @@ -78,7 +79,7 @@ async def convert_audio_to_opus(audio_path: str, output_path: str | None = None) # 生成输出文件路径 if output_path is None: temp_dir = get_astrbot_temp_path() - os.makedirs(temp_dir, exist_ok=True) + await anyio.Path(temp_dir).mkdir(parents=True, exist_ok=True) output_path = os.path.join(temp_dir, f"media_audio_{uuid.uuid4().hex}.opus") try: @@ -108,9 +109,9 @@ async def convert_audio_to_opus(audio_path: str, output_path: str | None = None) if process.returncode != 0: # 清理可能已生成但无效的临时文件 - if output_path and os.path.exists(output_path): + if output_path and await anyio.Path(output_path).exists(): try: - os.remove(output_path) + await anyio.Path(output_path).unlink() logger.debug( f"[Media Utils] 已清理失败的opus输出文件: {output_path}" ) @@ -157,7 +158,7 @@ async def convert_video_format( # 生成输出文件路径 if output_path is None: temp_dir = get_astrbot_temp_path() - os.makedirs(temp_dir, exist_ok=True) + await anyio.Path(temp_dir).mkdir(parents=True, exist_ok=True) output_path = os.path.join( temp_dir, f"media_video_{uuid.uuid4().hex}.{output_format}", @@ -183,9 +184,9 @@ async def convert_video_format( if process.returncode != 0: # 清理可能已生成但无效的临时文件 - if output_path and os.path.exists(output_path): + if output_path and await anyio.Path(output_path).exists(): try: - os.remove(output_path) + await anyio.Path(output_path).unlink() logger.debug( f"[Media Utils] 已清理失败的{output_format}输出文件: {output_path}" ) @@ -230,8 +231,8 @@ async def convert_audio_format( return audio_path if output_path is None: - temp_dir = Path(get_astrbot_temp_path()) - temp_dir.mkdir(parents=True, exist_ok=True) + temp_dir = anyio.Path(get_astrbot_temp_path()) + await temp_dir.mkdir(parents=True, exist_ok=True) output_path = str(temp_dir / f"media_audio_{uuid.uuid4().hex}.{output_format}") args = ["ffmpeg", "-y", "-i", audio_path] @@ -249,9 +250,9 @@ async def convert_audio_format( ) _, stderr = await process.communicate() if process.returncode != 0: - if output_path and os.path.exists(output_path): + if output_path and await anyio.Path(output_path).exists(): try: - os.remove(output_path) + await anyio.Path(output_path).unlink() except OSError as e: logger.warning(f"[Media Utils] 清理失败的音频输出文件时出错: {e}") error_msg = stderr.decode() if stderr else "未知错误" @@ -286,8 +287,8 @@ async def extract_video_cover( ) -> str: """从视频中提取封面图(JPG)。""" if output_path is None: - temp_dir = Path(get_astrbot_temp_path()) - temp_dir.mkdir(parents=True, exist_ok=True) + temp_dir = anyio.Path(get_astrbot_temp_path()) + await temp_dir.mkdir(parents=True, exist_ok=True) output_path = str(temp_dir / f"media_cover_{uuid.uuid4().hex}.jpg") try: @@ -306,9 +307,9 @@ async def extract_video_cover( ) _, stderr = await process.communicate() if process.returncode != 0: - if output_path and os.path.exists(output_path): + if output_path and await anyio.Path(output_path).exists(): try: - os.remove(output_path) + await anyio.Path(output_path).unlink() except OSError as e: logger.warning(f"[Media Utils] 清理失败的视频封面文件时出错: {e}") error_msg = stderr.decode() if stderr else "未知错误" diff --git a/astrbot/core/utils/tencent_record_helper.py b/astrbot/core/utils/tencent_record_helper.py index f342484bd..df4801185 100644 --- a/astrbot/core/utils/tencent_record_helper.py +++ b/astrbot/core/utils/tencent_record_helper.py @@ -6,6 +6,8 @@ import tempfile import wave from io import BytesIO +import anyio + from astrbot.core import logger from astrbot.core.utils.astrbot_path import get_astrbot_temp_path @@ -13,8 +15,8 @@ from astrbot.core.utils.astrbot_path import get_astrbot_temp_path async def tencent_silk_to_wav(silk_path: str, output_path: str) -> str: import pysilk - with open(silk_path, "rb") as f: - input_data = f.read() + async with await anyio.open_file(silk_path, "rb") as f: + input_data = await f.read() if input_data.startswith(b"\x02"): input_data = input_data[1:] input_io = BytesIO(input_data) @@ -97,7 +99,10 @@ async def convert_to_pcm_wav(input_path: str, output_path: str) -> str: logger.debug(f"[FFmpeg] stderr: {stderr.decode().strip()}") logger.info(f"[FFmpeg] return code: {p.returncode}") - if os.path.exists(output_path) and os.path.getsize(output_path) > 0: + if ( + await anyio.Path(output_path).exists() + and (await anyio.Path(output_path).stat()).st_size > 0 + ): return output_path raise RuntimeError("生成的WAV文件不存在或为空") @@ -118,7 +123,7 @@ async def audio_to_tencent_silk_base64(audio_path: str) -> tuple[str, float]: raise Exception("未安装 pilk: pip install pilk") from e temp_dir = get_astrbot_temp_path() - os.makedirs(temp_dir, exist_ok=True) + await anyio.Path(temp_dir).mkdir(parents=True, exist_ok=True) # 是否需要转换为 WAV ext = os.path.splitext(audio_path)[1].lower() @@ -132,7 +137,7 @@ async def audio_to_tencent_silk_base64(audio_path: str) -> tuple[str, float]: if ext != ".wav": await convert_to_pcm_wav(audio_path, temp_wav) # 删除原文件 - os.remove(audio_path) + await anyio.Path(audio_path).unlink() wav_path = temp_wav else: wav_path = audio_path @@ -156,13 +161,13 @@ async def audio_to_tencent_silk_base64(audio_path: str) -> tuple[str, float]: tencent=True, ) - with open(silk_path, "rb") as f: - silk_bytes = await asyncio.to_thread(f.read) + async with await anyio.open_file(silk_path, "rb") as f: + silk_bytes = await f.read() silk_b64 = base64.b64encode(silk_bytes).decode("utf-8") return silk_b64, duration # 已是秒 finally: - if os.path.exists(wav_path) and wav_path != audio_path: - os.remove(wav_path) - if os.path.exists(silk_path): - os.remove(silk_path) + if await anyio.Path(wav_path).exists() and wav_path != audio_path: + await anyio.Path(wav_path).unlink() + if await anyio.Path(silk_path).exists(): + await anyio.Path(silk_path).unlink() diff --git a/astrbot/dashboard/routes/backup.py b/astrbot/dashboard/routes/backup.py index ecc5dbfc8..232156b18 100644 --- a/astrbot/dashboard/routes/backup.py +++ b/astrbot/dashboard/routes/backup.py @@ -10,8 +10,8 @@ import traceback import uuid import zipfile from datetime import datetime -from pathlib import Path +import anyio import jwt from quart import request, send_file @@ -240,7 +240,7 @@ class BackupRoute(Route): if upload_id in self.upload_sessions: session = self.upload_sessions[upload_id] chunk_dir = session.get("chunk_dir") - if chunk_dir and os.path.exists(chunk_dir): + if chunk_dir and await anyio.Path(chunk_dir).exists(): try: shutil.rmtree(chunk_dir) except Exception as e: @@ -283,7 +283,7 @@ class BackupRoute(Route): page_size = request.args.get("page_size", 20, type=int) # 确保备份目录存在 - Path(self.backup_dir).mkdir(parents=True, exist_ok=True) + await anyio.Path(self.backup_dir).mkdir(parents=True, exist_ok=True) # 获取所有备份文件 backup_files = [] @@ -293,7 +293,7 @@ class BackupRoute(Route): continue file_path = os.path.join(self.backup_dir, filename) - if not os.path.isfile(file_path): + if not await anyio.Path(file_path).is_file(): continue # 读取 manifest.json 获取备份信息 @@ -403,7 +403,7 @@ class BackupRoute(Route): result={ "filename": os.path.basename(zip_path), "path": zip_path, - "size": os.path.getsize(zip_path), + "size": (await anyio.Path(zip_path).stat()).st_size, }, ) except Exception as e: @@ -437,7 +437,7 @@ class BackupRoute(Route): unique_filename = generate_unique_filename(safe_filename) # 保存上传的文件 - Path(self.backup_dir).mkdir(parents=True, exist_ok=True) + await anyio.Path(self.backup_dir).mkdir(parents=True, exist_ok=True) zip_path = os.path.join(self.backup_dir, unique_filename) await file.save(zip_path) @@ -451,7 +451,7 @@ class BackupRoute(Route): { "filename": unique_filename, "original_filename": file.filename, - "size": os.path.getsize(zip_path), + "size": (await anyio.Path(zip_path).stat()).st_size, } ) .__dict__ @@ -499,7 +499,7 @@ class BackupRoute(Route): # 创建分片存储目录 chunk_dir = os.path.join(self.chunks_dir, upload_id) - Path(chunk_dir).mkdir(parents=True, exist_ok=True) + await anyio.Path(chunk_dir).mkdir(parents=True, exist_ok=True) # 清洗文件名 safe_filename = secure_filename(filename) @@ -685,22 +685,24 @@ class BackupRoute(Route): chunk_dir = session["chunk_dir"] filename = session["filename"] - Path(self.backup_dir).mkdir(parents=True, exist_ok=True) + await anyio.Path(self.backup_dir).mkdir(parents=True, exist_ok=True) output_path = os.path.join(self.backup_dir, filename) try: - with open(output_path, "wb") as outfile: + async with await anyio.open_file(output_path, "wb") as outfile: for i in range(total): chunk_path = os.path.join(chunk_dir, f"{i}.part") - with open(chunk_path, "rb") as chunk_file: + async with await anyio.open_file( + chunk_path, "rb" + ) as chunk_file: # 分块读取,避免内存溢出 while True: - data_block = chunk_file.read(8192) + data_block = await chunk_file.read(8192) if not data_block: break - outfile.write(data_block) + await outfile.write(data_block) - file_size = os.path.getsize(output_path) + file_size = (await anyio.Path(output_path).stat()).st_size # 标记备份为上传来源(修改 manifest.json 中的 origin 字段) self._mark_backup_as_uploaded(output_path) @@ -725,8 +727,8 @@ class BackupRoute(Route): ) except Exception as e: # 如果合并失败,删除不完整的文件 - if os.path.exists(output_path): - os.remove(output_path) + if await anyio.Path(output_path).exists(): + await anyio.Path(output_path).unlink() raise e except Exception as e: @@ -787,7 +789,7 @@ class BackupRoute(Route): return Response().error("无效的文件名").__dict__ zip_path = os.path.join(self.backup_dir, filename) - if not os.path.exists(zip_path): + if not await anyio.Path(zip_path).exists(): return Response().error(f"备份文件不存在: {filename}").__dict__ # 获取知识库管理器(用于构造 importer) @@ -841,7 +843,7 @@ class BackupRoute(Route): return Response().error("无效的文件名").__dict__ zip_path = os.path.join(self.backup_dir, filename) - if not os.path.exists(zip_path): + if not await anyio.Path(zip_path).exists(): return Response().error(f"备份文件不存在: {filename}").__dict__ # 生成任务ID @@ -998,7 +1000,7 @@ class BackupRoute(Route): return Response().error("无效的文件名").__dict__ file_path = os.path.join(self.backup_dir, filename) - if not os.path.exists(file_path): + if not await anyio.Path(file_path).exists(): return Response().error("备份文件不存在").__dict__ return await send_file( @@ -1029,10 +1031,10 @@ class BackupRoute(Route): return Response().error("无效的文件名").__dict__ file_path = os.path.join(self.backup_dir, filename) - if not os.path.exists(file_path): + if not await anyio.Path(file_path).exists(): return Response().error("备份文件不存在").__dict__ - os.remove(file_path) + await anyio.Path(file_path).unlink() return Response().ok(message="删除备份成功").__dict__ except Exception as e: logger.error(f"删除备份失败: {e}") @@ -1077,12 +1079,12 @@ class BackupRoute(Route): # 检查原文件是否存在 old_path = os.path.join(self.backup_dir, filename) - if not os.path.exists(old_path): + if not await anyio.Path(old_path).exists(): return Response().error("备份文件不存在").__dict__ # 检查新文件名是否已存在 new_path = os.path.join(self.backup_dir, new_filename) - if os.path.exists(new_path): + if await anyio.Path(new_path).exists(): return Response().error(f"文件名 '{new_filename}' 已存在").__dict__ # 执行重命名 diff --git a/astrbot/dashboard/routes/knowledge_base.py b/astrbot/dashboard/routes/knowledge_base.py index f0ac5d43d..5d2bf2473 100644 --- a/astrbot/dashboard/routes/knowledge_base.py +++ b/astrbot/dashboard/routes/knowledge_base.py @@ -7,6 +7,7 @@ import uuid from typing import Any import aiofiles +import anyio from quart import request from astrbot.core import logger @@ -729,8 +730,8 @@ class KnowledgeBaseRoute(Route): ) finally: # 清理临时文件 - if os.path.exists(temp_file_path): - os.remove(temp_file_path) + if await anyio.Path(temp_file_path).exists(): + await anyio.Path(temp_file_path).unlink() # 获取知识库 kb_helper = await kb_manager.get_kb(kb_id) diff --git a/astrbot/dashboard/routes/live_chat.py b/astrbot/dashboard/routes/live_chat.py index 8d0af938d..9cd9b3517 100644 --- a/astrbot/dashboard/routes/live_chat.py +++ b/astrbot/dashboard/routes/live_chat.py @@ -7,6 +7,7 @@ import uuid import wave from typing import Any +import anyio import jwt from quart import websocket @@ -86,7 +87,7 @@ class LiveChatSession: self.temp_audio_path = audio_path logger.info( - f"[Live Chat] 音频文件已保存: {audio_path}, 大小: {os.path.getsize(audio_path)} bytes" + f"[Live Chat] 音频文件已保存: {audio_path}, 大小: {(await anyio.Path(audio_path).stat()).st_size} bytes" ) return audio_path, time.time() - start_time @@ -96,9 +97,9 @@ class LiveChatSession: def cleanup(self) -> None: """清理临时文件""" - if self.temp_audio_path and os.path.exists(self.temp_audio_path): + if self.temp_audio_path and await anyio.Path(self.temp_audio_path).exists(): try: - os.remove(self.temp_audio_path) + await anyio.Path(self.temp_audio_path).unlink() logger.debug(f"[Live Chat] 已删除临时文件: {self.temp_audio_path}") except Exception as e: logger.warning(f"[Live Chat] 删除临时文件失败: {e}") diff --git a/astrbot/dashboard/routes/plugin.py b/astrbot/dashboard/routes/plugin.py index 0511ccdad..489babdac 100644 --- a/astrbot/dashboard/routes/plugin.py +++ b/astrbot/dashboard/routes/plugin.py @@ -251,11 +251,11 @@ class PluginRoute(Route): def _load_cached_md5(self, cache_file: str) -> str | None: """从缓存文件中加载MD5""" - if not os.path.exists(cache_file): + if not await anyio.Path(cache_file).exists(): return None try: - with open(cache_file, encoding="utf-8") as f: + async with await anyio.open_file(cache_file, encoding="utf-8") as f: cache_data = json.load(f) return cache_data.get("md5") except Exception as e: @@ -311,8 +311,8 @@ class PluginRoute(Route): def _load_plugin_cache(self, cache_file: str): """加载本地缓存的插件市场数据""" try: - if os.path.exists(cache_file): - with open(cache_file, encoding="utf-8") as f: + if await anyio.Path(cache_file).exists(): + async with await anyio.open_file(cache_file, encoding="utf-8") as f: cache_data = json.load(f) # 检查缓存是否有效 if "data" in cache_data and "timestamp" in cache_data: @@ -336,7 +336,7 @@ class PluginRoute(Route): "md5": md5 or "", } - with open(cache_file, "w", encoding="utf-8") as f: + async with await anyio.open_file(cache_file, "w", encoding="utf-8") as f: json.dump(cache_data, f, ensure_ascii=False, indent=2) logger.debug(f"插件市场数据已缓存到: {cache_file}, MD5: {md5}") except Exception as e: @@ -771,13 +771,13 @@ class PluginRoute(Route): plugin_obj.root_dir_name, ) - if not os.path.isdir(plugin_dir): + if not await anyio.Path(plugin_dir).is_dir(): logger.warning(f"无法找到插件目录: {plugin_dir}") return Response().error(f"无法找到插件 {plugin_name} 的目录").__dict__ readme_path = os.path.join(plugin_dir, "README.md") - if not os.path.isfile(readme_path): + if not await anyio.Path(readme_path).is_file(): logger.warning(f"插件 {plugin_name} 没有README文件") return Response().error(f"插件 {plugin_name} 没有README文件").__dict__ @@ -832,7 +832,7 @@ class PluginRoute(Route): plugin_obj.root_dir_name, ) - if not os.path.isdir(plugin_dir): + if not await anyio.Path(plugin_dir).is_dir(): logger.warning(f"无法找到插件目录: {plugin_dir}") return Response().error(f"无法找到插件 {plugin_name} 的目录").__dict__ @@ -840,7 +840,7 @@ class PluginRoute(Route): changelog_names = ["CHANGELOG.md", "changelog.md", "CHANGELOG", "changelog"] for name in changelog_names: changelog_path = os.path.join(plugin_dir, name) - if os.path.isfile(changelog_path): + if await anyio.Path(changelog_path).is_file(): try: async with await anyio.open_file( changelog_path, encoding="utf-8" diff --git a/astrbot/dashboard/routes/skills.py b/astrbot/dashboard/routes/skills.py index 42ba7fd80..e7d9a4c94 100644 --- a/astrbot/dashboard/routes/skills.py +++ b/astrbot/dashboard/routes/skills.py @@ -7,6 +7,7 @@ from collections.abc import Awaitable, Callable from pathlib import Path from typing import Any +import anyio from quart import request, send_file from astrbot.core import DEMO_MODE, logger @@ -184,9 +185,9 @@ class SkillsRoute(Route): logger.error(traceback.format_exc()) return Response().error(str(e)).__dict__ finally: - if temp_path and os.path.exists(temp_path): + if temp_path and await anyio.Path(temp_path).exists(): try: - os.remove(temp_path) + await anyio.Path(temp_path).unlink() except Exception: logger.warning(f"Failed to remove temp skill file: {temp_path}") @@ -239,9 +240,9 @@ class SkillsRoute(Route): except Exception as e: failed.append({"filename": filename, "error": str(e)}) finally: - if temp_path and os.path.exists(temp_path): + if temp_path and await anyio.Path(temp_path).exists(): try: - os.remove(temp_path) + await anyio.Path(temp_path).unlink() except Exception: pass