protae5544 commited on
Commit
e250b4d
·
verified ·
1 Parent(s): 90d73a6

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1338 -19
index.html CHANGED
@@ -1,19 +1,1338 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </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.0">
6
+ <title>AI Chatbot with HuggingFace API - Enhanced</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
8
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --bg-primary: #0a0a0a;
12
+ --bg-secondary: #1a1a1a;
13
+ --bg-tertiary: #2a2a2a;
14
+ --text-primary: #ffffff;
15
+ --text-secondary: #b0b0b0;
16
+ --accent-primary: #00d4ff;
17
+ --accent-secondary: #ff6b35;
18
+ --accent-tertiary: #7c4dff;
19
+ --error: #ff4757;
20
+ --success: #2ed573;
21
+ --warning: #ffa502;
22
+ --glass-bg: rgba(255, 255, 255, 0.05);
23
+ --glass-border: rgba(255, 255, 255, 0.1);
24
+ --shadow-lg: 0 20px 40px rgba(0, 0, 0, 0.6);
25
+ --shadow-xl: 0 25px 50px rgba(0, 0, 0, 0.8);
26
+ --gradient-primary: linear-gradient(135deg, var(--accent-primary), var(--accent-tertiary));
27
+ --gradient-secondary: linear-gradient(135deg, var(--accent-secondary), var(--accent-primary));
28
+ --gradient-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29
+ }
30
+
31
+ * {
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ body {
36
+ margin: 0;
37
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Inter', sans-serif;
38
+ background: var(--bg-primary);
39
+ background-image:
40
+ radial-gradient(ellipse at top left, rgba(0, 212, 255, 0.05) 0%, transparent 50%),
41
+ radial-gradient(ellipse at bottom right, rgba(124, 77, 255, 0.05) 0%, transparent 50%);
42
+ color: var(--text-primary);
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: center;
46
+ min-height: 100vh;
47
+ overflow: hidden;
48
+ -webkit-tap-highlight-color: transparent;
49
+ backdrop-filter: blur(10px);
50
+ }
51
+
52
+ .app-container {
53
+ width: 95%;
54
+ max-width: 1400px;
55
+ background: var(--glass-bg);
56
+ backdrop-filter: blur(20px);
57
+ border: 1px solid var(--glass-border);
58
+ border-radius: 20px;
59
+ box-shadow: var(--shadow-xl);
60
+ display: flex;
61
+ overflow: hidden;
62
+ height: 90vh;
63
+ position: relative;
64
+ animation: slideIn 0.8s cubic-bezier(0.23, 1, 0.32, 1);
65
+ }
66
+
67
+ @keyframes slideIn {
68
+ from {
69
+ opacity: 0;
70
+ transform: translateY(50px) scale(0.95);
71
+ }
72
+ to {
73
+ opacity: 1;
74
+ transform: translateY(0) scale(1);
75
+ }
76
+ }
77
+
78
+ .settings-panel {
79
+ width: 320px;
80
+ padding: 24px;
81
+ background: var(--bg-secondary);
82
+ backdrop-filter: blur(15px);
83
+ border-right: 1px solid var(--glass-border);
84
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
85
+ overflow-y: auto;
86
+ scrollbar-width: thin;
87
+ scrollbar-color: var(--accent-primary) transparent;
88
+ }
89
+
90
+ .settings-panel::-webkit-scrollbar {
91
+ width: 6px;
92
+ }
93
+
94
+ .settings-panel::-webkit-scrollbar-track {
95
+ background: transparent;
96
+ }
97
+
98
+ .settings-panel::-webkit-scrollbar-thumb {
99
+ background: var(--accent-primary);
100
+ border-radius: 3px;
101
+ }
102
+
103
+ .settings-panel.collapsed {
104
+ width: 0;
105
+ padding: 0;
106
+ overflow: hidden;
107
+ }
108
+
109
+ .main-content {
110
+ flex: 1;
111
+ display: flex;
112
+ flex-direction: column;
113
+ position: relative;
114
+ background: var(--bg-primary);
115
+ }
116
+
117
+ .form-field {
118
+ margin-bottom: 20px;
119
+ animation: fadeInUp 0.6s cubic-bezier(0.23, 1, 0.32, 1);
120
+ }
121
+
122
+ .form-field label {
123
+ display: block;
124
+ margin-bottom: 8px;
125
+ font-size: 1rem;
126
+ font-weight: 600;
127
+ color: var(--text-secondary);
128
+ text-transform: uppercase;
129
+ letter-spacing: 0.5px;
130
+ }
131
+
132
+ .form-field select, .form-field textarea {
133
+ width: 100%;
134
+ padding: 12px 16px;
135
+ border: 2px solid transparent;
136
+ border-radius: 12px;
137
+ background: var(--bg-tertiary);
138
+ color: var(--text-primary);
139
+ font-size: 1rem;
140
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
141
+ backdrop-filter: blur(10px);
142
+ }
143
+
144
+ .form-field select:focus, .form-field textarea:focus {
145
+ outline: none;
146
+ border-color: var(--accent-primary);
147
+ box-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
148
+ transform: translateY(-2px);
149
+ }
150
+
151
+ .form-field textarea {
152
+ resize: vertical;
153
+ min-height: 100px;
154
+ }
155
+
156
+ button {
157
+ padding: 12px 24px;
158
+ border: none;
159
+ border-radius: 12px;
160
+ background: var(--gradient-primary);
161
+ color: var(--text-primary);
162
+ cursor: pointer;
163
+ font-size: 1rem;
164
+ font-weight: 600;
165
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
166
+ touch-action: manipulation;
167
+ position: relative;
168
+ overflow: hidden;
169
+ }
170
+
171
+ button::before {
172
+ content: '';
173
+ position: absolute;
174
+ top: 0;
175
+ left: -100%;
176
+ width: 100%;
177
+ height: 100%;
178
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
179
+ transition: left 0.5s;
180
+ }
181
+
182
+ button:hover::before {
183
+ left: 100%;
184
+ }
185
+
186
+ button:hover {
187
+ transform: translateY(-3px);
188
+ box-shadow: 0 10px 25px rgba(0, 212, 255, 0.4);
189
+ }
190
+
191
+ button:active {
192
+ transform: translateY(-1px);
193
+ }
194
+
195
+ .material-icons {
196
+ font-family: 'Material Icons';
197
+ font-size: 28px;
198
+ vertical-align: middle;
199
+ }
200
+
201
+ .chat-container {
202
+ flex: 1;
203
+ padding: 24px;
204
+ overflow-y: auto;
205
+ display: flex;
206
+ flex-direction: column;
207
+ gap: 16px;
208
+ scrollbar-width: thin;
209
+ scrollbar-color: var(--accent-primary) transparent;
210
+ }
211
+
212
+ .chat-container::-webkit-scrollbar {
213
+ width: 8px;
214
+ }
215
+
216
+ .chat-container::-webkit-scrollbar-track {
217
+ background: transparent;
218
+ }
219
+
220
+ .chat-container::-webkit-scrollbar-thumb {
221
+ background: var(--accent-primary);
222
+ border-radius: 4px;
223
+ }
224
+
225
+ .message {
226
+ max-width: 80%;
227
+ padding: 16px 20px;
228
+ border-radius: 20px;
229
+ font-size: 1rem;
230
+ line-height: 1.6;
231
+ position: relative;
232
+ animation: messageSlide 0.5s cubic-bezier(0.23, 1, 0.32, 1);
233
+ backdrop-filter: blur(10px);
234
+ }
235
+
236
+ @keyframes messageSlide {
237
+ from {
238
+ opacity: 0;
239
+ transform: translateY(20px);
240
+ }
241
+ to {
242
+ opacity: 1;
243
+ transform: translateY(0);
244
+ }
245
+ }
246
+
247
+ .message.user {
248
+ background: var(--gradient-primary);
249
+ align-self: flex-end;
250
+ box-shadow: 0 8px 20px rgba(0, 212, 255, 0.3);
251
+ }
252
+
253
+ .message.ai {
254
+ background: var(--glass-bg);
255
+ border: 1px solid var(--glass-border);
256
+ align-self: flex-start;
257
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
258
+ }
259
+
260
+ .input-container {
261
+ display: flex;
262
+ gap: 12px;
263
+ padding: 20px;
264
+ background: var(--glass-bg);
265
+ backdrop-filter: blur(20px);
266
+ border-top: 1px solid var(--glass-border);
267
+ align-items: center;
268
+ }
269
+
270
+ #userInput {
271
+ flex: 1;
272
+ padding: 16px 20px;
273
+ border: 2px solid transparent;
274
+ border-radius: 20px;
275
+ background: var(--bg-secondary);
276
+ color: var(--text-primary);
277
+ resize: none;
278
+ min-height: 60px;
279
+ max-height: 150px;
280
+ font-size: 1rem;
281
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
282
+ backdrop-filter: blur(10px);
283
+ }
284
+
285
+ #userInput:focus {
286
+ outline: none;
287
+ border-color: var(--accent-primary);
288
+ box-shadow: 0 0 25px rgba(0, 212, 255, 0.3);
289
+ transform: translateY(-2px);
290
+ }
291
+
292
+ #sendButton, #attachButton {
293
+ display: flex;
294
+ align-items: center;
295
+ justify-content: center;
296
+ width: 60px;
297
+ height: 60px;
298
+ border-radius: 50%;
299
+ background: var(--gradient-primary);
300
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
301
+ }
302
+
303
+ #sendButton:hover, #attachButton:hover {
304
+ transform: translateY(-3px) scale(1.05);
305
+ box-shadow: 0 12px 30px rgba(0, 212, 255, 0.5);
306
+ }
307
+
308
+ #sendButton:disabled {
309
+ background: var(--bg-tertiary);
310
+ cursor: not-allowed;
311
+ transform: none;
312
+ box-shadow: none;
313
+ }
314
+
315
+ .spinner {
316
+ width: 28px;
317
+ height: 28px;
318
+ border: 3px solid rgba(255, 255, 255, 0.3);
319
+ border-top: 3px solid var(--accent-primary);
320
+ border-radius: 50%;
321
+ animation: spin 1s linear infinite;
322
+ }
323
+
324
+ @keyframes spin {
325
+ to { transform: rotate(360deg); }
326
+ }
327
+
328
+ .notification {
329
+ position: fixed;
330
+ top: 24px;
331
+ right: 24px;
332
+ padding: 16px 24px;
333
+ border-radius: 12px;
334
+ color: #fff;
335
+ font-size: 1rem;
336
+ font-weight: 600;
337
+ z-index: 1000;
338
+ display: none;
339
+ backdrop-filter: blur(15px);
340
+ animation: notificationSlide 0.5s cubic-bezier(0.23, 1, 0.32, 1);
341
+ }
342
+
343
+ @keyframes notificationSlide {
344
+ from {
345
+ opacity: 0;
346
+ transform: translateX(100px);
347
+ }
348
+ to {
349
+ opacity: 1;
350
+ transform: translateX(0);
351
+ }
352
+ }
353
+
354
+ .error-message {
355
+ background: linear-gradient(135deg, var(--error), #ff6b6b);
356
+ box-shadow: 0 10px 25px rgba(255, 71, 87, 0.4);
357
+ }
358
+
359
+ .success-message {
360
+ background: linear-gradient(135deg, var(--success), #5af78e);
361
+ box-shadow: 0 10px 25px rgba(46, 213, 115, 0.4);
362
+ }
363
+ .carousel {
364
+ touch-action: pan-x pan-y;
365
+ transition: transform 0.6s ease-in-out;
366
+ }
367
+
368
+ .carousel-controls button {
369
+ touch-action: manipulation;
370
+ user-select: none; }
371
+
372
+ .carousel.dragging {
373
+ touch-action: none;
374
+ }
375
+
376
+ .carousel-container {
377
+ perspective: 1200px;
378
+ height: 100%;
379
+ display: flex;
380
+ flex-direction: column;
381
+ align-items: center;
382
+ justify-content: center;
383
+ position: relative;
384
+ user-select: none;
385
+ padding: 24px;
386
+ }
387
+
388
+ .carousel {
389
+ position: relative;
390
+ width: 90%;
391
+ max-width: 500px;
392
+ height: 300px;
393
+ transform-style: preserve-3d;
394
+ transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1);
395
+ cursor: grab;
396
+ }
397
+
398
+ .carousel.dragging {
399
+ cursor: grabbing;
400
+ }
401
+
402
+ .carousel-card {
403
+ position: absolute;
404
+ width: 100%;
405
+ height: 100%;
406
+ background: var(--glass-bg);
407
+ backdrop-filter: blur(20px);
408
+ border: 1px solid var(--glass-border);
409
+ border-radius: 16px;
410
+ padding: 24px;
411
+ box-shadow: var(--shadow-lg);
412
+ display: flex;
413
+ flex-direction: column;
414
+ gap: 12px;
415
+ transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
416
+ }
417
+
418
+ .carousel-controls, .carousel-indicator {
419
+ display: flex;
420
+ gap: 16px;
421
+ margin-top: 24px;
422
+ }
423
+
424
+ .carousel-dot {
425
+ width: 14px;
426
+ height: 14px;
427
+ background: var(--bg-tertiary);
428
+ border-radius: 50%;
429
+ cursor: pointer;
430
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
431
+ border: 2px solid transparent;
432
+ }
433
+
434
+ .carousel-dot.active {
435
+ background: var(--accent-primary);
436
+ box-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
437
+ transform: scale(1.2);
438
+ }
439
+
440
+ .carousel-dot:hover {
441
+ transform: scale(1.1);
442
+ border-color: var(--accent-primary);
443
+ }
444
+
445
+ .mode-toggle {
446
+ display: flex;
447
+ background: var(--bg-secondary);
448
+ backdrop-filter: blur(15px);
449
+ border-radius: 20px;
450
+ padding: 4px;
451
+ position: relative;
452
+ margin-bottom: 20px;
453
+ border: 1px solid var(--glass-border);
454
+ }
455
+
456
+ .mode-toggle button {
457
+ flex: 1;
458
+ padding: 12px 20px;
459
+ background: none;
460
+ border: none;
461
+ color: var(--text-secondary);
462
+ cursor: pointer;
463
+ z-index: 1;
464
+ font-size: 1rem;
465
+ font-weight: 600;
466
+ border-radius: 16px;
467
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
468
+ }
469
+
470
+ .mode-toggle button.active {
471
+ color: var(--text-primary);
472
+ }
473
+
474
+ .mode-toggle-slider {
475
+ position: absolute;
476
+ top: 4px;
477
+ left: 4px;
478
+ height: calc(100% - 8px);
479
+ background: var(--gradient-primary);
480
+ border-radius: 16px;
481
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
482
+ box-shadow: 0 4px 15px rgba(0, 212, 255, 0.3);
483
+ }
484
+
485
+ .dropzone {
486
+ position: absolute;
487
+ top: 0;
488
+ left: 0;
489
+ right: 0;
490
+ bottom: 0;
491
+ background: rgba(0, 212, 255, 0.1);
492
+ backdrop-filter: blur(20px);
493
+ border: 3px dashed var(--accent-primary);
494
+ display: none;
495
+ align-items: center;
496
+ justify-content: center;
497
+ color: var(--text-primary);
498
+ font-size: 1.4rem;
499
+ font-weight: 600;
500
+ z-index: 10;
501
+ border-radius: 20px;
502
+ }
503
+
504
+ .dropzone.active {
505
+ display: flex;
506
+ animation: pulse 2s infinite;
507
+ }
508
+
509
+ @keyframes pulse {
510
+ 0%, 100% { opacity: 0.7; }
511
+ 50% { opacity: 1; }
512
+ }
513
+
514
+ .file-name {
515
+ font-size: 1rem;
516
+ color: var(--accent-primary);
517
+ margin-left: 12px;
518
+ align-self: center;
519
+ max-width: 200px;
520
+ white-space: nowrap;
521
+ overflow: hidden;
522
+ text-overflow: ellipsis;
523
+ font-weight: 600;
524
+ }
525
+
526
+ .chip-container {
527
+ display: flex;
528
+ gap: 12px;
529
+ margin-bottom: 20px;
530
+ flex-wrap: wrap;
531
+ padding: 0 24px;
532
+ }
533
+
534
+ .chip {
535
+ padding: 10px 18px;
536
+ background: var(--glass-bg);
537
+ backdrop-filter: blur(15px);
538
+ border: 1px solid var(--glass-border);
539
+ border-radius: 20px;
540
+ font-size: 0.9rem;
541
+ font-weight: 600;
542
+ cursor: pointer;
543
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
544
+ color: var(--text-secondary);
545
+ }
546
+
547
+ .chip:hover {
548
+ background: var(--accent-primary);
549
+ color: var(--text-primary);
550
+ transform: translateY(-2px);
551
+ box-shadow: 0 6px 20px rgba(0, 212, 255, 0.4);
552
+ }
553
+
554
+ .floating-buttons {
555
+ position: absolute;
556
+ top: 20px;
557
+ right: 20px;
558
+ display: flex;
559
+ gap: 12px;
560
+ z-index: 100;
561
+ }
562
+
563
+ .floating-btn {
564
+ width: 48px;
565
+ height: 48px;
566
+ border-radius: 50%;
567
+ background: var(--glass-bg);
568
+ backdrop-filter: blur(15px);
569
+ border: 1px solid var(--glass-border);
570
+ display: flex;
571
+ align-items: center;
572
+ justify-content: center;
573
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
574
+ padding: 0;
575
+ }
576
+
577
+ .floating-btn:hover {
578
+ background: var(--accent-primary);
579
+ transform: translateY(-3px) scale(1.05);
580
+ box-shadow: 0 8px 25px rgba(0, 212, 255, 0.4);
581
+ }
582
+
583
+ .code-tools {
584
+ position: absolute;
585
+ top: 12px;
586
+ right: 12px;
587
+ display: flex;
588
+ gap: 8px;
589
+ }
590
+
591
+ .code-tools button {
592
+ padding: 6px 12px;
593
+ font-size: 0.85rem;
594
+ background: var(--glass-bg);
595
+ backdrop-filter: blur(10px);
596
+ border: 1px solid var(--glass-border);
597
+ }
598
+
599
+ pre {
600
+ position: relative;
601
+ background: var(--bg-secondary);
602
+ border: 1px solid var(--glass-border);
603
+ padding: 20px;
604
+ border-radius: 12px;
605
+ overflow-x: auto;
606
+ backdrop-filter: blur(10px);
607
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
608
+ }
609
+
610
+ code {
611
+ font-family: 'Fira Code', 'Consolas', monospace;
612
+ font-size: 0.9rem;
613
+ }
614
+
615
+ .image-preview {
616
+ max-width: 100%;
617
+ max-height: 300px;
618
+ border-radius: 12px;
619
+ margin-top: 12px;
620
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
621
+ }
622
+
623
+ @keyframes fadeInUp {
624
+ from {
625
+ opacity: 0;
626
+ transform: translateY(30px);
627
+ }
628
+ to {
629
+ opacity: 1;
630
+ transform: translateY(0);
631
+ }
632
+ }
633
+
634
+ @media (max-width: 768px) {
635
+ .app-container {
636
+ flex-direction: column;
637
+ height: auto;
638
+ min-height: 100vh;
639
+ border-radius: 0;
640
+ width: 100%;
641
+ }
642
+
643
+ .settings-panel {
644
+ width: 100%;
645
+ max-height: 40vh;
646
+ border-right: none;
647
+ border-bottom: 1px solid var(--glass-border);
648
+ }
649
+
650
+ .settings-panel.collapsed {
651
+ max-height: 0;
652
+ }
653
+
654
+ .chat-container {
655
+ max-height: 50vh;
656
+ padding: 16px;
657
+ }
658
+
659
+ .input-container {
660
+ flex-wrap: wrap;
661
+ gap: 12px;
662
+ padding: 16px;
663
+ }
664
+
665
+ #userInput {
666
+ width: 100%;
667
+ margin-bottom: 12px;
668
+ min-height: 50px;
669
+ }
670
+
671
+ #sendButton, #attachButton {
672
+ width: 56px;
673
+ height: 56px;
674
+ }
675
+
676
+ .carousel {
677
+ width: 95%;
678
+ height: 250px;
679
+ }
680
+
681
+ .floating-buttons {
682
+ top: 12px;
683
+ right: 12px;
684
+ }
685
+
686
+ .floating-btn {
687
+ width: 44px;
688
+ height: 44px;
689
+ }
690
+
691
+ .material-icons {
692
+ font-size: 24px;
693
+ }
694
+ }
695
+
696
+ @media (max-width: 480px) {
697
+ .chip-container {
698
+ padding: 0 16px;
699
+ }
700
+
701
+ .chip {
702
+ font-size: 0.8rem;
703
+ padding: 8px 14px;
704
+ }
705
+
706
+ .form-field select, .form-field textarea, #userInput {
707
+ font-size: 16px;
708
+ }
709
+ }
710
+ </style>
711
+ </head>
712
+ <body>
713
+ <div class="app-container" id="appContainer">
714
+ <div class="settings-panel" id="settingsPanel">
715
+ <h2 style="font-size: 1.4rem; margin-bottom: 24px; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">⚙️ Settings</h2>
716
+ <div class="form-field">
717
+ <label>🤖 Main Model:</label>
718
+ <select id="modelSelect">
719
+ <option value="Qwen/Qwen2.5-Coder-32B-Instruct">Qwen2.5-Coder 32B (Code/Text)</option>
720
+ <option value="Qwen/Qwen2-VL-72B-Instruct">Qwen2-VL 72B (Text/Image)</option>
721
+ <option value="microsoft/Florence-2-large">Florence-2 Large (Text/Image)</option>
722
+ <option value="mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral 8x7B (Text)</option>
723
+ <option value="meta-llama/Llama-2-70b-chat-hf">Llama-2 70B (Chat)</option>
724
+ </select>
725
+ <p style="font-size: 0.8rem; color: var(--text-secondary); margin-top: 8px;">
726
+ 💡 Choose a model. Use VL or Florence for image processing.
727
+ </p>
728
+ </div>
729
+ <div class="form-field">
730
+ <label>👁️ OCR Model (for images):</label>
731
+ <select id="ocrModelSelect">
732
+ <option value="none">None</option>
733
+ <option value="scb10x/typhoon-v1.5x-72b-instruct">Typhoon 1.5x 72B</option>
734
+ <option value="microsoft/trocr-base-printed">TrOCR Base</option>
735
+ </select>
736
+ </div>
737
+ <button id="saveSettingsBtn">💾 Save Settings</button>
738
+ </div>
739
+ <div class="main-content">
740
+ <div class="floating-buttons">
741
+ <button id="settingsToggle" class="floating-btn">
742
+ <span class="material-icons">settings</span>
743
+ </button>
744
+ <button id="fullscreenToggle" class="floating-btn">
745
+ <span class="material-icons">fullscreen</span>
746
+ </button>
747
+ <button id="refreshBtn" class="floating-btn">
748
+ <span class="material-icons">refresh</span>
749
+ </button>
750
+ </div>
751
+
752
+ <div class="mode-toggle">
753
+ <button id="carouselModeBtn" class="active">🎛️ Prompt Editor</button>
754
+ <button id="chatModeBtn">💬 Chat</button>
755
+ <div class="mode-toggle-slider" id="modeToggleSlider"></div>
756
+ </div>
757
+
758
+ <div id="carouselMode">
759
+ <div class="carousel-container">
760
+ <div class="carousel" id="promptCarousel">
761
+ <div class="carousel-card" style="transform: rotateY(0deg) translateZ(500px);">
762
+ <label>🎯 Primary System Prompt:</label>
763
+ <textarea id="primarySystemPrompt" placeholder="Enter primary system prompt for the AI assistant...">You are a powerful AI assistant that excels at understanding code, images, and technical content. Provide clear, accurate, and helpful responses. Focus on practical solutions and detailed explanations.</textarea>
764
+ </div>
765
+ <div class="carousel-card" style="transform: rotateY(60deg) translateZ(500px); opacity: 0.8;">
766
+ <label>👁️ OCR System Prompt:</label>
767
+ <textarea id="ocrSystemPrompt" placeholder="Enter OCR system prompt for image text extraction...">Extract all text from the provided image clearly and accurately. Preserve formatting, structure, and layout when possible. If text is unclear, indicate uncertain parts.</textarea>
768
+ </div>
769
+ <div class="carousel-card" style="transform: rotateY(120deg) translateZ(500px); opacity: 0.8;">
770
+ <label>💻 Code Template:</label>
771
+ <textarea id="codeTemplate" placeholder="Enter code formatting template...">```javascript
772
+ // Enhanced code implementation
773
+ function solution() {
774
+ // Your optimized code here
775
+ return result;
776
+ }
777
+ ```</textarea>
778
+ </div>
779
+ <div class="carousel-card" style="transform: rotateY(180deg) translateZ(500px); opacity: 0.8;">
780
+ <label>📋 Additional Instructions:</label>
781
+ <textarea id="additionalInstructions" placeholder="Enter additional instructions for the AI...">Always provide working, tested code examples. Include error handling and optimization suggestions. Explain complex concepts step by step. Use modern best practices.</textarea>
782
+ </div>
783
+ <div class="carousel-card" style="transform: rotateY(240deg) translateZ(500px); opacity: 0.8;">
784
+ <label>🚀 Prompt Prefix:</label>
785
+ <textarea id="promptPrefix" placeholder="Enter text to prepend to all prompts...">Please analyze the following request carefully and provide a comprehensive solution:</textarea>
786
+ </div>
787
+ <div class="carousel-card" style="transform: rotateY(300deg) translateZ(500px); opacity: 0.8;">
788
+ <label>✨ Prompt Suffix:</label>
789
+ <textarea id="promptSuffix" placeholder="Enter text to append to all prompts...">Ensure your response is complete, accurate, and includes practical examples where applicable.</textarea>
790
+ </div>
791
+ </div>
792
+ <div class="carousel-controls">
793
+ <button id="prevCard"><span class="material-icons">chevron_left</span></button>
794
+ <button id="nextCard"><span class="material-icons">chevron_right</span></button>
795
+ </div>
796
+ <div class="carousel-indicator" id="carouselIndicator">
797
+ <div class="carousel-dot active" data-index="0"></div>
798
+ <div class="carousel-dot" data-index="1"></div>
799
+ <div class="carousel-dot" data-index="2"></div>
800
+ <div class="carousel-dot" data-index="3"></div>
801
+ <div class="carousel-dot" data-index="4"></div>
802
+ <div class="carousel-dot" data-index="5"></div>
803
+ </div>
804
+ <button id="applyPromptBtn" style="margin-top: 24px;">✅ Apply Prompts & Switch to Chat</button>
805
+ </div>
806
+ </div>
807
+
808
+ <div id="chatMode" style="display: none;">
809
+ <div class="chip-container" id="quickPrompts">
810
+ <span class="chip" data-prompt="Explain this code in detail">🔍 Explain Code</span>
811
+ <span class="chip" data-prompt="Generate a complete function">⚡ Generate Function</span>
812
+ <span class="chip" data-prompt="Debug and fix this issue">🐛 Debug Code</span>
813
+ <span class="chip" data-prompt="Optimize this for performance">🚀 Optimize</span>
814
+ <span class="chip" data-prompt="Add error handling">🛡️ Error Handling</span>
815
+ <span class="chip" data-prompt="Convert to modern syntax">✨ Modernize</span>
816
+ </div>
817
+ <div class="chat-container" id="chatContainer"></div>
818
+ <div class="input-container">
819
+ <button id="attachButton"><span class="material-icons">attach_file</span></button>
820
+ <input type="file" id="fileInput" multiple accept="image/*" style="display: none;">
821
+ <span class="file-name" id="fileName"></span>
822
+ <textarea id="userInput" placeholder="Type your message here... (Shift+Enter for new line)"></textarea>
823
+ <button id="sendButton"><span class="material-icons">send</span></button>
824
+ </div>
825
+ <div class="dropzone" id="dropzone">📁 Drop files here to attach them</div>
826
+ </div>
827
+
828
+ <div class="notification error-message" id="errorMessage">
829
+ <span id="errorText"></span>
830
+ </div>
831
+ <div class="notification success-message" id="successMessage">
832
+ <span id="successText"></span>
833
+ </div>
834
+ </div>
835
+ </div>
836
+
837
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
838
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
839
+ <script>
840
+ // Global variables
841
+ let attachedFiles = [];
842
+ let currentCarouselIndex = 0;
843
+ let isLoading = false;
844
+ let isDragging = false;
845
+
846
+ // Initialize the application
847
+ document.addEventListener('DOMContentLoaded', function() {
848
+ loadSettings();
849
+ setupEventListeners();
850
+ setupCarousel();
851
+ setupDropzone();
852
+ hljs.highlightAll();
853
+ });
854
+
855
+ // Settings management
856
+ function loadSettings() {
857
+ const settings = {
858
+ model: localStorage.getItem('selectedModel') || 'Qwen/Qwen2.5-Coder-32B-Instruct',
859
+ ocrModel: localStorage.getItem('selectedOcrModel') || 'none',
860
+ primarySystemPrompt: localStorage.getItem('primarySystemPrompt') || 'You are a powerful AI assistant that excels at understanding code, images, and technical content. Provide clear, accurate, and helpful responses. Focus on practical solutions and detailed explanations.',
861
+ ocrSystemPrompt: localStorage.getItem('ocrSystemPrompt') || 'Extract all text from the provided image clearly and accurately. Preserve formatting, structure, and layout when possible. If text is unclear, indicate uncertain parts.',
862
+ codeTemplate: localStorage.getItem('codeTemplate') || '```javascript\n// Enhanced code implementation\nfunction solution() {\n // Your optimized code here\n return result;\n}\n```',
863
+ additionalInstructions: localStorage.getItem('additionalInstructions') || 'Always provide working, tested code examples. Include error handling and optimization suggestions. Explain complex concepts step by step. Use modern best practices.',
864
+ promptPrefix: localStorage.getItem('promptPrefix') || 'Please analyze the following request carefully and provide a comprehensive solution:',
865
+ promptSuffix: localStorage.getItem('promptSuffix') || 'Ensure your response is complete, accurate, and includes practical examples where applicable.'
866
+ };
867
+
868
+ document.getElementById('modelSelect').value = settings.model;
869
+ document.getElementById('ocrModelSelect').value = settings.ocrModel;
870
+ document.getElementById('primarySystemPrompt').value = settings.primarySystemPrompt;
871
+ document.getElementById('ocrSystemPrompt').value = settings.ocrSystemPrompt;
872
+ document.getElementById('codeTemplate').value = settings.codeTemplate;
873
+ document.getElementById('additionalInstructions').value = settings.additionalInstructions;
874
+ document.getElementById('promptPrefix').value = settings.promptPrefix;
875
+ document.getElementById('promptSuffix').value = settings.promptSuffix;
876
+ }
877
+
878
+ function saveSettings() {
879
+ localStorage.setItem('selectedModel', document.getElementById('modelSelect').value);
880
+ localStorage.setItem('selectedOcrModel', document.getElementById('ocrModelSelect').value);
881
+ localStorage.setItem('primarySystemPrompt', document.getElementById('primarySystemPrompt').value);
882
+ localStorage.setItem('ocrSystemPrompt', document.getElementById('ocrSystemPrompt').value);
883
+ localStorage.setItem('codeTemplate', document.getElementById('codeTemplate').value);
884
+ localStorage.setItem('additionalInstructions', document.getElementById('additionalInstructions').value);
885
+ localStorage.setItem('promptPrefix', document.getElementById('promptPrefix').value);
886
+ localStorage.setItem('promptSuffix', document.getElementById('promptSuffix').value);
887
+ showNotification('Settings saved successfully!', 'success');
888
+ }
889
+
890
+ // Event listeners setup
891
+ function setupEventListeners() {
892
+ let startX = 0;
893
+ let startY = 0;
894
+ let lastTranslateX = 0;
895
+ let lastTranslateY = 0;
896
+ let isDragging = false;
897
+
898
+ document.getElementById('carousel').addEventListener('touchstart', (e) => {
899
+ isDragging = true;
900
+ startX = e.touches[0].clientX;
901
+ startY = e.touches[0].clientY;
902
+ });
903
+
904
+ document.getElementById('carousel').addEventListener('touchmove', (e) => {
905
+ if (!isDragging) return;
906
+
907
+ const dx = e.touches[0].clientX - startX;
908
+ const dy = e.touches[0].clientY - startY;
909
+
910
+ const newX = lastTranslateX + dx;
911
+ const newY = lastTranslateY + dy;
912
+
913
+ document.getElementById('carousel').style.transform = `translate3D(${newX}px, ${newY}px, 0)`;
914
+
915
+ startX = e.touches[0].clientX;
916
+ startY = e.touches[0].clientY;
917
+ }, { passive: false });
918
+
919
+ document.getElementById('carousel').addEventListener('touchend', () => {
920
+ isDragging = false;
921
+ lastTranslateX = parseFloat(document.getElementById('carousel').style.transform.match(/-?\d+(\.\d+)?px/g)[0]);
922
+ lastTranslateY = parseFloat(document.getElementById('carousel').style.transform.match(/-?\d+(\.\d+)?px/g)[1]);
923
+ });
924
+ // Mode toggle
925
+ document.getElementById('carouselModeBtn').addEventListener('click', () => switchMode('carousel'));
926
+ document.getElementById('chatModeBtn').addEventListener('click', () => switchMode('chat'));
927
+
928
+ // Settings
929
+ document.getElementById('saveSettingsBtn').addEventListener('click', saveSettings);
930
+ document.getElementById('settingsToggle').addEventListener('click', toggleSettings);
931
+
932
+ // Carousel controls
933
+ document.getElementById('prevCard').addEventListener('touchstart', () => rotateCarousel(-1, 0));
934
+ document.getElementById('nextCard').addEventListener('touchstart', () => rotateCarousel(1, 0));
935
+
936
+ document.getElementById('prevCard').addEventListener('touchmove', (e) => {
937
+ const dx = e.touches[0].clientX - startX;
938
+ if (dx > 50) rotateCarousel(-1, 0);
939
+ });
940
+
941
+ document.getElementById('nextCard').addEventListener('touchmove', (e) => {
942
+ const dx = e.touches[0].clientX - startX;
943
+ if (dx < -50) rotateCarousel(1, 0);
944
+ });
945
+ document.getElementById('applyPromptBtn').addEventListener('click', applyPromptsAndSwitchToChat);
946
+
947
+ // Chat controls
948
+ document.getElementById('sendButton').addEventListener('click', sendMessage);
949
+ document.getElementById('attachButton').addEventListener('click', () => document.getElementById('fileInput').click());
950
+ document.getElementById('fileInput').addEventListener('change', handleFileSelect);
951
+ document.getElementById('userInput').addEventListener('keydown', handleKeyDown);
952
+
953
+ // Other controls
954
+ document.getElementById('fullscreenToggle').addEventListener('click', toggleFullscreen);
955
+ document.getElementById('refreshBtn').addEventListener('click', refreshApp);
956
+
957
+ // Quick prompts
958
+ document.querySelectorAll('.chip').forEach(chip => {
959
+ chip.addEventListener('click', (e) => {
960
+ const prompt = e.target.getAttribute('data-prompt');
961
+ document.getElementById('userInput').value = prompt;
962
+ document.getElementById('userInput').focus();
963
+ });
964
+ });
965
+
966
+ // Carousel dots
967
+ document.querySelectorAll('.carousel-dot').forEach(dot => {
968
+ dot.addEventListener('click', (e) => {
969
+ const index = parseInt(e.target.getAttribute('data-index'));
970
+ goToCarouselIndex(index);
971
+ });
972
+ });
973
+ }
974
+
975
+ // Mode switching
976
+ function switchMode(mode) {
977
+ const carouselMode = document.getElementById('carouselMode');
978
+ const chatMode = document.getElementById('chatMode');
979
+ const carouselBtn = document.getElementById('carouselModeBtn');
980
+ const chatBtn = document.getElementById('chatModeBtn');
981
+ const slider = document.getElementById('modeToggleSlider');
982
+
983
+ if (mode === 'carousel') {
984
+ carouselMode.style.display = 'block';
985
+ chatMode.style.display = 'none';
986
+ carouselBtn.classList.add('active');
987
+ chatBtn.classList.remove('active');
988
+ slider.style.width = '50%';
989
+ slider.style.left = '4px';
990
+ } else {
991
+ carouselMode.style.display = 'none';
992
+ chatMode.style.display = 'block';
993
+ carouselBtn.classList.remove('active');
994
+ chatBtn.classList.add('active');
995
+ slider.style.width = '50%';
996
+ slider.style.left = '50%';
997
+ }
998
+ }
999
+
1000
+
1001
+ // Carousel functionality
1002
+ function setupCarousel() {
1003
+ updateCarouselPosition();
1004
+ }
1005
+
1006
+ function rotateCarousel(direction) {
1007
+ const totalCards = 6;
1008
+ currentCarouselIndex = (currentCarouselIndex + direction + totalCards) % totalCards;
1009
+ updateCarouselPosition();
1010
+ }
1011
+ function rotateCarousel(dx, dy) {
1012
+ const totalCards = 6;
1013
+ const cardWidth = 100 / totalCards;
1014
+ const cardHeight = 100 / totalCards;
1015
+
1016
+ let newIndex = currentCarouselIndex;
1017
+
1018
+ if (dx > 0) newIndex--;
1019
+ if (dx < 0) newIndex++;
1020
+ if (dy > 0) newIndex++;
1021
+ if (dy < 0) newIndex--;
1022
+
1023
+ newIndex = (newIndex + totalCards) % totalCards;
1024
+
1025
+ currentCarouselIndex = newIndex;
1026
+ updateCarouselPosition();
1027
+ }
1028
+ function goToCarouselIndex(index) {
1029
+ currentCarouselIndex = index;
1030
+ updateCarouselPosition();
1031
+ }
1032
+
1033
+ function updateCarouselPosition() {
1034
+ const carousel = document.getElementById('promptCarousel');
1035
+ const cards = carousel.querySelectorAll('.carousel-card');
1036
+ const dots = document.querySelectorAll('.carousel-dot');
1037
+
1038
+ cards.forEach((card, index) => {
1039
+ const angle = (index - currentCarouselIndex) * 60;
1040
+ const isActive = index === currentCarouselIndex;
1041
+
1042
+ card.style.transform = `rotateY(${angle}deg) translateZ(500px)`;
1043
+ card.style.opacity = isActive ? '1' : '0.6';
1044
+ card.style.zIndex = isActive ? '10' : '1';
1045
+ });
1046
+
1047
+ dots.forEach((dot, index) => {
1048
+ dot.classList.toggle('active', index === currentCarouselIndex);
1049
+ });
1050
+ }
1051
+
1052
+ function applyPromptsAndSwitchToChat() {
1053
+ saveSettings();
1054
+ switchMode('chat');
1055
+ showNotification('Prompts applied successfully!', 'success');
1056
+ }
1057
+
1058
+ // File handling
1059
+ function setupDropzone() {
1060
+ const dropzone = document.getElementById('dropzone');
1061
+ const chatMode = document.getElementById('chatMode');
1062
+
1063
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
1064
+ chatMode.addEventListener(eventName, preventDefaults, false);
1065
+ });
1066
+
1067
+ function preventDefaults(e) {
1068
+ e.preventDefault();
1069
+ e.stopPropagation();
1070
+ }
1071
+
1072
+ ['dragenter', 'dragover'].forEach(eventName => {
1073
+ chatMode.addEventListener(eventName, () => dropzone.classList.add('active'), false);
1074
+ });
1075
+
1076
+ ['dragleave', 'drop'].forEach(eventName => {
1077
+ chatMode.addEventListener(eventName, () => dropzone.classList.remove('active'), false);
1078
+ });
1079
+
1080
+ chatMode.addEventListener('drop', handleDrop, false);
1081
+ }
1082
+
1083
+ function handleDrop(e) {
1084
+ const dt = e.dataTransfer;
1085
+ const files = dt.files;
1086
+ handleFiles(files);
1087
+ }
1088
+
1089
+ function handleFileSelect(e) {
1090
+ const files = e.target.files;
1091
+ handleFiles(files);
1092
+ }
1093
+
1094
+ function handleFiles(files) {
1095
+ attachedFiles = Array.from(files);
1096
+ updateFileDisplay();
1097
+ }
1098
+
1099
+ function updateFileDisplay() {
1100
+ const fileName = document.getElementById('fileName');
1101
+ if (attachedFiles.length === 0) {
1102
+ fileName.textContent = '';
1103
+ } else if (attachedFiles.length === 1) {
1104
+ fileName.textContent = attachedFiles[0].name;
1105
+ } else {
1106
+ fileName.textContent = `${attachedFiles.length} files selected`;
1107
+ }
1108
+ }
1109
+
1110
+ // Chat functionality
1111
+ function handleKeyDown(e) {
1112
+ if (e.key === 'Enter' && !e.shiftKey) {
1113
+ e.preventDefault();
1114
+ sendMessage();
1115
+ }
1116
+ }
1117
+
1118
+ async function sendMessage() {
1119
+ const userInput = document.getElementById('userInput');
1120
+ const message = userInput.value.trim();
1121
+
1122
+ if (!message && attachedFiles.length === 0) return;
1123
+ if (isLoading) return;
1124
+
1125
+ const chatContainer = document.getElementById('chatContainer');
1126
+
1127
+ // Add user message
1128
+ if (message) {
1129
+ addMessage(message, 'user');
1130
+ }
1131
+
1132
+ // Add file previews
1133
+ if (attachedFiles.length > 0) {
1134
+ for (const file of attachedFiles) {
1135
+ if (file.type.startsWith('image/')) {
1136
+ const imageUrl = URL.createObjectURL(file);
1137
+ addImageMessage(imageUrl, 'user');
1138
+ }
1139
+ }
1140
+ }
1141
+
1142
+ userInput.value = '';
1143
+ setLoading(true);
1144
+
1145
+ try {
1146
+ const response = await callHuggingFaceAPI(message, attachedFiles);
1147
+ addMessage(response, 'ai');
1148
+ } catch (error) {
1149
+ console.error('Error:', error);
1150
+ addMessage('Sorry, there was an error processing your request. Please try again.', 'ai');
1151
+ showNotification('Error: ' + error.message, 'error');
1152
+ } finally {
1153
+ setLoading(false);
1154
+ attachedFiles = [];
1155
+ updateFileDisplay();
1156
+ }
1157
+
1158
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1159
+ }
1160
+
1161
+ async function callHuggingFaceAPI(message, files) {
1162
+ const model = document.getElementById('modelSelect').value;
1163
+ const primaryPrompt = document.getElementById('primarySystemPrompt').value;
1164
+ const prefix = document.getElementById('promptPrefix').value;
1165
+ const suffix = document.getElementById('promptSuffix').value;
1166
+
1167
+ let fullPrompt = `${primaryPrompt}\n\n${prefix}\n\n${message}\n\n${suffix}`;
1168
+
1169
+ // Handle OCR for images if needed
1170
+ if (files.length > 0) {
1171
+ const ocrModel = document.getElementById('ocrModelSelect').value;
1172
+ if (ocrModel !== 'none') {
1173
+ for (const file of files) {
1174
+ if (file.type.startsWith('image/')) {
1175
+ try {
1176
+ const ocrText = await performOCR(file, ocrModel);
1177
+ fullPrompt += `\n\nExtracted text from image: ${ocrText}`;
1178
+ } catch (error) {
1179
+ console.warn('OCR failed:', error);
1180
+ }
1181
+ }
1182
+ }
1183
+ }
1184
+ }
1185
+
1186
+ const response = await fetch(`https://api-inference.huggingface.co/models/${model}`, {
1187
+ method: 'POST',
1188
+ headers: {
1189
+ 'Authorization': 'Bearer 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', // Replace with actual token
1190
+ 'Content-Type': 'application/json',
1191
+ },
1192
+ body: JSON.stringify({
1193
+ inputs: fullPrompt,
1194
+ parameters: {
1195
+ max_new_tokens: 2048,
1196
+ temperature: 0.7,
1197
+ top_p: 0.9,
1198
+ do_sample: true
1199
+ }
1200
+ })
1201
+ });
1202
+
1203
+ if (!response.ok) {
1204
+ throw new Error(`HTTP error! status: ${response.status}`);
1205
+ }
1206
+
1207
+ const data = await response.json();
1208
+
1209
+ if (data.error) {
1210
+ throw new Error(data.error);
1211
+ }
1212
+
1213
+ return data[0]?.generated_text || data.choices?.[0]?.message?.content || 'No response generated';
1214
+ }
1215
+
1216
+ async function performOCR(file, ocrModel) {
1217
+ const formData = new FormData();
1218
+ formData.append('file', file);
1219
+
1220
+ const response = await fetch(`https://api-inference.huggingface.co/models/${ocrModel}`, {
1221
+ method: 'POST',
1222
+ headers: {
1223
+ 'Authorization': 'Bearer hf_your_token_here', // Replace with actual token
1224
+ },
1225
+ body: formData
1226
+ });
1227
+
1228
+ if (!response.ok) {
1229
+ throw new Error(`OCR failed: ${response.status}`);
1230
+ }
1231
+
1232
+ const data = await response.json();
1233
+ return data.generated_text || data.text || 'Could not extract text';
1234
+ }
1235
+
1236
+ function addMessage(content, sender) {
1237
+ const chatContainer = document.getElementById('chatContainer');
1238
+ const messageDiv = document.createElement('div');
1239
+ messageDiv.className = `message ${sender}`;
1240
+
1241
+ if (sender === 'ai') {
1242
+ messageDiv.innerHTML = marked.parse(content);
1243
+ // Re-highlight code blocks
1244
+ messageDiv.querySelectorAll('pre code').forEach(block => {
1245
+ hljs.highlightElement(block);
1246
+ addCodeTools(block.parentElement);
1247
+ });
1248
+ } else {
1249
+ messageDiv.textContent = content;
1250
+ }
1251
+
1252
+ chatContainer.appendChild(messageDiv);
1253
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1254
+ }
1255
+
1256
+ function addImageMessage(imageUrl, sender) {
1257
+ const chatContainer = document.getElementById('chatContainer');
1258
+ const messageDiv = document.createElement('div');
1259
+ messageDiv.className = `message ${sender}`;
1260
+
1261
+ const img = document.createElement('img');
1262
+ img.src = imageUrl;
1263
+ img.className = 'image-preview';
1264
+ img.alt = 'Uploaded image';
1265
+
1266
+ messageDiv.appendChild(img);
1267
+ chatContainer.appendChild(messageDiv);
1268
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1269
+ }
1270
+
1271
+ function addCodeTools(preElement) {
1272
+ const toolsDiv = document.createElement('div');
1273
+ toolsDiv.className = 'code-tools';
1274
+
1275
+ const copyBtn = document.createElement('button');
1276
+ copyBtn.textContent = 'Copy';
1277
+ copyBtn.onclick = () => {
1278
+ navigator.clipboard.writeText(preElement.textContent);
1279
+ showNotification('Code copied to clipboard!', 'success');
1280
+ };
1281
+
1282
+ toolsDiv.appendChild(copyBtn);
1283
+ preElement.style.position = 'relative';
1284
+ preElement.appendChild(toolsDiv);
1285
+ }
1286
+
1287
+ function setLoading(loading) {
1288
+ isLoading = loading;
1289
+ const sendButton = document.getElementById('sendButton');
1290
+ const spinner = sendButton.querySelector('.spinner');
1291
+ const icon = sendButton.querySelector('.material-icons');
1292
+
1293
+ if (loading) {
1294
+ if (!spinner) {
1295
+ const spinnerDiv = document.createElement('div');
1296
+ spinnerDiv.className = 'spinner';
1297
+ sendButton.innerHTML = '';
1298
+ sendButton.appendChild(spinnerDiv);
1299
+ }
1300
+ sendButton.disabled = true;
1301
+ } else {
1302
+ sendButton.innerHTML = '<span class="material-icons">send</span>';
1303
+ sendButton.disabled = false;
1304
+ }
1305
+ }
1306
+
1307
+ // Utility functions
1308
+ function toggleSettings() {
1309
+ const settingsPanel = document.getElementById('settingsPanel');
1310
+ settingsPanel.classList.toggle('collapsed');
1311
+ }
1312
+
1313
+ function toggleFullscreen() {
1314
+ if (!document.fullscreenElement) {
1315
+ document.documentElement.requestFullscreen();
1316
+ } else {
1317
+ document.exitFullscreen();
1318
+ }
1319
+ }
1320
+
1321
+ function refreshApp() {
1322
+ location.reload();
1323
+ }
1324
+
1325
+ function showNotification(message, type) {
1326
+ const notification = document.getElementById(type === 'error' ? 'errorMessage' : 'successMessage');
1327
+ const textElement = document.getElementById(type === 'error' ? 'errorText' : 'successText');
1328
+
1329
+ textElement.textContent = message;
1330
+ notification.style.display = 'block';
1331
+
1332
+ setTimeout(() => {
1333
+ notification.style.display = 'none';
1334
+ }, 3000);
1335
+ }
1336
+ </script>
1337
+ </body>
1338
+ </html>