unify parse api

This commit is contained in:
seb
2026-09-18 04:35:42 +02:00
parent adb529d14f
commit bbd285109d
5 changed files with 491 additions and 443 deletions

View File

@@ -80,7 +80,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
| [`routes/customergroup/update.md`](routes/customergroup/update.md) | `PATCH /customergroup/{id}` |
| [`routes/delivery/list.md`](routes/delivery/list.md) | `GET /delivery` |
| [`routes/delivery/create.md`](routes/delivery/create.md) | `POST /delivery` |
| [`routes/delivery/parsePDF.md`](routes/delivery/parsePDF.md) | `POST /delivery/parsePDF` |
| [`routes/delivery/parse.md`](routes/delivery/parse.md) | `POST /delivery/parse` |
| [`routes/delivery/delete.md`](routes/delivery/delete.md) | `DELETE /delivery/{id}` |
| [`routes/delivery/get.md`](routes/delivery/get.md) | `GET /delivery/{id}` |
| [`routes/delivery/update.md`](routes/delivery/update.md) | `PATCH /delivery/{id}` |

View File

@@ -4258,23 +4258,23 @@
}
}
},
"/delivery/parsePDF": {
"/delivery/parse": {
"post": {
"tags": [
"Delivery"
],
"summary": "Parse PDF (SSE)",
"description": "Accepts a PDF invoice or delivery note (`multipart/form-data`, field `pdf`)\nand streams extraction results as Server-Sent Events until parsing is complete.\n\nThe PDF is read via `pdftotext -layout` and fed page-by-page to an LLM\n(OpenRouter) which fills a structured manifest of header data and line items.\nThe OpenRouter API key is read from the authenticated user's company setting\n`keys.openrouter`; the endpoint returns `400` if the key is not configured.\n\nThe stream ends after the final `result` event (or an `error` event on failure).\n",
"summary": "Parse document (SSE)",
"description": "Accepts an invoice or delivery note as PDF or text file\n(`multipart/form-data`, field `file`) and streams extraction results as\nServer-Sent Events until parsing is complete.\n\nPDFs are read via `pdftotext -layout`; text files are decoded as UTF-8.\nPages are separated by the form feed character (`\\f`). If no form feed\nis present, the input is treated as a single page.\n\nThe extracted pages are fed to an LLM (OpenRouter) which fills a structured\nmanifest of header data and line items. The OpenRouter API key is read from\nthe authenticated user's company setting `keys.openrouter`; the endpoint\nreturns `400` if the key is not configured.\n\nThe stream ends after the final `result` event (or an `error` event on failure).\n",
"security": [
{
"cookieAuth": []
}
],
"x-markdown": "delivery/parsePDF.md",
"x-markdown": "delivery/parse.md",
"x-sse-events": [
{
"name": "status",
"description": "PDF parse confirmation and LLM status messages",
"description": "Document parse confirmation and LLM status messages",
"payload": "{ \"message\": \"…\" }"
},
{
@@ -4304,7 +4304,7 @@
},
{
"name": "error",
"description": "Emitted on PDF parse or LLM failure; stream closes immediately after",
"description": "Emitted on document parse or LLM failure; stream closes immediately after",
"payload": "{ \"message\": \"…\" }"
}
],
@@ -4315,13 +4315,13 @@
"schema": {
"type": "object",
"required": [
"pdf"
"file"
],
"properties": {
"pdf": {
"file": {
"type": "string",
"format": "binary",
"description": "PDF file to parse (max 50 MB, application/pdf)"
"description": "Document to parse (max 50 MB, application/pdf or text file)"
}
}
}
@@ -4340,7 +4340,7 @@
}
},
"400": {
"description": "No PDF uploaded or OpenRouter key not configured",
"description": "No file uploaded, unsupported file type, or OpenRouter key not configured",
"content": {
"application/json": {
"schema": {

View File

@@ -1,16 +1,21 @@
# `POST /delivery/parsePDF`
# `POST /delivery/parse`
Protected. Requires a valid session cookie (`credentials: 'include'`).
Parse PDF (SSE)
Parse document (SSE)
Accepts a PDF invoice or delivery note (`multipart/form-data`, field `pdf`)
and streams extraction results as Server-Sent Events until parsing is complete.
Accepts an invoice or delivery note as PDF or text file
(`multipart/form-data`, field `file`) and streams extraction results as
Server-Sent Events until parsing is complete.
The PDF is read via `pdftotext -layout` and fed page-by-page to an LLM
(OpenRouter) which fills a structured manifest of header data and line items.
The OpenRouter API key is read from the authenticated user's company setting
`keys.openrouter`; the endpoint returns `400` if the key is not configured.
PDFs are read via `pdftotext -layout`; text files are decoded as UTF-8.
Pages are separated by the form feed character (`\f`). If no form feed
is present, the input is treated as a single page.
The extracted pages are fed to an LLM (OpenRouter) which fills a structured
manifest of header data and line items. The OpenRouter API key is read from
the authenticated user's company setting `keys.openrouter`; the endpoint
returns `400` if the key is not configured.
The stream ends after the final `result` event (or an `error` event on failure).
@@ -19,7 +24,7 @@ The stream ends after the final `result` event (or an `error` event on failure).
| Field | Required | Type | Description |
|-------|----------|------|-------------|
| `pdf` | yes | file | PDF file to parse (max 50 MB, application/pdf) |
| `file` | yes | file | Document to parse (max 50 MB, application/pdf or text file) |
## SSE Events
@@ -27,13 +32,13 @@ The response is a `text/event-stream`. Events are emitted in order until the str
| Event | Description | Payload |
|-------|-------------|---------|
| `status` | PDF parse confirmation and LLM status messages | `{ "message": "…" }` |
| `status` | Document parse confirmation and LLM status messages | `{ "message": "…" }` |
| `llm_call` | Fired before each LLM request | `{ "model": "…", "promptSize": 0, "messages": 0 }` |
| `tool_call` | Fired when the output_manifest tool is invoked | `{ "name": "output_manifest" }` |
| `usage` | Token usage after each LLM response | `{ "input": 0, "cached": 0, "output": 0, "cost": 0 }` |
| `progress` | Intermediate accumulated extraction state (basedata / notes / items) | `ManifestResult` |
| `result` | Final accumulated extraction — emitted just before the stream closes | `ManifestResult` |
| `error` | Emitted on PDF parse or LLM failure; stream closes immediately after | `{ "message": "…" }` |
| `error` | Emitted on document parse or LLM failure; stream closes immediately after | `{ "message": "…" }` |
## Response `200`
@@ -77,7 +82,7 @@ The response is a `text/event-stream`. Events are emitted in order until the str
| Status | Description |
|--------|-------------|
| 400 | No PDF uploaded or OpenRouter key not configured — `{"error":"…"}` |
| 400 | No file uploaded, unsupported file type, or OpenRouter key not configured — `{"error":"…"}` |
| 401 | Unauthorized — `{"error":"…"}` |
---