From 51a081b30ed051f09dd74d334e1ea9aed4d9583d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 4 Sep 2026 14:03:59 -0700 Subject: [PATCH] Change: skip documents with empty content in apply AI suggestions WF --- docs/usage.md | 3 ++- src/documents/tests/test_workflows.py | 33 +++++++++++++++++++++++++++ src/documents/workflows/ai.py | 10 ++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 805e15718..004fd5505 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -684,7 +684,8 @@ It requires [AI features](configuration.md#ai) to be enabled. You can specify: never replace the document's existing tags. The action works with every trigger **except Consumption Started**, because suggestions are made from -the document's text, which does not exist until after the document has been processed. +the document's text, which does not exist until after the document has been processed. Documents whose +processed text is empty or contains only whitespace are skipped. Because the query to the AI service is slow, the action is queued and runs in the background rather than as part of the workflow run itself. The document is updated once the suggestions come back. diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index 6376f6fc9..1f2d50639 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -5711,6 +5711,39 @@ class TestApplyAISuggestionsWorkflowAction( self.assertEqual(changed, []) self.assertIn("AI is not enabled", "".join(cm.output)) + def test_document_without_content_does_nothing(self) -> None: + """ + GIVEN: + - A document whose OCR content is empty or whitespace-only + WHEN: + - AI suggestions are applied by a workflow + THEN: + - The classifier is not called and the document is left unchanged + """ + action = self.make_action(ai_overwrite_existing=True) + + for content in ("", " \n\t"): + with self.subTest(content=content): + self.doc.content = content + self.doc.save(update_fields=["content"]) + + with ( + mock.patch( + "documents.workflows.ai.get_ai_document_classification", + ) as get_classification, + self.assertLogs( + "paperless.workflows.ai", + level="WARNING", + ) as cm, + ): + changed = apply_ai_suggestions_to_document(action, self.doc) + + self.assertEqual(changed, []) + get_classification.assert_not_called() + self.assertIn("has no content", "".join(cm.output)) + self.doc.refresh_from_db() + self.assertEqual(self.doc.title, "original.pdf") + def test_invalid_configuration_leaves_document_untouched(self) -> None: """ GIVEN: diff --git a/src/documents/workflows/ai.py b/src/documents/workflows/ai.py index 23ffbd71c..f73017ee9 100644 --- a/src/documents/workflows/ai.py +++ b/src/documents/workflows/ai.py @@ -138,6 +138,16 @@ def apply_ai_suggestions_to_document( ) return [] + if not document.content.strip(): + logger.warning( + "Document %s has no content, skipping AI suggestions for workflow " + "action %s", + document.pk, + action.pk, + extra={"group": logging_group}, + ) + return [] + # Workflows run without a user, so we use the document owner owner = document.owner