Skip to content

Commit 401d38c

Browse files
JSv4claude
andauthored
Document Gotenberg-powered file conversion for non-core formats (#2218)
Adds a "Convertible Formats (via Gotenberg)" section to docs/upload_methods/supported_formats.md explaining the ~126 LibreOffice-backed extensions the optional pre-parse converter can turn into PDF, and a screenshotted "File Converters (Gotenberg)" walkthrough in docs/pipelines/pipeline_configuration.md covering enabling/disabling via the Admin UI or DEFAULT_FILE_CONVERTER. Also documents the already-running gotenberg compose service in choose-and-configure-docker-stack.md, adds GOTENBERG_* examples to the sample .django env files, and updates README's Supported Formats section. Adds a data-testid to the File Converter row in FiletypeDefaults.tsx and three docScreenshot captures in the existing file-converter on/off Playwright component tests to back the walkthrough. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5f96d9a commit 401d38c

14 files changed

Lines changed: 346 additions & 23 deletions

File tree

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ Browse the full documentation at [jsv4.github.io/OpenContracts](https://jsv4.git
287287
| [PDF Data Format](docs/architecture/PDF-data-layer.md) | How text maps to PDF coordinates |
288288
| [LLM Framework](docs/architecture/llms/README.md) | PydanticAI integration and agents |
289289
| [Vector Stores](docs/extract_and_retrieval/vector_stores.md) | Semantic search architecture |
290-
| [Pipeline Overview](docs/pipelines/pipeline_overview.md) | Parser and embedder system |
290+
| [Pipeline Overview](docs/pipelines/pipeline_overview.md) | Parser, embedder, and file-converter system |
291+
| [Supported File Formats](docs/upload_methods/supported_formats.md) | Core parsers plus Gotenberg-convertible formats |
291292
| [Custom Extractors](docs/walkthrough/advanced/write-your-own-extractors.md) | Build your own data extraction tasks |
292293
| [v3.0.0.b3 Release Notes](docs/releases/v3.0.0.b3.md) | Latest features and migration guide |
293294

@@ -335,7 +336,13 @@ OpenContracts collects anonymous usage data to guide development priorities: ins
335336
- DOCX (Word documents, via the [Docxodus](https://github.com/JSv4/Docxodus) microservice — character-offset annotations aligned with WASM rendering)
336337
- Plain text (`.txt`, split into sentence annotations via spaCy)
337338

338-
See [Supported File Formats](docs/upload_methods/supported_formats.md) for parser details and the `supportedMimeTypes` GraphQL query that exposes the live list to the frontend.
339+
Plus **126 additional formats** — legacy Microsoft Office, OpenDocument, Apple
340+
iWork, WordPerfect, images, HTML, and more — convertible to PDF by an optional
341+
[Gotenberg](https://github.com/gotenberg/gotenberg)-powered file converter
342+
(off by default; enable it in Admin → Pipeline Configuration, no
343+
docker-compose changes needed).
344+
345+
See [Supported File Formats](docs/upload_methods/supported_formats.md) for parser and conversion details, and the `supportedMimeTypes` / `convertibleExtensions` GraphQL queries that expose the live lists to the frontend.
339346

340347
---
341348

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
- **Documented Gotenberg-powered file conversion for non-core formats.**
2+
`docs/upload_methods/supported_formats.md` gained a "Convertible Formats
3+
(via Gotenberg)" section explaining the ~126 legacy Office/OpenDocument/
4+
iWork/image/HTML extensions the optional pre-parse converter can turn into
5+
PDF, how it fits into the ingest pipeline, and its off-by-default posture.
6+
`docs/pipelines/pipeline_configuration.md` gained a "File Converters
7+
(Gotenberg)" section with a screenshotted step-by-step walkthrough for
8+
enabling/disabling conversion via the Admin UI or the `DEFAULT_FILE_CONVERTER`
9+
env var, plus a note that the `gotenberg` compose service already ships in
10+
`local.yml`/`production.yml` and needs no compose changes to use.
11+
`docs/configuration/choose-and-configure-docker-stack.md` gained an
12+
"Optional Services" section covering `gotenberg` (and pointers for
13+
`warp-ingest`/`privacy_filter`). Sample `.django` env files
14+
(`docs/sample_env_files/backend/{local,production}/.django`) now document
15+
`GOTENBERG_SERVICE_URL`, `GOTENBERG_CONVERTER_TIMEOUT`, and
16+
`DEFAULT_FILE_CONVERTER`. `README.md`'s "Supported Formats" section and
17+
documentation table now mention the conversion capability.
18+
- **New `data-testid="file-converter-row"`** on the File Converter row in
19+
`frontend/src/components/admin/system_settings/FiletypeDefaults.tsx`, used
20+
by three new `docScreenshot` captures in
21+
`frontend/tests/system-settings-flows.ct.tsx`'s "file converter on/off"
22+
suite (disabled row, converter picker modal, enabled row) that back the new
23+
docs walkthrough.
7.32 KB
Loading
11.5 KB
Loading
36.6 KB
Loading

docs/configuration/choose-and-configure-docker-stack.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,47 @@ docker compose -f production.yml up
170170

171171
You should now be able to access the OpenContracts frontend by visiting your configured domain (served through Traefik on port 80/443).
172172

173+
## Optional Services
174+
175+
Both `local.yml` and `production.yml` ship a handful of services that start
176+
alongside the core stack but sit idle, doing no work and costing negligible
177+
resources, until you opt into the feature they power. None require a
178+
compose-file edit to "turn on" — you don't need to add or remove services;
179+
enabling the feature is a Django/`PipelineSettings` configuration change,
180+
and the container is already there to receive requests once you do.
181+
182+
| Service | Powers | Enable via |
183+
|---|---|---|
184+
| `gotenberg` | Pre-parse file-to-PDF conversion for non-core formats (`.doc`, `.odt`, `.pptx`, images, ...) | `PipelineSettings.default_file_converter` (Admin UI or `DEFAULT_FILE_CONVERTER` env var) |
185+
| `warp-ingest` | Alternative deterministic PDF parser | `warp-ingest` compose profile + `PDF_PARSER` |
186+
| `privacy_filter` | PII redaction pass | `PRIVACY_FILTER_API_KEY` env var |
187+
188+
### Gotenberg (file conversion for non-core formats)
189+
190+
The `gotenberg` service (`gotenberg/gotenberg:8`) is defined in both
191+
`local.yml` and `production.yml` with no compose profile gate, so it starts
192+
automatically with `docker compose -f local.yml up` / `docker compose -f
193+
production.yml up` — there's nothing to add here. It has no published host
194+
port; `django` and `celeryworker` reach it internally at
195+
`http://gotenberg:3000` on the docker bridge network, and both declare it as
196+
an optional dependency (`required: false`) so the stack still starts if the
197+
container is ever removed from your override.
198+
199+
By default no file converter is selected, so uploads outside PDF/TXT/DOCX
200+
are rejected and the `gotenberg` container never receives a request. To
201+
accept the ~120 additional formats it can convert (legacy Office,
202+
OpenDocument, iWork, images, and more), configure it as the default file
203+
converter — see the step-by-step walkthrough with screenshots in
204+
[File Converters (Gotenberg)](../pipelines/pipeline_configuration.md#file-converters-gotenberg),
205+
and the capability/security overview in
206+
[Supported File Formats](../upload_methods/supported_formats.md#convertible-formats-via-gotenberg).
207+
208+
If you want to remove the service entirely (e.g. a minimal-footprint
209+
deployment that will never need conversion), delete or comment out the
210+
`gotenberg` block in your compose override — just make sure
211+
`default_file_converter` stays unset, or ingest will fail for any upload
212+
routed through it.
213+
173214
## ENV File Configurations
174215

175216
OpenContracts is configured via .env files. For a local deployment, these should go in `.envs/.local`. For production,

docs/pipelines/pipeline_configuration.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,111 @@ Sensitive configuration (API keys, credentials) is stored encrypted in the datab
172172
> 1. Export secrets via Django shell: `PipelineSettings.get_instance().get_secrets()`
173173
> 2. After rotation, re-import: `instance.set_secrets(exported_secrets); instance.save()`
174174
175+
## File Converters (Gotenberg)
176+
177+
File converters are an **optional pre-parse step** that turns an upload with
178+
no native parser (`.doc`, `.rtf`, `.odt`, `.pptx`, `.xlsx`, `.png`, and ~120
179+
other extensions — see [Supported File Formats](../upload_methods/supported_formats.md#convertible-formats-via-gotenberg))
180+
into a PDF before the normal parser/thumbnailer/embedder stages run. This is
181+
a single install-wide setting (`PipelineSettings.default_file_converter`),
182+
**not** file-type-scoped like the Parser/Thumbnailer columns above — there is
183+
one converter selection for the whole install.
184+
185+
**Disabled by default.** A fresh install accepts only the three core formats
186+
(PDF, TXT, DOCX) until you configure a converter. OpenContracts ships one
187+
implementation out of the box, `GotenbergFileConverter`, which delegates to a
188+
[Gotenberg](https://github.com/gotenberg/gotenberg) service's LibreOffice
189+
route. See [File Converters](pipeline_overview.md#file-converters) in the
190+
Pipeline Architecture doc for the full extension-eligibility and security
191+
model (stored-MIME-type hardening, conversion-service egress/SSRF posture).
192+
193+
### The `gotenberg` service already runs in your stack
194+
195+
`local.yml` and `production.yml` both define a `gotenberg` service
196+
(`gotenberg/gotenberg:8`) with no compose profile gate, so it starts
197+
automatically with the rest of the stack (`docker compose -f local.yml up`,
198+
etc.) alongside `django` and `celeryworker` — you don't need to add or start
199+
anything at the compose level. It has no published host port (it's reachable
200+
only on the docker bridge at `http://gotenberg:3000`, avoiding a collision
201+
with the frontend dev server's own port 3000) and `django`/`celeryworker`
202+
declare it as an optional dependency (`required: false`), so the stack still
203+
starts normally if the container is ever removed. Until a converter is
204+
selected in `PipelineSettings`, the container simply sits idle — no requests
205+
are ever sent to it.
206+
207+
**Enabling conversion is therefore purely a `PipelineSettings` change**, made
208+
either through the admin UI at runtime or via an environment variable at
209+
first boot.
210+
211+
### Enabling via the Admin UI (runtime, no restart)
212+
213+
1. Log in as a superuser and navigate to **Admin → Pipeline Configuration**.
214+
The **File Converter** row lives in the Filetype Defaults panel, below
215+
**Default Embedder**. A fresh install shows it disabled:
216+
217+
![File Converter row — disabled](../assets/images/screenshots/auto/admin--pipeline-settings--file-converter-disabled.png)
218+
219+
2. Click **Edit** on the File Converter row to open the picker. Choose the
220+
**Gotenberg PDF Converter** card (or type a custom converter class path
221+
directly into the input, if you've registered your own `BaseFileConverter`
222+
subclass):
223+
224+
![File Converter picker — Gotenberg selected](../assets/images/screenshots/auto/admin--pipeline-settings--file-converter-picker.png)
225+
226+
3. Click **Save**. The row now shows the configured converter's class path,
227+
and every subsequent upload whose extension is in Gotenberg's supported
228+
set is converted to PDF before parsing:
229+
230+
![File Converter row — enabled](../assets/images/screenshots/auto/admin--pipeline-settings--file-converter-enabled.png)
231+
232+
Changes take effect immediately for new uploads; documents already ingested
233+
are not reprocessed.
234+
235+
### Disabling via the Admin UI
236+
237+
Repeat the same flow and pick **None (conversion disabled)** in the picker,
238+
then **Save**. This writes an empty string to `default_file_converter`,
239+
which the backend treats as "conversion off" — uploads outside the three
240+
core formats are rejected again, exactly like a fresh install.
241+
242+
### Enabling/disabling via environment variable
243+
244+
For first-boot / infrastructure-as-code setups, set `DEFAULT_FILE_CONVERTER`
245+
in your `.django` env file before running migrations — it seeds
246+
`PipelineSettings.default_file_converter` the same way `PDF_PARSER` seeds the
247+
preferred parser (see [First-Time Setup](#first-time-setup-fresh-install)
248+
above):
249+
250+
```bash
251+
# .envs/.local/.django or .envs/.production/.django
252+
253+
# Enable Gotenberg-powered conversion for non-core formats:
254+
DEFAULT_FILE_CONVERTER=opencontractserver.pipeline.file_converters.gotenberg_converter.GotenbergFileConverter
255+
256+
# Leave unset (or empty) to keep conversion disabled — the default.
257+
# DEFAULT_FILE_CONVERTER=
258+
```
259+
260+
This only takes effect on first migration of a fresh `PipelineSettings`
261+
singleton, or after `migrate_pipeline_settings --sync-preferences`, per the
262+
[Configuration Priority](#configuration-priority) rules above — an existing
263+
install should use the Admin UI instead, since the database is the runtime
264+
source of truth.
265+
266+
Two related settings tune the Gotenberg connection itself (also configurable
267+
as `GotenbergFileConverter` component settings in the Admin UI's Component
268+
Library):
269+
270+
| Env var | Default | Purpose |
271+
|---|---|---|
272+
| `GOTENBERG_SERVICE_URL` | `http://gotenberg:3000` | Base URL of the Gotenberg service |
273+
| `GOTENBERG_CONVERTER_TIMEOUT` | `300` | Conversion request timeout, in seconds |
274+
275+
To narrow the converter to a subset of extensions (e.g. only spreadsheets),
276+
set its `convert_extensions` component setting to a comma-separated list —
277+
see the **Component Library** panel or `GotenbergFileConverter.Settings` in
278+
[`gotenberg_converter.py`](../../opencontractserver/pipeline/file_converters/gotenberg_converter.py).
279+
175280
## Management Command Reference
176281

177282
### `migrate_pipeline_settings`
@@ -290,6 +395,7 @@ separately via their own delete mutations if desired.
290395
## See Also
291396

292397
- [Pipeline Architecture Overview](pipeline_overview.md)
398+
- [Supported File Formats](../upload_methods/supported_formats.md)
293399
- [Docling Parser](docling_parser.md)
294400
- [LlamaParse Parser](llamaparse_parser.md)
295401
- [Multimodal Embedder](multimodal_embedder.md)

docs/sample_env_files/backend/local/.django

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,14 @@ WARP_INGEST_PARSER_SERVICE_URL=http://warp-ingest:5001/api/parse
6363
# Must match the WARP_API_KEY set on the warp-ingest container. Warp-Ingest always
6464
# requires a key (its own default is "abc123"), so a blank value yields a 401.
6565
WARP_INGEST_API_KEY=
66+
67+
# Gotenberg file converter (optional pre-parse conversion of non-core formats
68+
# -- .doc, .odt, .pptx, images, etc. -- to PDF). The `gotenberg` compose
69+
# service already runs by default; it sits idle until a converter is
70+
# selected. See docs/pipelines/pipeline_configuration.md#file-converters-gotenberg.
71+
# ------------------------------------------------------------------------------
72+
# Uncomment to enable conversion for non-core formats on first boot (or set
73+
# it later at runtime via the Admin -> Pipeline Configuration UI):
74+
# DEFAULT_FILE_CONVERTER=opencontractserver.pipeline.file_converters.gotenberg_converter.GotenbergFileConverter
75+
GOTENBERG_SERVICE_URL=http://gotenberg:3000
76+
GOTENBERG_CONVERTER_TIMEOUT=300

docs/sample_env_files/backend/production/.django

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,14 @@ WARP_INGEST_PARSER_SERVICE_URL=http://warp-ingest:5001/api/parse
8181
# Must match the WARP_API_KEY set on the warp-ingest container. Warp-Ingest always
8282
# requires a key (its own default is "abc123"), so a blank value yields a 401.
8383
WARP_INGEST_API_KEY=
84+
85+
# Gotenberg file converter (optional pre-parse conversion of non-core formats
86+
# -- .doc, .odt, .pptx, images, etc. -- to PDF). The `gotenberg` compose
87+
# service already runs by default; it sits idle until a converter is
88+
# selected. See docs/pipelines/pipeline_configuration.md#file-converters-gotenberg.
89+
# ------------------------------------------------------------------------------
90+
# Uncomment to enable conversion for non-core formats on first boot (or set
91+
# it later at runtime via the Admin -> Pipeline Configuration UI):
92+
# DEFAULT_FILE_CONVERTER=opencontractserver.pipeline.file_converters.gotenberg_converter.GotenbergFileConverter
93+
GOTENBERG_SERVICE_URL=http://gotenberg:3000
94+
GOTENBERG_CONVERTER_TIMEOUT=300

docs/upload_methods/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ effects that certain annotation types trigger on import.
99

1010
| Page | Description |
1111
|------|-------------|
12-
| [Supported File Formats](supported_formats.md) | File types accepted for upload and which parsers handle them |
12+
| [Supported File Formats](supported_formats.md) | File types accepted for upload, which parsers handle them, and the optional Gotenberg conversion step for everything else |
1313
| [Single Document Upload](single_upload.md) | Uploading individual documents through the UI or API |
1414
| [Bulk ZIP Import](bulk_zip_import.md) | Importing many documents at once with folder structure, metadata, and relationships |
1515
| [Corpus Export/Import](corpus_export_import.md) | Exporting and re-importing full corpuses with annotations, labels, and configuration |

0 commit comments

Comments
 (0)