Repository: deepset-ai/haystack

Issue:
PDFToTextOCRConverter returns empty document
Two newly introduced tests don't pass for `PDFToTextOCRConverter` because it unexpectedly returns an empty document whereas `PDFToTextConverter` returns the document's text content. We need to investigate what's the problem here and need to make sure that `PDFToTextOCRConverter` also returns the document's content.

Here is the PR where the two tests were added: https://github.com/deepset-ai/haystack/pull/2420

https://github.com/deepset-ai/haystack/blob/01ea4bf21f9013b918bb7ddecf86234c78eed3f2/test/test_file_converter.py#L38

https://github.com/deepset-ai/haystack/blob/01ea4bf21f9013b918bb7ddecf86234c78eed3f2/test/test_file_converter.py#L49


Discussion:

Resolving patch:
diff --git a/haystack/nodes/file_converter/image.py b/haystack/nodes/file_converter/image.py
--- a/haystack/nodes/file_converter/image.py
+++ b/haystack/nodes/file_converter/image.py
@@ -88,7 +88,7 @@ def convert(
         meta: Optional[Dict[str, str]] = None,
         remove_numeric_tables: Optional[bool] = None,
         valid_languages: Optional[List[str]] = None,
-        encoding: Optional[str] = "utf-8",
+        encoding: Optional[str] = None,
         id_hash_keys: Optional[List[str]] = None,
     ) -> List[Document]:
         """
@@ -107,6 +107,7 @@ def convert(
                                 This option can be used to add test for encoding errors. If the extracted text is
                                 not one of the valid languages, then it might likely be encoding error resulting
                                 in garbled text.
+        :param encoding: Not applicable
         :param id_hash_keys: Generate the document id from a custom list of strings that refer to the document's
             attributes. If you want to ensure you don't have duplicate documents in your DocumentStore but texts are
             not unique, you can modify the metadata and pass e.g. `"meta"` to this field (e.g. [`"content"`, `"meta"`]).
diff --git a/haystack/nodes/file_converter/pdf.py b/haystack/nodes/file_converter/pdf.py
--- a/haystack/nodes/file_converter/pdf.py
+++ b/haystack/nodes/file_converter/pdf.py
@@ -215,7 +215,7 @@ def convert(
         meta: Optional[Dict[str, str]] = None,
         remove_numeric_tables: Optional[bool] = None,
         valid_languages: Optional[List[str]] = None,
-        encoding: Optional[str] = "UTF-8",
+        encoding: Optional[str] = None,
         id_hash_keys: Optional[List[str]] = None,
     ) -> List[Document]:
         """
@@ -236,7 +236,7 @@ def convert(
                                 This option can be used to add test for encoding errors. If the extracted text is
                                 not one of the valid languages, then it might likely be encoding error resulting
                                 in garbled text.
-        :param encoding: Select the file encoding (default is `UTF-8`)
+        :param encoding: Not applicable
         :param id_hash_keys: Generate the document id from a custom list of strings that refer to the document's
             attributes. If you want to ensure you don't have duplicate documents in your DocumentStore but texts are
             not unique, you can modify the metadata and pass e.g. `"meta"` to this field (e.g. [`"content"`, `"meta"`]).
@@ -251,7 +251,7 @@ def convert(
             for image in images:
                 temp_img = tempfile.NamedTemporaryFile(dir=os.path.dirname(os.path.realpath(__file__)), suffix=".jpeg")
                 image.save(temp_img.name)
-                pages.append(self.image_2_text.convert(file_path=temp_img.name, encoding=encoding)[0].content)
+                pages.append(self.image_2_text.convert(file_path=temp_img.name)[0].content)
         except Exception as exception:
             logger.error(f"File {file_path} has an error \n {exception}")
 


Test patch:
diff --git a/test/nodes/test_file_converter.py b/test/nodes/test_file_converter.py
--- a/test/nodes/test_file_converter.py
+++ b/test/nodes/test_file_converter.py
@@ -1,5 +1,5 @@
-from pathlib import Path
 import os
+import subprocess
 
 import pytest
 
@@ -17,15 +17,16 @@
 
 
 @pytest.mark.tika
-@pytest.mark.parametrize(
-    # "Converter", [PDFToTextConverter, TikaConverter, PDFToTextOCRConverter]
-    "Converter",
-    [PDFToTextOCRConverter],
-)
+@pytest.mark.parametrize("Converter", [PDFToTextConverter, TikaConverter, PDFToTextOCRConverter])
 def test_convert(Converter):
     converter = Converter()
-    document = converter.convert(file_path=SAMPLES_PATH / "pdf" / "sample_pdf_1.pdf")[0]
+    document = converter.run(file_paths=SAMPLES_PATH / "pdf" / "sample_pdf_1.pdf")[0]["documents"][0]
     pages = document.content.split("\f")
+
+    assert (
+        len(pages) != 1 and pages[0] != ""
+    ), f'{type(converter).__name__} did return a single empty page indicating a potential issue with your installed poppler version. Try installing via "conda install -c conda-forge poppler" and check test_pdftoppm_command_format()'
+
     assert len(pages) == 4  # the sample PDF file has four pages.
     assert pages[0] != ""  # the page 1 of PDF contains text.
     assert pages[2] == ""  # the page 3 of PDF file is empty.
@@ -35,7 +36,21 @@ def test_convert(Converter):
     assert "Adobe Systems made the PDF specification available free of charge in 1993." in page_standard_whitespace
 
 
-@pytest.mark.parametrize("Converter", [PDFToTextConverter])  # TODO PDFToTextOCRConverter should pass this test too
+def test_pdftoppm_command_format():
+    # Haystack's PDFToTextOCRConverter uses pdf2image, which calls pdftoppm internally.
+    # Some installations of pdftoppm are incompatible with Haystack and won't raise an error but just return empty converted documents
+    # This test runs pdftoppm directly to check whether pdftoppm accepts the command format that pdf2image uses in Haystack
+    proc = subprocess.Popen(
+        ["pdftoppm", f"{SAMPLES_PATH}/pdf/sample_pdf_1.pdf"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
+    )
+    out, err = proc.communicate()
+    # If usage info of pdftoppm is sent to stderr then it's because Haystack's pdf2image uses an incompatible command format
+    assert (
+        not err
+    ), 'Your installation of poppler is incompatible with Haystack. Try installing via "conda install -c conda-forge poppler"'
+
+
+@pytest.mark.parametrize("Converter", [PDFToTextConverter])
 def test_pdf_encoding(Converter):
     converter = Converter()
 
@@ -46,7 +61,7 @@ def test_pdf_encoding(Converter):
     assert "ɪ" not in document.content
 
 
-@pytest.mark.parametrize("Converter", [PDFToTextConverter])  # TODO PDFToTextOCRConverter should pass this test too
+@pytest.mark.parametrize("Converter", [PDFToTextConverter])
 def test_pdf_ligatures(Converter):
     converter = Converter()