feat(duplication): implement duplicate file handling and detection across processing steps

This commit is contained in:
Christian Krakau-Louis
2026-02-12 02:37:51 +01:00
parent 70757e5644
commit 9a2c2d20b1
12 changed files with 325 additions and 28 deletions
+40 -2
View File
@@ -4,6 +4,7 @@ import json
import logging
import os
import time
from typing import Optional
import requests
@@ -55,7 +56,23 @@ def normalize_metadata_value(value) -> str:
return str_value
def poll_task_for_document_id(task_id: str) -> int:
def _is_duplicate_error(result_message: str) -> bool:
"""
Determine whether a Paperless task failure indicates a duplicate document.
Args:
result_message: Failure result string from Paperless.
Returns:
True if the message indicates a duplicate, otherwise False.
"""
if not result_message:
return False
lowered = result_message.lower()
return "duplicate" in lowered and "not consuming" in lowered
def poll_task_for_document_id(task_id: str) -> Optional[int]:
"""
Polls /api/tasks/?task_id=<uuid> until we get status=SUCCESS or FAILURE,
or until we run out of attempts.
@@ -92,7 +109,11 @@ def poll_task_for_document_id(task_id: str) -> int:
return int(doc_str)
raise RuntimeError(f"Task {task_id} completed but no doc ID found. Task info: {task_info}")
elif status == "FAILURE":
raise RuntimeError(f"Task {task_id} failed: {task_info.get('result')}")
result_message = task_info.get("result")
if _is_duplicate_error(result_message):
logger.info("Task %s reported duplicate document: %s", task_id, result_message)
return None
raise RuntimeError(f"Task {task_id} failed: {result_message}")
attempts += 1
time.sleep(POLL_INTERVAL_SEC)
@@ -266,6 +287,23 @@ def upload_to_paperless(self, file_path: str, file_id: int = None):
logger.info(f"[{task_id}] Polling for document ID")
log_task_progress(task_id, "poll_task", "in_progress", "Waiting for Paperless processing", file_id=file_id)
doc_id = poll_task_for_document_id(raw_task_id)
if doc_id is None:
logger.info(f"[{task_id}] Paperless reported duplicate for {file_path}; skipping upload")
log_task_progress(
task_id,
"upload_to_paperless",
"skipped",
"Duplicate document detected by Paperless - skipping",
file_id=file_id,
detail="Paperless reported duplicate; document was not consumed.",
)
return {
"status": "Duplicate",
"paperless_task_id": raw_task_id,
"paperless_document_id": None,
"file_path": file_path,
}
logger.info(f"[{task_id}] Document {file_path} successfully ingested => ID={doc_id}")
log_task_progress(
task_id, "upload_to_paperless", "success", f"Uploaded to Paperless: Doc ID {doc_id}", file_id=file_id