WebashalarForML commited on
Commit
b5d973c
verified
1 Parent(s): 71d3ab3

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +454 -182
templates/index.html CHANGED
@@ -5,270 +5,542 @@
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
  <style>
9
- /* Overall dark theme background */
10
- body {
11
- background-color: #1a1a2e;
12
- color: #eaeaea;
13
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 
 
 
 
 
 
 
 
 
 
 
14
  margin: 0;
15
  padding: 0;
16
  }
17
- .container {
18
- max-width: 800px;
19
- margin: 0 auto;
20
- padding: 20px;
 
 
 
 
 
21
  }
22
- header {
 
 
 
 
23
  display: flex;
24
  justify-content: space-between;
25
  align-items: center;
26
- margin-bottom: 20px;
27
  }
28
- h1 {
29
- margin-bottom: 20px;
30
- color: #eaeaea;
 
 
 
 
 
 
31
  }
 
32
  .btn {
33
- background-color: #007bff;
34
- color: #fff;
 
 
35
  padding: 8px 12px;
36
- text-decoration: none;
37
- border-radius: 5px;
38
- margin-left: 10px;
 
 
 
39
  }
 
40
  .btn:hover {
41
- background-color: #0056b3;
42
  }
43
- /* Chat conversation container */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  .chat-container {
45
- background-color: #16213e;
46
- border-radius: 8px;
47
- padding: 20px;
48
- height: 400px;
49
  overflow-y: auto;
50
- margin-bottom: 20px;
51
  }
52
- /* Logs container */
53
- .logs-container {
54
- background-color: #0f3460;
55
- border-radius: 8px;
56
  padding: 20px;
57
- height: 150px;
58
- overflow-y: auto;
59
- margin-bottom: 20px;
 
60
  }
61
- /* Message styling */
62
- .message {
63
- margin-bottom: 10px;
 
 
 
 
 
 
 
 
 
 
64
  display: flex;
65
- align-items: flex-start;
66
- }
67
- .message.user {
68
- justify-content: flex-end;
69
- }
70
- .message.agent {
71
- justify-content: flex-start;
72
- }
73
- .bubble {
74
- max-width: 70%;
75
- padding: 10px 15px;
76
- border-radius: 15px;
77
- line-height: 1.4;
78
- word-wrap: break-word;
79
- }
80
- /* User message bubble style */
81
- .bubble.user {
82
- background-color: #007bff;
83
- color: #fff;
84
- border-bottom-right-radius: 0;
85
- }
86
- /* Agent message bubble style */
87
- .bubble.agent {
88
- background-color: #2d3a55;
89
- color: #fff;
90
- border-bottom-left-radius: 0;
91
- }
92
- /* Log message bubble style */
93
- .bubble.log {
94
- background-color: #444;
95
- color: #ccc;
96
  font-size: 0.85rem;
97
- border-radius: 5px;
98
- padding: 5px 10px;
99
- margin: 2px 0;
100
  }
101
- /* Input area styling */
102
- .input-area {
 
 
 
 
 
 
 
103
  display: flex;
104
  gap: 10px;
105
  }
106
- .input-area textarea {
 
 
 
 
 
 
107
  flex: 1;
108
- padding: 10px;
109
- border-radius: 5px;
110
- border: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  resize: none;
112
  font-size: 1rem;
 
113
  }
114
- .input-area button {
115
- padding: 10px 20px;
116
- border-radius: 5px;
117
- border: none;
118
- background-color: #007bff;
119
- color: #fff;
120
- cursor: pointer;
121
  }
122
- .input-area button:hover {
123
- background-color: #0056b3;
 
 
 
 
 
124
  }
125
 
126
- .alert {
127
- padding: 10px;
128
- margin-bottom: 10px;
129
- border-radius: 5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  text-align: center;
 
 
 
131
  position: absolute;
132
- position-area: top center;
133
- top: 30px;
134
- align-items: center;
 
 
 
 
 
 
135
  }
