diff --git a/server/routers/knowledge_router.py b/server/routers/knowledge_router.py index cc37319f..7d2313f7 100644 --- a/server/routers/knowledge_router.py +++ b/server/routers/knowledge_router.py @@ -723,12 +723,16 @@ async def delete_document(db_id: str, doc_id: str, current_user: User = Depends( await knowledge_base.delete_folder(db_id, doc_id) return {"message": "文件夹删除成功"} - file_name = file_meta_info.get("meta", {}).get("filename") + file_name = file_meta_info.get("meta", {}).get("path", "").split("/")[-1] # 尝试从MinIO删除文件,如果失败(例如旧知识库没有MinIO实例),则忽略 try: minio_client = get_minio_client() await minio_client.adelete_file(MinIOClient.get_ref_bucket_name(db_id), file_name) + # 同时删除 parsed bucket 中的 parsed.md 文件 + await minio_client.adelete_file( + minio_client.KB_BUCKETS["parsed"], f"{db_id}/{doc_id}/parsed.md" + ) logger.debug(f"成功从MinIO删除文件: {file_name}") except Exception as minio_error: logger.warning(f"从MinIO删除文件失败(可能是旧知识库): {minio_error}") diff --git a/src/knowledge/base.py b/src/knowledge/base.py index c8718a97..849d284c 100644 --- a/src/knowledge/base.py +++ b/src/knowledge/base.py @@ -506,9 +506,9 @@ class KnowledgeBase(ABC): minio_client.adelete_objects_by_prefix(minio_client.KB_BUCKETS["parsed"], prefix), minio_client.adelete_objects_by_prefix(minio_client.KB_BUCKETS["documents"], prefix), minio_client.adelete_objects_by_prefix(minio_client.KB_BUCKETS["images"], prefix), - # 删除 ref bucket 中的文件(两种命名格式) - minio_client.adelete_objects_by_prefix(minio_client.get_ref_bucket_name(db_id), prefix), - minio_client.adelete_objects_by_prefix(minio_client.get_ref_bucket_name_full(db_id), prefix), + # 直接删除 ref bucket(两种命名格式) + minio_client.adelete_bucket(minio_client.get_ref_bucket_name(db_id)), + minio_client.adelete_bucket(minio_client.get_ref_bucket_name_full(db_id)), ) # 3. 删除数据库记录 diff --git a/src/storage/minio/client.py b/src/storage/minio/client.py index bb672a65..ecde8595 100644 --- a/src/storage/minio/client.py +++ b/src/storage/minio/client.py @@ -283,6 +283,29 @@ class MinIOClient: await asyncio.to_thread(_delete_objects) return deleted_count + async def adelete_bucket(self, bucket_name: str) -> bool: + """ + 删除 bucket(先删除所有对象,再删除 bucket) + + Args: + bucket_name: bucket 名称 + + Returns: + 是否成功 + """ + try: + # 先删除所有对象 + await self.adelete_objects_by_prefix(bucket_name, "") + # 再删除 bucket + await asyncio.to_thread(self.client.remove_bucket, bucket_name) + logger.info(f"成功删除 bucket: {bucket_name}") + return True + except S3Error as e: + if "NoSuchBucket" in str(e): + logger.warning(f"bucket 不存在: {bucket_name}") + return False + raise StorageError(f"删除 bucket 失败: {e}") + def file_exists(self, bucket_name: str, object_name: str) -> bool: """检查文件是否存在""" try: