fix for doc to image

This commit is contained in:
Sebastian Husch Lee
2026-09-23 13:15:44 +02:00
parent 9678a741d6
commit 4ab72a09f0
3 changed files with 45 additions and 40 deletions
@@ -113,23 +113,30 @@ class DocumentToImageContent:
:returns:
Dictionary containing one key:
- "image_contents": ImageContents created from the processed documents. These contain base64-encoded image
data and metadata. The order corresponds to order of input documents.
:raises ValueError:
If any document is missing the required metadata keys, has an invalid file path, or has an unsupported
MIME type. The error message will specify which document and what information is missing or incorrect.
data and metadata. The order corresponds to order of input documents. A document that is missing the
required metadata keys, has an invalid file path, or has an unsupported MIME type gets None in its
position and a logged warning with the reason.
"""
if not documents:
return {"image_contents": []}
images_source_info = _extract_image_sources_info(
documents=documents, file_path_meta_field=self.file_path_meta_field, root_path=self.root_path
)
image_contents: list[ImageContent | None] = [None] * len(documents)
pdf_page_infos: list[_PDFPageInfo] = []
for doc_idx, image_source_info in enumerate(images_source_info):
for doc_idx, document in enumerate(documents):
# Validate each document on its own so one invalid document leaves None in its slot
# instead of failing the whole batch
try:
image_source_info = _extract_image_sources_info(
documents=[document], file_path_meta_field=self.file_path_meta_field, root_path=self.root_path
)[0]
except ValueError as error:
logger.warning(
"Skipping document with ID {document_id}: {error}", document_id=document.id, error=str(error)
)
continue
mime_type = image_source_info["mime_type"]
path = image_source_info["path"]
if mime_type == "application/pdf":
@@ -146,7 +153,7 @@ class DocumentToImageContent:
base64_image=base64_image,
mime_type=mime_type,
detail=self.detail,
meta={"file_path": documents[doc_idx].meta[self.file_path_meta_field]},
meta={"file_path": document.meta[self.file_path_meta_field]},
)
# efficiently convert PDF pages to images: each PDF is opened and processed only once
@@ -0,0 +1,8 @@
---
fixes:
- |
``DocumentToImageContent`` no longer raises a ``ValueError`` for the whole batch when one document is missing
the file path or ``page_number`` metadata, has an invalid file path, or has an unsupported MIME type.
That document now gets ``None`` in ``image_contents`` and a warning with the reason is logged, while the other
documents are still converted. This lets ``LLMDocumentContentExtractor`` return such documents in
``failed_documents`` instead of failing the entire run.
@@ -53,32 +53,20 @@ class TestDocumentToImageContent:
results = converter.run(documents=[])
assert results == {"image_contents": []}
def test_run_with_missing_file_path_metadata(self) -> None:
@pytest.mark.parametrize(
"meta, reason",
[
({}, "is missing the 'file_path' key"),
({"file_path": "test/test_files/docx/sample_docx.docx"}, "has an unsupported MIME type"),
({"file_path": "wrong_name.jpg"}, "has an invalid file path 'wrong_name.jpg'"),
({"file_path": "test/test_files/pdf/sample_pdf_1.pdf"}, "is missing the 'page_number' key"),
],
)
def test_run_with_invalid_document(self, meta: dict, reason: str, caplog: pytest.LogCaptureFixture) -> None:
converter = DocumentToImageContent()
# Document without file_path in metadata
doc_no_path = Document(content="test", meta={})
# Document with file_path but file doesn't exist
doc_no_file = Document(content="test", meta={"file_path": "nonexistent.jpg"})
with pytest.raises(ValueError, match="is missing the 'file_path' key"):
_ = converter.run(documents=[doc_no_path, doc_no_file])
def test_run_with_non_image_documents(self) -> None:
converter = DocumentToImageContent()
docx_doc = Document(content="test", meta={"file_path": "test/test_files/docx/sample_docx.docx"})
with pytest.raises(ValueError, match="has an unsupported MIME type"):
_ = converter.run(documents=[docx_doc])
def test_run_with_invalid_file_path(self, caplog: pytest.LogCaptureFixture) -> None:
converter = DocumentToImageContent()
pdf_doc = Document(content="test", meta={"file_path": "wrong_name.jpg"})
with pytest.raises(ValueError, match="has an invalid file path 'wrong_name.jpg'"):
_ = converter.run(documents=[pdf_doc])
def test_run_with_pdf_missing_page_number(self, caplog: pytest.LogCaptureFixture) -> None:
converter = DocumentToImageContent()
pdf_doc = Document(content="test", meta={"file_path": "test/test_files/pdf/sample_pdf_1.pdf"})
with pytest.raises(ValueError, match="is missing the 'page_number' key"):
_ = converter.run(documents=[pdf_doc])
results = converter.run(documents=[Document(content="test", meta=meta)])
assert results == {"image_contents": [None]}
assert reason in caplog.text
def test_run_with_image_documents(self) -> None:
converter = DocumentToImageContent(root_path="test/test_files/images")
@@ -105,8 +93,10 @@ class TestDocumentToImageContent:
Document(content="", meta={"file_path": "pdf/sample_pdf_1.pdf", "page_number": 1}),
Document(content="text", meta={"file_path": "docx/sample_docx.docx"}),
]
with pytest.raises(ValueError, match="has an unsupported MIME type"):
_ = converter.run(documents=documents)
image_contents = converter.run(documents=documents)["image_contents"]
assert image_contents[0] is not None
assert image_contents[1] is not None
assert image_contents[2] is None
@patch("haystack.components.converters.image.document_to_image._extract_image_sources_info")
@patch("haystack.components.converters.image.document_to_image._batch_convert_pdf_pages_to_images")
@@ -122,9 +112,9 @@ class TestDocumentToImageContent:
):
converter = DocumentToImageContent()
mocked_extract_image_sources_info.return_value = [
{"path": "doc1.pdf", "mime_type": "application/pdf", "page_number": 999}, # Page 999 doesn't exist
{"path": "image1.jpg", "mime_type": "image/jpeg"},
mocked_extract_image_sources_info.side_effect = [
[{"path": "doc1.pdf", "mime_type": "application/pdf", "page_number": 999}], # Page 999 doesn't exist
[{"path": "image1.jpg", "mime_type": "image/jpeg"}],
]
mocked_batch_convert_pdf_pages_to_images.return_value = {} # Empty dict because page was skipped
mocked_pil_open.return_value = Image.new("RGB", (100, 100))