136
 
137
- .alert-error {
138
- background-color: #D84040;
139
- color: #ffffff;
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
 
142
  .alert-success {
143
- background-color: #D2DE32;
144
- color: #ffffff;
145
  }
146
 
147
  .alert-warning {
148
- background-color: #FFC700;
149
- color: #ffffff;
150
  }
151
 
152
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  </style>
154
  </head>
155
  <body>
156
-
157
- <div class="container-flash">
158
- {% with messages = get_flashed_messages(with_categories=true) %}
159
- {% if messages %}
160
- <div id="flash-message" class="alert alert-{{ messages[0][0] }}">
161
- <strong>{{ messages[0][1] }}</strong>
162
- </div>
163
- {% endif %}
164
- {% endwith %}
165
- </div>
166
-
167
- <div class="container">
168
- <header>
169
- <h1>Agent Chat</h1>
170
- <div>
171
- <!-- Link to upload page -->
172
- <a href="/upload" class="btn">Upload DB</a>
173
- <!-- Link to view the uploaded DB file using the static route -->
174
- <a href="/files/uploaded.db" class="btn">View Uploaded DB</a>
175
- </div>
176
- </header>
177
- <!-- Chat conversation container -->
178
  <div class="chat-container" id="chat">
179
- <!-- Conversation messages will appear here -->
 
 
 
 
 
 
 
 
 
180
  </div>
181
- <!-- Logs container -->
182
- <div class="logs-container" id="logs">
183
- <!-- Log messages will appear here -->
 
 
 
 
 
 
 
 
 
 
184
  </div>
185
- <!-- Input area for sending prompts -->
186
- <div class="input-area">
187
- <textarea id="prompt" rows="2" placeholder="Type your message here..."></textarea>
188
- <button id="send">Send</button>
189
  </div>
190
- </div>
191
-
 
 
 
 
 
 
192
  <script>
193
  const socket = io();
194
  const chatContainer = document.getElementById("chat");
195
  const logsContainer = document.getElementById("logs");
196
- const sendButton = document.getElementById("send");
 
197
  const promptTextarea = document.getElementById("prompt");
198
  const flashMessage = document.getElementById('flash-message');
199
- //for flash message
200
- if (flashMessage) {
201
- setTimeout(function() {
202
- flashMessage.style.display = 'none';
203
- }, 2000); // Hide after 2 seconds
204
- }
205
-
206
- // Function to add a chat message bubble
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  function addMessage(sender, text) {
208
  const messageDiv = document.createElement("div");
209
- messageDiv.classList.add("message", sender);
210
- const bubbleDiv = document.createElement("div");
211
- bubbleDiv.classList.add("bubble", sender);
212
- bubbleDiv.textContent = text;
213
- messageDiv.appendChild(bubbleDiv);
 
 
 
 
 
 
 
 
 
214
  chatContainer.appendChild(messageDiv);
215
  chatContainer.scrollTop = chatContainer.scrollHeight;
216
  }
217
 
218
- // Function to add a log message bubble
219
- function addLogMessage(text) {
 
 
220
  const logDiv = document.createElement("div");
221
- logDiv.classList.add("bubble", "log");
222
- logDiv.textContent = text;
 
 
 
 
 
 
 
 
 
 
 
223
  logsContainer.appendChild(logDiv);
224
  logsContainer.scrollTop = logsContainer.scrollHeight;
225
  }
226
 
227
- // Send user's message when "Send" button is clicked
228
- sendButton.addEventListener("click", () => {
229
- const prompt = promptTextarea.value.trim();
230
- if (!prompt) return;
231
- addMessage("user", prompt);
232
- promptTextarea.value = "";
233
- // Send prompt to the server via a POST request
234
- fetch("/generate", {
235
- method: "POST",
236
- headers: { "Content-Type": "application/json" },
237
- body: JSON.stringify({ prompt: prompt })
238
- });
239
- });
240
 
241
- // Handle streaming tokens for the agent's reply.
242
- let agentMessageBubble = null;
 
243
  socket.on("final_stream", (data) => {
244
- if (!agentMessageBubble) {
245
- // Create an agent message bubble if one does not exist.
246
- const messageDiv = document.createElement("div");
247
- messageDiv.classList.add("message", "agent");
248
- agentMessageBubble = document.createElement("div");
249
- agentMessageBubble.classList.add("bubble", "agent");
250
- messageDiv.appendChild(agentMessageBubble);
251
- chatContainer.appendChild(messageDiv);
 
 
 
 
 
 
 
252
  }
253
- // Append incoming data to the agent's bubble.
254
- agentMessageBubble.textContent += data.message;
 
255
  chatContainer.scrollTop = chatContainer.scrollHeight;
256
  });
257
 
258
- // When the final answer is sent, finish the bubble.
259
  socket.on("final", (data) => {
260
- if (!agentMessageBubble) {
261
- addMessage("agent", data.message);
 
 
 
 
262
  } else {
263
- agentMessageBubble.textContent = data.message;
264
- agentMessageBubble = null;
265
  }
266
  });
267
 
268
- // Append incoming log messages to the logs container.
269
  socket.on("log", (data) => {
270
- addLogMessage(data.message);
 
 
 
 
 
271
  });
 
 
 
 
 
 
 
272
  </script>
273
  </body>
274
  </html>
 
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
+ .log-toggle {
277
  position: absolute;
278
+ right: 20px;
279
+ top: -12px;
280
+ background: var(--log-bg);
281
+ border: 1px solid var(--border-color);
282
+ border-radius: 12px;
283
+ padding: 2px 8px;
284
+ font-size: 0.7rem;
285
+ cursor: pointer;
286
+ z-index: 1;
287
  }
288
 
289
+ .alert {
290
+ position: fixed;
291
+ top: 20px;
292
+ left: 50%;
293
+ transform: translateX(-50%);
294
+ padding: 12px 20px;
295
+ border-radius: 8px;
296
+ background-color: var(--error-color);
297
+ color: white;
298
+ z-index: 1000;
299
+ display: flex;
300
+ align-items: center;
301
+ gap: 8px;
302
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
303
+ animation: slideIn 0.3s ease-out;
304
  }
305
 
306
  .alert-success {
307
+ background-color: var(--primary);
 
308
  }
309
 
310
  .alert-warning {
311
+ background-color: var(--warning-color);
 
312
  }
313
 
314
+ @keyframes slideIn {
315
+ from { top: -50px; opacity: 0; }
316
+ to { top: 20px; opacity: 1; }
317
+ }
318
+
319
+ .markdown-content pre {
320
+ background-color: rgba(0,0,0,0.2);
321
+ padding: 12px;
322
+ border-radius: 6px;
323
+ overflow-x: auto;
324
+ margin: 12px 0;
325
+ }
326
+
327
+ .markdown-content code {
328
+ font-family: 'Courier New', Courier, monospace;
329
+ font-size: 0.9rem;
330
+ }
331
  </style>
332
  </head>
333
  <body>
334
+ <nav>
335
+ <div class="nav-title">Agent Chat</div>
336
+ <div class="nav-actions">
337
+ <button class="btn">
338
+ <i class="fas fa-plus"></i> New Chat
339
+ </button>
340
+ </div>
341
+ </nav>
342
+
343
+ <main>
 
 
 
 
 
 
 
 
 
 
 
 
344
  <div class="chat-container" id="chat">
345
+ <!-- Messages will be inserted here -->
346
+ </div>
347
+
348
+ <div class="typing-indicator" id="typing-indicator" style="display: none;">
349
+ <div class="typing-dots">
350
+ <div class="typing-dot"></div>
351
+ <div class="typing-dot"></div>
352
+ <div class="typing-dot"></div>
353
+ </div>
354
+ <span>Agent is typing...</span>
355
  </div>
356
+
357
+ <div class="input-container">
358
+ <div class="input-wrapper">
359
+ <textarea id="prompt" rows="1" placeholder="Message Agent..." autofocus></textarea>
360
+ <div class="input-actions">
361
+ <button class="btn-icon" id="upload-btn" title="Upload Database">
362
+ <i class="fas fa-database"></i>
363
+ </button>
364
+ <button class="btn-icon" id="send-btn" title="Send message">
365
+ <i class="fas fa-paper-plane"></i>
366
+ </button>
367
+ </div>
368
+ </div>
369
  </div>
370
+
371
+ <div class="logs-container" id="logs-container">
372
+ <div class="log-toggle" id="log-toggle">Hide Logs</div>
373
+ <div id="logs"></div>
374
  </div>
375
+ </main>
376
+
377
+ <footer>
378
+ <div>Agent Chat v1.0 路 漏 2023</div>
379
+ </footer>
380
+
381
+ <div id="flash-message" class="alert" style="display: none;"></div>
382
+
383
  <script>
384
  const socket = io();
385
  const chatContainer = document.getElementById("chat");
386
  const logsContainer = document.getElementById("logs");
387
+ const sendButton = document.getElementById("send-btn");
388
+ const uploadButton = document.getElementById("upload-btn");
389
  const promptTextarea = document.getElementById("prompt");
390
  const flashMessage = document.getElementById('flash-message');
391
+ const typingIndicator = document.getElementById('typing-indicator');
392
+ const logToggle = document.getElementById('log-toggle');
393
+ const logsContainerElement = document.getElementById('logs-container');
394
+
395
+ // Auto-resize textarea
396
+ promptTextarea.addEventListener('input', function() {
397
+ this.style.height = 'auto';
398
+ this.style.height = (this.scrollHeight) + 'px';
399
+ });
400
+
401
+ // Handle Enter key (Shift+Enter for new line)
402
+ promptTextarea.addEventListener('keydown', function(e) {
403
+ if (e.key === 'Enter' && !e.shiftKey) {
404
+ e.preventDefault();
405
+ sendMessage();
406
+ }
407
+ });
408
+
409
+ // Send button click handler
410
+ sendButton.addEventListener('click', sendMessage);
411
+
412
+ // Upload button click handler
413
+ uploadButton.addEventListener('click', () => {
414
+ window.location.href = '/upload';
415
+ });
416
+
417
+ // Log toggle handler
418
+ logToggle.addEventListener('click', () => {
419
+ logsContainerElement.classList.toggle('collapsed');
420
+ logToggle.textContent = logsContainerElement.classList.contains('collapsed') ? 'Show Logs' : 'Hide Logs';
421
+ });
422
+
423
+ function sendMessage() {
424
+ const prompt = promptTextarea.value.trim();
425
+ if (!prompt) return;
426
+
427
+ addMessage("user", prompt);
428
+ promptTextarea.value = '';
429
+ promptTextarea.style.height = 'auto';
430
+ typingIndicator.style.display = 'flex';
431
+
432
+ fetch("/generate", {
433
+ method: "POST",
434
+ headers: { "Content-Type": "application/json" },
435
+ body: JSON.stringify({ prompt: prompt })
436
+ });
437
+ }
438
+
439
  function addMessage(sender, text) {
440
  const messageDiv = document.createElement("div");
441
+ messageDiv.classList.add("message", `message-${sender}`);
442
+
443
+ const avatarDiv = document.createElement("div");
444
+ avatarDiv.classList.add("avatar", `avatar-${sender}`);
445
+ avatarDiv.innerHTML = sender === 'user' ?
446
+ '<i class="fas fa-user"></i>' :
447
+ '<i class="fas fa-robot"></i>';
448
+
449
+ const contentDiv = document.createElement("div");
450
+ contentDiv.classList.add("message-content");
451
+ contentDiv.innerHTML = `<div class="markdown-content">${text}</div>`;
452
+
453
+ messageDiv.appendChild(avatarDiv);
454
+ messageDiv.appendChild(contentDiv);
455
  chatContainer.appendChild(messageDiv);
456
  chatContainer.scrollTop = chatContainer.scrollHeight;
457
  }
458
 
459
+ function addLogMessage(text, type = 'info') {
460
+ const now = new Date();
461
+ const timestamp = now.toLocaleTimeString();
462
+
463
  const logDiv = document.createElement("div");
464
+ logDiv.classList.add("log-entry");
465
+
466
+ const timeDiv = document.createElement("div");
467
+ timeDiv.classList.add("log-timestamp");
468
+ timeDiv.textContent = timestamp;
469
+
470
+ const messageDiv = document.createElement("div");
471
+ messageDiv.classList.add("log-message");
472
+ if (type !== 'info') messageDiv.classList.add(`log-${type}`);
473
+ messageDiv.textContent = text;
474
+
475
+ logDiv.appendChild(timeDiv);
476
+ logDiv.appendChild(messageDiv);
477
  logsContainer.appendChild(logDiv);
478
  logsContainer.scrollTop = logsContainer.scrollHeight;
479
  }
480
 
481
+ function showFlashMessage(message, type = 'error') {
482
+ flashMessage.textContent = message;
483
+ flashMessage.className = `alert alert-${type}`;
484
+ flashMessage.style.display = 'flex';
485
+
486
+ setTimeout(() => {
487
+ flashMessage.style.display = 'none';
488
+ }, 3000);
489
+ }
 
 
 
 
490
 
491
+ // Socket.io handlers
492
+ let agentMessageDiv = null;
493
+
494
  socket.on("final_stream", (data) => {
495
+ if (!agentMessageDiv) {
496
+ agentMessageDiv = document.createElement("div");
497
+ agentMessageDiv.classList.add("message", "message-agent");
498
+
499
+ const avatarDiv = document.createElement("div");
500
+ avatarDiv.classList.add("avatar", "avatar-agent");
501
+ avatarDiv.innerHTML = '<i class="fas fa-robot"></i>';
502
+
503
+ const contentDiv = document.createElement("div");
504
+ contentDiv.classList.add("message-content");
505
+ contentDiv.id = "agent-message-content";
506
+
507
+ agentMessageDiv.appendChild(avatarDiv);
508
+ agentMessageDiv.appendChild(contentDiv);
509
+ chatContainer.appendChild(agentMessageDiv);
510
  }
511
+
512
+ const contentDiv = document.getElementById("agent-message-content");
513
+ contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
514
  chatContainer.scrollTop = chatContainer.scrollHeight;
515
  });
516
 
 
517
  socket.on("final", (data) => {
518
+ typingIndicator.style.display = 'none';
519
+
520
+ if (agentMessageDiv) {
521
+ const contentDiv = document.getElementById("agent-message-content");
522
+ contentDiv.innerHTML = `<div class="markdown-content">${data.message}</div>`;
523
+ agentMessageDiv = null;
524
  } else {
525
+ addMessage("agent", data.message);
 
526
  }
527
  });
528
 
 
529
  socket.on("log", (data) => {
530
+ addLogMessage(data.message, data.type || 'info');
531
+ });
532
+
533
+ socket.on("error", (data) => {
534
+ showFlashMessage(data.message, 'error');
535
+ typingIndicator.style.display = 'none';
536
  });
537
+
538
+ // Handle flash messages from server
539
+ if (flashMessage) {
540
+ setTimeout(() => {
541
+ flashMessage.style.display = 'none';
542
+ }, 3000);
543
+ }
544
  </script>
545
  </body>
546
  </html>