This commit is contained in:
seb
2026-09-26 14:42:29 +02:00
parent f0176e0fe0
commit cbb2fdeb6d
4 changed files with 15 additions and 5 deletions

View File

@@ -4609,7 +4609,7 @@
"Delivery"
],
"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",
"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` (or the server's\n`OPENROUTER_FREE_KEY` if not configured); 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": []

View File

@@ -14,7 +14,8 @@ 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
the authenticated user's company setting `keys.openrouter` (or the server's
`OPENROUTER_FREE_KEY` if not configured); the endpoint
returns `400` if the key is not configured.
The stream ends after the final `result` event (or an `error` event on failure).

View File

@@ -5,6 +5,7 @@ import multer from 'multer';
import { LLMOrbiter, OpenRouterProvider, defineTool, DirectReturnError } from 'libllmorbiter';
import * as dbCompanySetting from '../../db/companysetting.js';
import * as dbSupplier from '../../db/supplier.js';
import env from '../../config/env.js';
// ─── Multer — memory storage (no temp files); accepts PDF or text ───────────────
const upload = multer({
@@ -113,14 +114,20 @@ ${supplierList}`;
* @param {string} opts.sourceLabel e.g. 'PDF' or 'Text'
*/
async function parseDocumentManifest({ req, res, pages, sourceLabel }) {
// ── Fetch OpenRouter API key from company settings ────────────────
// ── Fetch OpenRouter API key from company settings (or fallback) ──
let apiKey;
try {
const setting = await dbCompanySetting.getByKey(req.user.id, 'keys.openrouter', { maskWriteonly: false });
apiKey = setting?.value;
apiKey = setting?.value?.trim();
} catch (err) {
console.error('delivery parse: failed to read OpenRouter key:', err);
}
if (!apiKey) {
apiKey = env.openrouterFreeKey?.trim();
if (apiKey) {
console.log('delivery parse: using fallback OPENROUTER_FREE_KEY');
}
}
if (!apiKey) {
return res.status(400).json({ error: 'OpenRouter API key not configured (companysetting: keys.openrouter)' });
}
@@ -447,7 +454,8 @@ export function register(app, basePath = '') {
*
* 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
* the authenticated user's company setting `keys.openrouter` (or the server's
* `OPENROUTER_FREE_KEY` if not configured); the endpoint
* returns `400` if the key is not configured.
*
* The stream ends after the final `result` event (or an `error` event on failure).

View File

@@ -16,6 +16,7 @@ export default {
implicitCreate: process.env.IMPLICIT_CREATE === 'true',
jwtSecret: process.env.JWT_SECRET || 'fallback_secret_please_change_in_production',
dbProvider: process.env.DB_PROVIDER || (process.env.SQLITE_PATH ? 'sqlite' : 'mssql'),
openrouterFreeKey: process.env.OPENROUTER_FREE_KEY,
sqlite: {
filename: process.env.SQLITE_PATH || process.env.SQLITE_FILENAME || resolve(__dirname, '../../data/dash.db'),
},