WebashalarForML commited on
Commit
fb44fc6
·
verified ·
1 Parent(s): c2c8c47

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +584 -560
templates/index.html CHANGED
@@ -1,565 +1,589 @@
1
  <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Agent Chat</title>
7
- <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.js"></script>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <style>
10
- :root {
11
- --primary: #10a37f;
12
- --primary-dark: #0d8a6a;
13
- --bg-color: #343541;
14
- --chat-bg: #444654;
15
- --user-bg: #343541;
16
- --text-color: #ececf1;
17
- --text-secondary: #acacbe;
18
- --border-color: #565869;
19
- --log-bg: #2a2b32;
20
- --error-color: #ef4146;
21
- --warning-color: #f0b72f;
22
- }
23
-
24
- * {
25
- box-sizing: border-box;
26
- margin: 0;
27
- padding: 0;
28
- }
29
-
30
- body {
31
- background-color: var(--bg-color);
32
- color: var(--text-color);
33
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
34
- display: flex;
35
- flex-direction: column;
36
- height: 100vh;
37
- overflow: hidden;
38
- }
39
-
40
- nav {
41
- background-color: var(--user-bg);
42
- padding: 12px 20px;
43
- border-bottom: 1px solid var(--border-color);
44
- display: flex;
45
- justify-content: space-between;
46
- align-items: center;
47
- }
48
-
49
- .nav-title {
50
- font-size: 1.2rem;
51
- font-weight: 600;
52
- }
53
-
54
- .nav-actions {
55
- display: flex;
56
- gap: 10px;
57
- }
58
-
59
- .btn {
60
- background-color: var(--primary);
61
- color: white;
62
- border: none;
63
- border-radius: 4px;
64
- padding: 8px 12px;
65
- font-size: 0.9rem;
66
- cursor: pointer;
67
- display: flex;
68
- align-items: center;
69
- gap: 6px;
70
- transition: background-color 0.2s;
71
- }
72
-
73
- .btn:hover {
74
- background-color: var(--primary-dark);
75
- }
76
-
77
- .btn-sm {
78
- padding: 6px 10px;
79
- font-size: 0.8rem;
80
- }
81
-
82
- .btn-icon {
83
- padding: 8px;
84
- border-radius: 4px;
85
- background: transparent;
86
- color: var(--text-color);
87
- }
88
-
89
- .btn-icon:hover {
90
- background-color: rgba(255,255,255,0.1);
91
- }
92
-
93
- main {
94
- flex: 1;
95
- display: flex;
96
- flex-direction: column;
97
- overflow: hidden;
98
- }
99
-
100
- .chat-container {
101
- flex: 1;
102
- overflow-y: auto;
103
- padding: 20px 0;
104
- }
105
-
106
- .message {
107
- padding: 20px;
108
- display: flex;
109
- max-width: 900px;
110
- margin: 0 auto;
111
- gap: 20px;
112
- }
113
-
114
- .message-user {
115
- background-color: var(--user-bg);
116
- }
117
-
118
- .message-agent {
119
- background-color: var(--chat-bg);
120
- }
121
-
122
- .avatar {
123
- width: 36px;
124
- height: 36px;
125
- border-radius: 4px;
126
- display: flex;
127
- align-items: center;
128
- justify-content: center;
129
- flex-shrink: 0;
130
- }
131
-
132
- .avatar-user {
133
- background-color: var(--primary);
134
- }
135
-
136
- .avatar-agent {
137
- background-color: #5436da;
138
- }
139
-
140
- .message-content {
141
- flex: 1;
142
- line-height: 1.5;
143
- padding-top: 4px;
144
- }
145
-
146
- .logs-container {
147
- background-color: var(--log-bg);
148
- border-top: 1px solid var(--border-color);
149
- padding: 12px 20px;
150
- max-height: 120px;
151
- overflow-y: auto;
152
- font-size: 0.85rem;
153
- color: var(--text-secondary);
154
- transition: all 0.3s ease;
155
- }
156
-
157
- .logs-container.collapsed {
158
- max-height: 0;
159
- padding: 0;
160
- overflow: hidden;
161
- }
162
-
163
- .log-entry {
164
- margin-bottom: 6px;
165
- display: flex;
166
- gap: 10px;
167
- }
168
-
169
- .log-timestamp {
170
- color: var(--text-secondary);
171
- flex-shrink: 0;
172
- }
173
-
174
- .log-message {
175
- flex: 1;
176
- }
177
-
178
- .log-error {
179
- color: var(--error-color);
180
- }
181
-
182
- .log-warning {
183
- color: var(--warning-color);
184
- }
185
-
186
- .input-container {
187
- padding: 20px;
188
- border-top: 1px solid var(--border-color);
189
- background-color: var(--user-bg);
190
- position: relative;
191
- }
192
-
193
- .input-wrapper {
194
- max-width: 900px;
195
- margin: 0 auto;
196
- position: relative;
197
- }
198
-
199
- .input-actions {
200
- position: absolute;
201
- right: 12px;
202
- bottom: 12px;
203
- display: flex;
204
- gap: 8px;
205
- z-index: 2;
206
- }
207
-
208
- textarea {
209
- width: 100%;
210
- min-height: 60px;
211
- max-height: 200px;
212
- padding: 12px 50px 12px 16px;
213
- border-radius: 8px;
214
- border: 1px solid var(--border-color);
215
- background-color: var(--chat-bg);
216
- color: var(--text-color);
217
- resize: none;
218
- font-size: 1rem;
219
- line-height: 1.5;
220
- }
221
-
222
- textarea:focus {
223
- outline: none;
224
- border-color: var(--primary);
225
- box-shadow: 0 0 0 1px var(--primary);
226
- }
227
-
228
- .typing-indicator {
229
- display: flex;
230
- gap: 4px;
231
- padding: 0 20px 10px;
232
- color: var(--text-secondary);
233
- font-size: 0.9rem;
234
- }
235
-
236
- .typing-dots {
237
- display: flex;
238
- gap: 2px;
239
- align-items: flex-end;
240
- }
241
-
242
- .typing-dot {
243
- width: 6px;
244
- height: 6px;
245
- background-color: var(--text-secondary);
246
- border-radius: 50%;
247
- animation: typingAnimation 1.4s infinite ease-in-out;
248
- }
249
-
250
- .typing-dot:nth-child(1) {
251
- animation-delay: 0s;
252
- }
253
-
254
- .typing-dot:nth-child(2) {
255
- animation-delay: 0.2s;
256
- }
257
-
258
- .typing-dot:nth-child(3) {
259
- animation-delay: 0.4s;
260
- }
261
-
262
- @keyframes typingAnimation {
263
- 0%, 60%, 100% { transform: translateY(0); }
264
- 30% { transform: translateY(-4px); }
265
- }
266
-
267
- footer {
268
- background-color: var(--user-bg);
269
- padding: 12px 20px;
270
- border-top: 1px solid var(--border-color);
271
- font-size: 0.8rem;
272
- color: var(--text-secondary);
273
- text-align: center;
274
- }
275
-
276
- /* Add this new style for log toggle */
277
- .logs-container {
278
- position: relative;
279
- background-color: var(--log-bg);
280
- border-top: 1px solid var(--border-color);
281
- padding: 12px 20px;
282
- max-height: 120px;
283
- overflow-y: auto;
284
- font-size: 0.85rem;
285
- color: var(--text-secondary);
286
- transition: all 0.3s ease;
287
- }
288
-
289
- .log-toggle {
290
- position: absolute;
291
- right: 20px;
292
- top: -12px;
293
- background: var(--log-bg);
294
- border: 1px solid var(--border-color);
295
- border-radius: 12px;
296
- padding: 2px 8px;
297
- font-size: 0.7rem;
298
- cursor: pointer;
299
- z-index: 1;
300
- color: var(--text-secondary);
301
- }
302
-
303
- .log-toggle:hover {
304
- background: var(--border-color);
305
- }
306
-
307
- .alert {
308
- position: fixed;
309
- top: 20px;
310
- left: 50%;
311
- transform: translateX(-50%);
312
- padding: 12px 20px;
313
- border-radius: 8px;
314
- background-color: var(--error-color);
315
- color: white;
316
- z-index: 1000;
317
- display: flex;
318
- align-items: center;
319
- gap: 8px;
320
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
321
- animation: slideIn 0.3s ease-out;
322
- }
323
-
324
- .alert-success {
325
- background-color: var(--primary);
326
- }
327
-
328
- .alert-warning {
329
- background-color: var(--warning-color);
330
- }
331
-
332
- @keyframes slideIn {
333
- from { top: -50px; opacity: 0; }
334
- to { top: 20px; opacity: 1; }
335
- }
336
-
337
- .markdown-content pre {
338
- background-color: rgba(0,0,0,0.2);
339
- padding: 12px;
340
- border-radius: 6px;
341
- overflow-x: auto;
342
- margin: 12px 0;
343
- }
344
-
345
- .markdown-content code {
346
- font-family: 'Courier New', Courier, monospace;
347
- font-size: 0.9rem;
348
- }
349
- </style>
350
- </head>
351
- <body>
352
- <nav>
353
- <div class="nav-title">Agent Chat</div>
354
- <div class="nav-actions">
355
- <button class="btn">
356
- <i class="fas fa-plus"></i> New Chat
357
- </button>
358
- </div>
359
- </nav>
360
-
361
- <main>
362
- <div class="chat-container" id="chat">
363
- <!-- Messages will be inserted here -->
364
- </div>
365
-
366
- <div class="typing-indicator" id="typing-indicator" style="display: none;">
367
- <div class="typing-dots">
368
- <div class="typing-dot"></div>
369
- <div class="typing-dot"></div>
370
- <div class="typing-dot"></div>
371
- </div>
372
- <span>Agent is typing...</span>
373
- </div>
374
-
375
- <div class="input-container">
376
- <div class="input-wrapper">
377
- <textarea id="prompt" rows="1" placeholder="Message Agent..." autofocus></textarea>
378
- <div class="input-actions">
379
- <button class="btn-icon" id="upload-btn" title="Upload Database">
380
- <i class="fas fa-database"></i>
381
  </button>
