Skip to content

Commit 3ef1bca

Browse files
committed
Reworked Setup, Added Debug Information, Changed Docker-Compose, added Version number, fixed unnecessary OpenAI requests hurting you balance
1 parent ead1baf commit 3ef1bca

File tree

9 files changed

+443
-211
lines changed

9 files changed

+443
-211
lines changed

config/config.js

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ console.log('Loaded environment variables:', {
1111
});
1212

1313
module.exports = {
14+
PAPERLESS_AI_VERSION: '1.3.0',
1415
paperless: {
1516
apiUrl: process.env.PAPERLESS_API_URL,
1617
apiToken: process.env.PAPERLESS_API_TOKEN

docker-compose.yml

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
version: '3.8'
2-
31
services:
42
paperless-ai:
5-
build: .
3+
image: clusterzx/paperless-ai
64
container_name: paperless-ai
5+
network_mode: bridge
76
volumes:
8-
- data:/app/data
7+
- paperless-ai_data:/app/data
98
ports:
109
- "3000:3000"
11-
healthcheck:
12-
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
13-
interval: 30s
14-
timeout: 10s
15-
retries: 3
16-
start_period: 40s
1710
restart: unless-stopped
1811

1912
volumes:
20-
data:
13+
paperless-ai_data:

ecosystem.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
apps: [{
3-
name: 'paperless-assistant',
3+
name: 'paperless-ai',
44
script: 'server.js',
55
instances: 1,
66
autorestart: true,

public/css/setup.css

+58
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,62 @@ textarea.disabled {
379379

380380
.fade-in {
381381
animation: fadeIn 0.3s ease-in-out;
382+
}
383+
384+
/* Tooltip Custom Theme */
385+
.tippy-box[data-theme~='custom'] {
386+
background-color: var(--bg-primary);
387+
color: var(--text-primary);
388+
border: 1px solid var(--border-color);
389+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
390+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
391+
border-radius: 8px;
392+
}
393+
394+
.tippy-box[data-theme~='custom'] .tippy-content {
395+
padding: 0;
396+
}
397+
398+
.tippy-box[data-theme~='custom'] .tooltip-content {
399+
font-size: 0.875rem;
400+
line-height: 1.4;
401+
}
402+
403+
.tippy-box[data-theme~='custom'][data-placement^='right'] > .tippy-arrow::before {
404+
border-right-color: var(--border-color);
405+
}
406+
407+
.tippy-box[data-theme~='custom'] code {
408+
font-family: monospace;
409+
background-color: var(--input-bg); /* Nutzt die Input-Hintergrundfarbe */
410+
border: 1px solid var(--border-color);
411+
}
412+
413+
/* Mobile adjustments for tooltip */
414+
@media (max-width: 768px) {
415+
.tippy-box[data-theme~='custom'] {
416+
max-width: 90vw !important; /* Override default max-width on mobile */
417+
}
418+
419+
.tippy-box[data-theme~='custom'][data-placement^='bottom'] > .tippy-arrow::before {
420+
border-bottom-color: var(--border-color);
421+
}
422+
423+
.tooltip-content {
424+
font-size: 0.875rem !important; /* Slightly smaller font on mobile */
425+
}
426+
427+
.tooltip-content code {
428+
word-break: break-all; /* Break long URLs */
429+
}
430+
431+
/* Adjust padding for better mobile display */
432+
.tooltip-content .p-2 {
433+
padding: 0.75rem !important;
434+
}
435+
}
436+
437+
/* Dark mode adjustments */
438+
[data-theme="dark"] .tippy-box[data-theme~='custom'] {
439+
background-color: var(--bg-secondary);
382440
}

routes/setup.js

+91-99
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const openaiService = require('../services/openaiService.js');
66
const ollamaService = require('../services/ollamaService.js');
77
const documentModel = require('../models/document.js');
88
const debugService = require('../services/debugService.js');
9+
const configFile = require('../config/config.js');
910

1011
// API endpoints that should not redirect
1112
const API_ENDPOINTS = ['/health', '/manual'];
@@ -52,11 +53,11 @@ router.get('/setup', async (req, res) => {
5253
SYSTEM_PROMPT: process.env.SYSTEM_PROMPT || '',
5354
PROCESS_PREDEFINED_DOCUMENTS: process.env.PROCESS_PREDEFINED_DOCUMENTS || 'no',
5455
TAGS: normalizeArray(process.env.TAGS),
55-
// Neue Konfigurationsoptionen
5656
ADD_AI_PROCESSED_TAG: process.env.ADD_AI_PROCESSED_TAG || 'no',
5757
AI_PROCESSED_TAG_NAME: process.env.AI_PROCESSED_TAG_NAME || 'ai-processed',
5858
USE_PROMPT_TAGS: process.env.USE_PROMPT_TAGS || 'no',
59-
PROMPT_TAGS: normalizeArray(process.env.PROMPT_TAGS)
59+
PROMPT_TAGS: normalizeArray(process.env.PROMPT_TAGS),
60+
PAPERLESS_AI_VERSION: configFile.PAPERLESS_AI_VERSION || ' '
6061
};
6162

6263
if (isConfigured) {
@@ -65,14 +66,13 @@ router.get('/setup', async (req, res) => {
6566
savedConfig.PAPERLESS_API_URL = savedConfig.PAPERLESS_API_URL.replace(/\/api$/, '');
6667
}
6768

68-
// Normalisiere die Arrays in der gespeicherten Konfiguration
6969
savedConfig.TAGS = normalizeArray(savedConfig.TAGS);
7070
savedConfig.PROMPT_TAGS = normalizeArray(savedConfig.PROMPT_TAGS);
7171

7272
config = { ...config, ...savedConfig };
7373
}
7474

75-
// Debug-Ausgabe
75+
// Debug-output
7676
console.log('Current config TAGS:', config.TAGS);
7777
console.log('Current config PROMPT_TAGS:', config.PROMPT_TAGS);
7878

@@ -265,109 +265,101 @@ router.get('/health', async (req, res) => {
265265
}
266266
});
267267

268-
router.post('/setup', express.urlencoded({ extended: true }), async (req, res) => {
268+
router.post('/setup', express.json(), async (req, res) => {
269269
try {
270-
const {
271-
paperlessUrl,
272-
paperlessToken,
273-
aiProvider,
274-
openaiKey,
275-
openaiModel,
276-
ollamaUrl,
277-
ollamaModel,
278-
scanInterval,
279-
systemPrompt,
280-
showTags,
281-
tags,
282-
aiProcessedTag,
283-
aiTagName,
284-
usePromptTags,
285-
promptTags
286-
} = req.body;
287-
288-
const normalizeArray = (value) => {
289-
if (!value) return [];
290-
if (Array.isArray(value)) return value;
291-
if (typeof value === 'string') return value.split(',').filter(Boolean).map(item => item.trim());
292-
return [];
293-
};
294-
295-
// Sicheres Verarbeiten des systemPrompt
296-
const processedPrompt = systemPrompt
297-
? systemPrompt.replace(/\r\n/g, '\n').replace(/\n/g, '\\n')
298-
: '';
299-
300-
// Validate Paperless config
301-
const isPaperlessValid = await setupService.validatePaperlessConfig(paperlessUrl, paperlessToken);
302-
if (!isPaperlessValid) {
303-
return res.render('setup', {
304-
error: 'Paperless-ngx connection failed. Please check URL and Token.',
305-
config: req.body
306-
});
307-
}
308-
309-
// Prepare base config
310-
const config = {
311-
PAPERLESS_API_URL: paperlessUrl + '/api',
312-
PAPERLESS_API_TOKEN: paperlessToken,
313-
AI_PROVIDER: aiProvider,
314-
SCAN_INTERVAL: scanInterval || '*/30 * * * *', // Default-Wert hinzugefügt
315-
SYSTEM_PROMPT: processedPrompt,
316-
PROCESS_PREDEFINED_DOCUMENTS: showTags || 'no',
317-
TAGS: normalizeArray(tags),
318-
ADD_AI_PROCESSED_TAG: aiProcessedTag || 'no',
319-
AI_PROCESSED_TAG_NAME: aiTagName || 'ai-processed',
320-
USE_PROMPT_TAGS: usePromptTags || 'no',
321-
PROMPT_TAGS: normalizeArray(promptTags)
322-
};
323-
324-
// Debug-Ausgabe
325-
console.log('Saving config TAGS:', config.TAGS);
326-
console.log('Saving config PROMPT_TAGS:', config.PROMPT_TAGS);
327-
328-
// Validate AI provider config
329-
if (aiProvider === 'openai') {
330-
const isOpenAIValid = await setupService.validateOpenAIConfig(openaiKey);
331-
if (!isOpenAIValid) {
332-
return res.render('setup', {
333-
error: 'OpenAI API Key is not valid. Please check the key.',
334-
config: req.body
335-
});
270+
const {
271+
paperlessUrl,
272+
paperlessToken,
273+
aiProvider,
274+
openaiKey,
275+
openaiModel,
276+
ollamaUrl,
277+
ollamaModel,
278+
scanInterval,
279+
systemPrompt,
280+
showTags,
281+
tags,
282+
aiProcessedTag,
283+
aiTagName,
284+
usePromptTags,
285+
promptTags
286+
} = req.body;
287+
288+
const normalizeArray = (value) => {
289+
if (!value) return [];
290+
if (Array.isArray(value)) return value;
291+
if (typeof value === 'string') return value.split(',').filter(Boolean).map(item => item.trim());
292+
return [];
293+
};
294+
295+
const processedPrompt = systemPrompt
296+
? systemPrompt.replace(/\r\n/g, '\n').replace(/\n/g, '\\n')
297+
: '';
298+
299+
// Validate Paperless config
300+
const isPaperlessValid = await setupService.validatePaperlessConfig(paperlessUrl, paperlessToken);
301+
if (!isPaperlessValid) {
302+
return res.status(400).json({
303+
error: 'Paperless-ngx connection failed. Please check URL and Token.'
304+
});
336305
}
337-
config.OPENAI_API_KEY = openaiKey;
338-
config.OPENAI_MODEL = openaiModel || 'gpt-4o-mini';
339-
} else if (aiProvider === 'ollama') {
340-
const isOllamaValid = await setupService.validateOllamaConfig(ollamaUrl, ollamaModel);
341-
if (!isOllamaValid) {
342-
return res.render('setup', {
343-
error: 'Ollama connection failed. Please check URL and Model.',
344-
config: req.body
345-
});
306+
307+
// Prepare base config
308+
const config = {
309+
PAPERLESS_API_URL: paperlessUrl + '/api',
310+
PAPERLESS_API_TOKEN: paperlessToken,
311+
AI_PROVIDER: aiProvider,
312+
SCAN_INTERVAL: scanInterval || '*/30 * * * *',
313+
SYSTEM_PROMPT: processedPrompt,
314+
PROCESS_PREDEFINED_DOCUMENTS: showTags || 'no',
315+
TAGS: normalizeArray(tags),
316+
ADD_AI_PROCESSED_TAG: aiProcessedTag || 'no',
317+
AI_PROCESSED_TAG_NAME: aiTagName || 'ai-processed',
318+
USE_PROMPT_TAGS: usePromptTags || 'no',
319+
PROMPT_TAGS: normalizeArray(promptTags)
320+
};
321+
322+
// Validate AI provider config
323+
if (aiProvider === 'openai') {
324+
const isOpenAIValid = await setupService.validateOpenAIConfig(openaiKey);
325+
if (!isOpenAIValid) {
326+
return res.status(400).json({
327+
error: 'OpenAI API Key is not valid. Please check the key.'
328+
});
329+
}
330+
config.OPENAI_API_KEY = openaiKey;
331+
config.OPENAI_MODEL = openaiModel || 'gpt-4o-mini';
332+
} else if (aiProvider === 'ollama') {
333+
const isOllamaValid = await setupService.validateOllamaConfig(ollamaUrl, ollamaModel);
334+
if (!isOllamaValid) {
335+
return res.status(400).json({
336+
error: 'Ollama connection failed. Please check URL and Model.'
337+
});
338+
}
339+
config.OLLAMA_API_URL = ollamaUrl || 'http://localhost:11434';
340+
config.OLLAMA_MODEL = ollamaModel || 'llama3.2';
346341
}
347-
config.OLLAMA_API_URL = ollamaUrl || 'http://localhost:11434';
348-
config.OLLAMA_MODEL = ollamaModel || 'llama3.2';
349-
}
350342

351-
// Save configuration
352-
await setupService.saveConfig(config);
343+
// Save configuration
344+
await setupService.saveConfig(config);
353345

354-
// Send success response
355-
res.render('setup', {
356-
success: 'Configuration saved successfully. The application will restart...',
357-
config: req.body
358-
});
346+
// Send success response
347+
res.json({
348+
success: true,
349+
message: 'Configuration saved successfully.',
350+
restart: true
351+
});
359352

360-
// Trigger application restart
361-
setTimeout(() => {
362-
process.exit(0);
363-
}, 1000);
353+
// Trigger application restart
354+
setTimeout(() => {
355+
process.exit(0);
356+
}, 5000);
364357

365358
} catch (error) {
366-
console.error('Setup error:', error);
367-
res.render('setup', {
368-
error: 'An error occurred: ' + error.message,
369-
config: req.body
370-
});
359+
console.error('Setup error:', error);
360+
res.status(500).json({
361+
error: 'An error occurred: ' + error.message
362+
});
371363
}
372364
});
373365

0 commit comments

Comments
 (0)