Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ const limitFunctions = {
activateCorrespondents: parseEnvBoolean(process.env.ACTIVATE_CORRESPONDENTS, 'yes'),
activateDocumentType: parseEnvBoolean(process.env.ACTIVATE_DOCUMENT_TYPE, 'yes'),
activateTitle: parseEnvBoolean(process.env.ACTIVATE_TITLE, 'yes'),
activateCustomFields: parseEnvBoolean(process.env.ACTIVATE_CUSTOM_FIELDS, 'yes')
activateCustomFields: parseEnvBoolean(process.env.ACTIVATE_CUSTOM_FIELDS, 'yes'),
activateNotes: parseEnvBoolean(process.env.ACTIVATE_NOTES, 'yes')
};

// Initialize AI restrictions with defaults
Expand Down Expand Up @@ -371,7 +372,8 @@ module.exports = {
activateCorrespondents: limitFunctions.activateCorrespondents,
activateDocumentType: limitFunctions.activateDocumentType,
activateTitle: limitFunctions.activateTitle,
activateCustomFields: limitFunctions.activateCustomFields
activateCustomFields: limitFunctions.activateCustomFields,
activateNotes: limitFunctions.activateNotes
},
specialPromptPreDefinedTags: `You are a document analysis AI. You will analyze the document.
You take the main information to associate tags with the document.
Expand All @@ -398,6 +400,7 @@ module.exports = {
"document_type": "Invoice/Contract/...",
"document_date": "YYYY-MM-DD",
"language": "en/de/es/...",
"notes": "Brief summary of the document: what it is about, key details, amounts, parties involved, deadlines, and any required actions (2-4 sentences)",
%CUSTOMFIELDS%
}`,
};
14 changes: 14 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,11 @@ async function buildUpdateData(analysis, doc) {
}
}

// Process notes (added as a note via API, not via PATCH)
if (config.limitFunctions?.activateNotes !== 'no' && analysis.document.notes) {
updateData._notesForPost = analysis.document.notes;
}

// Only process correspondent if correspondent detection is activated
if (config.limitFunctions?.activateCorrespondents !== 'no' && analysis.document.correspondent) {
try {
Expand Down Expand Up @@ -789,11 +794,20 @@ async function saveDocumentChanges(docId, updateData, analysis, originalData) {

await documentModel.saveOriginalData(docId, originalTags, originalCorrespondent, originalTitle, origDocType, origLanguage);

// Extract notes before removing from updateData
const noteText = updateData._notesForPost || null;
delete updateData._notesForPost;

const updatedDocument = await paperlessService.updateDocument(docId, updateData);
if (!updatedDocument) {
throw new Error(`Paperless update failed for document ${docId}`);
}

// Add note via Paperless notes API (POST /api/documents/{id}/notes/)
if (noteText) {
await paperlessService.addDocumentNote(docId, noteText);
}

const persistenceTasks = [
documentModel.addProcessedDocument(docId, updateData.title),
documentModel.addToHistory(
Expand Down
15 changes: 11 additions & 4 deletions services/ollamaService.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class OllamaService {
custom_fields: {
type: "object",
additionalProperties: true
}
},
notes: { type: "string" }
},
required: ["title", "correspondent", "tags", "document_type", "document_date", "language"]
};
Expand Down Expand Up @@ -461,6 +462,7 @@ class OllamaService {
"document_type": "Invoice/Contract/...",
"document_date": "YYYY-MM-DD",
"language": "en/de/es/...",
"notes": "Brief summary of the document (2-3 sentences)",
%CUSTOMFIELDS%
}
ALWAYS USE THE INFORMATION TO FILL OUT THE JSON OBJECT. DO NOT ASK BACK QUESTIONS.
Expand Down Expand Up @@ -630,7 +632,8 @@ class OllamaService {
document_date: responseData.response.document_date || null,
document_type: responseData.response.document_type || null,
language: responseData.response.language || null,
custom_fields: responseData.response.custom_fields || null
custom_fields: responseData.response.custom_fields || null,
notes: responseData.response.notes || null
};
} else if (responseData.response) {
// Fall back to parsing from text response
Expand Down Expand Up @@ -685,7 +688,8 @@ class OllamaService {
document_date: result.document_date || null,
document_type: result.document_type || null,
language: result.language || null,
custom_fields: result.custom_fields || null
custom_fields: result.custom_fields || null,
notes: result.notes || null
};

} catch (jsonError) {
Expand All @@ -702,7 +706,10 @@ class OllamaService {
correspondent: sanitizedResult.correspondent || null,
title: sanitizedResult.title || null,
document_date: sanitizedResult.document_date || null,
language: sanitizedResult.language || null
document_type: sanitizedResult.document_type || null,
language: sanitizedResult.language || null,
custom_fields: sanitizedResult.custom_fields || null,
notes: sanitizedResult.notes || null
};
} catch (finalError) {
console.error('Final JSON parsing failed after sanitization. This happens when the JSON structure is too complex or invalid. That indicates an issue with the generated JSON string by Ollama. Switch to OpenAI for better results or fine tune your prompt.');
Expand Down
20 changes: 20 additions & 0 deletions services/paperlessService.js
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,26 @@ async getOrCreateDocumentType(name, options = {}) {
}
}

/**
* Add a note to a document via the Paperless notes API.
* Uses POST /api/documents/{id}/notes/ with {"note": "..."}.
* @param {number} documentId
* @param {string} noteText - The note content
* @returns {Promise<Object|null>} Created note or null on failure
*/
async addDocumentNote(documentId, noteText) {
this.initialize();
if (!this.client || !noteText) return null;
try {
const response = await this.client.post(`/documents/${documentId}/notes/`, { note: noteText });
console.log(`[SUCCESS] Added note to document ${documentId}`);
return response.data;
} catch (error) {
console.error(`[ERROR] Adding note to document ${documentId}: ${error.message}`);
return null;
}
}

/**
* Restore a document to its original state (before AI processing).
* Unlike updateDocument(), this method does NOT merge tags or skip correspondents —
Expand Down