382
- <button class="btn-icon" id="send-btn" title="Send message">
383
- <i class="fas fa-paper-plane"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  </button>
385
  </div>
 
 
 
386
  </div>
387
- </div>
388
-
389
- <div class="logs-container" id="logs-container">
390
- <button class="log-toggle" id="log-toggle">Hide Logs</button>
391
- <div id="logs"></div>
392
- </div>
393
-
394
- </main>
395
-
396
- <footer>
397
- <div>Agent Chat v1.0 · © 2023</div>
398
- </footer>
399
-
400
- <div id="flash-message" class="alert" style="display: none;"></div>
401
-
402
- <script>
403
- const socket = io();
404
- const chatContainer = document.getElementById("chat");
405
- const logsContainer = document.getElementById("logs");
406
- const sendButton = document.getElementById("send-btn");
407
- const uploadButton = document.getElementById("upload-btn");
408
- const promptTextarea = document.getElementById("prompt");
409
- const flashMessage = document.getElementById('flash-message');
410
- const typingIndicator = document.getElementById('typing-indicator');
411
- const logToggle = document.getElementById('log-toggle');
412
- const logsContainerElement = document.getElementById('logs-container');
413
-
414
- // Auto-resize textarea
415
- promptTextarea.addEventListener('input', function() {
416
- this.style.height = 'auto';
417
- this.style.height = (this.scrollHeight) + 'px';
418
- });
419
-
420
- // Handle Enter key (Shift+Enter for new line)
421
- promptTextarea.addEventListener('keydown', function(e) {
422
- if (e.key === 'Enter' && !e.shiftKey) {
423
- e.preventDefault();
424
- sendMessage();
425
- }
426
- });
427
-
428
- // Send button click handler
429
- sendButton.addEventListener('click', sendMessage);
430
-
431
- // Upload button click handler
432
- uploadButton.addEventListener('click', () => {
433
- window.location.href = '/upload';
434
- });
435
-
436
- // Log toggle handler
437
- logToggle.addEventListener('click', () => {
438
- logsContainerElement.classList.toggle('collapsed');
439
- logToggle.textContent = logsContainerElement.classList.contains('collapsed') ? 'Show Logs' : 'Hide Logs';
440
- });
441
-
442
- function sendMessage() {
443
- const prompt = promptTextarea.value.trim();
444
- if (!prompt) return;
445
-
446
- addMessage("user", prompt);
447
- promptTextarea.value = '';
448
- promptTextarea.style.height = 'auto';
449
- typingIndicator.style.display = 'flex';
450
-
451
- fetch("/generate", {
452
- method: "POST",
453
- headers: { "Content-Type": "application/json" },
454
- body: JSON.stringify({ prompt: prompt })
455
- });
456
- }
457
-
458
- function addMessage(sender, text) {
459
- const messageDiv = document.createElement("div");
460
- messageDiv.classList.add("message", `message-${sender}`);
461
-
462
- const avatarDiv = document.createElement("div");
463
- avatarDiv.classList.add("avatar", `avatar-${sender}`);
464
- avatarDiv.innerHTML = sender === 'user' ?
465
- '<i class="fas fa-user"></i>' :
466
- '<i class="fas fa-robot"></i>';
467
-
468
- const contentDiv = document.createElement("div");
469
- contentDiv.classList.add("message-content");
470
- contentDiv.innerHTML = `<div class="markdown-content">${text}</div>`;
471
-
472
- messageDiv.appendChild(avatarDiv);
473
- messageDiv.appendChild(contentDiv);
474
- chatContainer.appendChild(messageDiv);
475
- chatContainer.scrollTop = chatContainer.scrollHeight;
476
- }
477
-
478
- function addLogMessage(text, type = 'info') {
479
- const now = new Date();
480
- const timestamp = now.toLocaleTimeString();
481
-
482
- const logDiv = document.createElement("div");
483
- logDiv.classList.add("log-entry");
484
-
485
- const timeDiv = document.createElement("div");
486
- timeDiv.classList.add("log-timestamp");
487
- timeDiv.textContent = timestamp;
488
-
489
- const messageDiv = document.createElement("div");
490
- messageDiv.classList.add("log-message");
491
- if (type !== 'info') messageDiv.classList.add(`log-${type}`);
492
- messageDiv.textContent = text;
493
-
494
- logDiv.appendChild(timeDiv);
495
- logDiv.appendChild(messageDiv);
496
- logsContainer.appendChild(logDiv);
497
- logsContainer.scrollTop = logsContainer.scrollHeight;
498
- }
499
-
500
- function showFlashMessage(message, type = 'error') {
501
- flashMessage.textContent = message;
502
- flashMessage.className = `alert alert-${type}`;
503
- flashMessage.style.display = 'flex';
504
-
505
- setTimeout(() => {
506
- flashMessage.style.display = 'none';
507
- }, 3000);
508
- }
509
-
510
- // Socket.io handlers
511
- let agentMessageDiv = null;
512
-
513
- socket.on("final_stream", (data) => {
514
- if (!agentMessageDiv) {
515
- agentMessageDiv = document.createElement("div");
516
- agentMessageDiv.classList.add("message", "message-agent");
517
-
518
- const avatarDiv = document.createElement("div");
519
- avatarDiv.classList.add("avatar", "avatar-agent");
520
- avatarDiv.innerHTML = '<i class="fas fa-robot"></i>';
521
-
522
- const contentDiv = document.createElement("div");
523
- contentDiv.classList.add("message-content");
524
- contentDiv.id = "agent-message-content";
525
-
526
- agentMessageDiv.appendChild(avatarDiv);
527
- agentMessageDiv.appendChild(contentDiv);
528
- chatContainer.appendChild(agentMessageDiv);
529
- }
530
-
531
- const contentDiv = document.getElementById("agent-message-content");
532
- contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
533
- chatContainer.scrollTop = chatContainer.scrollHeight;
534
- });
535
-
536
- socket.on("final", (data) => {
537
- typingIndicator.style.display = 'none';
538
-
539
- if (agentMessageDiv) {
540
- const contentDiv = document.getElementById("agent-message-content");
541
- contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
542
- agentMessageDiv = null;
543
- } else {
544
- addMessage("agent", data.message);
545
- }
546
- });
547
-
548
- socket.on("log", (data) => {
549
- addLogMessage(data.message, data.type || 'info');
550
- });
551
-
552
- socket.on("error", (data) => {
553
- showFlashMessage(data.message, 'error');
554
- typingIndicator.style.display = 'none';
555
- });
556
-
557
- // Handle flash messages from server
558
- if (flashMessage) {
559
- setTimeout(() => {
560
- flashMessage.style.display = 'none';
561
- }, 3000);
562
- }
563
- </script>
564
- </body>
565
- </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Agent Chat</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.js"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ :root {
11
+ --primary: #10a37f;
12
+ --primary-dark: #0d8a6a;
13
+ --bg-color: #343541;
14
+ --chat-bg: #444654;
15
+ --user-bg: #343541;
16
+ --text-color: #ececf1;
17
+ --text-secondary: #acacbe;
18
+ --border-color: #565869;
19
+ --log-bg: #2a2b32;
20
+ --error-color: #ef4146;
21
+ --warning-color: #f0b72f;
22
+ --panel-width: 300px; /* Define panel width */
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ margin: 0;
28
+ padding: 0;
29
+ }
30
+
31
+ body {
32
+ background-color: var(--bg-color);
33
+ color: var(--text-color);
34
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
35
+ display: flex;
36
+ flex-direction: column;
37
+ height: 100vh;
38
+ overflow: hidden;
39
+ }
40
+
41
+ nav {
42
+ background-color: var(--user-bg);
43
+ padding: 12px 20px;
44
+ border-bottom: 1px solid var(--border-color);
45
+ display: flex;
46
+ justify-content: space-between;
47
+ align-items: center;
48
+ flex-shrink: 0; /* Prevent nav from shrinking */
49
+ }
50
+
51
+ .nav-title {
52
+ font-size: 1.2rem;
53
+ font-weight: 600;
54
+ }
55
+
56
+ .nav-actions {
57
+ display: flex;
58
+ gap: 10px;
59
+ }
60
+
61
+ .btn {
62
+ background-color: var(--primary);
63
+ color: white;
64
+ border: none;
65
+ border-radius: 4px;
66
+ padding: 8px 12px;
67
+ font-size: 0.9rem;
68
+ cursor: pointer;
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 6px;
72
+ transition: background-color 0.2s;
73
+ }
74
+
75
+ .btn:hover {
76
+ background-color: var(--primary-dark);
77
+ }
78
+
79
+ .btn-sm {
80
+ padding: 6px 10px;
81
+ font-size: 0.8rem;
82
+ }
83
+
84
+ .btn-icon {
85
+ padding: 8px;
86
+ border-radius: 4px;
87
+ background: transparent;
88
+ color: var(--text-color);
89
+ border: none; /* Ensure no default button border */
90
+ cursor: pointer;
91
+ }
92
+
93
+ .btn-icon:hover {
94
+ background-color: rgba(255,255,255,0.1);
95
+ }
96
+
97
+ main {
98
+ flex: 1;
99
+ display: flex;
100
+ flex-direction: column;
101
+ overflow: hidden;
102
+ }
103
+
104
+ .chat-container {
105
+ flex: 1;
106
+ overflow-y: auto;
107
+ padding: 20px 0;
108
+ }
109
+
110
+ .message {
111
+ padding: 20px;
112
+ display: flex;
113
+ max-width: 900px;
114
+ margin: 0 auto;
115
+ gap: 20px;
116
+ }
117
+
118
+ .message-user {
119
+ background-color: var(--user-bg);
120
+ }
121
+
122
+ .message-agent {
123
+ background-color: var(--chat-bg);
124
+ }
125
+
126
+ .avatar {
127
+ width: 36px;
128
+ height: 36px;
129
+ border-radius: 4px;
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ flex-shrink: 0;
134
+ }
135
+
136
+ .avatar-user {
137
+ background-color: var(--primary);
138
+ }
139
+
140
+ .avatar-agent {
141
+ background-color: #5436da;
142
+ }
143
+
144
+ .message-content {
145
+ flex: 1;
146
+ line-height: 1.5;
147
+ padding-top: 4px;
148
+ }
149
+
150
+ .input-container {
151
+ padding: 20px;
152
+ border-top: 1px solid var(--border-color);
153
+ background-color: var(--user-bg);
154
+ position: relative;
155
+ flex-shrink: 0; /* Prevent input area from shrinking */
156
+ }
157
+
158
+ .input-wrapper {
159
+ max-width: 900px;
160
+ margin: 0 auto;
161
+ position: relative;
162
+ }
163
+
164
+ .input-actions {
165
+ position: absolute;
166
+ right: 12px;
167
+ bottom: 12px;
168
+ display: flex;
169
+ gap: 8px;
170
+ z-index: 2;
171
+ }
172
+
173
+ textarea {
174
+ width: 100%;
175
+ min-height: 60px;
176
+ max-height: 200px;
177
+ padding: 12px 50px 12px 16px;
178
+ border-radius: 8px;
179
+ border: 1px solid var(--border-color);
180
+ background-color: var(--chat-bg);
181
+ color: var(--text-color);
182
+ resize: none;
183
+ font-size: 1rem;
184
+ line-height: 1.5;
185
+ }
186
+
187
+ textarea:focus {
188
+ outline: none;
189
+ border-color: var(--primary);
190
+ box-shadow: 0 0 0 1px var(--primary);
191
+ }
192
+
193
+ .typing-indicator {
194
+ display: flex;
195
+ gap: 4px;
196
+ padding: 0 20px 10px;
197
+ color: var(--text-secondary);
198
+ font-size: 0.9rem;
199
+ flex-shrink: 0; /* Prevent indicator from shrinking */
200
+ }
201
+
202
+ .typing-dots {
203
+ display: flex;
204
+ gap: 2px;
205
+ align-items: flex-end;
206
+ }
207
+
208
+ .typing-dot {
209
+ width: 6px;
210
+ height: 6px;
211
+ background-color: var(--text-secondary);
212
+ border-radius: 50%;
213
+ animation: typingAnimation 1.4s infinite ease-in-out;
214
+ }
215
+
216
+ .typing-dot:nth-child(1) {
217
+ animation-delay: 0s;
218
+ }
219
+
220
+ .typing-dot:nth-child(2) {
221
+ animation-delay: 0.2s;
222
+ }
223
+
224
+ .typing-dot:nth-child(3) {
225
+ animation-delay: 0.4s;
226
+ }
227
+
228
+ @keyframes typingAnimation {
229
+ 0%, 60%, 100% { transform: translateY(0); }
230
+ 30% { transform: translateY(-4px); }
231
+ }
232
+
233
+ footer {
234
+ background-color: var(--user-bg);
235
+ padding: 12px 20px;
236
+ border-top: 1px solid var(--border-color);
237
+ font-size: 0.8rem;
238
+ color: var(--text-secondary);
239
+ text-align: center;
240
+ flex-shrink: 0; /* Prevent footer from shrinking */
241
+ }
242
+
243
+ /* Side Panel Styles */
244
+ .side-panel {
245
+ position: fixed;
246
+ top: 0;
247
+ right: calc(-1 * var(--panel-width)); /* Initially hidden */
248
+ width: var(--panel-width);
249
+ height: 100vh;
250
+ background-color: var(--log-bg);
251
+ border-left: 1px solid var(--border-color);
252
+ box-shadow: -4px 0 12px rgba(0,0,0,0.15);
253
+ transition: right 0.3s ease-in-out;
254
+ display: flex;
255
+ flex-direction: column;
256
+ z-index: 999; /* Ensure it's above other content */
257
+ }
258
+
259
+ .side-panel.open {
260
+ right: 0; /* Slide in */
261
+ }
262
+
263
+ .side-panel-header {
264
+ padding: 12px 20px;
265
+ background-color: var(--user-bg);
266
+ border-bottom: 1px solid var(--border-color);
267
+ display: flex;
268
+ justify-content: space-between;
269
+ align-items: center;
270
+ flex-shrink: 0;
271
+ }
272
+
273
+ .side-panel-header h3 {
274
+ font-size: 1rem;
275
+ margin: 0;
276
+ }
277
+
278
+ .side-panel-content {
279
+ flex: 1;
280
+ overflow-y: auto;
281
+ padding: 12px 20px;
282
+ font-size: 0.85rem;
283
+ color: var(--text-secondary);
284
+ }
285
+
286
+ .log-entry {
287
+ margin-bottom: 6px;
288
+ display: flex;
289
+ gap: 10px;
290
+ }
291
+
292
+ .log-timestamp {
293
+ color: var(--text-secondary);
294
+ flex-shrink: 0;
295
+ }
296
+
297
+ .log-message {
298
+ flex: 1;
299
+ word-break: break-word; /* Prevent long words from overflowing */
300
+ }
301
+
302
+ .log-error {
303
+ color: var(--error-color);
304
+ }
305
+
306
+ .log-warning {
307
+ color: var(--warning-color);
308
+ }
309
+
310
+
311
+ .alert {
312
+ position: fixed;
313
+ top: 20px;
314
+ left: 50%;
315
+ transform: translateX(-50%);
316
+ padding: 12px 20px;
317
+ border-radius: 8px;
318
+ background-color: var(--error-color);
319
+ color: white;
320
+ z-index: 1000;
321
+ display: flex;
322
+ align-items: center;
323
+ gap: 8px;
324
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
325
+ animation: slideIn 0.3s ease-out;
326
+ }
327
+
328
+ .alert-success {
329
+ background-color: var(--primary);
330
+ }
331
+
332
+ .alert-warning {
333
+ background-color: var(--warning-color);
334
+ }
335
+
336
+ @keyframes slideIn {
337
+ from { top: -50px; opacity: 0; }
338
+ to { top: 20px; opacity: 1; }
339
+ }
340
+
341
+ .markdown-content pre {
342
+ background-color: rgba(0,0,0,0.2);
343
+ padding: 12px;
344
+ border-radius: 6px;
345
+ overflow-x: auto;
346
+ margin: 12px 0;
347
+ }
348
+
349
+ .markdown-content code {
350
+ font-family: 'Courier New', Courier, monospace;
351
+ font-size: 0.9rem;
352
+ }
353
+ </style>
354
+ </head>
355
+ <body>
356
+ <nav>
357
+ <div class="nav-title">Agent Chat</div>
358
+ <div class="nav-actions">
359
+ <button class="btn">
360
+ <i class="fas fa-plus"></i> New Chat
361
+ </button>
362
+ <!-- Button to open logs panel -->
363
+ <button class="btn-icon" id="open-logs-btn" title="Show Logs">
364
+ <i class="fas fa-list-alt"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  </button>
366
+ </div>
367
+ </nav>
368
+
369
+ <main>
370
+ <div class="chat-container" id="chat">
371
+ <!-- Messages will be inserted here -->
372
+ </div>
373
+
374
+ <div class="typing-indicator" id="typing-indicator" style="display: none;">
375
+ <div class="typing-dots">
376
+ <div class="typing-dot"></div>
377
+ <div class="typing-dot"></div>
378
+ <div class="typing-dot"></div>
379
+ </div>
380
+ <span>Agent is typing...</span>
381
+ </div>
382
+
383
+ <div class="input-container">
384
+ <div class="input-wrapper">
385
+ <textarea id="prompt" rows="1" placeholder="Message Agent..." autofocus></textarea>
386
+ <div class="input-actions">
387
+ <button class="btn-icon" id="upload-btn" title="Upload Database">
388
+ <i class="fas fa-database"></i>
389
+ </button>
390
+ <button class="btn-icon" id="send-btn" title="Send message">
391
+ <i class="fas fa-paper-plane"></i>
392
+ </button>
393
+ </div>
394
+ </div>
395
+ </div>
396
+
397
+ </main>
398
+
399
+ <footer>
400
+ <div>Agent Chat v1.0 · © 2023</div>
401
+ </footer>
402
+
403
+ <!-- Side Panel for Logs -->
404
+ <div id="side-panel" class="side-panel">
405
+ <div class="side-panel-header">
406
+ <h3>Logs</h3>
407
+ <button class="btn-icon" id="close-panel-btn" title="Hide Logs">
408
+ <i class="fas fa-times"></i>
409
  </button>
