mirror of
https://github.com/HKUDS/LightRAG.git
synced 2025-06-26 22:00:19 +00:00
Feat: Add delete upload file option to document deletion
This commit is contained in:
parent
6a1737784d
commit
bdcd55a871
@ -261,6 +261,10 @@ Attributes:
|
||||
|
||||
class DeleteDocRequest(BaseModel):
|
||||
doc_ids: List[str] = Field(..., description="The IDs of the documents to delete.")
|
||||
delete_file: bool = Field(
|
||||
default=False,
|
||||
description="Whether to delete the corresponding file in the upload directory.",
|
||||
)
|
||||
|
||||
@field_validator("doc_ids", mode="after")
|
||||
@classmethod
|
||||
@ -793,7 +797,12 @@ async def run_scanning_process(rag: LightRAG, doc_manager: DocumentManager):
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
async def background_delete_documents(rag: LightRAG, doc_ids: List[str]):
|
||||
async def background_delete_documents(
|
||||
rag: LightRAG,
|
||||
doc_manager: DocumentManager,
|
||||
doc_ids: List[str],
|
||||
delete_file: bool = False,
|
||||
):
|
||||
"""Background task to delete multiple documents"""
|
||||
from lightrag.kg.shared_storage import (
|
||||
get_namespace_data,
|
||||
@ -847,6 +856,46 @@ async def background_delete_documents(rag: LightRAG, doc_ids: List[str]):
|
||||
|
||||
async with pipeline_status_lock:
|
||||
pipeline_status["history_messages"].append(success_msg)
|
||||
|
||||
# Handle file deletion if requested and file_path is available
|
||||
if (
|
||||
delete_file
|
||||
and result.file_path
|
||||
and result.file_path != "unknown_source"
|
||||
):
|
||||
try:
|
||||
file_path = doc_manager.input_dir / result.file_path
|
||||
if file_path.exists():
|
||||
file_path.unlink()
|
||||
file_delete_msg = (
|
||||
f"Successfully deleted file: {result.file_path}"
|
||||
)
|
||||
logger.info(file_delete_msg)
|
||||
async with pipeline_status_lock:
|
||||
pipeline_status["history_messages"].append(
|
||||
file_delete_msg
|
||||
)
|
||||
else:
|
||||
file_not_found_msg = (
|
||||
f"File not found for deletion: {result.file_path}"
|
||||
)
|
||||
logger.warning(file_not_found_msg)
|
||||
async with pipeline_status_lock:
|
||||
pipeline_status["history_messages"].append(
|
||||
file_not_found_msg
|
||||
)
|
||||
except Exception as file_error:
|
||||
file_error_msg = f"Failed to delete file {result.file_path}: {str(file_error)}"
|
||||
logger.error(file_error_msg)
|
||||
async with pipeline_status_lock:
|
||||
pipeline_status["history_messages"].append(
|
||||
file_error_msg
|
||||
)
|
||||
elif delete_file:
|
||||
no_file_msg = f"No valid file path found for document {doc_id}"
|
||||
logger.warning(no_file_msg)
|
||||
async with pipeline_status_lock:
|
||||
pipeline_status["history_messages"].append(no_file_msg)
|
||||
else:
|
||||
failed_deletions.append(doc_id)
|
||||
error_msg = f"Failed to delete document {i}/{total_docs}: {doc_id} - {result.message}"
|
||||
@ -1395,7 +1444,7 @@ def create_document_routes(
|
||||
This operation is irreversible and will interact with the pipeline status.
|
||||
|
||||
Args:
|
||||
delete_request (DeleteDocRequest): The request containing the document IDs.
|
||||
delete_request (DeleteDocRequest): The request containing the document IDs and delete_file options.
|
||||
background_tasks: FastAPI BackgroundTasks for async processing
|
||||
|
||||
Returns:
|
||||
@ -1433,7 +1482,13 @@ def create_document_routes(
|
||||
)
|
||||
|
||||
# Add deletion task to background tasks
|
||||
background_tasks.add_task(background_delete_documents, rag, doc_ids)
|
||||
background_tasks.add_task(
|
||||
background_delete_documents,
|
||||
rag,
|
||||
doc_manager,
|
||||
doc_ids,
|
||||
delete_request.delete_file,
|
||||
)
|
||||
|
||||
return DeleteDocByIdResponse(
|
||||
status="deletion_started",
|
||||
|
@ -685,3 +685,4 @@ class DeletionResult:
|
||||
doc_id: str
|
||||
message: str
|
||||
status_code: int = 200
|
||||
file_path: str | None = None
|
||||
|
@ -1694,6 +1694,7 @@ class LightRAG:
|
||||
- `doc_id` (str): The ID of the document attempted to be deleted.
|
||||
- `message` (str): A summary of the operation's result.
|
||||
- `status_code` (int): HTTP status code (e.g., 200, 404, 500).
|
||||
- `file_path` (str | None): The file path of the deleted document, if available.
|
||||
"""
|
||||
deletion_operations_started = False
|
||||
original_exception = None
|
||||
@ -1961,11 +1962,15 @@ class LightRAG:
|
||||
logger.error(f"Failed to delete document and status: {e}")
|
||||
raise Exception(f"Failed to delete document and status: {e}") from e
|
||||
|
||||
# Get file path from document status for return value
|
||||
file_path = doc_status_data.get("file_path") if doc_status_data else None
|
||||
|
||||
return DeletionResult(
|
||||
status="success",
|
||||
doc_id=doc_id,
|
||||
message=log_message,
|
||||
status_code=200,
|
||||
file_path=file_path,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
@ -521,9 +521,9 @@ export const clearCache = async (modes?: string[]): Promise<{
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const deleteDocuments = async (docIds: string[]): Promise<DeleteDocResponse> => {
|
||||
export const deleteDocuments = async (docIds: string[], deleteFile: boolean = false): Promise<DeleteDocResponse> => {
|
||||
const response = await axiosInstance.delete('/documents/delete_document', {
|
||||
data: { doc_ids: docIds }
|
||||
data: { doc_ids: docIds, delete_file: deleteFile }
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ export default function DeleteDocumentsDialog({ selectedDocIds, totalCompletedCo
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [confirmText, setConfirmText] = useState('')
|
||||
const [deleteFile, setDeleteFile] = useState(false)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
const isConfirmEnabled = confirmText.toLowerCase() === 'yes' && !isDeleting
|
||||
|
||||
@ -50,6 +51,7 @@ export default function DeleteDocumentsDialog({ selectedDocIds, totalCompletedCo
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setConfirmText('')
|
||||
setDeleteFile(false)
|
||||
setIsDeleting(false)
|
||||
}
|
||||
}, [open])
|
||||
@ -65,7 +67,7 @@ export default function DeleteDocumentsDialog({ selectedDocIds, totalCompletedCo
|
||||
|
||||
setIsDeleting(true)
|
||||
try {
|
||||
const result = await deleteDocuments(selectedDocIds)
|
||||
const result = await deleteDocuments(selectedDocIds, deleteFile)
|
||||
|
||||
if (result.status === 'deletion_started') {
|
||||
toast.success(t('documentPanel.deleteDocuments.success', { count: selectedDocIds.length }))
|
||||
@ -99,7 +101,7 @@ export default function DeleteDocumentsDialog({ selectedDocIds, totalCompletedCo
|
||||
} finally {
|
||||
setIsDeleting(false)
|
||||
}
|
||||
}, [isConfirmEnabled, selectedDocIds, totalCompletedCount, setOpen, t, onDocumentsDeleted])
|
||||
}, [isConfirmEnabled, selectedDocIds, totalCompletedCount, deleteFile, setOpen, t, onDocumentsDeleted])
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
@ -146,6 +148,20 @@ export default function DeleteDocumentsDialog({ selectedDocIds, totalCompletedCo
|
||||
disabled={isDeleting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="delete-file"
|
||||
checked={deleteFile}
|
||||
onChange={(e) => setDeleteFile(e.target.checked)}
|
||||
disabled={isDeleting}
|
||||
className="h-4 w-4 text-red-600 focus:ring-red-500 border-gray-300 rounded"
|
||||
/>
|
||||
<Label htmlFor="delete-file" className="text-sm font-medium cursor-pointer">
|
||||
{t('documentPanel.deleteDocuments.deleteFileOption')}
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
|
@ -66,7 +66,9 @@
|
||||
"confirmPrompt": "اكتب 'yes' لتأكيد هذا الإجراء",
|
||||
"confirmPlaceholder": "اكتب yes للتأكيد",
|
||||
"confirmButton": "نعم",
|
||||
"success": "تم حذف المستندات بنجاح",
|
||||
"deleteFileOption": "حذف الملفات المرفوعة أيضًا",
|
||||
"deleteFileTooltip": "حدد هذا الخيار لحذف الملفات المرفوعة المقابلة على الخادم أيضًا",
|
||||
"success": "تم بدء تشغيل خط معالجة حذف المستندات بنجاح",
|
||||
"failed": "فشل حذف المستندات:\n{{message}}",
|
||||
"error": "فشل حذف المستندات:\n{{error}}",
|
||||
"busy": "خط المعالجة مشغول، يرجى المحاولة مرة أخرى لاحقًا",
|
||||
|
@ -66,7 +66,9 @@
|
||||
"confirmPrompt": "Type 'yes' to confirm this action",
|
||||
"confirmPlaceholder": "Type yes to confirm",
|
||||
"confirmButton": "YES",
|
||||
"success": "Documents deleted successfully",
|
||||
"deleteFileOption": "Also delete uploaded files",
|
||||
"deleteFileTooltip": "Check this option to also delete the corresponding uploaded files on the server",
|
||||
"success": "Document deletion pipeline started successfully",
|
||||
"failed": "Delete Documents Failed:\n{{message}}",
|
||||
"error": "Delete Documents Failed:\n{{error}}",
|
||||
"busy": "Pipeline is busy, please try again later",
|
||||
|
@ -66,7 +66,9 @@
|
||||
"confirmPrompt": "Tapez 'yes' pour confirmer cette action",
|
||||
"confirmPlaceholder": "Tapez yes pour confirmer",
|
||||
"confirmButton": "OUI",
|
||||
"success": "Documents supprimés avec succès",
|
||||
"deleteFileOption": "Supprimer également les fichiers téléchargés",
|
||||
"deleteFileTooltip": "Cochez cette option pour supprimer également les fichiers téléchargés correspondants sur le serveur",
|
||||
"success": "Pipeline de suppression de documents démarré avec succès",
|
||||
"failed": "Échec de la suppression des documents :\n{{message}}",
|
||||
"error": "Échec de la suppression des documents :\n{{error}}",
|
||||
"busy": "Le pipeline est occupé, veuillez réessayer plus tard",
|
||||
|
@ -66,7 +66,9 @@
|
||||
"confirmPrompt": "请输入 yes 确认操作",
|
||||
"confirmPlaceholder": "输入 yes 确认",
|
||||
"confirmButton": "确定",
|
||||
"success": "文档删除成功",
|
||||
"deleteFileOption": "同时删除上传文件",
|
||||
"deleteFileTooltip": "选中此选项将同时删除服务器上对应的上传文件",
|
||||
"success": "文档删除流水线启动成功",
|
||||
"failed": "删除文档失败:\n{{message}}",
|
||||
"error": "删除文档失败:\n{{error}}",
|
||||
"busy": "流水线被占用,请稍后再试",
|
||||
|
@ -66,7 +66,9 @@
|
||||
"confirmPrompt": "請輸入 yes 確認操作",
|
||||
"confirmPlaceholder": "輸入 yes 以確認",
|
||||
"confirmButton": "確定",
|
||||
"success": "文件刪除成功",
|
||||
"deleteFileOption": "同時刪除上傳檔案",
|
||||
"deleteFileTooltip": "選取此選項將同時刪除伺服器上對應的上傳檔案",
|
||||
"success": "文件刪除流水線啟動成功",
|
||||
"failed": "刪除文件失敗:\n{{message}}",
|
||||
"error": "刪除文件失敗:\n{{error}}",
|
||||
"busy": "pipeline 被佔用,請稍後再試",
|
||||
|
Loading…
x
Reference in New Issue
Block a user