Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
376aef3
stop creating doubles of same doctype, correspondent or tag.
OvisMaximus Jul 25, 2026
78f1d6c
use names not implying a problem where is none.
OvisMaximus Jul 25, 2026
0dc0ea0
adopt paperless-ngx datatype longtext
OvisMaximus Aug 9, 2026
9065588
prevent to publish IDE configuration
OvisMaximus Jul 27, 2026
e41a13c
prevent to publish IDE configuration
OvisMaximus Jul 27, 2026
8627823
Cleanup
OvisMaximus Aug 9, 2026
7274e73
prevent to publish IDE configuration
OvisMaximus Aug 9, 2026
8de9870
Defer Paperless service loading in Azure service
OvisMaximus Aug 9, 2026
842511a
Merge remote-tracking branch 'origin/main'
OvisMaximus Aug 26, 2026
fa2ccde
fix merge conflict resolution bugs
OvisMaximus Aug 26, 2026
ac8ef47
use CachedNameIdEnum also for tag cache
OvisMaximus Aug 26, 2026
92e9857
cleanup linter warnings and errors
OvisMaximus Aug 26, 2026
11381fe
fix(ollama): fit document content into the configured context window
OvisMaximus Aug 26, 2026
4b2d44e
fix(predefined-scan): let the trigger tag re-queue processed documents
OvisMaximus Aug 26, 2026
a8d12f9
fix(ollama): surface the upstream cause of 5xx failures and retry once
OvisMaximus Aug 26, 2026
545d740
disable debug output into logs
OvisMaximus Aug 26, 2026
9095c82
Bugfix: Void function return value was used as promise.
OvisMaximus Aug 26, 2026
3b6b58e
Merge remote-tracking branch 'origin/main'
OvisMaximus Aug 30, 2026
614b9b7
upstream merge and refactorings
OvisMaximus Aug 30, 2026
238dc81
initial
OvisMaximus Aug 31, 2026
df5bd93
sharpened the plan
OvisMaximus Aug 31, 2026
41741a2
restructured the plan
OvisMaximus Aug 31, 2026
30ee409
added Agent suggestions
OvisMaximus Aug 31, 2026
47bdf28
fix namings and orders
OvisMaximus Aug 31, 2026
4142da6
fix namings
OvisMaximus Aug 31, 2026
8c69549
add refactoring step to plan: group llm services into a subdirectory
OvisMaximus Aug 31, 2026
e1a219c
rework refactoring plan with claude, extend scope to include all four…
OvisMaximus Sep 1, 2026
5181025
refactoring 1: remove first approach code and update plan
OvisMaximus Sep 1, 2026
99206ee
refactoring: check business outcome instead of implementation detail
OvisMaximus Sep 1, 2026
4580e4f
Bugfix
OvisMaximus Sep 1, 2026
63c51f2
Refactoring Step 1
OvisMaximus Sep 1, 2026
38a5352
pre merge upstream
OvisMaximus Sep 19, 2026
2762e84
Merge remote-tracking branch 'origin/main'
OvisMaximus Sep 19, 2026
9d337d2
Merge upstream admonstrator/zettelrobbe v2026.09.03 into main
OvisMaximus Oct 4, 2026
c88a448
Make the entrypoint readable for the unprivileged user
OvisMaximus Oct 4, 2026
355ac29
Keep the OCR fallback marker in Custom's response structure errors
OvisMaximus Oct 4, 2026
3e4581c
Bring the LLM refactoring plan up to date with the upstream merge
OvisMaximus Oct 4, 2026
56b278f
Build the analysis prompt once for all four providers
OvisMaximus Oct 4, 2026
49a04fc
Parse the analysis answer once for all four providers
OvisMaximus Oct 11, 2026
aec628d
Shape the analysis result and spend the token budget in one place each
OvisMaximus Oct 11, 2026
992b2ea
Send the analysis request through one transport per API family
OvisMaximus Oct 11, 2026
fdd4e5a
Send generateText() through the transports as well
OvisMaximus Oct 11, 2026
8908cd3
Record the step 6 decisions and a handoff for whoever continues
OvisMaximus Oct 11, 2026
8dd6121
Merge upstream admonstrator/zettelrobbe v2026.10.01 into the step 6 b…
OvisMaximus Oct 15, 2026
5afb774
Let Azure follow the configured temperature on both paths
OvisMaximus Oct 15, 2026
fa2d516
Fail an answer without metadata and shape every success on all four p…
OvisMaximus Oct 15, 2026
519044a
Recognise a refusal as insufficient content on all four providers
OvisMaximus Oct 15, 2026
3628087
Pin byte-identical analysis results across the four providers
OvisMaximus Oct 15, 2026
1552a15
Collapse the OpenAI and Azure analysis onto one DocumentAnalyzer
OvisMaximus Oct 15, 2026
fc8a28f
Move the Custom provider onto the DocumentAnalyzer
OvisMaximus Oct 15, 2026
5cfd7e2
Move the Ollama provider onto the DocumentAnalyzer
OvisMaximus Oct 15, 2026
4c511aa
Record step 6 as done and hand over for step 7
OvisMaximus Oct 15, 2026
0a7a2f8
Record the step 7 decisions in the refactoring plan
OvisMaximus Oct 15, 2026
5775203
Route POST /manual/analyze through the AI service factory
OvisMaximus Oct 15, 2026
c225558
Delete the dead services/manualService.js
OvisMaximus Oct 15, 2026
28f6027
Record step 7 as done and hand over for step 8
OvisMaximus Oct 15, 2026
965cca6
Drop the unreachable Ollama and Custom clients from the OpenAI provider
OvisMaximus Oct 15, 2026
d511101
Move the refactoring plan to docs/ and record the refactoring as done
OvisMaximus Oct 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ dist/
.local/
*.local.*
.vscode/
.idea/
.ollamassist/
# AI context files (auto-generated)
COPILOT.md
.DS_Store
GEMINI.md
CVE/*
.todo/*
.todo/*
.ai/
12 changes: 12 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ COPY --chown=node:node schemas.js swagger.js ./
COPY --chown=node:node scripts ./scripts/
COPY docker-entrypoint.sh start-services.sh ./

RUN chmod +x docker-entrypoint.sh start-services.sh
# An explicit mode rather than +x: the entrypoint re-executes itself after the
# privilege drop, so the unprivileged user has to be able to read it, too. A
# build context that hands the files over without read permission for others
# (e.g. a Samba share with a restrictive create mask) would otherwise produce
# 0711 and a restart loop with "cannot open ./docker-entrypoint.sh".
RUN chmod 755 docker-entrypoint.sh start-services.sh

# Configure persistent data volume.
# Docker seeds a fresh named volume from the image including ownership and mode,
Expand Down
72 changes: 20 additions & 52 deletions OPENAPI/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@
},
"AnalysisResult": {
"type": "object",
"description": "What analyzeDocument() returns on every AI provider. A failed analysis is\nreturned, not thrown: `document` is then `{ tags: [], correspondent: null }`,\n`metrics` is null and `error` says why.\n",
"properties": {
"document": {
"type": "object",
Expand All @@ -348,6 +349,7 @@
},
"correspondent": {
"type": "string",
"nullable": true,
"description": "Suggested correspondent name",
"example": "ABC Corporation"
},
Expand Down Expand Up @@ -389,6 +391,8 @@
},
"metrics": {
"type": "object",
"nullable": true,
"description": "Token usage of the analysis; null when it failed",
"properties": {
"promptTokens": {
"type": "integer",
Expand All @@ -407,10 +411,20 @@
}
}
},
"truncated": {
"type": "boolean",
"description": "Whether the document content was cut to fit the token limit",
"example": false
},
"error": {
"type": "string",
"description": "Error message if analysis failed",
"example": null
},
"errorCode": {
"type": "string",
"description": "Machine-readable reason of a failed analysis, when the provider gave one",
"example": null
}
}
},
Expand Down Expand Up @@ -6715,7 +6729,7 @@
"/manual/analyze": {
"post": {
"summary": "Analyze document content manually",
"description": "Analyzes document content using the configured AI provider and returns structured metadata.\nThis endpoint processes the document text to extract relevant information such as tags,\ncorrespondent, and document type based on content analysis.\n\nThe analysis is performed using the AI provider configured in the application settings.\n",
"description": "Analyzes document content using the configured AI provider and returns structured metadata.\nThis endpoint processes the document text to extract relevant information such as tags,\ncorrespondent, and document type based on content analysis.\n\nThe analysis is performed by the AI provider configured in the application settings, the\nsame one the scan uses. The existing tags, correspondents and document types are read from\nPaperless-ngx. When the request carries an `id`, the token usage is recorded against it.\n",
"tags": [
"Documents",
"API"
Expand All @@ -6742,7 +6756,7 @@
},
"existingTags": {
"type": "array",
"description": "List of existing tags in the system to help with tag matching",
"description": "Accepted but not read; the existing tags are taken from Paperless-ngx",
"items": {
"type": "string"
},
Expand All @@ -6754,7 +6768,7 @@
},
"id": {
"type": "string",
"description": "Optional document ID for tracking metrics",
"description": "Optional Paperless-ngx document ID; the token usage is recorded against it",
"example": "doc_123"
}
}
Expand All @@ -6764,57 +6778,11 @@
},
"responses": {
"200": {
"description": "Document analysis results",
"description": "The analysis result. A failed analysis is answered with status 200 as well, with\n`error` set and `metrics` null.\n",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"correspondent": {
"type": "string",
"description": "Detected correspondent name",
"example": "Acme Corp"
},
"title": {
"type": "string",
"description": "Suggested document title",
"example": "Acme Corp Invoice - August 2023"
},
"tags": {
"type": "array",
"description": "Suggested tags for the document",
"items": {
"type": "string"
},
"example": [
"Invoice",
"Finance"
]
},
"documentType": {
"type": "string",
"description": "Detected document type",
"example": "Invoice"
},
"metrics": {
"type": "object",
"description": "Token usage metrics (when using OpenAI)",
"properties": {
"promptTokens": {
"type": "number",
"example": 350
},
"completionTokens": {
"type": "number",
"example": 120
},
"totalTokens": {
"type": "number",
"example": 470
}
}
}
}
"$ref": "#/components/schemas/AnalysisResult"
}
}
}
Expand All @@ -6830,7 +6798,7 @@
}
},
"500": {
"description": "Server error or AI provider not configured",
"description": "Server error, e.g. Paperless-ngx could not be reached",
"content": {
"application/json": {
"schema": {
Expand Down
Empty file modified build.sh
100755 → 100644
Empty file.
5 changes: 5 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,11 @@ module.exports = {
globalRateLimitMax: parseInt(process.env.GLOBAL_RATE_LIMIT_MAX || '1000', 10),
predefinedMode: process.env.PROCESS_PREDEFINED_DOCUMENTS,
ignoreTags: process.env.IGNORE_TAGS || '',
// Predefined-scan trigger tags (TAGS in predefined mode) are removed from a
// document after it has been processed, so re-adding the tag is what queues
// a re-run. Off by default: without it the tag stays, matching legacy
// behaviour.
removeTriggerTags: parseEnvBoolean(process.env.REMOVE_TRIGGER_TAGS, 'no'),
// The context window the provider is told to respect. Read through the
// strict parser: a NaN here used to travel all the way into
// truncateToTokenLimit(), which then sent the model an empty document.
Expand Down
Loading