Skip to content

feat: add Gotenberg converter integration - #3839

Open
maxdswain wants to merge 4 commits into
deepset-ai:mainfrom
maxdswain:gotenberg
Open

feat: add Gotenberg converter integration#3839
maxdswain wants to merge 4 commits into
deepset-ai:mainfrom
maxdswain:gotenberg

Conversation

@maxdswain

Copy link
Copy Markdown
Contributor

Related Issues

Proposed Changes:

Add new integration that uses gotenberg docker containers to scale document conversion from a variety of formats.

How did you test it?

Added unit tests, integration tests and instructions for running tests locally using a docker container.

Notes for the reviewer

Checklist

@maxdswain
maxdswain requested a review from a team as a code owner August 23, 2026 18:09
@maxdswain
maxdswain requested review from sjrl and removed request for a team August 23, 2026 18:09
@github-actions

Copy link
Copy Markdown
Contributor

Hi @maxdswain, thanks for your interest in contributing to Haystack! 🙏

⚠️ You currently have 3 open pull requests in this repository (#3835, #3833 and this one). Our review capacity is limited, so please hold off opening more PRs until we've had a chance to review your first 2 open PRs. This helps us give each contribution the attention it deserves. Thank you!

This is an automated message to help us keep the review queue healthy.

@github-actions github-actions Bot added topic:CI type:documentation Improvements or additions to documentation labels Aug 23, 2026
@socket-security

socket-security Bot commented Aug 23, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​gotenberg-client@​1.0.09810010010070

View full report

"""
Convert files, UTF-8 HTML or Markdown, and web URLs to ordered PDFs with Gotenberg.

Resources are supported only for HTML and Markdown conversions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets add a short Usage example in the docstrings here

Resources are supported only for HTML and Markdown conversions.
"""

def __init__(self, url: str = "http://localhost:3000", timeout: float = 30.0) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets make sure to add docstrings for the init method

return default_from_dict(cls, data)

@staticmethod
def _pdf(response: SingleFileResponse | ZipFileResponse) -> ByteStream:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even for these private methods could we add docstrings as well? It makes it easier to understand and review.

"""
with self._prepare(sources, conversion_type, resources) as (prepared, resource_paths):
with SyncGotenbergClient(self.url, timeout=self.timeout, backend="httpx") as client:
output = [self._pdf(_route(client, source, resource_paths).run()) for source in prepared]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when doing function calls in general it would be nice to use the variable names in the call signature

Comment on lines +36 to +39
class GotenbergFileConverterOutput(TypedDict):
"""The output returned by `GotenbergFileConverter`."""

output: list[ByteStream]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit overkill, could we just update the return signature to be dict[str, list[ByteStream]] instead of using a typed dict?

Comment on lines +5 to +7
from haystack_integrations.components.converters.gotenberg.converter import ConversionType, GotenbergFileConverter

__all__ = ["ConversionType", "GotenbergFileConverter"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to re-export ConversionType here. If its okay with you lets remove it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's okay with me, I'll remove it.

Convert sources to PDF using the selected Gotenberg route.

:param sources: Sources interpreted according to `conversion_type`.
:param conversion_type: Route to use: `libreoffice`, `html`, `markdown`, or `url`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets expand on this docstring. Currently this is lacking information to properly understand what this routing means. Does it mean the incoming sources are all of type conversion_type?

Comment on lines +242 to +244
def run(
self, sources: list[Source], conversion_type: ConversionType, resources: list[Path] | None = None
) -> GotenbergFileConverterOutput:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically in our converters we also like to support

meta: dict[str, Any] | list[dict[str, Any]] | None = None,

as a second argument to allow users to attach metadata to sources they are converting. Please check out how our Markdown converter handles this such that it also preserves any metadata that might already be attached to a Source that is a ByteStream

self, sources: list[Source], conversion_type: ConversionType, resources: list[Path] | None = None
) -> GotenbergFileConverterOutput:
"""
Convert sources to PDF using the selected Gotenberg route.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also general design question why do we force users to have to pick a conversion type? Why not auto route based on the detected mime type of the incoming source? The str, and Path sources should have a suffix and we can throw an error if ByteStream doesn't come with a populated mime type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was modelling this integration off of the existing libreoffice integration where we forced users to pick a conversation, but yeah you're right in that we don't need to force users for this integration. I'll implement auto detection of mime type.

@maxdswain

Copy link
Copy Markdown
Contributor Author

Thanks for the review @sjrl, I think I've addressed all of your comments now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:CI type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add new Gotenberg Integration

2 participants