Skip to content

Commit da45b7c

Browse files
committed
Major Update:
Addressing Fixes and new Features: Fixes: #66 #61 #58 #55 #53 #45 #59 #52 #49 #31 #37 #52 Added: - Big New Feature: Playground - Try your prompts on your documents and see how they perform. In Playground no data will be updated in Paperless. - Added Code and Markdown interpretation in Chat Mode. - Chat Mode now works with Ollama
1 parent bed1de3 commit da45b7c

25 files changed

+2585
-305
lines changed

.dockerignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ preview.png
1515
.env.bak
1616
data bak/
1717
.env*
18-
docker-compose-dev.yml
18+
docker-compose-dev.yml
19+
public/images/
20+
delete_all.js
21+
documents.json

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ data bak/
1010
data_bak/
1111
data_*/
1212
.env*
13-
docker-compose-dev.yml
13+
docker-compose-dev.yml
14+
public/images/
15+
delete_all.js
16+
documents.json

config/config.js

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

1313
module.exports = {
14-
PAPERLESS_AI_VERSION: '1.4.6',
14+
PAPERLESS_AI_VERSION: '2.0.0',
15+
CONFIGURED: false,
1516
paperless: {
1617
apiUrl: process.env.PAPERLESS_API_URL,
1718
apiToken: process.env.PAPERLESS_API_TOKEN

models/document.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module.exports = {
6565
// Bei UNIQUE constraint failure wird der existierende Eintrag aktualisiert
6666
const result = insertDocument.run(documentId, title, documentId);
6767
if (result.changes > 0) {
68-
console.log(`Document ${documentId} ${result.lastInsertRowid ? 'added to' : 'updated in'} processed_documents`);
68+
console.log(`Document ${title} ${result.lastInsertRowid ? 'added to' : 'updated in'} processed_documents`);
6969
return true;
7070
}
7171
return false;

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
"artificial",
1414
"intelligence"
1515
],
16+
"nodemonConfig": {
17+
"ignore": ["test/*", "docs/*", "node_modules/*", ".git/*", "*.log", "public/*", "views/*", "document.json" ]
18+
},
1619
"author": "Clusterzx",
1720
"license": "MIT",
1821
"dependencies": {

public/css/chat.css

+94
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
--chat-user-text: #ffffff;
1515
--chat-assistant-text: #0f172a;
1616
--shadow-color: rgba(0, 0, 0, 0.1);
17+
--code-bg: #f8f9fa;
1718
}
1819

1920
:root[data-theme="dark"] {
@@ -31,8 +32,10 @@
3132
--chat-user-text: #ffffff;
3233
--chat-assistant-text: #f8fafc;
3334
--shadow-color: rgba(0, 0, 0, 0.3);
35+
--code-bg: #2d2d2d;
3436
}
3537

38+
3639
/* Base Styles */
3740
* {
3841
margin: 0;
@@ -294,6 +297,97 @@ body {
294297
}
295298
}
296299

300+
.message.assistant pre {
301+
background: var(--code-bg);
302+
padding: 1rem;
303+
border-radius: 0.5rem;
304+
overflow-x: auto;
305+
margin: 0.5rem 0;
306+
}
307+
308+
.message.assistant code {
309+
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
310+
font-size: 0.9em;
311+
}
312+
313+
.message.assistant p {
314+
margin: 0.5rem 0;
315+
}
316+
317+
.message.assistant ul,
318+
.message.assistant ol {
319+
margin: 0.5rem 0;
320+
padding-left: 1.5rem;
321+
}
322+
323+
.message.assistant blockquote {
324+
border-left: 3px solid var(--accent-primary);
325+
margin: 0.5rem 0;
326+
padding-left: 1rem;
327+
color: var(--text-secondary);
328+
}
329+
330+
.message.assistant table {
331+
border-collapse: collapse;
332+
width: 100%;
333+
margin: 0.5rem 0;
334+
}
335+
336+
.message.assistant th,
337+
.message.assistant td {
338+
border: 1px solid var(--border-color);
339+
padding: 0.5rem;
340+
}
341+
342+
.message.assistant img {
343+
max-width: 100%;
344+
height: auto;
345+
border-radius: 0.5rem;
346+
margin: 0.5rem 0;
347+
}
348+
349+
.message.assistant table {
350+
border-collapse: collapse;
351+
width: 100%;
352+
margin: 1rem 0;
353+
font-size: 0.9em;
354+
}
355+
356+
.message.assistant th,
357+
.message.assistant td {
358+
border: 1px solid var(--border-color);
359+
padding: 0.5rem;
360+
text-align: left;
361+
}
362+
363+
.message.assistant th {
364+
background-color: var(--bg-secondary);
365+
font-weight: 600;
366+
}
367+
368+
.message.assistant tr:nth-child(even) {
369+
background-color: var(--bg-secondary);
370+
}
371+
372+
.message.assistant tr:hover {
373+
background-color: var(--hover-bg);
374+
}
375+
376+
/* Verbesserte Darstellung für Mobile */
377+
@media (max-width: 768px) {
378+
.message.assistant table {
379+
display: block;
380+
overflow-x: auto;
381+
white-space: nowrap;
382+
}
383+
}
384+
385+
/* Dark mode specific code highlighting */
386+
[data-theme="dark"] .hljs {
387+
background: var(--code-bg);
388+
color: var(--text-primary);
389+
}
390+
297391
/* Dark Mode Input Fixes */
298392
[data-theme="dark"] select,
299393
[data-theme="dark"] input,

public/js/chat.js

+58-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
let currentDocumentId = null;
22

3+
// Initialize marked with options for code highlighting
4+
marked.setOptions({
5+
highlight: function(code, lang) {
6+
if (lang && hljs.getLanguage(lang)) {
7+
return hljs.highlight(code, { language: lang }).value;
8+
}
9+
return hljs.highlightAuto(code).value;
10+
},
11+
breaks: true,
12+
gfm: true
13+
});
14+
315
// Load saved theme on page load
416
document.addEventListener('DOMContentLoaded', () => {
517
const savedTheme = localStorage.getItem('theme') || 'light';
@@ -49,7 +61,10 @@ async function sendMessage(message) {
4961
});
5062

5163
if (!response.ok) throw new Error('Failed to send message');
52-
return await response.json();
64+
const data = await response.json();
65+
66+
// Return the actual response text from the JSON
67+
return data.reply || data.message || 'No response received';
5368
} catch (error) {
5469
console.error('Error sending message:', error);
5570
throw error;
@@ -65,7 +80,30 @@ function addMessage(message, isUser = true) {
6580

6681
const messageDiv = document.createElement('div');
6782
messageDiv.className = `message ${isUser ? 'user' : 'assistant'}`;
68-
messageDiv.innerHTML = `<p>${message}</p>`;
83+
84+
if (isUser) {
85+
// User messages are displayed as plain text
86+
messageDiv.innerHTML = `<p>${escapeHtml(message)}</p>`;
87+
} else {
88+
// For assistant messages, try to extract content from JSON if it's a string
89+
let messageContent = message;
90+
try {
91+
if (typeof message === 'string' && message.trim().startsWith('{')) {
92+
const jsonResponse = JSON.parse(message);
93+
messageContent = jsonResponse.reply || jsonResponse.message || message;
94+
}
95+
} catch (e) {
96+
console.log('Message is not JSON, using as is');
97+
}
98+
99+
// Parse the message content as Markdown
100+
messageDiv.innerHTML = marked.parse(messageContent);
101+
102+
// Apply syntax highlighting to code blocks
103+
messageDiv.querySelectorAll('pre code').forEach((block) => {
104+
hljs.highlightBlock(block);
105+
});
106+
}
69107

70108
containerDiv.appendChild(messageDiv);
71109
const chatHistory = document.getElementById('chatHistory');
@@ -81,12 +119,24 @@ function showError(message) {
81119
errorDiv.className = 'message-container assistant';
82120
errorDiv.innerHTML = `
83121
<div class="message assistant error">
84-
<p>Error: ${message}</p>
122+
<p>Error: ${escapeHtml(message)}</p>
85123
</div>
86124
`;
87125
document.getElementById('chatHistory').appendChild(errorDiv);
88126
}
89127

128+
/**
129+
* Escape HTML to prevent XSS
130+
*/
131+
function escapeHtml(unsafe) {
132+
return unsafe
133+
.replace(/&/g, "&amp;")
134+
.replace(/</g, "&lt;")
135+
.replace(/>/g, "&gt;")
136+
.replace(/"/g, "&quot;")
137+
.replace(/'/g, "&#039;");
138+
}
139+
90140
/**
91141
* Theme handling functions
92142
*/
@@ -150,17 +200,19 @@ document.getElementById('messageForm').addEventListener('submit', async function
150200
if (!message) return;
151201

152202
try {
153-
// Show user message
203+
// Show user message immediately
154204
addMessage(message, true);
205+
206+
// Clear input and reset height
155207
messageInput.value = '';
156208
messageInput.style.height = 'auto';
157209

158210
// Send message and get response
159211
const response = await sendMessage(message);
160212

161213
// Show assistant response
162-
if (response.reply) {
163-
addMessage(response.reply, false);
214+
if (response) {
215+
addMessage(response, false);
164216
}
165217
} catch (error) {
166218
showError('Failed to send message');

0 commit comments

Comments
 (0)