mirror of
https://github.com/deepset-ai/haystack.git
synced 2026-10-12 02:12:50 +00:00
fix for doc to image
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user