HI7RAI commited on
Commit
d65e348
·
verified ·
1 Parent(s): 2222377

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1056 -997
index.html CHANGED
@@ -1,1010 +1,1069 @@
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.0">
6
- <title>AI Transformers Workbench</title>
7
- <!-- Import FontAwesome for Icons -->
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <!-- Import Google Fonts -->
10
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
11
-
12
- <style>
13
- /* --- CSS Variables & Reset --- */
14
- :root {
15
- --bg-dark: #0d1117;
16
- --bg-panel: #161b22;
17
- --bg-input: #0d1117;
18
- --border: #30363d;
19
- --accent: #58a6ff;
20
- --accent-hover: #79c0ff;
21
- --success: #238636;
22
- --danger: #da3633;
23
- --text-main: #c9d1d9;
24
- --text-muted: #8b949e;
25
- --font-main: 'Inter', sans-serif;
26
- --font-code: 'JetBrains Mono', monospace;
27
- --shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
28
- }
29
-
30
- * {
31
- box-sizing: border-box;
32
- margin: 0;
33
- padding: 0;
34
- outline: none;
35
- }
36
-
37
- body {
38
- font-family: var(--font-main);
39
- background-color: var(--bg-dark);
40
- color: var(--text-main);
41
- height: 100vh;
42
- display: flex;
43
- flex-direction: column;
44
- overflow: hidden;
45
- }
46
-
47
- /* --- Scrollbar Styling --- */
48
- ::-webkit-scrollbar {
49
- width: 8px;
50
- height: 8px;
51
- }
52
- ::-webkit-scrollbar-track {
53
- background: var(--bg-dark);
54
- }
55
- ::-webkit-scrollbar-thumb {
56
- background: var(--border);
57
- border-radius: 4px;
58
- }
59
- ::-webkit-scrollbar-thumb:hover {
60
- background: var(--text-muted);
61
- }
62
-
63
- /* --- Header --- */
64
- header {
65
- height: 60px;
66
- background-color: var(--bg-panel);
67
- border-bottom: 1px solid var(--border);
68
- display: flex;
69
- align-items: center;
70
- justify-content: space-between;
71
- padding: 0 20px;
72
- flex-shrink: 0;
73
- z-index: 50;
74
- }
75
-
76
- .logo {
77
- font-weight: 700;
78
- font-size: 1.2rem;
79
- display: flex;
80
- align-items: center;
81
- gap: 10px;
82
- color: var(--text-main);
83
- cursor: pointer;
84
- }
85
-
86
- .logo i { color: var(--accent); }
87
-
88
- .header-links a {
89
- color: var(--accent);
90
- text-decoration: none;
91
- font-size: 0.9rem;
92
- transition: opacity 0.2s;
93
- font-weight: 500;
94
- }
95
- .header-links a:hover { opacity: 0.8; text-decoration: underline; }
96
-
97
- .header-controls { display: flex; gap: 10px; }
98
-
99
- /* --- Main Layout --- */
100
- .main-container {
101
- display: flex;
102
- flex: 1;
103
- overflow: hidden;
104
- position: relative;
105
- }
106
-
107
- /* --- Sidebar (History) --- */
108
- .sidebar {
109
- width: 280px;
110
- background-color: var(--bg-panel);
111
- border-right: 1px solid var(--border);
112
- display: flex;
113
- flex-direction: column;
114
- transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
115
- z-index: 40;
116
- }
117
-
118
- .sidebar-header { padding: 15px; border-bottom: 1px solid var(--border); }
119
-
120
- .btn-new-chat {
121
- width: 100%;
122
- padding: 10px;
123
- background-color: var(--success);
124
- color: white;
125
- border: none;
126
- border-radius: 6px;
127
- cursor: pointer;
128
- font-weight: 600;
129
- display: flex;
130
- align-items: center;
131
- justify-content: center;
132
- gap: 8px;
133
- transition: background 0.2s;
134
- }
135
- .btn-new-chat:hover { background-color: #2ea043; }
136
-
137
- .history-list { flex: 1; overflow-y: auto; padding: 10px; }
138
-
139
- .history-item {
140
- padding: 10px;
141
- border-radius: 6px;
142
- cursor: pointer;
143
- display: flex;
144
- align-items: center;
145
- justify-content: space-between;
146
- margin-bottom: 5px;
147
- color: var(--text-main);
148
- transition: background 0.2s;
149
- group: item;
150
- }
151
- .history-item:hover, .history-item.active { background-color: rgba(88, 166, 255, 0.1); }
152
-
153
- .history-name {
154
- font-size: 0.9rem;
155
- white-space: nowrap;
156
- overflow: hidden;
157
- text-overflow: ellipsis;
158
- flex: 1;
159
- margin-right: 8px;
160
- padding: 2px 4px;
161
- border: 1px solid transparent;
162
- border-radius: 4px;
163
- }
164
- .history-name:focus {
165
- border-color: var(--accent);
166
- background: var(--bg-input);
167
- }
168
-
169
- .history-actions i {
170
- color: var(--text-muted);
171
- margin-left: 5px;
172
- font-size: 0.8rem;
173
- padding: 4px;
174
- border-radius: 4px;
175
- transition: all 0.2s;
176
- }
177
- .history-actions i:hover { color: var(--danger); background: rgba(218, 54, 51, 0.1); }
178
-
179
- .sidebar-footer { padding: 15px; border-top: 1px solid var(--border); }
180
-
181
- .btn-import {
182
- width: 100%;
183
- padding: 8px;
184
- background: transparent;
185
- border: 1px dashed var(--text-muted);
186
- color: var(--text-muted);
187
- border-radius: 6px;
188
- cursor: pointer;
189
- transition: all 0.2s;
190
- }
191
- .btn-import:hover { border-color: var(--accent); color: var(--accent); }
192
-
193
- /* --- Chat Area --- */
194
- .chat-area {
195
- flex: 1;
196
- display: flex;
197
- flex-direction: column;
198
- background-color: var(--bg-dark);
199
- position: relative;
200
- min-width: 0; /* Fix flex overflow */
201
- }
202
-
203
- .chat-header {
204
- padding: 10px 20px;
205
- border-bottom: 1px solid var(--border);
206
- display: flex;
207
- justify-content: space-between;
208
- align-items: center;
209
- background: rgba(22, 27, 34, 0.8);
210
- backdrop-filter: blur(10px);
211
- }
212
-
213
- .model-indicator { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 0.95rem; }
214
- .badge { font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; background: var(--border); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
215
- .badge.active { background: var(--accent); color: white; }
216
-
217
- .chat-messages {
218
- flex: 1;
219
- overflow-y: auto;
220
- padding: 20px;
221
- display: flex;
222
- flex-direction: column;
223
- gap: 20px;
224
- }
225
 
226
- .message {
227
- max-width: 85%;
228
- line-height: 1.6;
229
- position: relative;
230
- animation: fadeIn 0.3s ease;
231
- }
232
-
233
- @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
234
-
235
- .message.user { align-self: flex-end; }
236
- .message.ai { align-self: flex-start; }
237
- .message.system { align-self: center; max-width: 90%; font-size: 0.85rem; color: var(--text-muted); text-align: center; background: rgba(139, 148, 158, 0.1); padding: 4px 12px; border-radius: 20px; }
238
-
239
- .bubble {
240
- padding: 12px 18px;
241
- border-radius: 12px;
242
- position: relative;
243
- word-wrap: break-word;
244
- white-space: pre-wrap;
245
- }
246
-
247
- .message.user .bubble {
248
- background-color: var(--accent);
249
- color: white;
250
- border-bottom-right-radius: 2px;
251
- box-shadow: 0 2px 5px rgba(0,0,0,0.2);
252
- }
253
-
254
- .message.ai .bubble {
255
- background-color: var(--bg-panel);
256
- border: 1px solid var(--border);
257
- border-bottom-left-radius: 2px;
258
- color: var(--text-main);
259
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
260
- }
261
-
262
- .msg-actions {
263
- position: absolute; top: -25px; right: 0; display: none; gap: 8px;
264
- }
265
- .message:hover .msg-actions { display: flex; }
266
-
267
- .action-btn {
268
- background: var(--bg-panel); border: 1px solid var(--border); color: var(--text-muted);
269
- padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; cursor: pointer;
270
- display: flex; align-items: center; gap: 4px; transition: all 0.2s;
271
- }
272
- .action-btn:hover { color: var(--accent); border-color: var(--accent); transform: translateY(-2px); }
273
-
274
- .input-area { padding: 20px; border-top: 1px solid var(--border); background-color: var(--bg-panel); }
275
- .input-wrapper { position: relative; max-width: 900px; margin: 0 auto; }
276
-
277
- .chat-input {
278
- width: 100%;
279
- background-color: var(--bg-input);
280
- border: 1px solid var(--border);
281
- border-radius: 8px;
282
- padding: 15px 50px 15px 15px;
283
- color: var(--text-main);
284
- font-family: var(--font-main);
285
- resize: none;
286
- min-height: 54px;
287
- max-height: 200px;
288
- line-height: 1.5;
289
- transition: border-color 0.2s;
290
- }
291
- .chat-input:focus { border-color: var(--accent); }
292
-
293
- .send-btn {
294
- position: absolute; right: 12px; bottom: 12px;
295
- background: none; border: none; color: var(--text-muted);
296
- cursor: pointer; font-size: 1.2rem; transition: color 0.2s;
297
- }
298
- .send-btn:hover { color: var(--accent); transform: scale(1.1); }
299
-
300
- /* --- Right Panel (Models & Config) --- */
301
- .right-panel {
302
- width: 350px;
303
- background-color: var(--bg-panel);
304
- border-left: 1px solid var(--border);
305
- display: flex;
306
- flex-direction: column;
307
- overflow-y: auto;
308
- transition: width 0.3s ease;
309
- }
310
-
311
- .panel-section { padding: 20px; border-bottom: 1px solid var(--border); }
312
- .panel-title {
313
- font-size: 0.75rem; text-transform: uppercase; color: var(--text-muted);
314
- margin-bottom: 12px; font-weight: 700; letter-spacing: 0.5px;
315
- display: flex; align-items: center; gap: 8px;
316
- }
317
-
318
- /* Model Cards */
319
- .model-card {
320
- background: var(--bg-input); border: 1px solid var(--border);
321
- border-radius: 8px; padding: 12px; margin-bottom: 10px;
322
- cursor: pointer; transition: all 0.2s ease;
323
- }
324
- .model-card:hover { border-color: var(--text-muted); transform: translateY(-2px); }
325
- .model-card.active { border-color: var(--accent); background: rgba(88, 166, 255, 0.05); box-shadow: 0 0 0 1px var(--accent); }
326
-
327
- .model-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
328
- .model-name { font-weight: 600; font-size: 0.95rem; color: var(--text-main); }
329
- .model-meta { font-size: 0.8rem; color: var(--text-muted); line-height: 1.4; }
330
-
331
- .showcase-stats { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
332
- .stat { font-size: 0.7rem; background: var(--border); padding: 2px 6px; border-radius: 4px; color: var(--text-muted); }
333
-
334
- /* Configuration & Downloads */
335
- .download-controls { display: flex; flex-direction: column; gap: 12px; }
336
- .form-group { display: flex; flex-direction: column; gap: 6px; }
337
- .form-group label { font-size: 0.8rem; color: var(--text-muted); font-weight: 500; }
338
-
339
- .form-input {
340
- background: var(--bg-input); border: 1px solid var(--border); color: var(--text-main);
341
- padding: 8px 12px; border-radius: 6px; font-family: var(--font-code); font-size: 0.85rem;
342
- transition: border-color 0.2s;
343
- }
344
- .form-input:focus { border-color: var(--accent); }
345
-
346
- .btn-download {
347
- background-color: var(--accent); color: white; border: none;
348
- padding: 10px; border-radius: 6px; cursor: pointer; font-weight: 600;
349
- display: flex; align-items: center; justify-content: center; gap: 8px;
350
- transition: background 0.2s;
351
- }
352
- .btn-download:hover { background-color: var(--accent-hover); }
353
-
354
- .btn-secondary {
355
- background-color: transparent; border: 1px solid var(--border); color: var(--text-main);
356
- padding: 10px; border-radius: 6px; cursor: pointer; font-weight: 600;
357
- display: flex; align-items: center; justify-content: center; gap: 8px;
358
- transition: all 0.2s;
359
- }
360
- .btn-secondary:hover { border-color: var(--text-muted); background: var(--bg-input); }
361
-
362
- /* Terminal Simulation */
363
- .terminal {
364
- background: #000; color: #3fb950; font-family: var(--font-code);
365
- font-size: 0.75rem; padding: 12px; border-radius: 6px; height: 180px;
366
- overflow-y: auto; border: 1px solid #30363d;
367
- }
368
- .terminal-line { margin-bottom: 4px; word-break: break-all; }
369
- .terminal-line.error { color: var(--danger); }
370
- .terminal-line.info { color: var(--text-muted); }
371
- .terminal-line.command { color: var(--text-main); font-weight: bold; }
372
-
373
- /* Toast Notification */
374
- .toast {
375
- position: fixed; bottom: 24px; right: 24px;
376
- background: var(--bg-panel); border: 1px solid var(--accent);
377
- color: var(--text-main); padding: 12px 20px; border-radius: 8px;
378
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
379
- transform: translateY(100px); opacity: 0; transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
380
- z-index: 1000; display: flex; align-items: center; gap: 10px;
381
- }
382
- .toast.show { transform: translateY(0); opacity: 1; }
383
- .toast i { color: var(--accent); }
384
-
385
- /* Loading Dots */
386
- .typing-indicator span {
387
- display: inline-block; width: 6px; height: 6px; background-color: var(--text-muted);
388
- border-radius: 50%; animation: typing 1.4s infinite ease-in-out both; margin: 0 2px;
389
- }
390
- .typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
391
- .typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
392
- @keyframes typing { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
393
-
394
- /* Responsive */
395
- @media (max-width: 1024px) {
396
- .right-panel { position: absolute; right: 0; height: 100%; transform: translateX(100%); z-index: 60; box-shadow: -5px 0 15px rgba(0,0,0,0.5); }
397
- .right-panel.open { transform: translateX(0); }
398
- }
399
-
400
- @media (max-width: 768px) {
401
- .sidebar { position: absolute; left: 0; height: 100%; transform: translateX(-100%); box-shadow: 5px 0 15px rgba(0,0,0,0.5); }
402
- .sidebar.open { transform: translateX(0); }
403
- .message { max-width: 95%; }
404
- }
405
-
406
- /* Animations */
407
- .spinner { animation: spin 1s linear infinite; }
408
- @keyframes spin { 100% { transform: rotate(360deg); } }
409
-
410
- .mobile-overlay {
411
- position: fixed; top: 0; left: 0; width: 100%; height: 100%;
412
- background: rgba(0,0,0,0.5); z-index: 30; display: none;
413
- }
414
- .mobile-overlay.active { display: block; }
415
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  </head>
417
 
418
  <body>
419
- <!-- Header -->
420
- <header>
421
- <div class="logo">
422
- <i class="fa-solid fa-cube"></i>
423
- <span>Transformers<span style="color:var(--text-muted); font-weight:400; font-size:0.9em;">WebApp</span></span>
424
- </div>
425
-
426
- <div class="header-links">
427
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">
428
- Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em;"></i>
429
- </a>
430
- </div>
431
-
432
- <div class="header-controls">
433
- <button class="action-btn" id="toggle-terminal" title="Toggle Tools Panel">
434
- <i class="fa-solid fa-sliders"></i>
435
- </button>
436
- <button class="action-btn" id="toggle-sidebar" style="display:none;" title="Toggle History">
437
- <i class="fa-solid fa-bars"></i>
438
- </button>
439
- </div>
440
- </header>
441
-
442
- <div class="main-container">
443
- <!-- Mobile Overlay -->
444
- <div class="mobile-overlay" id="mobile-overlay"></div>
445
-
446
- <!-- Sidebar -->
447
- <aside class="sidebar" id="sidebar">
448
- <div class="sidebar-header">
449
- <button class="btn-new-chat" onclick="createNewConversation()">
450
- <i class="fa-solid fa-plus"></i> New Conversation
451
- </button>
452
- </div>
453
- <div class="history-list" id="history-list">
454
- <!-- History Items Injected via JS -->
455
- </div>
456
- <div class="sidebar-footer">
457
- <button class="btn-import" onclick="importConversation()">
458
- <i class="fa-solid fa-file-import"></i> Import JSON
459
- </button>
460
- </div>
461
- </aside>
462
-
463
- <!-- Main Chat Area -->
464
- <main class="chat-area">
465
- <div class="chat-header">
466
- <div class="model-indicator">
467
- <i class="fa-solid fa-microchip" style="color: var(--accent);"></i>
468
- <span id="current-model-display">Llama-3-8B</span>
469
- <span class="badge" id="focus-mode-badge">Focus: OFF</span>
470
- </div>
471
- <div>
472
- <button class="action-btn" onclick="toggleFocusMode()" title="Toggle Focus Mode">
473
- <i class="fa-solid fa-crosshairs"></i> Focus
474
- </button>
475
- </div>
476
- </div>
477
-
478
- <div class="chat-messages" id="chat-messages">
479
- <!-- Messages Injected via JS -->
480
- </div>
481
-
482
- <div class="input-area">
483
- <div class="input-wrapper">
484
- <textarea class="chat-input" id="user-input" placeholder="Type a message... (Shift+Enter for new line)"></textarea>
485
- <button class="send-btn" onclick="sendMessage()"><i class="fa-solid fa-paper-plane"></i></button>
486
- </div>
487
- </div>
488
- </main>
489
-
490
- <!-- Right Panel (Models & Tools) -->
491
- <aside class="right-panel" id="right-panel">
492
- <!-- Model Showcase -->
493
- <div class="panel-section">
494
- <div class="panel-title"><i class="fa-solid fa-layer-group"></i> Model Showcase</div>
495
- <div id="model-list">
496
- <!-- Models injected JS -->
497
- </div>
498
- </div>
499
-
500
- <!-- Configuration & Downloads -->
501
- <div class="panel-section">
502
- <div class="panel-title"><i class="fa-solid fa-gears"></i> Configuration & API</div>
503
- <div class="download-controls">
504
- <div class="form-group">
505
- <label>WebApp Folder Path</label>
506
- <input type="text" class="form-input" value=":/app/models" id="app-path">
507
- </div>
508
- <div class="form-group">
509
- <label>Download Destination</label>
510
- <input type="text" class="form-input" value="~/Downloads/" id="dl-path">
511
- </div>
512
- <button class="btn-download" onclick="startDownloadProcess()">
513
- <i class="fa-solid fa-cloud-arrow-down"></i> Fetch & Download Models
514
- </button>
515
- <button class="btn-secondary" onclick="simulateAutoConfig()">
516
- <i class="fa-solid fa-wand-magic-sparkles"></i> Auto Config App
517
- </button>
518
- </div>
519
- </div>
520
-
521
- <!-- Simulated Terminal -->
522
- <div class="panel-section">
523
- <div class="panel-title">
524
- <i class="fa-solid fa-terminal"></i> System Terminal
525
- <span style="margin-left:auto; font-size:0.6em; cursor:pointer;" onclick="clearTerminal()">Clear</span>
526
- </div>
527
- <div class="terminal" id="terminal-output">
528
- <div class="terminal-line info">> System initialized...</div>
529
- <div class="terminal-line info">> Ready for commands.</div>
530
- </div>
531
- </div>
532
- </aside>
533
  </div>
534
 
535
- <!-- Toast Notification -->
536
- <div class="toast" id="toast">
537
- <i class="fa-solid fa-circle-check"></i>
538
- <span id="toast-msg">Operation Successful</span>
539
  </div>
540
 
541
- <script>
542
- // --- State Management ---
543
- const state = {
544
- conversations: [],
545
- currentConversationId: null,
546
- models: [
547
- { id: 'llama-3', name: 'Llama-3-8B', type: 'Instruct', size: '4.7GB', desc: 'General purpose assistant.' },
548
- { id: 'mistral', name: 'Mistral-7B', type: 'Creative', size: '4.1GB', desc: 'Good for creative writing.' },
549
- { id: 'falcon', name: 'Falcon-40B', type: 'Logic', size: '80GB', desc: 'Advanced reasoning.' },
550
- { id: 'bert', name: 'BERT-Large', type: 'NLP', size: '1.2GB', desc: 'Text classification & embeddings.' }
551
- ],
552
- currentModel: 'llama-3',
553
- focusMode: false,
554
- appPath: ':/app/models',
555
- dlPath: '~/Downloads/'
556
- };
557
-
558
- // --- Initialization ---
559
- document.addEventListener('DOMContentLoaded', () => {
560
- loadFromStorage();
561
- if (state.conversations.length === 0) {
562
- createNewConversation(true);
563
- } else {
564
- loadConversation(state.conversations[0].id);
565
- }
566
- renderModelList();
567
- renderHistoryList();
568
- checkResponsive();
569
-
570
- // Auto-refresh simulation (AJAX polling visual)
571
- setInterval(() => {
572
- if(Math.random() > 0.95) {
573
- logTerminal(`> Checking HuggingFace API for updates...`, 'info');
574
- }
575
- }, 15000);
576
-
577
- // Textarea auto-resize
578
- const ta = document.getElementById('user-input');
579
- ta.addEventListener('input', function() {
580
- this.style.height = 'auto';
581
- this.style.height = (this.scrollHeight) + 'px';
582
- });
583
-
584
- // Handle Enter key
585
- ta.addEventListener('keydown', function(e) {
586
- if (e.key === 'Enter' && !e.shiftKey) {
587
- e.preventDefault();
588
- sendMessage();
589
- }
590
- });
591
-
592
- // Handle window resize
593
- window.addEventListener('resize', checkResponsive);
594
- });
595
-
596
- function checkResponsive() {
597
- const toggleBtn = document.getElementById('toggle-sidebar');
598
- if (window.innerWidth <= 768) {
599
- toggleBtn.style.display = 'block';
600
- } else {
601
- toggleBtn.style.display = 'none';
602
- document.getElementById('sidebar').classList.remove('open');
603
- document.getElementById('mobile-overlay').classList.remove('active');
604
- }
605
- }
606
-
607
- // --- Core Logic ---
608
-
609
- function createNewConversation(isFirst = false) {
610
- const newId = Date.now().toString();
611
- const currentModelObj = state.models.find(m => m.id === state.currentModel);
612
-
613
- const newConv = {
614
- id: newId,
615
- name: isFirst ? 'New Conversation' : `Conversation ${state.conversations.length + 1}`,
616
- model: state.currentModel,
617
- messages: []
618
- };
619
-
620
- // Pre-suggestion based on model
621
- if (currentModelObj) {
622
- newConv.messages.push({
623
- role: 'system',
624
- content: `Switched to ${currentModelObj.name}. ${currentModelObj.desc} Suggestion: Try asking for a summary or creative story.`
625
- });
626
- }
627
-
628
- state.conversations.unshift(newConv);
629
- state.currentConversationId = newId;
630
- saveToStorage();
631
- renderHistoryList();
632
- renderChat();
633
-
634
- if(!isFirst) showToast("New Conversation Created");
635
-
636
- // Close sidebar on mobile if open
637
- if(window.innerWidth <= 768) toggleSidebar();
638
- }
639
-
640
- function loadConversation(id) {
641
- state.currentConversationId = id;
642
- const conv = state.conversations.find(c => c.id === id);
643
- if (conv) {
644
- // Update current model to match the conversation's model
645
- if (conv.model && state.models.find(m => m.id === conv.model)) {
646
- state.currentModel = conv.model;
647
- document.getElementById('current-model-display').innerText = state.models.find(m => m.id === conv.model).name;
648
- renderModelList(); // Update active state
649
- }
650
- renderChat();
651
- renderHistoryList(); // Update active class
652
- }
653
- }
654
-
655
- function deleteConversation(id, e) {
656
- e.stopPropagation();
657
- if(confirm("Delete this conversation?")) {
658
- state.conversations = state.conversations.filter(c => c.id !== id);
659
- if (state.conversations.length === 0) {
660
- createNewConversation();
661
- } else {
662
- loadConversation(state.conversations[0].id);
663
- }
664
- saveToStorage();
665
- renderHistoryList();
666
- }
667
- }
668
-
669
- function updateConversationName(id, newName) {
670
- const conv = state.conversations.find(c => c.id === id);
671
- if (conv) {
672
- conv.name = newName;
673
- saveToStorage();
674
- renderHistoryList();
675
- }
676
- }
677
-
678
- function sendMessage() {
679
- const input = document.getElementById('user-input');
680
- const text = input.value.trim();
681
- if (!text) return;
682
-
683
- const conv = state.conversations.find(c => c.id === state.currentConversationId);
684
- if (!conv) return;
685
-
686
- // Add User Message
687
- conv.messages.push({ role: 'user', content: text });
688
- input.value = '';
689
- input.style.height = 'auto'; // Reset height
690
- saveToStorage();
691
- renderChat();
692
-
693
- // Show typing indicator
694
- const typingId = 'typing-' + Date.now();
695
- addTypingIndicator(typingId);
696
-
697
- // Simulate AI Response
698
- setTimeout(() => {
699
- removeTypingIndicator(typingId);
700
- const aiResponse = generateSimulatedResponse(text);
701
- conv.messages.push({ role: 'ai', content: aiResponse });
702
- saveToStorage();
703
- renderChat();
704
- }, 1200 + Math.random() * 1000);
705
- }
706
-
707
- function switchModel(modelId) {
708
- state.currentModel = modelId;
709
- const model = state.models.find(m => m.id === modelId);
710
-
711
- // Update UI
712
- document.getElementById('current-model-display').innerText = model.name;
713
- renderModelList();
714
-
715
- // Add intro suggestion to current chat
716
- const conv = state.conversations.find(c => c.id === state.currentConversationId);
717
- if (conv) {
718
- conv.model = modelId;
719
- conv.messages.push({
720
- role: 'system',
721
- content: `Model switched to ${model.name}. Intro suggestion: This model is optimized for ${model.type} tasks.`
722
- });
723
- saveToStorage();
724
- renderChat();
725
- }
726
- showToast(`Switched to ${model.name}`);
727
- }
728
-
729
- function toggleFocusMode() {
730
- state.focusMode = !state.focusMode;
731
- const badge = document.getElementById('focus-mode-badge');
732
- const rightPanel = document.getElementById('right-panel');
733
-
734
- if (state.focusMode) {
735
- badge.classList.add('active');
736
- badge.innerText = 'Focus: ON';
737
- // Hide right panel in focus mode
738
- rightPanel.style.display = 'none';
739
- showToast("Focus Mode Enabled: Distractions hidden");
740
- } else {
741
- badge.classList.remove('active');
742
- badge.innerText = 'Focus: OFF';
743
- // Restore right panel
744
- rightPanel.style.display = 'flex';
745
- showToast("Focus Mode Disabled");
746
- }
747
- }
748
-
749
- function importConversation() {
750
- const input = document.createElement('input');
751
- input.type = 'file';
752
- input.accept = '.json';
753
- input.onchange = e => {
754
- const file = e.target.files[0];
755
- if (file) {
756
- const reader = new FileReader();
757
- reader.onload = function(e) {
758
- try {
759
- const imported = JSON.parse(e.target.result);
760
- // Basic validation
761
- if(!Array.isArray(imported)) throw new Error("Invalid format");
762
-
763
- imported.id = Date.now().toString(); // Ensure unique ID
764
- state.conversations.unshift(imported);
765
- saveToStorage();
766
- renderHistoryList();
767
- loadConversation(imported.id);
768
- showToast("Conversation Imported Successfully");
769
- logTerminal(`> Imported ${file.name} to repository.`, 'info');
770
- } catch (err) {
771
- showToast("Invalid JSON file");
772
- logTerminal(`> Error importing file: ${err.message}`, 'error');
773
- }
774
- };
775
- reader.readAsText(file);
776
- }
777
- };
778
- input.click();
779
- }
780
-
781
- // --- Render Functions ---
782
-
783
- function renderHistoryList() {
784
- const list = document.getElementById('history-list');
785
- list.innerHTML = '';
786
- state.conversations.forEach(conv => {
787
- const div = document.createElement('div');
788
- div.className = `history-item ${conv.id === state.currentConversationId ? 'active' : ''}`;
789
- div.onclick = () => loadConversation(conv.id);
790
- div.innerHTML = `
791
- <div class="history-name" contenteditable="true"
792
- onblur="updateConversationName('${conv.id}', this.innerText)"
793
- onkeydown="if(event.key==='Enter'){event.preventDefault();this.blur();}">
794
- ${escapeHtml(conv.name)}
795
- </div>
796
- <div class="history-actions">
797
- <i class="fa-solid fa-trash" onclick="deleteConversation('${conv.id}', event)" title="Delete"></i>
798
- </div>
799
- `;
800
- list.appendChild(div);
801
- });
802
- }
803
-
804
- function renderChat() {
805
- const container = document.getElementById('chat-messages');
806
- const conv = state.conversations.find(c => c.id === state.currentConversationId);
807
- container.innerHTML = '';
808
-
809
- if (!conv) return;
810
-
811
- conv.messages.forEach(msg => {
812
- const div = document.createElement('div');
813
- div.className = `message ${msg.role}`;
814
-
815
- let contentHtml = escapeHtml(msg.content);
816
-
817
- // Action buttons for User/AI messages
818
- if (msg.role === 'user' || msg.role === 'ai') {
819
- div.innerHTML = `
820
- <div class="msg-actions">
821
- <button class="action-btn" onclick="copyText(this)" title="Copy">
822
- <i class="fa-regular fa-copy"></i>
823
- </button>
824
- </div>
825
- <div class="bubble">${contentHtml}</div>
826
- `;
827
- } else {
828
- div.innerHTML = contentHtml;
829
- }
830
-
831
- container.appendChild(div);
832
- });
833
-
834
- // Scroll to bottom
835
- container.scrollTop = container.scrollHeight;
836
- }
837
-
838
- function addTypingIndicator(id) {
839
- const container = document.getElementById('chat-messages');
840
- const div = document.createElement('div');
841
- div.className = 'message ai';
842
- div.id = id;
843
- div.innerHTML = `
844
- <div class="bubble typing-indicator">
845
- <span></span><span></span><span></span>
846
- </div>
847
- `;
848
- container.appendChild(div);
849
- container.scrollTop = container.scrollHeight;
850
- }
851
-
852
- function removeTypingIndicator(id) {
853
- const el = document.getElementById(id);
854
- if(el) el.remove();
855
- }
856
-
857
- function renderModelList() {
858
- const list = document.getElementById('model-list');
859
- list.innerHTML = '';
860
- state.models.forEach(model => {
861
- const div = document.createElement('div');
862
- div.className = `model-card ${model.id === state.currentModel ? 'active' : ''}`;
863
- div.onclick = () => switchModel(model.id);
864
- div.innerHTML = `
865
- <div class="model-header">
866
- <span class="model-name">${model.name}</span>
867
- <i class="fa-solid fa-check-circle" style="opacity: ${model.id === state.currentModel ? 1 : 0}; color: var(--accent);"></i>
868
- </div>
869
- <div class="model-meta">${model.desc}</div>
870
- <div class="showcase-stats">
871
- <span class="stat">${model.type}</span>
872
- <span class="stat">${model.size}</span>
873
- </div>
874
- `;
875
- list.appendChild(div);
876
- });
877
- }
878
-
879
- // --- Features & Simulation ---
880
-
881
- function copyText(btn) {
882
- const text = btn.closest('.message').querySelector('.bubble').innerText;
883
- navigator.clipboard.writeText(text).then(() => {
884
- showToast("Copied to clipboard");
885
- });
886
- }
887
-
888
- function startDownloadProcess() {
889
- const appPath = document.getElementById('app-path').value;
890
- const dlPath = document.getElementById('dl-path').value;
891
-
892
- logTerminal(`> Initializing HuggingFace API client...`, 'info');
893
- logTerminal(`> Fetching model list...`, 'info');
894
-
895
- setTimeout(() => {
896
- logTerminal(`> Found 4 new models available.`, 'info');
897
- logTerminal(`> Starting download to ${dlPath}...`, 'info');
898
- simulateProgress();
899
- }, 1000);
900
- }
901
-
902
- function simulateProgress() {
903
- let progress = 0;
904
- const interval = setInterval(() => {
905
- progress += 10;
906
- if (progress <= 100) {
907
- logTerminal(`> Downloading model weights... [${progress}%]`);
908
- } else {
909
- clearInterval(interval);
910
- completeDownload();
911
- }
912
- }, 300);
913
- }
914
-
915
- function completeDownload() {
916
- const appPath = document.getElementById('app-path').value;
917
- logTerminal(`> Download complete. Verifying checksums...`, 'info');
918
- logTerminal(`> Moving files to ${appPath}...`, 'info');
919
- logTerminal(`> python bash_script.py --move-source ~/Downloads/ --dest ${appPath}`, 'command');
920
-
921
- setTimeout(() => {
922
- logTerminal(`> SUCCESS: Models integrated into app folder.`, 'info');
923
- showToast("Models Downloaded & Integrated");
924
- }, 1000);
925
- }
926
-
927
- function simulateAutoConfig() {
928
- logTerminal(`> Auto-configuring application...`);
929
- logTerminal(`> Detecting system architecture... x86_64`);
930
- logTerminal(`> Setting default paths... Done.`);
931
- logTerminal(`> Optimizing CSS3 rendering... Done.`);
932
- setTimeout(() => {
933
- showToast("Auto Configuration Complete");
934
- }, 800);
935
- }
936
-
937
- function logTerminal(msg, type = '') {
938
- const term = document.getElementById('terminal-output');
939
- const line = document.createElement('div');
940
- line.className = `terminal-line ${type}`;
941
- line.innerText = msg;
942
- term.appendChild(line);
943
- term.scrollTop = term.scrollHeight;
944
- }
945
-
946
- function clearTerminal() {
947
- document.getElementById('terminal-output').innerHTML = '';
948
- }
949
-
950
- // --- Utilities ---
951
-
952
- function showToast(message) {
953
- const toast = document.getElementById('toast');
954
- const msgSpan = document.getElementById('toast-msg');
955
- msgSpan.innerText = message;
956
- toast.classList.add('show');
957
- setTimeout(() => {
958
- toast.classList.remove('show');
959
- }, 3000);
960
- }
961
-
962
- function escapeHtml(text) {
963
- const map = {
964
- '&': '&amp;',
965
- '<': '&lt;',
966
- '>': '&gt;',
967
- '"': '&quot;',
968
- "'": '&#039;'
969
- };
970
- return text.replace(/[&<>"']/g, function(m) { return map[m]; });
971
- }
972
-
973
- function generateSimulatedResponse(input) {
974
- const responses = [
975
- "That is an interesting perspective. Could you elaborate on how this relates to the model architecture?",
976
- "I have processed your request using the current transformer model. The output suggests a high probability of success.",
977
- "Based on the file repository analysis, the configuration seems optimal.",
978
- "Here is a suggestion for your code: Ensure you are handling the asynchronous nature of the AJAX calls correctly.",
979
- "I can help you move those files. Please confirm the destination path in the settings panel.",
980
- "Analysis complete. The latent vectors indicate a strong correlation with the input prompt."
981
- ];
982
- return responses[Math.floor(Math.random() * responses.length)];
983
- }
984
 
985
- // --- Storage ---
986
- function saveToStorage() {
987
- localStorage.setItem('transformers_app_data', JSON.stringify(state.conversations));
988
- }
989
 
990
- function loadFromStorage() {
991
- const data = localStorage.getItem('transformers_app_data');
992
- if (data) {
993
- try {
994
- state.conversations = JSON.parse(data);
995
- } catch(e) {
996
- console.error("Failed to load history", e);
997
- }
998
- }
999
- }
1000
-
1001
- // --- Toggles ---
1002
-
1003
- function toggleSidebar() {
1004
- const sb = document.getElementById('sidebar');
1005
- const overlay = document.getElementById('mobile-overlay');
1006
- sb.classList.toggle('open');
1007
- overlay.classList.toggle('active');
1008
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1009
 
1010
- document.getElementById('toggle-sidebar').addEventListener('click', toggle
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AI Transformers Workbench</title>
8
+ <!-- Import FontAwesome for Icons -->
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <!-- Import Google Fonts -->
11
+ <link
12
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap"
13
+ rel="stylesheet">
14
+
15
+ <style>
16
+ /* --- CSS Variables & Reset --- */
17
+ :root {
18
+ --bg-dark: #0d1117;
19
+ --bg-panel: #161b22;
20
+ --bg-card: #21262d;
21
+ --bg-input: #0d1117;
22
+ --border: #30363d;
23
+ --border-hover: #8b949e;
24
+ --accent: #58a6ff;
25
+ --accent-glow: rgba(88, 166, 255, 0.15);
26
+ --accent-hover: #79c0ff;
27
+ --success: #238636;
28
+ --danger: #da3633;
29
+ --text-main: #c9d1d9;
30
+ --text-muted: #8b949e;
31
+ --font-main: 'Inter', sans-serif;
32
+ --font-code: 'JetBrains Mono', monospace;
33
+ --shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
34
+ --header-height: 60px;
35
+ }
36
+
37
+ * {
38
+ box-sizing: border-box;
39
+ margin: 0;
40
+ padding: 0;
41
+ outline: none;
42
+ }
43
+
44
+ body {
45
+ font-family: var(--font-main);
46
+ background-color: var(--bg-dark);
47
+ color: var(--text-main);
48
+ height: 100vh;
49
+ display: flex;
50
+ flex-direction: column;
51
+ overflow: hidden;
52
+ }
53
+
54
+ /* --- Scrollbar Styling --- */
55
+ ::-webkit-scrollbar {
56
+ width: 8px;
57
+ height: 8px;
58
+ }
59
+
60
+ ::-webkit-scrollbar-track {
61
+ background: var(--bg-dark);
62
+ }
63
+
64
+ ::-webkit-scrollbar-thumb {
65
+ background: var(--border);
66
+ border-radius: 4px;
67
+ }
68
+
69
+ ::-webkit-scrollbar-thumb:hover {
70
+ background: var(--text-muted);
71
+ }
72
+
73
+ /* --- Header --- */
74
+ header {
75
+ height: var(--header-height);
76
+ background-color: var(--bg-panel);
77
+ border-bottom: 1px solid var(--border);
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: space-between;
81
+ padding: 0 20px;
82
+ flex-shrink: 0;
83
+ z-index: 50;
84
+ box-shadow: 0 2px 10px rgba(0,0,0,0.2);
85
+ }
86
+
87
+ .logo {
88
+ font-weight: 700;
89
+ font-size: 1.2rem;
90
+ display: flex;
91
+ align-items: center;
92
+ gap: 10px;
93
+ color: var(--text-main);
94
+ cursor: pointer;
95
+ transition: opacity 0.2s;
96
+ }
97
+
98
+ .logo:hover {
99
+ opacity: 0.9;
100
+ }
101
+
102
+ .logo i {
103
+ color: var(--accent);
104
+ font-size: 1.4rem;
105
+ }
106
+
107
+ .header-links a {
108
+ color: var(--accent);
109
+ text-decoration: none;
110
+ font-size: 0.9rem;
111
+ transition: opacity 0.2s, color 0.2s;
112
+ font-weight: 500;
113
+ padding: 6px 12px;
114
+ border-radius: 6px;
115
+ background: rgba(88, 166, 255, 0.1);
116
+ }
117
+
118
+ .header-links a:hover {
119
+ opacity: 1;
120
+ background: rgba(88, 166, 255, 0.2);
121
+ text-decoration: none;
122
+ }
123
+
124
+ .header-controls {
125
+ display: flex;
126
+ gap: 10px;
127
+ }
128
+
129
+ /* --- Main Layout --- */
130
+ .main-container {
131
+ display: flex;
132
+ flex: 1;
133
+ overflow: hidden;
134
+ position: relative;
135
+ }
136
+
137
+ /* --- Sidebar (History) --- */
138
+ .sidebar {
139
+ width: 280px;
140
+ background-color: var(--bg-panel);
141
+ border-right: 1px solid var(--border);
142
+ display: flex;
143
+ flex-direction: column;
144
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
145
+ z-index: 40;
146
+ }
147
+
148
+ .sidebar-header {
149
+ padding: 15px;
150
+ border-bottom: 1px solid var(--border);
151
+ }
152
+
153
+ .btn-new-chat {
154
+ width: 100%;
155
+ padding: 10px;
156
+ background-color: var(--success);
157
+ color: white;
158
+ border: none;
159
+ border-radius: 6px;
160
+ cursor: pointer;
161
+ font-weight: 600;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ gap: 8px;
166
+ transition: background 0.2s, transform 0.1s;
167
+ box-shadow: 0 2px 5px rgba(35, 134, 54, 0.3);
168
+ }
169
+
170
+ .btn-new-chat:hover {
171
+ background-color: #2ea043;
172
+ transform: translateY(-1px);
173
+ }
174
+
175
+ .btn-new-chat:active {
176
+ transform: translateY(0);
177
+ }
178
+
179
+ .history-list {
180
+ flex: 1;
181
+ overflow-y: auto;
182
+ padding: 10px;
183
+ }
184
+
185
+ .history-item {
186
+ padding: 10px;
187
+ border-radius: 6px;
188
+ cursor: pointer;
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: space-between;
192
+ margin-bottom: 5px;
193
+ color: var(--text-main);
194
+ transition: background 0.2s, transform 0.1s;
195
+ border: 1px solid transparent;
196
+ }
197
+
198
+ .history-item:hover {
199
+ background-color: var(--bg-card);
200
+ border-color: var(--border);
201
+ }
202
+
203
+ .history-item.active {
204
+ background-color: var(--accent-glow);
205
+ border-color: var(--accent);
206
+ }
207
+
208
+ .history-name {
209
+ font-size: 0.9rem;
210
+ white-space: nowrap;
211
+ overflow: hidden;
212
+ text-overflow: ellipsis;
213
+ flex: 1;
214
+ margin-right: 8px;
215
+ padding: 2px 4px;
216
+ border: 1px solid transparent;
217
+ border-radius: 4px;
218
+ cursor: text;
219
+ }
220
+
221
+ .history-name:focus {
222
+ border-color: var(--accent);
223
+ background: var(--bg-input);
224
+ }
225
+
226
+ .history-actions i {
227
+ color: var(--text-muted);
228
+ margin-left: 5px;
229
+ font-size: 0.8rem;
230
+ padding: 4px;
231
+ border-radius: 4px;
232
+ transition: all 0.2s;
233
+ }
234
+
235
+ .history-actions i:hover {
236
+ color: var(--danger);
237
+ background: rgba(218, 54, 51, 0.1);
238
+ }
239
+
240
+ .sidebar-footer {
241
+ padding: 15px;
242
+ border-top: 1px solid var(--border);
243
+ }
244
+
245
+ .btn-import {
246
+ width: 100%;
247
+ padding: 8px;
248
+ background: transparent;
249
+ border: 1px dashed var(--text-muted);
250
+ color: var(--text-muted);
251
+ border-radius: 6px;
252
+ cursor: pointer;
253
+ transition: all 0.2s;
254
+ }
255
+
256
+ .btn-import:hover {
257
+ border-color: var(--accent);
258
+ color: var(--accent);
259
+ background: rgba(88, 166, 255, 0.05);
260
+ }
261
+
262
+ /* --- Chat Area --- */
263
+ .chat-area {
264
+ flex: 1;
265
+ display: flex;
266
+ flex-direction: column;
267
+ background-color: var(--bg-dark);
268
+ position: relative;
269
+ min-width: 0;
270
+ }
271
+
272
+ .chat-header {
273
+ padding: 10px 20px;
274
+ border-bottom: 1px solid var(--border);
275
+ display: flex;
276
+ justify-content: space-between;
277
+ align-items: center;
278
+ background: rgba(22, 27, 34, 0.8);
279
+ backdrop-filter: blur(10px);
280
+ }
281
+
282
+ .model-indicator {
283
+ display: flex;
284
+ align-items: center;
285
+ gap: 10px;
286
+ font-weight: 600;
287
+ font-size: 0.95rem;
288
+ }
289
+
290
+ .badge {
291
+ font-size: 0.7rem;
292
+ padding: 2px 8px;
293
+ border-radius: 12px;
294
+ background: var(--bg-card);
295
+ border: 1px solid var(--border);
296
+ color: var(--text-muted);
297
+ text-transform: uppercase;
298
+ letter-spacing: 0.5px;
299
+ font-weight: 700;
300
+ transition: all 0.3s;
301
+ }
302
+
303
+ .badge.active {
304
+ background: var(--success);
305
+ color: white;
306
+ border-color: var(--success);
307
+ box-shadow: 0 0 8px rgba(35, 134, 54, 0.4);
308
+ }
309
+
310
+ .chat-messages {
311
+ flex: 1;
312
+ overflow-y: auto;
313
+ padding: 20px;
314
+ display: flex;
315
+ flex-direction: column;
316
+ gap: 20px;
317
+ scroll-behavior: smooth;
318
+ }
319
+
320
+ .message {
321
+ max-width: 85%;
322
+ line-height: 1.6;
323
+ position: relative;
324
+ animation: fadeIn 0.3s ease;
325
+ }
326
+
327
+ @keyframes fadeIn {
328
+ from { opacity: 0; transform: translateY(10px); }
329
+ to { opacity: 1; transform: translateY(0); }
330
+ }
331
+
332
+ .message.user {
333
+ align-self: flex-end;
334
+ }
335
+
336
+ .message.ai {
337
+ align-self: flex-start;
338
+ }
339
+
340
+ .message.system {
341
+ align-self: center;
342
+ max-width: 90%;
343
+ font-size: 0.85rem;
344
+ color: var(--text-muted);
345
+ text-align: center;
346
+ background: rgba(139, 148, 158, 0.1);
347
+ padding: 4px 12px;
348
+ border-radius: 20px;
349
+ border: 1px solid var(--border);
350
+ }
351
+
352
+ .bubble {
353
+ padding: 12px 18px;
354
+ border-radius: 12px;
355
+ position: relative;
356
+ word-wrap: break-word;
357
+ white-space: pre-wrap;
358
+ font-size: 0.95rem;
359
+ }
360
+
361
+ .message.user .bubble {
362
+ background-color: var(--accent);
363
+ color: #fff;
364
+ border-bottom-right-radius: 2px;
365
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
366
+ }
367
+
368
+ .message.ai .bubble {
369
+ background-color: var(--bg-panel);
370
+ border: 1px solid var(--border);
371
+ border-bottom-left-radius: 2px;
372
+ color: var(--text-main);
373
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
374
+ }
375
+
376
+ .msg-actions {
377
+ position: absolute;
378
+ top: -25px;
379
+ right: 0;
380
+ display: none;
381
+ gap: 8px;
382
+ }
383
+
384
+ .message:hover .msg-actions {
385
+ display: flex;
386
+ }
387
+
388
+ .action-btn {
389
+ background: var(--bg-panel);
390
+ border: 1px solid var(--border);
391
+ color: var(--text-muted);
392
+ padding: 4px 8px;
393
+ border-radius: 4px;
394
+ font-size: 0.75rem;
395
+ cursor: pointer;
396
+ display: flex;
397
+ align-items: center;
398
+ gap: 4px;
399
+ transition: all 0.2s;
400
+ }
401
+
402
+ .action-btn:hover {
403
+ color: var(--accent);
404
+ border-color: var(--accent);
405
+ transform: translateY(-2px);
406
+ }
407
+
408
+ .input-area {
409
+ padding: 20px;
410
+ border-top: 1px solid var(--border);
411
+ background-color: var(--bg-panel);
412
+ }
413
+
414
+ .input-wrapper {
415
+ position: relative;
416
+ max-width: 900px;
417
+ margin: 0 auto;
418
+ }
419
+
420
+ .chat-input {
421
+ width: 100%;
422
+ background-color: var(--bg-input);
423
+ border: 1px solid var(--border);
424
+ border-radius: 8px;
425
+ padding: 15px 50px 15px 15px;
426
+ color: var(--text-main);
427
+ font-family: var(--font-main);
428
+ resize: none;
429
+ min-height: 54px;
430
+ max-height: 200px;
431
+ line-height: 1.5;
432
+ transition: border-color 0.2s, box-shadow 0.2s;
433
+ }
434
+
435
+ .chat-input:focus {
436
+ border-color: var(--accent);
437
+ box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
438
+ }
439
+
440
+ .send-btn {
441
+ position: absolute;
442
+ right: 12px;
443
+ bottom: 12px;
444
+ background: none;
445
+ border: none;
446
+ color: var(--text-muted);
447
+ cursor: pointer;
448
+ font-size: 1.2rem;
449
+ transition: color 0.2s, transform 0.2s;
450
+ }
451
+
452
+ .send-btn:hover {
453
+ color: var(--accent);
454
+ transform: scale(1.1);
455
+ }
456
+
457
+ /* --- Right Panel (Models & Config) --- */
458
+ .right-panel {
459
+ width: 350px;
460
+ background-color: var(--bg-panel);
461
+ border-left: 1px solid var(--border);
462
+ display: flex;
463
+ flex-direction: column;
464
+ overflow-y: auto;
465
+ transition: width 0.3s ease, transform 0.3s ease;
466
+ }
467
+
468
+ .panel-section {
469
+ padding: 20px;
470
+ border-bottom: 1px solid var(--border);
471
+ }
472
+
473
+ .panel-title {
474
+ font-size: 0.75rem;
475
+ text-transform: uppercase;
476
+ color: var(--text-muted);
477
+ margin-bottom: 12px;
478
+ font-weight: 700;
479
+ letter-spacing: 0.5px;
480
+ display: flex;
481
+ align-items: center;
482
+ gap: 8px;
483
+ }
484
+
485
+ /* Model Cards */
486
+ .model-card {
487
+ background: var(--bg-card);
488
+ border: 1px solid var(--border);
489
+ border-radius: 8px;
490
+ padding: 12px;
491
+ margin-bottom: 10px;
492
+ cursor: pointer;
493
+ transition: all 0.2s ease;
494
+ position: relative;
495
+ overflow: hidden;
496
+ }
497
+
498
+ .model-card:hover {
499
+ border-color: var(--text-muted);
500
+ transform: translateY(-2px);
501
+ background: rgba(33, 38, 45, 0.8);
502
+ }
503
+
504
+ .model-card.active {
505
+ border-color: var(--accent);
506
+ background: var(--accent-glow);
507
+ box-shadow: 0 0 0 1px var(--accent);
508
+ }
509
+
510
+ .model-header {
511
+ display: flex;
512
+ justify-content: space-between;
513
+ align-items: center;
514
+ margin-bottom: 6px;
515
+ }
516
+
517
+ .model-name {
518
+ font-weight: 600;
519
+ font-size: 0.95rem;
520
+ color: var(--text-main);
521
+ }
522
+
523
+ .model-meta {
524
+ font-size: 0.8rem;
525
+ color: var(--text-muted);
526
+ line-height: 1.4;
527
+ }
528
+
529
+ .showcase-stats {
530
+ display: flex;
531
+ gap: 8px;
532
+ margin-top: 10px;
533
+ flex-wrap: wrap;
534
+ }
535
+
536
+ .stat {
537
+ font-size: 0.7rem;
538
+ background: rgba(255, 255, 255, 0.05);
539
+ padding: 2px 6px;
540
+ border-radius: 4px;
541
+ color: var(--text-muted);
542
+ border: 1px solid var(--border);
543
+ }
544
+
545
+ /* Configuration & Downloads */
546
+ .download-controls {
547
+ display: flex;
548
+ flex-direction: column;
549
+ gap: 12px;
550
+ }
551
+
552
+ .form-group {
553
+ display: flex;
554
+ flex-direction: column;
555
+ gap: 6px;
556
+ }
557
+
558
+ .form-group label {
559
+ font-size: 0.8rem;
560
+ color: var(--text-muted);
561
+ font-weight: 500;
562
+ }
563
+
564
+ .form-input {
565
+ background: var(--bg-input);
566
+ border: 1px solid var(--border);
567
+ color: var(--text-main);
568
+ padding: 8px 12px;
569
+ border-radius: 6px;
570
+ font-family: var(--font-code);
571
+ font-size: 0.85rem;
572
+ transition: border-color 0.2s;
573
+ }
574
+
575
+ .form-input:focus {
576
+ border-color: var(--accent);
577
+ }
578
+
579
+ .btn-download {
580
+ background-color: var(--accent);
581
+ color: white;
582
+ border: none;
583
+ padding: 10px;
584
+ border-radius: 6px;
585
+ cursor: pointer;
586
+ font-weight: 600;
587
+ display: flex;
588
+ align-items: center;
589
+ justify-content: center;
590
+ gap: 8px;
591
+ transition: background 0.2s, transform 0.1s;
592
+ }
593
+
594
+ .btn-download:hover {
595
+ background-color: var(--accent-hover);
596
+ transform: translateY(-1px);
597
+ }
598
+
599
+ .btn-secondary {
600
+ background-color: transparent;
601
+ border: 1px solid var(--border);
602
+ color: var(--text-main);
603
+ padding: 10px;
604
+ border-radius: 6px;
605
+ cursor: pointer;
606
+ font-weight: 600;
607
+ display: flex;
608
+ align-items: center;
609
+ justify-content: center;
610
+ gap: 8px;
611
+ transition: all 0.2s;
612
+ }
613
+
614
+ .btn-secondary:hover {
615
+ border-color: var(--text-muted);
616
+ background: var(--bg-input);
617
+ }
618
+
619
+ /* Terminal Simulation */
620
+ .terminal {
621
+ background: #000;
622
+ color: #3fb950;
623
+ font-family: var(--font-code);
624
+ font-size: 0.75rem;
625
+ padding: 12px;
626
+ border-radius: 6px;
627
+ height: 180px;
628
+ overflow-y: auto;
629
+ border: 1px solid #30363d;
630
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
631
+ }
632
+
633
+ .terminal-line {
634
+ margin-bottom: 4px;
635
+ word-break: break-all;
636
+ }
637
+
638
+ .terminal-line.error {
639
+ color: var(--danger);
640
+ }
641
+
642
+ .terminal-line.info {
643
+ color: var(--text-muted);
644
+ }
645
+
646
+ .terminal-line.command {
647
+ color: var(--text-main);
648
+ font-weight: bold;
649
+ }
650
+
651
+ /* Toast Notification */
652
+ .toast {
653
+ position: fixed;
654
+ bottom: 24px;
655
+ right: 24px;
656
+ background: var(--bg-panel);
657
+ border: 1px solid var(--accent);
658
+ color: var(--text-main);
659
+ padding: 12px 20px;
660
+ border-radius: 8px;
661
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
662
+ transform: translateY(100px);
663
+ opacity: 0;
664
+ transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
665
+ z-index: 1000;
666
+ display: flex;
667
+ align-items: center;
668
+ gap: 10px;
669
+ }
670
+
671
+ .toast.show {
672
+ transform: translateY(0);
673
+ opacity: 1;
674
+ }
675
+
676
+ .toast i {
677
+ color: var(--accent);
678
+ }
679
+
680
+ /* Loading Dots */
681
+ .typing-indicator span {
682
+ display: inline-block;
683
+ width: 6px;
684
+ height: 6px;
685
+ background-color: var(--text-muted);
686
+ border-radius: 50%;
687
+ animation: typing 1.4s infinite ease-in-out both;
688
+ margin: 0 2px;
689
+ }
690
+
691
+ .typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
692
+ .typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
693
+
694
+ @keyframes typing {
695
+ 0%, 80%, 100% { transform: scale(0); }
696
+ 40% { transform: scale(1); }
697
+ }
698
+
699
+ /* Responsive */
700
+ @media (max-width: 1024px) {
701
+ .right-panel {
702
+ position: absolute;
703
+ right: 0;
704
+ height: 100%;
705
+ transform: translateX(100%);
706
+ z-index: 60;
707
+ box-shadow: -5px 0 15px rgba(0, 0, 0, 0.5);
708
+ }
709
+
710
+ .right-panel.open {
711
+ transform: translateX(0);
712
+ }
713
+ }
714
+
715
+ @media (max-width: 768px) {
716
+ .sidebar {
717
+ position: absolute;
718
+ left: 0;
719
+ height: 100%;
720
+ transform: translateX(-100%);
721
+ box-shadow: 5px 0 15px rgba(0, 0, 0, 0.5);
722
+ }
723
+
724
+ .sidebar.open {
725
+ transform: translateX(0);
726
+ }
727
+
728
+ .message {
729
+ max-width: 95%;
730
+ }
731
+
732
+ .header-links span {
733
+ display: none;
734
+ }
735
+ }
736
+
737
+ /* Animations */
738
+ .spinner {
739
+ animation: spin 1s linear infinite;
740
+ }
741
+
742
+ @keyframes spin {
743
+ 100% { transform: rotate(360deg); }
744
+ }
745
+
746
+ .mobile-overlay {
747
+ position: fixed;
748
+ top: 0;
749
+ left: 0;
750
+ width: 100%;
751
+ height: 100%;
752
+ background: rgba(0, 0, 0, 0.5);
753
+ z-index: 30;
754
+ display: none;
755
+ opacity: 0;
756
+ transition: opacity 0.3s;
757
+ }
758
+
759
+ .mobile-overlay.active {
760
+ display: block;
761
+ opacity: 1;
762
+ }
763
+ </style>
764
  </head>
765
 
766
  <body>
767
+ <!-- Header -->
768
+ <header>
769
+ <div class="logo">
770
+ <i class="fa-solid fa-cube"></i>
771
+ <span>Transformers<span style="color:var(--text-muted); font-weight:400; font-size:0.9em;">WebApp</span></span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
772
  </div>
773
 
774
+ <div class="header-links">
775
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">
776
+ Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em;"></i>
777
+ </a>
778
  </div>
779
 
780
+ <div class="header-controls">
781
+ <button class="action-btn" id="toggle-terminal" title="Toggle Tools Panel">
782
+ <i class="fa-solid fa-sliders"></i>
783
+ </button>
784
+ <button class="action-btn" id="toggle-sidebar" style="display:none;" title="Toggle History">
785
+ <i class="fa-solid fa-bars"></i>
786
+ </button>
787
+ </div>
788
+ </header>
789
+
790
+ <div class="main-container">
791
+ <!-- Mobile Overlay -->
792
+ <div class="mobile-overlay" id="mobile-overlay"></div>
793
+
794
+ <!-- Sidebar -->
795
+ <aside class="sidebar" id="sidebar">
796
+ <div class="sidebar-header">
797
+ <button class="btn-new-chat" onclick="createNewConversation()">
798
+ <i class="fa-solid fa-plus"></i> New Conversation
799
+ </button>
800
+ </div>
801
+ <div class="history-list" id="history-list">
802
+ <!-- History Items Injected via JS -->
803
+ </div>
804
+ <div class="sidebar-footer">
805
+ <button class="btn-import" onclick="importConversation()">
806
+ <i class="fa-solid fa-file-import"></i> Import JSON
807
+ </button>
808
+ </div>
809
+ </aside>
810
+
811
+ <!-- Main Chat Area -->
812
+ <main class="chat-area">
813
+ <div class="chat-header">
814
+ <div class="model-indicator">
815
+ <i class="fa-solid fa-microchip" style="color: var(--accent);"></i>
816
+ <span id="current-model-display">Llama-3-8B</span>
817
+ <span class="badge" id="focus-mode-badge">Focus: OFF</span>
818
+ </div>
819
+ <div>
820
+ <button class="action-btn" onclick="toggleFocusMode()" title="Toggle Focus Mode">
821
+ <i class="fa-solid fa-crosshairs"></i> Focus
822
+ </button>
823
+ </div>
824
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
 
826
+ <div class="chat-messages" id="chat-messages">
827
+ <!-- Messages Injected via JS -->
828
+ </div>
 
829
 
830
+ <div class="input-area">
831
+ <div class="input-wrapper">
832
+ <textarea class="chat-input" id="user-input" placeholder="Type a message... (Shift+Enter for new line)"></textarea>
833
+ <button class="send-btn" onclick="sendMessage()"><i class="fa-solid fa-paper-plane"></i></button>
834
+ </div>
835
+ </div>
836
+ </main>
837
+
838
+ <!-- Right Panel (Models & Tools) -->
839
+ <aside class="right-panel" id="right-panel">
840
+ <!-- Model Showcase -->
841
+ <div class="panel-section">
842
+ <div class="panel-title"><i class="fa-solid fa-layer-group"></i> Model Showcase</div>
843
+ <div id="model-list">
844
+ <!-- Models injected JS -->
845
+ </div>
846
+ </div>
847
+
848
+ <!-- Configuration & Downloads -->
849
+ <div class="panel-section">
850
+ <div class="panel-title"><i class="fa-solid fa-gears"></i> Configuration & API</div>
851
+ <div class="download-controls">
852
+ <div class="form-group">
853
+ <label>WebApp Folder Path</label>
854
+ <input type="text" class="form-input" value=":/app/models" id="app-path">
855
+ </div>
856
+ <div class="form-group">
857
+ <label>Download Destination</label>
858
+ <input type="text" class="form-input" value="~/Downloads/" id="dl-path">
859
+ </div>
860
+ <button class="btn-download" onclick="startDownloadProcess()">
861
+ <i class="fa-solid fa-cloud-arrow-down"></i> Fetch & Download Models
862
+ </button>
863
+ <button class="btn-secondary" onclick="simulateAutoConfig()">
864
+ <i class="fa-solid fa-wand-magic-sparkles"></i> Auto Config App
865
+ </button>
866
+ </div>
867
+ </div>
868
 
869
+ <!-- Simulated Terminal -->
870
+ <div class="panel-section">
871
+ <div class="panel-title">
872
+ <i class="fa-solid fa-terminal"></i> System Terminal
873
+ <span style="margin-left:auto; font-size:0.6em; cursor:pointer; color: var(--text-muted);" onclick="clearTerminal()">Clear</span>
874
+ </div>
875
+ <div class="terminal" id="terminal-output">
876
+ <div class="terminal-line info">> System initialized...</div>
877
+ <div class="terminal-line info">> Waiting for input...</div>
878
+ </div>
879
+ </div>
880
+ </aside>
881
+ </div>
882
+
883
+ <!-- Toast Notification -->
884
+ <div class="toast" id="toast">
885
+ <i class="fa-solid fa-circle-check"></i>
886
+ <span id="toast-msg">Operation Successful</span>
887
+ </div>
888
+
889
+ <script>
890
+ // --- State Management ---
891
+ const state = {
892
+ conversations: [],
893
+ currentConversationId: null,
894
+ models: [
895
+ { id: 'llama-3', name: 'Llama-3-8B', type: 'Instruct', size: '4.7GB', desc: 'General purpose assistant.' },
896
+ { id: 'mistral', name: 'Mistral-7B', type: 'Creative', size: '4.1GB', desc: 'Good for creative writing.' },
897
+ { id: 'falcon', name: 'Falcon-40B', type: 'Logic', size: '80GB', desc: 'Advanced reasoning.' },
898
+ { id: 'bert', name: 'BERT-Large', type: 'NLP', size: '1.2GB', desc: 'Text classification & embeddings.' }
899
+ ],
900
+ currentModel: 'llama-3',
901
+ focusMode: false,
902
+ appPath: ':/app/models',
903
+ dlPath: '~/Downloads/'
904
+ };
905
+
906
+ // --- Initialization ---
907
+ document.addEventListener('DOMContentLoaded', () => {
908
+ loadFromStorage();
909
+
910
+ if (state.conversations.length === 0) {
911
+ createNewConversation(true);
912
+ } else {
913
+ loadConversation(state.conversations[0].id);
914
+ }
915
+
916
+ renderModelList();
917
+ renderHistoryList();
918
+ checkResponsive();
919
+
920
+ // Auto-refresh simulation (AJAX polling visual)
921
+ setInterval(() => {
922
+ if(Math.random() > 0.95) {
923
+ logTerminal(`> Checking HuggingFace API for updates...`, 'info');
924
+ }
925
+ }, 15000);
926
+
927
+ // Textarea auto-resize
928
+ const ta = document.getElementById('user-input');
929
+ ta.addEventListener('input', function() {
930
+ this.style.height = 'auto';
931
+ this.style.height = (this.scrollHeight) + 'px';
932
+ });
933
+
934
+ // Handle Enter key
935
+ ta.addEventListener('keydown', function(e) {
936
+ if (e.key === 'Enter' && !e.shiftKey) {
937
+ e.preventDefault();
938
+ sendMessage();
939
+ }
940
+ });
941
+
942
+ // Handle window resize
943
+ window.addEventListener('resize', checkResponsive);
944
+
945
+ // Toggle Terminal Panel Button
946
+ document.getElementById('toggle-terminal').addEventListener('click', () => {
947
+ const panel = document.getElementById('right-panel');
948
+ if (window.innerWidth <= 1024) {
949
+ panel.classList.toggle('open');
950
+ } else {
951
+ // Toggle visibility on desktop
952
+ if (panel.style.width === '0px') {
953
+ panel.style.width = '350px';
954
+ panel.style.opacity = '1';
955
+ panel.style.padding = '0'; // reset padding if needed
956
+ } else {
957
+ panel.style.width = '0px';
958
+ panel.style.opacity = '0';
959
+ panel.style.overflow = 'hidden';
960
+ panel.style.padding = '0'; // hide content
961
+ }
962
+ }
963
+ });
964
+ });
965
+
966
+ function checkResponsive() {
967
+ const toggleBtn = document.getElementById('toggle-sidebar');
968
+ if (window.innerWidth <= 768) {
969
+ toggleBtn.style.display = 'block';
970
+ } else {
971
+ toggleBtn.style.display = 'none';
972
+ document.getElementById('sidebar').classList.remove('open');
973
+ document.getElementById('mobile-overlay').classList.remove('active');
974
+ }
975
+ }
976
+
977
+ // --- Core Logic ---
978
+
979
+ function createNewConversation(isFirst = false) {
980
+ const newId = Date.now().toString();
981
+ const currentModelObj = state.models.find(m => m.id === state.currentModel);
982
+
983
+ const newConv = {
984
+ id: newId,
985
+ name: isFirst ? 'New Conversation' : `Conversation ${state.conversations.length + 1}`,
986
+ model: state.currentModel,
987
+ messages: []
988
+ };
989
+
990
+ // Pre-suggestion based on model
991
+ if (currentModelObj) {
992
+ newConv.messages.push({
993
+ role: 'system',
994
+ content: `Switched to ${currentModelObj.name}. ${currentModelObj.desc} Suggestion: Try asking for a summary or creative story.`
995
+ });
996
+ }
997
+
998
+ state.conversations.unshift(newConv);
999
+ state.currentConversationId = newId;
1000
+ saveToStorage();
1001
+ renderHistoryList();
1002
+ renderChat();
1003
+
1004
+ if(!isFirst) showToast("New Conversation Created");
1005
+
1006
+ // Close sidebar on mobile if open
1007
+ if(window.innerWidth <= 768) toggleSidebar();
1008
+ }
1009
+
1010
+ function loadConversation(id) {
1011
+ state.currentConversationId = id;
1012
+ const conv = state.conversations.find(c => c.id === id);
1013
+ if (conv) {
1014
+ // Update current model to match the conversation's model
1015
+ if (conv.model && state.models.find(m => m.id === conv.model)) {
1016
+ state.currentModel = conv.model;
1017
+ document.getElementById('current-model-display').innerText = state.models.find(m => m.id === conv.model).name;
1018
+ renderModelList(); // Update active state
1019
+ }
1020
+ renderChat();
1021
+ renderHistoryList(); // Update active class
1022
+ }
1023
+ }
1024
+
1025
+ function deleteConversation(id, e) {
1026
+ e.stopPropagation();
1027
+ if(confirm("Delete this conversation?")) {
1028
+ state.conversations = state.conversations.filter(c => c.id !== id);
1029
+ if (state.conversations.length === 0) {
1030
+ createNewConversation();
1031
+ } else {
1032
+ loadConversation(state.conversations[0].id);
1033
+ }
1034
+ saveToStorage();
1035
+ renderHistoryList();
1036
+ }
1037
+ }
1038
+
1039
+ function updateConversationName(id, newName) {
1040
+ const conv = state.conversations.find(c => c.id === id);
1041
+ if (conv) {
1042
+ conv.name = newName;
1043
+ saveToStorage();
1044
+ renderHistoryList();
1045
+ }
1046
+ }
1047
+
1048
+ function sendMessage() {
1049
+ const input = document.getElementById('user-input');
1050
+ const text = input.value.trim();
1051
+ if (!text) return;
1052
+
1053
+ const conv = state.conversations.find(c => c.id === state.currentConversationId);
1054
+ if (!conv) return;
1055
+
1056
+ // Add User Message
1057
+ conv.messages.push({ role: 'user', content: text });
1058
+ input.value = '';
1059
+ input.style.height = 'auto'; // Reset height
1060
+ saveToStorage();
1061
+ renderChat();
1062
+
1063
+ // Show typing indicator
1064
+ const typingId = 'typing-' + Date.now();
1065
+ addTypingIndicator(typingId);
1066
+
1067
+ // Simulate AI Response
1068
+ setTimeout(() => {
1069
+ removeTypingIndicator(typ