{ "updatedAt": "2026-10-01T11:55:03.918Z", "createdAt": "2026-10-01T08:16:25.450Z", "id": "NljcXxbg9UqJVBEW", "name": "paperless_ollama", "active": true, "isArchived": false, "nodes": [ { "parameters": { "workflowInputs": { "values": [ { "name": "correspondents", "type": "any" }, { "name": "tags", "type": "any" }, { "name": "documents", "type": "any" }, { "name": "content", "type": "any" } ] } }, "type": "n8n-nodes-base.executeWorkflowTrigger", "typeVersion": 1.1, "position": [ -256, -368 ], "id": "4606e8a4-69c3-4ee1-b54e-a826590aa12e", "name": "Input" }, { "parameters": { "jsCode": "const raw = $json.content || $json.text || \"\";\n\n// 1. Markdown entfernen & zuschneiden\nlet cleaned = raw.replace(/```json|```/g, '').trim();\n\n// 2. JSON-Bereich isolieren\nconst firstBrace = cleaned.indexOf('{');\nconst firstBracket = cleaned.indexOf('[');\nlet start = -1;\n\nif (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {\n start = firstBrace;\n} else if (firstBracket !== -1) {\n start = firstBracket;\n}\n\nif (start !== -1) {\n cleaned = cleaned.substring(start);\n}\n\n// 3. Parsen\nlet parsed;\ntry {\n parsed = JSON.parse(cleaned);\n} catch (e) {\n // Notfall-Reparatur, falls schließende Klammer fehlte\n parsed = JSON.parse(cleaned + (cleaned.startsWith('[') ? ']' : '}'));\n}\n\n// 4. n8n-konformes Format zurückgeben\nif (Array.isArray(parsed)) {\n // Array -> Mehrere n8n Items\n return parsed.map(entry => ({\n json: typeof entry === 'object' && entry !== null ? entry : { value: entry }\n }));\n}\n\nif (typeof parsed === 'object' && parsed !== null) {\n // Normales Objekt -> Ein n8n Item\n return [{ json: parsed }];\n}\n\n// Primitiver Wert (String, Zahl etc.)\nreturn [{ json: { value: parsed } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 352, -352 ], "id": "937e6c25-05c3-4e95-b8bf-76c310f80207", "name": "Code in JavaScript", "executeOnce": true }, { "parameters": { "modelId": { "__rl": true, "value": "ministral-3:3b", "mode": "list", "cachedResultName": "ministral-3:3b" }, "messages": { "values": [ { "content": "=\n{{ (Array.isArray($json.correspondents) ?$json.correspondents : []).map(c => `[${c.paperless_id ?? c.id}] ${c.name}`).join(', ') }}\n\n\n\n{{ (Array.isArray($json.tags) ?$json.tags : []).map(t => `[${t.paperless_id ?? t.id}] ${t.name}`).join(', ') }}\n\n\n\n{{ (Array.isArray($json.documents) ?$json.documents : []).map(d => `[${d.paperless_id ?? d.id}] ${d.name}`).join(', ') }}\n\n\n\n{{ ($json.content || '').substring(0, 1200) }}\n" } ] }, "options": { "system": "Klassifiziere den Dokumentenauszug anhand der bereitgestellten Listen.\n\nRegel für alle Entitäten:\n- Verwende die ID aus der jeweiligen Liste.\n- Falls kein passender Eintrag existiert: Setze die ID zwingend auf null und trage den neu erkannten Namen ein.\n- Tags dürfen mehrere Treffer oder ein leeres Array [] sein.\n\nAntworte ausschließlich mit reinem JSON (keine Markdown-Backticks, beginne direkt mit {):\n{\n \"Title\": \"Kurzer aussagekräftiger Dokumenttitel\",\n \"Korrespondent-ID\": number | null,\n \"Korrespondent\": \"string\",\n \"Dokumententyp-ID\": number | null,\n \"Dokumententyp\": \"string\",\n \"Tags\": [\n {\n \"Tag-ID\": number | null,\n \"Name\": \"string\"\n }\n ]\n}", "temperature": 0, "num_predict": 150, "keep_alive": "5m", "format": "json" } }, "type": "@n8n/n8n-nodes-langchain.ollama", "typeVersion": 1, "position": [ -32, -368 ], "id": "b7823307-d92a-4ec4-89fe-fdb0b0e7141c", "name": "Mistral", "executeOnce": true, "credentials": { "ollamaApi": { "id": "fgaZliEtIoej3jtn", "name": "Ollama account" } } } ], "connections": { "Input": { "main": [ [ { "node": "Mistral", "type": "main", "index": 0 } ] ] }, "Mistral": { "main": [ [ { "node": "Code in JavaScript", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "staticData": null, "meta": null, "pinData": {}, "versionId": "4bec14cf-b613-45e5-918b-73f02b6384d5", "activeVersionId": "4bec14cf-b613-45e5-918b-73f02b6384d5", "triggerCount": 0, "shared": [ { "updatedAt": "2026-10-01T08:16:25.453Z", "createdAt": "2026-10-01T08:16:25.453Z", "role": "workflow:owner", "workflowId": "NljcXxbg9UqJVBEW", "projectId": "cSAaWNJydnksD5EB" } ], "activeVersion": { "updatedAt": "2026-10-01T11:55:06.000Z", "createdAt": "2026-10-01T11:54:59.108Z", "versionId": "4bec14cf-b613-45e5-918b-73f02b6384d5", "workflowId": "NljcXxbg9UqJVBEW", "nodes": [ { "parameters": { "workflowInputs": { "values": [ { "name": "correspondents", "type": "any" }, { "name": "tags", "type": "any" }, { "name": "documents", "type": "any" }, { "name": "content", "type": "any" } ] } }, "type": "n8n-nodes-base.executeWorkflowTrigger", "typeVersion": 1.1, "position": [ -256, -368 ], "id": "4606e8a4-69c3-4ee1-b54e-a826590aa12e", "name": "Input" }, { "parameters": { "jsCode": "const raw = $json.content || $json.text || \"\";\n\n// 1. Markdown entfernen & zuschneiden\nlet cleaned = raw.replace(/```json|```/g, '').trim();\n\n// 2. JSON-Bereich isolieren\nconst firstBrace = cleaned.indexOf('{');\nconst firstBracket = cleaned.indexOf('[');\nlet start = -1;\n\nif (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {\n start = firstBrace;\n} else if (firstBracket !== -1) {\n start = firstBracket;\n}\n\nif (start !== -1) {\n cleaned = cleaned.substring(start);\n}\n\n// 3. Parsen\nlet parsed;\ntry {\n parsed = JSON.parse(cleaned);\n} catch (e) {\n // Notfall-Reparatur, falls schließende Klammer fehlte\n parsed = JSON.parse(cleaned + (cleaned.startsWith('[') ? ']' : '}'));\n}\n\n// 4. n8n-konformes Format zurückgeben\nif (Array.isArray(parsed)) {\n // Array -> Mehrere n8n Items\n return parsed.map(entry => ({\n json: typeof entry === 'object' && entry !== null ? entry : { value: entry }\n }));\n}\n\nif (typeof parsed === 'object' && parsed !== null) {\n // Normales Objekt -> Ein n8n Item\n return [{ json: parsed }];\n}\n\n// Primitiver Wert (String, Zahl etc.)\nreturn [{ json: { value: parsed } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 352, -352 ], "id": "937e6c25-05c3-4e95-b8bf-76c310f80207", "name": "Code in JavaScript", "executeOnce": true }, { "parameters": { "modelId": { "__rl": true, "value": "ministral-3:3b", "mode": "list", "cachedResultName": "ministral-3:3b" }, "messages": { "values": [ { "content": "=\n{{ (Array.isArray($json.correspondents) ?$json.correspondents : []).map(c => `[${c.paperless_id ?? c.id}] ${c.name}`).join(', ') }}\n\n\n\n{{ (Array.isArray($json.tags) ?$json.tags : []).map(t => `[${t.paperless_id ?? t.id}] ${t.name}`).join(', ') }}\n\n\n\n{{ (Array.isArray($json.documents) ?$json.documents : []).map(d => `[${d.paperless_id ?? d.id}] ${d.name}`).join(', ') }}\n\n\n\n{{ ($json.content || '').substring(0, 1200) }}\n" } ] }, "options": { "system": "Klassifiziere den Dokumentenauszug anhand der bereitgestellten Listen.\n\nRegel für alle Entitäten:\n- Verwende die ID aus der jeweiligen Liste.\n- Falls kein passender Eintrag existiert: Setze die ID zwingend auf null und trage den neu erkannten Namen ein.\n- Tags dürfen mehrere Treffer oder ein leeres Array [] sein.\n\nAntworte ausschließlich mit reinem JSON (keine Markdown-Backticks, beginne direkt mit {):\n{\n \"Title\": \"Kurzer aussagekräftiger Dokumenttitel\",\n \"Korrespondent-ID\": number | null,\n \"Korrespondent\": \"string\",\n \"Dokumententyp-ID\": number | null,\n \"Dokumententyp\": \"string\",\n \"Tags\": [\n {\n \"Tag-ID\": number | null,\n \"Name\": \"string\"\n }\n ]\n}", "temperature": 0, "num_predict": 150, "keep_alive": "5m", "format": "json" } }, "type": "@n8n/n8n-nodes-langchain.ollama", "typeVersion": 1, "position": [ -32, -368 ], "id": "b7823307-d92a-4ec4-89fe-fdb0b0e7141c", "name": "Mistral", "executeOnce": true, "credentials": { "ollamaApi": { "id": "fgaZliEtIoej3jtn", "name": "Ollama account" } } } ], "connections": { "Input": { "main": [ [ { "node": "Mistral", "type": "main", "index": 0 } ] ] }, "Mistral": { "main": [ [ { "node": "Code in JavaScript", "type": "main", "index": 0 } ] ] } }, "authors": "Prasanna Ranjan", "name": "Version 4bec14cf", "description": "", "autosaved": false }, "tags": [] }