docling-serve-client 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +312 -251
- package/dist/client.d.ts +3 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/core/input.d.ts.map +1 -1
- package/dist/core/pdf.d.ts.map +1 -1
- package/dist/core/validate.d.ts.map +1 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -29
- package/dist/index.js.map +11 -11
- package/dist/options.d.ts +25 -3
- package/dist/options.d.ts.map +1 -1
- package/dist/types.d.ts +52 -14
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/capabilities.ts +1 -1
- package/src/client.ts +126 -20
- package/src/core/http.ts +2 -4
- package/src/core/input.ts +0 -2
- package/src/core/pdf.ts +0 -1
- package/src/core/validate.ts +0 -1
- package/src/document.ts +7 -19
- package/src/images.ts +1 -3
- package/src/index.ts +1 -0
- package/src/options.ts +123 -24
- package/src/response.ts +1 -1
- package/src/types.ts +65 -30
package/README.md
CHANGED
|
@@ -6,19 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
# docling-serve-client
|
|
8
8
|
|
|
9
|
-
Typed HTTP client for a running [docling-serve](https://github.com/docling-project/docling-serve): **PDF or image
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
- **Calls never throw on runtime failures.** Every call resolves to `{ ok: true, data } | { ok: false, error }`.
|
|
18
|
-
Two exceptions are programming errors: the factory throws a `TypeError` on invalid config, and any call with an
|
|
19
|
-
invalid option rejects with a `TypeError` before sending a request.
|
|
20
|
-
- Sync (`convert*`) and async (`submit*` + `check`). No built-in polling, queueing or rate limiting.
|
|
21
|
-
- Zero dependencies. ESM, works in Node ≥ 22.12 (also via `require()`) and Bun.
|
|
9
|
+
Typed HTTP client for a running [docling-serve](https://github.com/docling-project/docling-serve): **PDF or image bytes in, docling's Markdown or DoclingDocument JSON out**.
|
|
10
|
+
|
|
11
|
+
- **Two outputs**: `convertMarkdown` returns docling's Markdown unchanged (with configurable image handling); `convertDocument` returns the full DoclingDocument JSON AST (labels, reading order, page metadata, bounding boxes).
|
|
12
|
+
- **No text heuristics**: raw docling output is preserved exactly as returned by the server (e.g. HTML entities, soft hyphens, dot leaders).
|
|
13
|
+
- **In-memory only**: no file I/O or streaming dependencies.
|
|
14
|
+
- **Never throws on runtime failures**: all client calls resolve to `{ ok: true, data } | { ok: false, error }`. Programming errors throw a `TypeError` (synchronously on the factory for invalid configuration; rejected on methods before sending requests for invalid options).
|
|
15
|
+
- **Three execution modes**: single requests (`convert*`), background jobs (`submit*` + `check`), and automated polling helpers (`run*`, `waitForJob`). See [Single request or job?](#single-request-or-job).
|
|
16
|
+
- **Zero dependencies**: pure ESM, runs on Node ≥ 22.12 (including `require()`) and Bun.
|
|
22
17
|
|
|
23
18
|
## Installation
|
|
24
19
|
|
|
@@ -36,204 +31,267 @@ import { createDoclingClient } from 'docling-serve-client';
|
|
|
36
31
|
|
|
37
32
|
const docling = createDoclingClient({ baseUrl: 'http://127.0.0.1:5001' });
|
|
38
33
|
|
|
39
|
-
// Input is
|
|
34
|
+
// Input is a Uint8Array (Node Buffer is an instance): PDF, PNG, JPEG, TIFF, or WebP
|
|
40
35
|
const pdf = await readFile('paper.pdf');
|
|
41
|
-
// const pdf = await Bun.file('paper.pdf').bytes();
|
|
42
|
-
// const pdf = new Uint8Array(await (await fetch(pdfUrl)).arrayBuffer()); // any download
|
|
36
|
+
// const pdf = await Bun.file('paper.pdf').bytes(); // Bun
|
|
43
37
|
|
|
38
|
+
// 1. Convert to Markdown
|
|
44
39
|
const md = await docling.convertMarkdown(pdf);
|
|
45
|
-
if (md.ok)
|
|
40
|
+
if (md.ok) {
|
|
41
|
+
console.log(md.data.markdown, md.data.warnings);
|
|
42
|
+
}
|
|
46
43
|
|
|
44
|
+
// 2. Convert to DoclingDocument JSON AST
|
|
47
45
|
const doc = await docling.convertDocument(pdf);
|
|
48
46
|
if (doc.ok) {
|
|
49
47
|
for (const item of doc.data.document.texts) {
|
|
50
|
-
if (item.label === 'section_header')
|
|
48
|
+
if (item.label === 'section_header') {
|
|
49
|
+
console.log(item.level, item.text, item.prov[0]?.page_no);
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
} else {
|
|
53
53
|
console.error(doc.error.code, doc.error.message);
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
// 3. Automated job helper (identical data, typically faster for small inputs)
|
|
57
|
+
const fast = await docling.runDocument(pdf);
|
|
58
|
+
if (fast.ok) {
|
|
59
|
+
console.log(fast.data.document.texts.length, fast.data.settings);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Single request or job?
|
|
64
|
+
|
|
65
|
+
docling-serve exposes two endpoint families, covered by three client patterns:
|
|
66
|
+
|
|
67
|
+
| Client Calls | docling-serve Endpoints | Execution Model |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Single request: `convertMarkdown`, `convertDocument` | Sync: `POST /v1/convert/file` | Holds a single HTTP connection open until conversion completes |
|
|
70
|
+
| Background job: `submitMarkdown`, `submitDocument`, `check` | Async: `POST /v1/convert/file/async`, `GET /v1/status/poll/{id}`, `GET /v1/result/{id}` | Returns a job ID immediately; caller persists job and polls with `check()` |
|
|
71
|
+
| Job helper: `runMarkdown`, `runDocument`, `waitForJob` | Async (as above) | Submits (or takes a stored job) and polls every `pollMs` (default 10 ms) until complete |
|
|
72
|
+
|
|
73
|
+
Under the hood, docling-serve processes single requests as background jobs polled at intervals of `DOCLING_SERVE_SYNC_POLL_INTERVAL` seconds (default 2). A sync request only finishes on a tick: a 0.5 s conversion waits up to 2 s, and a 2.1 s conversion waits 4 s. Measured on a one-page PDF (docling-serve 1.38.2, 5 calls each after warm-up):
|
|
74
|
+
|
|
75
|
+
| Call | Duration per call |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `convertDocument`, `convertMarkdown` | 2006 to 2033 ms |
|
|
78
|
+
| `runDocument`, `runMarkdown` | 221 to 420 ms |
|
|
79
|
+
|
|
80
|
+
Which to use:
|
|
81
|
+
|
|
82
|
+
- **Small inputs or latency-sensitive tasks** (single images, OCR crops, one-page PDFs): use `runMarkdown` or `runDocument`. They resolve to the same `data` as `convert*` and act as drop-in replacements.
|
|
83
|
+
- **Long documents**: any call works (latency overhead is at most one tick). Single requests fail with HTTP 504 after `DOCLING_SERVE_MAX_SYNC_WAIT` (120 s), so use a job or job helper for long conversions.
|
|
84
|
+
- **Cross-process workflows, queue progress, or recovery**: use `submit*`, persist the job object, and poll with `check()` or `waitForJob()`.
|
|
85
|
+
- **Single HTTP request without polling**: use `convert*`.
|
|
86
|
+
|
|
87
|
+
Relevant docling-serve environment variables (read from the server environment or `.env` in the server root):
|
|
88
|
+
|
|
89
|
+
| Variable | Default | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `DOCLING_SERVE_SYNC_POLL_INTERVAL` | `2` | Seconds between status checks on the sync endpoint (integer; `1` halves single-request wait; fractions like `0.5` fail server startup) |
|
|
92
|
+
| `DOCLING_SERVE_MAX_SYNC_WAIT` | `120` | Seconds a single request waits before returning HTTP 504 (the server task continues running) |
|
|
93
|
+
| `DOCLING_SERVE_SINGLE_USE_RESULTS` | `true` | Purges task results `DOCLING_SERVE_RESULT_REMOVAL_DELAY` seconds after first result fetch (see [Jobs](#jobs)) |
|
|
94
|
+
| `DOCLING_SERVE_RESULT_REMOVAL_DELAY` | `300` | Seconds from first result fetch until the task is deleted |
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
DOCLING_SERVE_SYNC_POLL_INTERVAL=1 docling-serve run --host 127.0.0.1 --port 5001
|
|
55
98
|
```
|
|
56
99
|
|
|
57
|
-
|
|
100
|
+
In Node, `fetch` aborts if response headers take longer than 300 s (`network` error due to undici's default `headersTimeout`), so single requests fail after 300 s even if `DOCLING_SERVE_MAX_SYNC_WAIT` is set higher. Jobs are not affected.
|
|
58
101
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
[conversion settings](#conversion-settings) of its submission; `check()` does not need them, so a stored job may omit
|
|
63
|
-
`settings`, and the `done` state does not repeat them.
|
|
102
|
+
### Jobs
|
|
103
|
+
|
|
104
|
+
`submitMarkdown()` and `submitDocument()` return a plain JSON job object. Persist it and pass it to `check()` or `waitForJob()`. A Markdown job preserves its image handling settings across processes and restarts, returning the result type matching the job's `kind`. Jobs also store the [conversion settings](#conversion-settings) sent at submission; `check()` and `waitForJob()` do not require `settings` and omit them from their result.
|
|
64
105
|
|
|
65
106
|
```ts
|
|
66
107
|
import type { DocumentJob } from 'docling-serve-client';
|
|
67
108
|
|
|
109
|
+
// 1. One awaited helper call: submit, poll every 10 ms, return result (same data as convertDocument)
|
|
110
|
+
const res = await docling.runDocument(pdf, { images: 'placeholder' });
|
|
111
|
+
if (res.ok) {
|
|
112
|
+
console.log(res.data.document, res.data.settings);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 2. Or submit and store the job handle:
|
|
68
116
|
const job = await docling.submitDocument(pdf);
|
|
69
|
-
if (!job.ok)
|
|
117
|
+
if (!job.ok) {
|
|
118
|
+
throw new Error(`${job.error.code}: ${job.error.message}`);
|
|
119
|
+
}
|
|
70
120
|
await save(JSON.stringify(job.data)); // { kind: 'document', id, settings }
|
|
71
121
|
|
|
72
|
-
//
|
|
122
|
+
// 3. Later (in this or another process): poll until complete
|
|
73
123
|
const storedJob: DocumentJob = JSON.parse(await load());
|
|
124
|
+
const done = await docling.waitForJob(storedJob, { pollMs: 100 }); // Result<ConvertedDocument>
|
|
125
|
+
if (done.ok) {
|
|
126
|
+
console.log(done.data.document);
|
|
127
|
+
} else {
|
|
128
|
+
console.error(done.error.code, done.error.message);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 4. Or check status on demand (e.g. for progress bars):
|
|
74
132
|
const state = await docling.check(storedJob);
|
|
75
133
|
if (state.ok) {
|
|
76
134
|
switch (state.data.status) {
|
|
77
135
|
case 'queued': console.log('Queue position:', state.data.position); break;
|
|
78
136
|
case 'running': console.log('Processing...'); break;
|
|
79
|
-
case 'done':
|
|
137
|
+
case 'done': console.log(state.data.document); break;
|
|
80
138
|
}
|
|
81
139
|
} else {
|
|
82
|
-
// state.error.code: 'not_found' (
|
|
140
|
+
// state.error.code: 'not_found' (expired or unknown ID), 'http', 'conversion_failed', etc.
|
|
83
141
|
console.error(state.error.code, state.error.message);
|
|
84
142
|
}
|
|
85
|
-
|
|
86
|
-
// In-process polling loop until done:
|
|
87
|
-
while (true) {
|
|
88
|
-
const poll = await docling.check(storedJob);
|
|
89
|
-
if (!poll.ok) {
|
|
90
|
-
console.error('Job error:', poll.error.code, poll.error.message);
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
if (poll.data.status === 'done') {
|
|
94
|
-
use(poll.data.document);
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
98
|
-
}
|
|
99
143
|
```
|
|
100
144
|
|
|
101
|
-
For Markdown jobs (`submitMarkdown`), `check()` returns `JobState<ConvertedMarkdown>`
|
|
102
|
-
|
|
145
|
+
For Markdown jobs (`submitMarkdown`), `check()` returns `JobState<ConvertedMarkdown>` (`done` provides `markdown`, `images`, `warnings`, `versions`) and `waitForJob()` returns `ConvertedMarkdown`.
|
|
146
|
+
|
|
147
|
+
Job helper details:
|
|
103
148
|
|
|
104
|
-
|
|
105
|
-
(`
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
149
|
+
- `runMarkdown()` / `runDocument()` = `submit*()` + `waitForJob()`. They accept `convert*` options plus `pollMs` and resolve to `WithSettings<...>` (matching `convert*`).
|
|
150
|
+
- `waitForJob()` resolves to `check()`'s `done` data without `status` (`ConvertedMarkdown | ConvertedDocument` when called with an unnarrowed `JobRef`).
|
|
151
|
+
- The first status poll runs immediately; `pollMs` delays only after `queued` or `running` states, keeping at most one request in flight. Finished jobs return in a single check.
|
|
152
|
+
- The first encountered error terminates the call without retries (same error codes as `submit*` and `check()`).
|
|
153
|
+
- `signal` covers submission, status polls, and waits. Factory `timeoutMs` limits individual HTTP requests. Use `signal: AbortSignal.timeout(ms)` to bound total execution time.
|
|
154
|
+
- Aborting a call (or encountering an HTTP 504 on `convert*`) cancels only client-side execution; docling-serve has no task cancellation endpoint, so the server task continues.
|
|
155
|
+
- `run*` does not return the job handle. To retain job IDs across restarts or retry result downloads, use `submit*` with `waitForJob()`.
|
|
109
156
|
|
|
110
|
-
|
|
157
|
+
When `DOCLING_SERVE_SINGLE_USE_RESULTS=true` (the default), docling-serve purges a task `DOCLING_SERVE_RESULT_REMOVAL_DELAY` seconds (default 300) after its result is first fetched. If a download in `check()` or `waitForJob()` fails (e.g. network interruption or abort), it can be retried within this window. Once purged, calls return `not_found` (`Unknown job id`). To retain completed tasks on the server, configure `DOCLING_SERVE_SINGLE_USE_RESULTS=false`. Single requests (`convert*`) are unaffected.
|
|
111
158
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(`Option "x" is not supported`, `Invalid value for option "x"`; nested keys are named like `imageOptions.prefix`).
|
|
159
|
+
### Client configuration and options
|
|
160
|
+
|
|
161
|
+
Create a client instance with `createDoclingClient(config)`:
|
|
116
162
|
|
|
117
163
|
```ts
|
|
164
|
+
import { createDoclingClient } from 'docling-serve-client';
|
|
165
|
+
|
|
118
166
|
const docling = createDoclingClient({
|
|
119
|
-
baseUrl: 'http://127.0.0.1:5001',
|
|
120
|
-
apiKey: '
|
|
121
|
-
timeoutMs: 120_000, // optional
|
|
122
|
-
|
|
123
|
-
|
|
167
|
+
baseUrl: 'http://127.0.0.1:5001', // base URL (may include a path prefix); trailing slash stripped; no query, fragment, or auth
|
|
168
|
+
apiKey: 'my-secret-key', // optional X-Api-Key header
|
|
169
|
+
timeoutMs: 120_000, // optional per-request timeout in ms (resolves to aborted)
|
|
170
|
+
pollMs: 10, // default polling interval in ms for job helpers (default 10)
|
|
171
|
+
options: { ocrLang: ['de', 'en'] }, // default docling options applied to every call
|
|
172
|
+
fetch: customFetch, // optional custom fetch implementation
|
|
124
173
|
});
|
|
125
|
-
|
|
126
|
-
await docling.convertDocument(pdf, { ocr: false, images: 'placeholder', signal: AbortSignal.timeout(60_000) });
|
|
127
174
|
```
|
|
128
175
|
|
|
129
|
-
|
|
176
|
+
#### Factory configuration (`DoclingConfig`)
|
|
130
177
|
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
client for
|
|
145
|
-
|
|
146
|
-
| option | default | effect |
|
|
147
|
-
|---|---|---|
|
|
148
|
-
| `ocrLang` | engine default | BCP-47 hints in order of preference, e.g. `['de', 'en-US']`; `[]` = engine default |
|
|
149
|
-
| `pageRange` | all pages | `[from, to]`, 1-based, inclusive |
|
|
150
|
-
| `documentTimeout` | server default | server-side limit in seconds |
|
|
178
|
+
| Option | Type | Default | Description |
|
|
179
|
+
|---|---|---|---|
|
|
180
|
+
| `baseUrl` | `string` | *required* | docling-serve base URL (e.g. `'http://127.0.0.1:5001'`). May include a path prefix; trailing slash stripped; no query, fragment, or credentials |
|
|
181
|
+
| `apiKey` | `string` | none | Sent in `X-Api-Key` request header |
|
|
182
|
+
| `timeoutMs` | `number` | none | Per-request timeout in milliseconds (integer `1..2147483647`; resolves to `aborted` on expiry; excludes `/version`) |
|
|
183
|
+
| `pollMs` | `number` | `10` | Default polling interval in ms for job helpers (`run*`, `waitForJob`) (integer `1..2147483647`) |
|
|
184
|
+
| `options` | `ClientOptions` | none | Default conversion options applied to every call |
|
|
185
|
+
| `fetch` | `typeof fetch` | `globalThis.fetch` | Custom fetch implementation for proxies, mocking, or custom dispatchers |
|
|
186
|
+
|
|
187
|
+
The default `pollMs` of 10 ms sends up to 100 status requests per second per active job. On a local docling-serve instance with the default in-memory engine, status lookups are in-memory checks. For remote servers, queue-backed workers (RQ or Ray), or high-concurrency environments, configure 100 to 500 ms. The client performs no internal request queueing or rate limiting.
|
|
188
|
+
|
|
189
|
+
#### Conversion options (`DoclingOptions`)
|
|
190
|
+
|
|
191
|
+
Configurable on the factory as defaults and overridable per call. Invalid option keys or values throw a `TypeError` synchronously on the factory, or reject with a `TypeError` on client calls before sending a request (`Option "x" is not supported`, `Invalid value for option "x"`; nested keys are named like `imageOptions.prefix`).
|
|
151
192
|
|
|
152
|
-
|
|
193
|
+
| Option | Type | Default | Description |
|
|
194
|
+
|---|---|---|---|
|
|
195
|
+
| `headingHierarchy` | `boolean` | `true` | Infers heading levels from bookmarks, numbering, and font styles. When `false`, all headings are level 1 |
|
|
196
|
+
| `formulaEnrichment` | `boolean` | `true` | Extracts math formulas as LaTeX via dedicated model. When `false`, formula text is empty and Markdown shows `<!-- formula-not-decoded -->` |
|
|
197
|
+
| `codeEnrichment` | `boolean` | `false` | Extracts code listings via dedicated model (slower) |
|
|
198
|
+
| `chartExtraction` | `boolean` | `false` | Extracts charts and plots as structured data via vision model (slower) |
|
|
199
|
+
| `pipeline` | `'standard' \| 'vlm'` | `'standard'` | Processing pipeline. `'vlm'` runs a vision-language model per page (slow) |
|
|
200
|
+
| `pdfBackend` | `'docling_parse' \| 'pypdfium2'` | `'docling_parse'` | Text extraction engine. `'pypdfium2'` handles ligatures and word spaces better but omits page headers/footers |
|
|
201
|
+
| `ocr` | `boolean` | `true` | Runs OCR on scanned pages and raster graphics. Image input always runs OCR |
|
|
202
|
+
| `forceOcr` | `boolean` | `false` | Forces full-page OCR across all pages and drops the PDF text layer (for PDFs with corrupt text encodings). Enables OCR even with `ocr: false`. Slower than standard OCR, so prefer using it per document. Ignored for image input |
|
|
203
|
+
| `ocrEngine` | `OcrEngine` | `'auto'` | OCR engine preset (`ocr_preset`), e.g. `'auto'`, `'rapidocr'`, `'easyocr'`, `'tesseract'`, `'tesserocr'`, `'ocrmac'`, or any non-empty preset ID allowed by the server. An unallowed preset is rejected by the server with `http` status 422 (see [Server capabilities](#server-capabilities)) |
|
|
204
|
+
|
|
205
|
+
#### Factory-only options
|
|
206
|
+
|
|
207
|
+
Configured in `options` of `createDoclingClient`. Passing these per-call rejects with a `TypeError: Option "x" is not supported`. Use a separate client instance if different values are required.
|
|
153
208
|
|
|
154
|
-
|
|
|
209
|
+
| Option | Type | Default | Description |
|
|
155
210
|
|---|---|---|---|
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`
|
|
170
|
-
|
|
211
|
+
| `ocrLang` | `string[]` | engine default | BCP-47 language priority codes, e.g. `['de', 'en-US']`. `[]` uses the engine default |
|
|
212
|
+
| `pageRange` | `[number, number]` | all pages | Inclusive 1-based page range `[from, to]` |
|
|
213
|
+
| `documentTimeout` | `number` | server default | Server-side conversion timeout in seconds |
|
|
214
|
+
|
|
215
|
+
#### Per-call options
|
|
216
|
+
|
|
217
|
+
Options passed to individual conversion calls. These cannot be set in factory `options` (the factory throws a synchronous `TypeError: Option "x" is not supported`).
|
|
218
|
+
|
|
219
|
+
| Option | Applicable Calls | Type | Default | Description |
|
|
220
|
+
|---|---|---|---|---|
|
|
221
|
+
| `images` | Markdown calls | `'placeholder' \| 'none' \| 'extract'` | `'placeholder'` | Markdown image handling mode (see [Images in Markdown](#images-in-markdown)) |
|
|
222
|
+
| `imageOptions` | Markdown calls | `{ prefix: string, omitSmall?: boolean }` | none | Link prefix and size filtering. Required with `images: 'extract'`; rejected otherwise |
|
|
223
|
+
| `images` | Document calls | `'embedded' \| 'placeholder'` | `'embedded'` | AST picture image mode (see [Images in the DoclingDocument](#images-in-the-doclingdocument)) |
|
|
224
|
+
| `pageImages` | Document calls | `boolean` | `false` | Renders pages as images, decoded into `data.pageImages` (see [Page images](#page-images)) |
|
|
225
|
+
| `signal` | All calls | `AbortSignal` | none | Cancels the request or overall operation on abort |
|
|
226
|
+
| `pollMs` | `runMarkdown`, `runDocument`, `waitForJob` | `number` | factory `pollMs` (`10`) | Polling interval in milliseconds (integer `1..2147483647`). Rejected by `convert*`, `submit*`, and `check` |
|
|
227
|
+
|
|
228
|
+
#### Pinned server settings
|
|
229
|
+
|
|
230
|
+
The client enforces explicit server settings for consistent output:
|
|
231
|
+
- **Table structure**: Accurate TableFormer model is always enabled (`do_table_structure: true`, `table_mode: 'accurate'`, `table_structure_preset: 'tableformer_v1_accurate'`, `table_cell_matching: true`).
|
|
232
|
+
- **Resolution**: Pictures and page images render at 144 DPI (`images_scale: 2`, exported as `PAGE_IMAGE_SCALE`). Note: OCR runs independently at docling's internal 216 DPI.
|
|
233
|
+
- **Markdown format**: Compact tables are enabled (`md_compact_tables: true`) without page break placeholders (`md_page_break_placeholder: ''`). For document output, both parameters are omitted (`null`).
|
|
234
|
+
- **Model presets**: Pinned to `granite_docling` for `pipeline: 'vlm'`, `granite_vision_v4` for `chartExtraction`, and `codeformulav2` for code and formula enrichment. Picture classification and description remain disabled.
|
|
171
235
|
|
|
172
236
|
### Input formats
|
|
173
237
|
|
|
174
|
-
|
|
238
|
+
Input is supplied as a `Uint8Array` (Node `Buffer` instances are compatible). File formats are detected directly from header magic bytes; unsupported formats immediately resolve to `invalid_input` without sending an HTTP request:
|
|
175
239
|
|
|
176
|
-
|
|
|
240
|
+
| Format | Detection Signature | Sent As |
|
|
177
241
|
|---|---|---|
|
|
178
242
|
| PDF | `%PDF-` within the first 1024 bytes | `from_formats=pdf`, `document.pdf` |
|
|
179
|
-
| PNG
|
|
243
|
+
| PNG | `89 50 4E 47 0D 0A 1A 0A` at byte 0 | `from_formats=image`, `document.png` |
|
|
244
|
+
| JPEG | `FF D8 FF` at byte 0 | `from_formats=image`, `document.jpg` |
|
|
245
|
+
| TIFF | Little-endian `49 49 2A 00` or big-endian `4D 4D 00 2A` at byte 0 | `from_formats=image`, `document.tiff` |
|
|
246
|
+
| WebP | `RIFF` at byte 0 and `WEBP` at byte 8 | `from_formats=image`, `document.webp` |
|
|
180
247
|
|
|
181
|
-
|
|
182
|
-
on for images and never full-page: `ocr: false` would return no text, and `forceOcr: true` merges words (`stepsand`),
|
|
183
|
-
so both are ignored for image input. Use it e.g. to re-read a crop of a page whose text layer is broken. Text only
|
|
184
|
-
comes back if the server has a working OCR engine. PDF-only options (`pdfBackend`, `pageRange`) have no effect on
|
|
185
|
-
images.
|
|
248
|
+
Image inputs are converted as single-page documents. Docling runs layout detection and OCR on the image (`ocrLang` applies). Because images contain no embedded text layer, text extraction requires a working OCR engine on the server. OCR is always active for images: `ocr: false` and `forceOcr: true` are ignored (forcing full-page OCR on images merges words like `stepsand`). PDF-specific options (`pdfBackend`, `pageRange`) do not affect images.
|
|
186
249
|
|
|
187
250
|
### Images in the DoclingDocument
|
|
188
251
|
|
|
189
|
-
| `images` |
|
|
252
|
+
| `images` | Effect |
|
|
190
253
|
|---|---|
|
|
191
|
-
| `'embedded'` (default) | `pictures[].image.uri`
|
|
192
|
-
| `'placeholder'` | `pictures[].image` is `null
|
|
254
|
+
| `'embedded'` (default) | `pictures[].image.uri` contains a `data:image/png;base64,…` URI. Pictures retain bounding boxes, captions, and dimensions |
|
|
255
|
+
| `'placeholder'` | `pictures[].image` is `null`. Picture entries, bounding boxes, and captions remain intact; document payload is significantly smaller |
|
|
193
256
|
|
|
194
|
-
|
|
195
|
-
document. `isSmallImage(picture.image.size)` applies the same size filter as `omitSmall` (see below).
|
|
257
|
+
Base64 image data remains inside the document JSON. `isSmallImage(picture.image.size)` can be used to filter icons and decorative elements using the same heuristic as `omitSmall`.
|
|
196
258
|
|
|
197
259
|
### Page images
|
|
198
260
|
|
|
199
|
-
`pageImages: true` (
|
|
200
|
-
client moves them out of the document: `document.pages[n].image` is always `null`, so the JSON stays small, and the
|
|
201
|
-
images come back decoded in `data.pageImages`, in page order:
|
|
261
|
+
Setting `pageImages: true` (document conversions only; default `false`) requests page renderings from docling (`include_page_images`). The client strips embedded base64 data from `document.pages[n].image` (setting it to `null`) and returns decoded raw PNG images in `data.pageImages`:
|
|
202
262
|
|
|
203
263
|
```ts
|
|
204
264
|
import { writeFile } from 'node:fs/promises';
|
|
205
265
|
|
|
206
266
|
const res = await docling.convertDocument(pdf, { pageImages: true, images: 'placeholder' });
|
|
207
267
|
if (res.ok) {
|
|
208
|
-
await writeFile(`out/${docId}.json`, JSON.stringify(res.data.document)); //
|
|
268
|
+
await writeFile(`out/${docId}.json`, JSON.stringify(res.data.document)); // Small JSON without embedded page images
|
|
209
269
|
for (const image of res.data.pageImages) {
|
|
210
|
-
await writeFile(`out/${docId}-p${image.page}.png`, image.bytes);
|
|
270
|
+
await writeFile(`out/${docId}-p${image.page}.png`, image.bytes); // { page, mimeType, width, height, dpi, bytes }
|
|
211
271
|
}
|
|
212
272
|
}
|
|
213
273
|
```
|
|
214
274
|
|
|
215
|
-
- `page
|
|
216
|
-
- `width` and `height
|
|
217
|
-
|
|
218
|
-
-
|
|
219
|
-
-
|
|
220
|
-
|
|
221
|
-
|
|
275
|
+
- `page`: 1-based page number (absolute, preserved across `pageRange`); `dpi` is the resolution reported by docling (typically 144), or `0` if not reported.
|
|
276
|
+
- `width` and `height`: Pixel dimensions parsed from the PNG header (or docling's `image.size`). Scaled at 2 px per PDF point (an A4 page is ~1190 × 1684 px, ~0.4–0.6 MB PNG).
|
|
277
|
+
- Independent of `images`: `{ images: 'placeholder', pageImages: true }` drops figure raster data while returning page images.
|
|
278
|
+
- Job persistence: `submitDocument(pdf, { pageImages: true })` requires no extra storage; `check()` and `waitForJob()` return decoded page images.
|
|
279
|
+
- Any page image whose URI is not a base64 data URI, or contains invalid or empty data, is omitted from `pageImages`, retained in `document.pages[].image` as docling sent it, and reported in `data.warnings` with code `page_image_not_decoded` (`details.page`).
|
|
280
|
+
|
|
281
|
+
#### Mapping bounding boxes to page images (`toPageImageBox`)
|
|
222
282
|
|
|
223
|
-
|
|
224
|
-
onto its page image as `{ page, x, y, width, height }` in pixels with a top-left origin (unrounded), ready to store
|
|
225
|
-
next to the page image file or to crop with:
|
|
283
|
+
Docling documents store coordinates in PDF points, typically with a `BOTTOMLEFT` origin. The helper `toPageImageBox` maps any provenance bounding box to top-left pixel coordinates matching rendered page images:
|
|
226
284
|
|
|
227
285
|
```ts
|
|
228
286
|
import { toPageImageBox } from 'docling-serve-client';
|
|
229
287
|
|
|
230
288
|
for (const item of res.data.document.texts) {
|
|
231
289
|
for (const prov of item.prov) {
|
|
232
|
-
const box = toPageImageBox(res.data.document, prov); //
|
|
290
|
+
const box = toPageImageBox(res.data.document, prov); // { page, x, y, width, height }
|
|
233
291
|
}
|
|
234
292
|
}
|
|
235
293
|
|
|
236
|
-
//
|
|
294
|
+
// Table cells provide their own bbox (with TOPLEFT origin) and belong to their table's page:
|
|
237
295
|
for (const table of res.data.document.tables) {
|
|
238
296
|
const pageNo = table.prov[0]?.page_no ?? 1;
|
|
239
297
|
for (const row of table.data.grid) {
|
|
@@ -246,36 +304,37 @@ for (const table of res.data.document.tables) {
|
|
|
246
304
|
}
|
|
247
305
|
```
|
|
248
306
|
|
|
249
|
-
|
|
307
|
+
`toPageImageBox` calculates pixel coordinates using `PAGE_IMAGE_SCALE` (`2`). It works on any conversion result, even when `pageImages: false` was used. Returns `undefined` if page dimensions or coordinates are missing or invalid.
|
|
250
308
|
|
|
251
309
|
### DoclingDocument structure
|
|
252
310
|
|
|
253
311
|
`convertDocument()` returns the full JSON AST (`doc.data.document`) typed as `DoclingDocument`:
|
|
254
312
|
|
|
255
|
-
- `texts`:
|
|
256
|
-
- `tables`:
|
|
257
|
-
- `pictures`:
|
|
258
|
-
- `groups`:
|
|
259
|
-
- `key_value_items`:
|
|
260
|
-
- `form_items`:
|
|
261
|
-
- `pages`:
|
|
262
|
-
- `body`:
|
|
263
|
-
- `furniture`:
|
|
313
|
+
- `texts`: Array of text blocks (`label`, `text`, `orig`, `prov: [{ page_no, bbox, charspan }]`). Common labels: `'paragraph'`, `'section_header'`, `'title'`, `'list_item'`, `'code'`, `'formula'`, `'footnote'`, `'page_header'`, `'page_footer'`, `'caption'`. Section headers include heading `level`. List items include `enumerated` and `marker`. Code listings include `code_language`. Formulas contain LaTeX in `text` when `formulaEnrichment` is enabled. Note on `prov.charspan`: `[start, end)` is in Python Unicode code points; slice in JavaScript using `Array.from(item.text).slice(start, end).join('')` instead of `item.text.slice(start, end)` to handle surrogate pairs.
|
|
314
|
+
- `tables`: Array of tables (`prov`, `data: { grid: TableCell[][], num_rows, num_cols }`). Cells provide `text`, `row_span`, `col_span`, `bbox`, `column_header`, and `row_header`.
|
|
315
|
+
- `pictures`: Array of figures with `captions`, `prov`, `image` (`ImageRef` with base64 data URI when `images: 'embedded'`, or `null` when `images: 'placeholder'`), and `annotations` (e.g. chart data when `chartExtraction` was enabled, classifications, descriptions).
|
|
316
|
+
- `groups`: Structural groupings (`(ListGroup | InlineGroup | GroupItem)[]`) such as lists, inline formatting runs, chapters, or form sections.
|
|
317
|
+
- `key_value_items`: Key-value regions extracted from forms or documents (`graph: { cells: GraphCell[], links: GraphLink[] }`).
|
|
318
|
+
- `form_items`: Form regions and fields (`graph: { cells: GraphCell[], links: GraphLink[] }`).
|
|
319
|
+
- `pages`: Record of page metadata keyed by 1-based page number string (`"1"`, `"2"`, ...) with `size: { width, height }` in PDF points.
|
|
320
|
+
- `body`: Root container of content in logical reading order. Walk `body.children` (`{ $ref: string }` JSON pointers, e.g. `'#/texts/0'`) depth-first to traverse the document flow.
|
|
321
|
+
- `furniture`: Root container of headers, footers, and page numbers outside the body flow.
|
|
264
322
|
|
|
265
323
|
#### Navigating the AST in reading order
|
|
266
324
|
|
|
267
|
-
|
|
325
|
+
Root document flow is organized under `body.children`. Each child contains a JSON pointer reference (e.g. `#/texts/0`, `#/tables/1`, `#/groups/2`). References can be resolved and traversed like this:
|
|
268
326
|
|
|
269
327
|
```ts
|
|
270
328
|
import type { DoclingDocument } from 'docling-serve-client';
|
|
271
329
|
|
|
272
|
-
//
|
|
330
|
+
// Resolves a JSON pointer reference (e.g. '#/texts/0' or '#/body'):
|
|
273
331
|
function resolveRef(doc: DoclingDocument, ref: string) {
|
|
274
|
-
const
|
|
275
|
-
return (doc as Record<string, any>)[
|
|
332
|
+
const parts = ref.replace(/^#\//, '').split('/');
|
|
333
|
+
if (parts.length === 1) return (doc as Record<string, any>)[parts[0]!];
|
|
334
|
+
return (doc as Record<string, any>)[parts[0]!]?.[Number(parts[1])];
|
|
276
335
|
}
|
|
277
336
|
|
|
278
|
-
//
|
|
337
|
+
// Walks body items in logical reading order:
|
|
279
338
|
function* walkReadingOrder(
|
|
280
339
|
doc: DoclingDocument,
|
|
281
340
|
node: { children: { $ref: string }[] } = doc.body,
|
|
@@ -292,159 +351,141 @@ function* walkReadingOrder(
|
|
|
292
351
|
}
|
|
293
352
|
```
|
|
294
353
|
|
|
295
|
-
### Images in
|
|
354
|
+
### Images in Markdown
|
|
296
355
|
|
|
297
|
-
| `images` |
|
|
356
|
+
| `images` | Effect |
|
|
298
357
|
|---|---|
|
|
299
|
-
| `'placeholder'` (default) | `<!-- image -->` marks
|
|
300
|
-
| `'none'` |
|
|
301
|
-
| `'extract'` |
|
|
358
|
+
| `'placeholder'` (default) | `<!-- image -->` comment marks figure locations as produced by docling |
|
|
359
|
+
| `'none'` | Removes image comments |
|
|
360
|
+
| `'extract'` | Extracts images as binary buffers in `data.images` and updates Markdown links to `<prefix><n>.<ext>` |
|
|
302
361
|
|
|
303
|
-
|
|
362
|
+
When `images: 'extract'` is selected, `imageOptions` is required:
|
|
304
363
|
|
|
305
364
|
```ts
|
|
306
365
|
import { writeFile } from 'node:fs/promises';
|
|
307
366
|
|
|
308
367
|
const res = await docling.convertMarkdown(pdf, {
|
|
309
368
|
images: 'extract',
|
|
310
|
-
imageOptions: { prefix: `images/${docId}-` }, // omitSmall
|
|
369
|
+
imageOptions: { prefix: `images/${docId}-` }, // omitSmall defaults to true
|
|
311
370
|
});
|
|
312
371
|
if (res.ok) {
|
|
313
|
-
await writeFile(`out/${docId}.md`, res.data.markdown);
|
|
372
|
+
await writeFile(`out/${docId}.md`, res.data.markdown); // e.g. 
|
|
314
373
|
for (const image of res.data.images) {
|
|
315
|
-
await writeFile(`out/${image.path}`, image.bytes);
|
|
374
|
+
await writeFile(`out/${image.path}`, image.bytes); // { path, mimeType, bytes, width, height }
|
|
316
375
|
}
|
|
317
376
|
}
|
|
318
377
|
```
|
|
319
378
|
|
|
320
|
-
- `n` starts at 1 and counts
|
|
321
|
-
|
|
322
|
-
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
- A picture with invalid or empty base64 data is removed and reported as an `image_not_decoded` warning
|
|
326
|
-
(`details.index`: 1-based position among all embedded pictures); the conversion still succeeds.
|
|
327
|
-
- A picture docling sent without image data keeps its `<!-- image -->` placeholder, as in `'placeholder'` mode.
|
|
328
|
-
- Removing a picture or placeholder keeps the blank line that separates the paragraphs around it.
|
|
379
|
+
- Image numbering `n` starts at 1 and counts only retained images. Extension `<ext>` is derived from MIME type (`png`, `jpg`, `gif`, `webp`, `svg`, `tiff`, `bmp`, or `bin`).
|
|
380
|
+
- `omitSmall` (default `true`): Drops small icons, bullets, and decorative lines. Small images meet any of: area < 15,000 px, long side < 200 px, or short side < 24 px (`isSmallImage`). Only PNG images have known dimensions (`readPngSize`); non-PNG formats are retained with `width` and `height` set to `0`.
|
|
381
|
+
- Corrupt or empty base64 image data is removed and recorded in `data.warnings` with code `image_not_decoded` (`details.index` is the 1-based index among embedded images).
|
|
382
|
+
- Figures emitted by docling without image data retain their `<!-- image -->` placeholder comment.
|
|
383
|
+
- Removing placeholders or small images preserves adjacent paragraph line spacing.
|
|
329
384
|
|
|
330
385
|
### Warnings
|
|
331
386
|
|
|
332
|
-
`data.warnings`
|
|
387
|
+
`data.warnings` contains non-fatal issues encountered during an otherwise successful conversion:
|
|
333
388
|
|
|
334
|
-
|
|
|
389
|
+
| Code | `details` | Description |
|
|
335
390
|
|---|---|---|
|
|
336
|
-
| `server` | `{ component, module, category, page }` |
|
|
337
|
-
| `image_not_decoded` | `{ index }` | Markdown
|
|
338
|
-
| `page_image_not_decoded` | `{ page }` |
|
|
391
|
+
| `server` | `{ component, module, category, page }` | Warning reported by docling-serve (e.g. single page failure or `document timeout exceeded`). `page` is the 1-based page number or `null` |
|
|
392
|
+
| `image_not_decoded` | `{ index }` | Undecodable embedded image in Markdown (`images: 'extract'`). `index` is 1-based |
|
|
393
|
+
| `page_image_not_decoded` | `{ page }` | Undecodable page image in Document output (`pageImages: true`). `page` is 1-based |
|
|
339
394
|
|
|
340
|
-
Pages
|
|
341
|
-
failed page.
|
|
395
|
+
Pages abandoned by the server (e.g. due to `documentTimeout`) contain no extracted content and trigger a `server` warning.
|
|
342
396
|
|
|
343
397
|
### Server versions
|
|
344
398
|
|
|
345
|
-
`data.versions`
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
`document.version` is the DoclingDocument schema version. Errors from a request the server answered (`http`,
|
|
349
|
-
`not_found`, `conversion_failed`, `invalid_response`) carry the same `error.versions`. Each client asks for the
|
|
350
|
-
versions once and keeps them; the request has its own 2 s limit, and when it fails `versions` is `null` and the next
|
|
351
|
-
result asks again. Create a new client after a server update.
|
|
399
|
+
`data.versions` contains version metadata reported by `GET /version` (e.g. `{ 'docling-serve': '1.38.2', docling: '2.135.0', 'docling-core': '2.101.1', ... }`), or `null` if unreachable.
|
|
400
|
+
|
|
401
|
+
Storing versions alongside converted documents aids reproducibility, as conversion output can vary across docling releases (`document.version` indicates the DoclingDocument schema version, whereas `data.versions` reflects server runtime packages). Errors from requests answered by the server (`http`, `not_found`, `conversion_failed`, `invalid_response`) also populate `error.versions`. The client caches versions across requests; if a version check fails (2 s timeout), `versions` is `null` and retried on the next request. Create a new client instance after upgrading docling-serve.
|
|
352
402
|
|
|
353
403
|
### Conversion settings
|
|
354
404
|
|
|
355
|
-
`convert*()`
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
to know how a document was converted.
|
|
405
|
+
Results from `convert*()` and `run*()` (`data.settings`) and job objects from `submit*()` (`job.settings`) include a typed `DoclingSettings` record of all form parameters sent to docling-serve.
|
|
406
|
+
|
|
407
|
+
The client sends explicit values for every setting it controls, avoiding reliance on server defaults:
|
|
359
408
|
|
|
360
409
|
```ts
|
|
361
410
|
const res = await docling.convertMarkdown(pdf, { ocrEngine: 'rapidocr' });
|
|
362
411
|
if (res.ok) {
|
|
363
|
-
res.data.settings.ocrPreset; // 'rapidocr'
|
|
364
|
-
res.data.settings.tableStructurePreset; // 'tableformer_v1_accurate'
|
|
365
|
-
res.data.settings.vlmPipelinePreset; // null
|
|
412
|
+
console.log(res.data.settings.ocrPreset); // 'rapidocr'
|
|
413
|
+
console.log(res.data.settings.tableStructurePreset); // 'tableformer_v1_accurate'
|
|
414
|
+
console.log(res.data.settings.vlmPipelinePreset); // null (pipeline is 'standard')
|
|
366
415
|
}
|
|
367
416
|
```
|
|
368
417
|
|
|
369
|
-
-
|
|
370
|
-
- `null`
|
|
371
|
-
|
|
372
|
-
-
|
|
373
|
-
- Server configuration
|
|
374
|
-
`stages.layout` of the [server capabilities](#server-capabilities).
|
|
418
|
+
- Keys represent camelCase mappings of server form parameters (`ocrPreset` = `ocr_preset`).
|
|
419
|
+
- `null` indicates the parameter was omitted: Markdown-specific fields for JSON output, presets of inactive pipeline stages, or unset factory options (`pageRange`, `documentTimeout`). An empty `ocrLang` is omitted (server engine default).
|
|
420
|
+
- For image input, `doOcr: true` and `forceOcr: false` are recorded regardless of option flags.
|
|
421
|
+
- For PDF input with `forceOcr: true`, `doOcr: true` is recorded even when `ocr: false`.
|
|
422
|
+
- Server configuration outside request fields (e.g. default layout model) is not included; inspect `stages.layout` via `docling.capabilities()`.
|
|
375
423
|
|
|
376
424
|
### Server capabilities
|
|
377
425
|
|
|
378
|
-
`docling.capabilities()`
|
|
379
|
-
diagnostics, e.g. to list the allowed `ocrEngine` ids; conversions never call it. It takes only `{ signal }`.
|
|
426
|
+
`docling.capabilities({ signal? })` queries `GET /v1/capabilities` to inspect supported presets, stages, and limits. Used for diagnostics (e.g. checking available OCR engines); conversion calls do not invoke it automatically:
|
|
380
427
|
|
|
381
428
|
```ts
|
|
382
429
|
const caps = await docling.capabilities();
|
|
383
430
|
if (caps.ok) {
|
|
384
|
-
caps.data.stages.ocr?.presets.map((
|
|
385
|
-
caps.data.stages.table_structure?.default;
|
|
386
|
-
caps.data.limits.maxImagesScale;
|
|
387
|
-
caps.data.features.apiKeyRequired;
|
|
431
|
+
console.log(caps.data.stages.ocr?.presets.map((p) => p.id)); // ['auto', 'easyocr', 'rapidocr', 'tesseract', ...]
|
|
432
|
+
console.log(caps.data.stages.table_structure?.default); // 'tableformer_v1_accurate'
|
|
433
|
+
console.log(caps.data.limits.maxImagesScale); // 2 or null
|
|
434
|
+
console.log(caps.data.features.apiKeyRequired); // false
|
|
388
435
|
}
|
|
389
436
|
```
|
|
390
437
|
|
|
391
|
-
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
-
|
|
395
|
-
- An allowed preset is not always usable: e.g. `ocrmac` only runs on macOS.
|
|
396
|
-
- An older server without the endpoint answers `http` with `status: 404`.
|
|
438
|
+
- Snake_case server keys are converted to camelCase, while `stages` keys retain their server names (`ocr`, `layout`, `table_structure`, `vlm_pipeline`, `chart_extraction`, etc.). Each stage provides its form parameter name (`option`), server default (`default`), and allowed presets (`presets: { id, name, description, source }[]`).
|
|
439
|
+
- Missing or mistyped payload properties fall back to safe empty defaults (`[]`, `''`, `null`, `false`).
|
|
440
|
+
- Capabilities do not guarantee runtime availability (e.g. `ocrmac` requires macOS).
|
|
441
|
+
- Older server versions lacking the endpoint return an `http` error with status `404`.
|
|
397
442
|
|
|
398
|
-
###
|
|
443
|
+
### Corrupt text encodings & special characters
|
|
399
444
|
|
|
400
|
-
If
|
|
401
|
-
(seen with `/MacRomanEncoding` PDFs from Mac Word). Re-convert that document with `{ forceOcr: true }` (with `ocrLang: ['de']` on the factory).
|
|
402
|
-
It is slower, so use it per document, not by default.
|
|
445
|
+
If output displays corrupted umlauts or symbols (e.g. `fŸhrt`, `Nu§baum`, `…sterreich`), the PDF text layer uses an encoding incompatible with docling's parser (common in Mac Word documents with `/MacRomanEncoding`). Re-convert with `{ forceOcr: true }` (and configure `ocrLang` on the factory) to bypass the corrupt text layer and run full-page OCR.
|
|
403
446
|
|
|
404
447
|
### Errors
|
|
405
448
|
|
|
406
|
-
All client
|
|
449
|
+
All client methods return a discriminated `Result<T>` union:
|
|
407
450
|
- `{ ok: true, data: T }` on success
|
|
408
451
|
- `{ ok: false, error: ConvertError }` on runtime failure
|
|
409
452
|
|
|
410
|
-
#### Error
|
|
453
|
+
#### Error structure
|
|
411
454
|
|
|
412
455
|
Every `ConvertError` contains:
|
|
413
|
-
- `code`:
|
|
414
|
-
- `message`:
|
|
415
|
-
- `status`:
|
|
416
|
-
- `versions`:
|
|
417
|
-
- `details`: `{ errors: ServerError[]; failure: TaskFailure | null }` (present only when `code === 'conversion_failed'`)
|
|
456
|
+
- `code`: Error classification (see table below)
|
|
457
|
+
- `message`: Diagnostic description
|
|
458
|
+
- `status`: Optional HTTP status code when answered by the server (e.g. `400`, `404`, `422`, `500`)
|
|
459
|
+
- `versions`: Server versions captured via `GET /version`, or `null`
|
|
460
|
+
- `details`: `{ errors: ServerError[]; failure: TaskFailure | null }` (present only when `code === 'conversion_failed'`). `errors` lists docling error items with `{ message, details: { component, module, category, page } }`; `failure` categorizes task failure as `{ category, phase, retryable }` (or `null`)
|
|
418
461
|
|
|
419
|
-
|
|
|
462
|
+
| Code | Cause |
|
|
420
463
|
|---|---|
|
|
421
|
-
| `invalid_input` | not a non-empty
|
|
422
|
-
| `network` |
|
|
423
|
-
| `aborted` |
|
|
424
|
-
| `http` |
|
|
425
|
-
| `not_found` | `check()`: `Unknown job id`
|
|
426
|
-
| `conversion_failed` |
|
|
427
|
-
| `invalid_response` |
|
|
464
|
+
| `invalid_input` | Input is not a non-empty `Uint8Array`, contains an unrecognized file signature, has a truncated PDF cross-reference table, is an invalid job object, or failed buffer preparation before upload. No request sent |
|
|
465
|
+
| `network` | Server unreachable or connection refused |
|
|
466
|
+
| `aborted` | Abort signal fired (including `AbortSignal.timeout()`), or factory `timeoutMs` expired |
|
|
467
|
+
| `http` | Non-2xx HTTP response, or single-request timeout (HTTP 504 after `DOCLING_SERVE_MAX_SYNC_WAIT`) |
|
|
468
|
+
| `not_found` | `check()` or `waitForJob()`: unknown or expired job ID (`Unknown job id` after server restart or expiration of 300 s result delay), or task purged between poll and fetch (`Result already fetched or expired`). Server message follows in parentheses |
|
|
469
|
+
| `conversion_failed` | Server failed to convert the document (or returned partial success without output content). Details provided in `error.details` |
|
|
470
|
+
| `invalid_response` | Unexpected response payload (unparseable JSON, missing task ID, missing output data, or body exceeding readable bounds) |
|
|
428
471
|
|
|
429
|
-
|
|
430
|
-
`{ message, details }` (component, module, category, page); `failure` is docling's task classification
|
|
431
|
-
`{ category, phase, retryable }` for async jobs, or `null`.
|
|
472
|
+
#### Error narrowing in TypeScript
|
|
432
473
|
|
|
433
|
-
TypeScript narrows `error` on `error.code`:
|
|
474
|
+
TypeScript automatically narrows `error.details` based on `error.code`:
|
|
434
475
|
|
|
435
476
|
```ts
|
|
436
477
|
if (!res.ok) {
|
|
437
478
|
switch (res.error.code) {
|
|
438
479
|
case 'conversion_failed':
|
|
439
480
|
console.error('Conversion failed:', res.error.message);
|
|
440
|
-
console.error('Server
|
|
481
|
+
console.error('Server errors:', res.error.details.errors);
|
|
441
482
|
console.error('Task failure:', res.error.details.failure);
|
|
442
483
|
break;
|
|
443
484
|
case 'http':
|
|
444
485
|
console.error(`HTTP error ${res.error.status}:`, res.error.message);
|
|
445
486
|
break;
|
|
446
487
|
case 'invalid_input':
|
|
447
|
-
console.error('
|
|
488
|
+
console.error('Validation failed before request:', res.error.message);
|
|
448
489
|
break;
|
|
449
490
|
default:
|
|
450
491
|
console.error(res.error.code, res.error.message);
|
|
@@ -452,12 +493,12 @@ if (!res.ok) {
|
|
|
452
493
|
}
|
|
453
494
|
```
|
|
454
495
|
|
|
455
|
-
####
|
|
496
|
+
#### Runtime errors vs programming errors
|
|
456
497
|
|
|
457
|
-
|
|
|
498
|
+
| Category | Causes | Handling |
|
|
458
499
|
|---|---|---|
|
|
459
|
-
| **Runtime failure** | Server
|
|
460
|
-
| **Programming error** |
|
|
500
|
+
| **Runtime failure** | Server down, invalid file bytes, HTTP 4xx/5xx, model crash, request timeout, abort signal | Resolves to `{ ok: false, error: ConvertError }` (never throws) |
|
|
501
|
+
| **Programming error** | Malformed base URL, invalid config types, unsupported call options, mutually exclusive options (e.g. `imageOptions` without `images: 'extract'`) | Factory throws `TypeError` synchronously; methods reject with `TypeError` before sending a request |
|
|
461
502
|
|
|
462
503
|
### Exported types, utilities & constants
|
|
463
504
|
|
|
@@ -470,45 +511,65 @@ import {
|
|
|
470
511
|
isSmallImage,
|
|
471
512
|
readPngSize,
|
|
472
513
|
PAGE_IMAGE_SCALE,
|
|
473
|
-
type DoclingClient,
|
|
474
|
-
type DoclingConfig,
|
|
475
|
-
type ClientOptions,
|
|
476
|
-
type DoclingOptions,
|
|
477
|
-
type MarkdownOptions,
|
|
478
|
-
type DocumentOptions,
|
|
479
514
|
type CallOptions,
|
|
480
|
-
type
|
|
515
|
+
type CapabilityLimits,
|
|
516
|
+
type CapabilityPreset,
|
|
517
|
+
type CapabilityStage,
|
|
518
|
+
type ClientOptions,
|
|
519
|
+
type ConversionFailure,
|
|
481
520
|
type ConvertError,
|
|
482
|
-
type ErrorCode,
|
|
483
|
-
type ConvertedMarkdown,
|
|
484
521
|
type ConvertedDocument,
|
|
522
|
+
type ConvertedMarkdown,
|
|
523
|
+
type ConvertInput,
|
|
524
|
+
type DoclingClient,
|
|
525
|
+
type DoclingConfig,
|
|
485
526
|
type DoclingDocument,
|
|
527
|
+
type DoclingOptions,
|
|
528
|
+
type DoclingSettings,
|
|
529
|
+
type DocumentImageMode,
|
|
486
530
|
type DocumentJob,
|
|
487
|
-
type
|
|
531
|
+
type DocumentOptions,
|
|
532
|
+
type DocumentWarning,
|
|
533
|
+
type ErrorCode,
|
|
534
|
+
type ExtractedImage,
|
|
535
|
+
type ImageOptions,
|
|
536
|
+
type ImageSize,
|
|
537
|
+
type ImageWarning,
|
|
488
538
|
type Job,
|
|
489
539
|
type JobRef,
|
|
490
540
|
type JobState,
|
|
491
|
-
type
|
|
492
|
-
type
|
|
493
|
-
type
|
|
541
|
+
type MarkdownImageMode,
|
|
542
|
+
type MarkdownJob,
|
|
543
|
+
type MarkdownJobOutput,
|
|
544
|
+
type MarkdownOptions,
|
|
545
|
+
type MarkdownWarning,
|
|
546
|
+
type OcrEngine,
|
|
494
547
|
type PageImage,
|
|
495
548
|
type PageImageBox,
|
|
496
|
-
type
|
|
497
|
-
type
|
|
498
|
-
type
|
|
549
|
+
type PageImageWarning,
|
|
550
|
+
type PdfBackend,
|
|
551
|
+
type PdfInput,
|
|
552
|
+
type Pipeline,
|
|
553
|
+
type PollOptions,
|
|
554
|
+
type Result,
|
|
555
|
+
type ServerCapabilities,
|
|
556
|
+
type ServerDetails,
|
|
499
557
|
type ServerError,
|
|
558
|
+
type ServerVersions,
|
|
559
|
+
type ServerWarning,
|
|
500
560
|
type TaskFailure,
|
|
561
|
+
type WithSettings,
|
|
501
562
|
} from 'docling-serve-client';
|
|
502
563
|
```
|
|
503
564
|
|
|
504
|
-
- `toPageImageBox(document, prov)`:
|
|
505
|
-
- `isSmallImage(size)`:
|
|
506
|
-
- `readPngSize(bytes)`:
|
|
507
|
-
- `PAGE_IMAGE_SCALE`:
|
|
565
|
+
- `toPageImageBox(document, prov)`: Maps a provenance entry `{ page_no, bbox }` to `{ page, x, y, width, height }` in top-left pixel coordinates. Returns `undefined` if page dimensions or coordinates are missing or invalid.
|
|
566
|
+
- `isSmallImage(size)`: Returns `true` if pixel dimensions match the `omitSmall` filter (area < 15,000 px, long side < 200 px, or short side < 24 px).
|
|
567
|
+
- `readPngSize(bytes)`: Extracts `{ width, height }` directly from a PNG's IHDR chunk. Returns `undefined` for invalid or non-PNG data.
|
|
568
|
+
- `PAGE_IMAGE_SCALE`: Constant `2` (144 DPI resolution used by docling page images and coordinate scaling).
|
|
508
569
|
|
|
509
570
|
## Running docling-serve
|
|
510
571
|
|
|
511
|
-
The client connects to a running [docling-serve](https://github.com/docling-project/docling-serve)
|
|
572
|
+
The client connects to a running [docling-serve](https://github.com/docling-project/docling-serve) instance:
|
|
512
573
|
|
|
513
574
|
```bash
|
|
514
575
|
# Install docling-serve (default / CPU)
|