410
  </div>
411
+ <div class="side-panel-content" id="logs">
412
+ <!-- Logs will be inserted here -->
413
+ </div>
414
  </div>
415
+
416
+ <div id="flash-message" class="alert" style="display: none;"></div>
417
+
418
+ <script>
419
+ const socket = io();
420
+ const chatContainer = document.getElementById("chat");
421
+ const logsContainer = document.getElementById("logs"); // This is now the content div inside the panel
422
+ const sendButton = document.getElementById("send-btn");
423
+ const uploadButton = document.getElementById("upload-btn");
424
+ const promptTextarea = document.getElementById("prompt");
425
+ const flashMessage = document.getElementById('flash-message');
426
+ const typingIndicator = document.getElementById('typing-indicator');
427
+
428
+ // New elements for side panel
429
+ const sidePanel = document.getElementById('side-panel');
430
+ const openLogsBtn = document.getElementById('open-logs-btn');
431
+ const closePanelBtn = document.getElementById('close-panel-btn');
432
+
433
+
434
+ // Auto-resize textarea
435
+ promptTextarea.addEventListener('input', function() {
436
+ this.style.height = 'auto';
437
+ this.style.height = (this.scrollHeight) + 'px';
438
+ });
439
+
440
+ // Handle Enter key (Shift+Enter for new line)
441
+ promptTextarea.addEventListener('keydown', function(e) {
442
+ if (e.key === 'Enter' && !e.shiftKey) {
443
+ e.preventDefault();
444
+ sendMessage();
445
+ }
446
+ });
447
+
448
+ // Send button click handler
449
+ sendButton.addEventListener('click', sendMessage);
450
+
451
+ // Upload button click handler
452
+ uploadButton.addEventListener('click', () => {
453
+ window.location.href = '/upload';
454
+ });
455
+
456
+ // Side panel toggle handlers
457
+ openLogsBtn.addEventListener('click', () => {
458
+ sidePanel.classList.add('open');
459
+ });
460
+
461
+ closePanelBtn.addEventListener('click', () => {
462
+ sidePanel.classList.remove('open');
463
+ });
464
+
465
+
466
+ function sendMessage() {
467
+ const prompt = promptTextarea.value.trim();
468
+ if (!prompt) return;
469
+
470
+ addMessage("user", prompt);
471
+ promptTextarea.value = '';
472
+ promptTextarea.style.height = 'auto';
473
+ typingIndicator.style.display = 'flex';
474
+
475
+ fetch("/generate", {
476
+ method: "POST",
477
+ headers: { "Content-Type": "application/json" },
478
+ body: JSON.stringify({ prompt: prompt })
479
+ });
480
+ }
481
+
482
+ function addMessage(sender, text) {
483
+ const messageDiv = document.createElement("div");
484
+ messageDiv.classList.add("message", `message-${sender}`);
485
+
486
+ const avatarDiv = document.createElement("div");
487
+ avatarDiv.classList.add("avatar", `avatar-${sender}`);
488
+ avatarDiv.innerHTML = sender === 'user' ?
489
+ '<i class="fas fa-user"></i>' :
490
+ '<i class="fas fa-robot"></i>';
491
+
492
+ const contentDiv = document.createElement("div");
493
+ contentDiv.classList.add("message-content");
494
+ contentDiv.innerHTML = `<div class="markdown-content">${text}</div>`;
495
+
496
+ messageDiv.appendChild(avatarDiv);
497
+ messageDiv.appendChild(contentDiv);
498
+ chatContainer.appendChild(messageDiv);
499
+ chatContainer.scrollTop = chatContainer.scrollHeight;
500
+ }
501
+
502
+ function addLogMessage(text, type = 'info') {
503
+ const now = new Date();
504
+ const timestamp = now.toLocaleTimeString();
505
+
506
+ const logDiv = document.createElement("div");
507
+ logDiv.classList.add("log-entry");
508
+
509
+ const timeDiv = document.createElement("div");
510
+ timeDiv.classList.add("log-timestamp");
511
+ timeDiv.textContent = timestamp;
512
+
513
+ const messageDiv = document.createElement("div");
514
+ messageDiv.classList.add("log-message");
515
+ if (type !== 'info') messageDiv.classList.add(`log-${type}`);
516
+ messageDiv.textContent = text;
517
+
518
+ logDiv.appendChild(timeDiv);
519
+ logDiv.appendChild(messageDiv);
520
+ logsContainer.appendChild(logDiv); // Append to the logs content div
521
+ logsContainer.scrollTop = logsContainer.scrollHeight; // Scroll logs panel
522
+ }
523
+
524
+ function showFlashMessage(message, type = 'error') {
525
+ flashMessage.textContent = message;
526
+ flashMessage.className = `alert alert-${type}`;
527
+ flashMessage.style.display = 'flex';
528
+
529
+ setTimeout(() => {
530
+ flashMessage.style.display = 'none';
531
+ }, 3000);
532
+ }
533
+
534
+ // Socket.io handlers
535
+ let agentMessageDiv = null;
536
+
537
+ socket.on("final_stream", (data) => {
538
+ if (!agentMessageDiv) {
539
+ agentMessageDiv = document.createElement("div");
540
+ agentMessageDiv.classList.add("message", "message-agent");
541
+
542
+ const avatarDiv = document.createElement("div");
543
+ avatarDiv.classList.add("avatar", "avatar-agent");
544
+ avatarDiv.innerHTML = '<i class="fas fa-robot"></i>';
545
+
546
+ const contentDiv = document.createElement("div");
547
+ contentDiv.classList.add("message-content");
548
+ contentDiv.id = "agent-message-content";
549
+
550
+ agentMessageDiv.appendChild(avatarDiv);
551
+ agentMessageDiv.appendChild(contentDiv);
552
+ chatContainer.appendChild(agentMessageDiv);
553
+ }
554
+
555
+ const contentDiv = document.getElementById("agent-message-content");
556
+ contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
557
+ chatContainer.scrollTop = chatContainer.scrollHeight;
558
+ });
559
+
560
+ socket.on("final", (data) => {
561
+ typingIndicator.style.display = 'none';
562
+
563
+ if (agentMessageDiv) {
564
+ const contentDiv = document.getElementById("agent-message-content");
565
+ contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
566
+ agentMessageDiv = null;
567
+ } else {
568
+ addMessage("agent", data.message);
569
+ }
570
+ });
571
+
572
+ socket.on("log", (data) => {
573
+ addLogMessage(data.message, data.type || 'info');
574
+ });
575
+
576
+ socket.on("error", (data) => {
577
+ showFlashMessage(data.message, 'error');
578
+ typingIndicator.style.display = 'none';
579
+ });
580
+
581
+ // Handle flash messages from server
582
+ if (flashMessage) {
583
+ setTimeout(() => {
584
+ flashMessage.style.display = 'none';
585
+ }, 3000);
586
+ }
587
+ </script>
588
+ </body>
589
+ </html>