protae5544 commited on
Commit
6250849
·
verified ·
1 Parent(s): 1791341

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1266 -12
index.html CHANGED
@@ -1,13 +1,1267 @@
1
  <!DOCTYPE html>
2
- <html lang="">
3
- <head>
4
- <meta charset="UTF-8">
5
- <link rel="icon" href="/favicon.ico">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Vite App</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/src/main.ts"></script>
12
- </body>
13
- </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, maximum-scale=1.0, user-scalable=no">
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
+
364
+ .carousel-container {
365
+ perspective: 1200px;
366
+ height: 100%;
367
+ display: flex;
368
+ flex-direction: column;
369
+ align-items: center;
370
+ justify-content: center;
371
+ position: relative;
372
+ user-select: none;
373
+ padding: 24px;
374
+ }
375
+
376
+ .carousel {
377
+ position: relative;
378
+ width: 90%;
379
+ max-width: 500px;
380
+ height: 300px;
381
+ transform-style: preserve-3d;
382
+ transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1);
383
+ cursor: grab;
384
+ }
385
+
386
+ .carousel.dragging {
387
+ cursor: grabbing;
388
+ }
389
+
390
+ .carousel-card {
391
+ position: absolute;
392
+ width: 100%;
393
+ height: 100%;
394
+ background: var(--glass-bg);
395
+ backdrop-filter: blur(20px);
396
+ border: 1px solid var(--glass-border);
397
+ border-radius: 16px;
398
+ padding: 24px;
399
+ box-shadow: var(--shadow-lg);
400
+ display: flex;
401
+ flex-direction: column;
402
+ gap: 12px;
403
+ transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
404
+ }
405
+
406
+ .carousel-controls, .carousel-indicator {
407
+ display: flex;
408
+ gap: 16px;
409
+ margin-top: 24px;
410
+ }
411
+
412
+ .carousel-dot {
413
+ width: 14px;
414
+ height: 14px;
415
+ background: var(--bg-tertiary);
416
+ border-radius: 50%;
417
+ cursor: pointer;
418
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
419
+ border: 2px solid transparent;
420
+ }
421
+
422
+ .carousel-dot.active {
423
+ background: var(--accent-primary);
424
+ box-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
425
+ transform: scale(1.2);
426
+ }
427
+
428
+ .carousel-dot:hover {
429
+ transform: scale(1.1);
430
+ border-color: var(--accent-primary);
431
+ }
432
+
433
+ .mode-toggle {
434
+ display: flex;
435
+ background: var(--bg-secondary);
436
+ backdrop-filter: blur(15px);
437
+ border-radius: 20px;
438
+ padding: 4px;
439
+ position: relative;
440
+ margin-bottom: 20px;
441
+ border: 1px solid var(--glass-border);
442
+ }
443
+
444
+ .mode-toggle button {
445
+ flex: 1;
446
+ padding: 12px 20px;
447
+ background: none;
448
+ border: none;
449
+ color: var(--text-secondary);
450
+ cursor: pointer;
451
+ z-index: 1;
452
+ font-size: 1rem;
453
+ font-weight: 600;
454
+ border-radius: 16px;
455
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
456
+ }
457
+
458
+ .mode-toggle button.active {
459
+ color: var(--text-primary);
460
+ }
461
+
462
+ .mode-toggle-slider {
463
+ position: absolute;
464
+ top: 4px;
465
+ left: 4px;
466
+ height: calc(100% - 8px);
467
+ background: var(--gradient-primary);
468
+ border-radius: 16px;
469
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
470
+ box-shadow: 0 4px 15px rgba(0, 212, 255, 0.3);
471
+ }
472
+
473
+ .dropzone {
474
+ position: absolute;
475
+ top: 0;
476
+ left: 0;
477
+ right: 0;
478
+ bottom: 0;
479
+ background: rgba(0, 212, 255, 0.1);
480
+ backdrop-filter: blur(20px);
481
+ border: 3px dashed var(--accent-primary);
482
+ display: none;
483
+ align-items: center;
484
+ justify-content: center;
485
+ color: var(--text-primary);
486
+ font-size: 1.4rem;
487
+ font-weight: 600;
488
+ z-index: 10;
489
+ border-radius: 20px;
490
+ }
491
+
492
+ .dropzone.active {
493
+ display: flex;
494
+ animation: pulse 2s infinite;
495
+ }
496
+
497
+ @keyframes pulse {
498
+ 0%, 100% { opacity: 0.7; }
499
+ 50% { opacity: 1; }
500
+ }
501
+
502
+ .file-name {
503
+ font-size: 1rem;
504
+ color: var(--accent-primary);
505
+ margin-left: 12px;
506
+ align-self: center;
507
+ max-width: 200px;
508
+ white-space: nowrap;
509
+ overflow: hidden;
510
+ text-overflow: ellipsis;
511
+ font-weight: 600;
512
+ }
513
+
514
+ .chip-container {
515
+ display: flex;
516
+ gap: 12px;
517
+ margin-bottom: 20px;
518
+ flex-wrap: wrap;
519
+ padding: 0 24px;
520
+ }
521
+
522
+ .chip {
523
+ padding: 10px 18px;
524
+ background: var(--glass-bg);
525
+ backdrop-filter: blur(15px);
526
+ border: 1px solid var(--glass-border);
527
+ border-radius: 20px;
528
+ font-size: 0.9rem;
529
+ font-weight: 600;
530
+ cursor: pointer;
531
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
532
+ color: var(--text-secondary);
533
+ }
534
+
535
+ .chip:hover {
536
+ background: var(--accent-primary);
537
+ color: var(--text-primary);
538
+ transform: translateY(-2px);
539
+ box-shadow: 0 6px 20px rgba(0, 212, 255, 0.4);
540
+ }
541
+
542
+ .floating-buttons {
543
+ position: absolute;
544
+ top: 20px;
545
+ right: 20px;
546
+ display: flex;
547
+ gap: 12px;
548
+ z-index: 100;
549
+ }
550
+
551
+ .floating-btn {
552
+ width: 48px;
553
+ height: 48px;
554
+ border-radius: 50%;
555
+ background: var(--glass-bg);
556
+ backdrop-filter: blur(15px);
557
+ border: 1px solid var(--glass-border);
558
+ display: flex;
559
+ align-items: center;
560
+ justify-content: center;
561
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
562
+ padding: 0;
563
+ }
564
+
565
+ .floating-btn:hover {
566
+ background: var(--accent-primary);
567
+ transform: translateY(-3px) scale(1.05);
568
+ box-shadow: 0 8px 25px rgba(0, 212, 255, 0.4);
569
+ }
570
+
571
+ .code-tools {
572
+ position: absolute;
573
+ top: 12px;
574
+ right: 12px;
575
+ display: flex;
576
+ gap: 8px;
577
+ }
578
+
579
+ .code-tools button {
580
+ padding: 6px 12px;
581
+ font-size: 0.85rem;
582
+ background: var(--glass-bg);
583
+ backdrop-filter: blur(10px);
584
+ border: 1px solid var(--glass-border);
585
+ }
586
+
587
+ pre {
588
+ position: relative;
589
+ background: var(--bg-secondary);
590
+ border: 1px solid var(--glass-border);
591
+ padding: 20px;
592
+ border-radius: 12px;
593
+ overflow-x: auto;
594
+ backdrop-filter: blur(10px);
595
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
596
+ }
597
+
598
+ code {
599
+ font-family: 'Fira Code', 'Consolas', monospace;
600
+ font-size: 0.9rem;
601
+ }
602
+
603
+ .image-preview {
604
+ max-width: 100%;
605
+ max-height: 300px;
606
+ border-radius: 12px;
607
+ margin-top: 12px;
608
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
609
+ }
610
+
611
+ @keyframes fadeInUp {
612
+ from {
613
+ opacity: 0;
614
+ transform: translateY(30px);
615
+ }
616
+ to {
617
+ opacity: 1;
618
+ transform: translateY(0);
619
+ }
620
+ }
621
+
622
+ @media (max-width: 768px) {
623
+ .app-container {
624
+ flex-direction: column;
625
+ height: auto;
626
+ min-height: 100vh;
627
+ border-radius: 0;
628
+ width: 100%;
629
+ }
630
+
631
+ .settings-panel {
632
+ width: 100%;
633
+ max-height: 40vh;
634
+ border-right: none;
635
+ border-bottom: 1px solid var(--glass-border);
636
+ }
637
+
638
+ .settings-panel.collapsed {
639
+ max-height: 0;
640
+ }
641
+
642
+ .chat-container {
643
+ max-height: 50vh;
644
+ padding: 16px;
645
+ }
646
+
647
+ .input-container {
648
+ flex-wrap: wrap;
649
+ gap: 12px;
650
+ padding: 16px;
651
+ }
652
+
653
+ #userInput {
654
+ width: 100%;
655
+ margin-bottom: 12px;
656
+ min-height: 50px;
657
+ }
658
+
659
+ #sendButton, #attachButton {
660
+ width: 56px;
661
+ height: 56px;
662
+ }
663
+
664
+ .carousel {
665
+ width: 95%;
666
+ height: 250px;
667
+ }
668
+
669
+ .floating-buttons {
670
+ top: 12px;
671
+ right: 12px;
672
+ }
673
+
674
+ .floating-btn {
675
+ width: 44px;
676
+ height: 44px;
677
+ }
678
+
679
+ .material-icons {
680
+ font-size: 24px;
681
+ }
682
+ }
683
+
684
+ @media (max-width: 480px) {
685
+ .chip-container {
686
+ padding: 0 16px;
687
+ }
688
+
689
+ .chip {
690
+ font-size: 0.8rem;
691
+ padding: 8px 14px;
692
+ }
693
+
694
+ .form-field select, .form-field textarea, #userInput {
695
+ font-size: 16px;
696
+ }
697
+ }
698
+ </style>
699
+ </head>
700
+ <body>
701
+ <div class="app-container" id="appContainer">
702
+ <div class="settings-panel" id="settingsPanel">
703
+ <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>
704
+ <div class="form-field">
705
+ <label>🤖 Main Model:</label>
706
+ <select id="modelSelect">
707
+ <option value="Qwen/Qwen2.5-Coder-32B-Instruct">Qwen2.5-Coder 32B (Code/Text)</option>
708
+ <option value="Qwen/Qwen2-VL-72B-Instruct">Qwen2-VL 72B (Text/Image)</option>
709
+ <option value="microsoft/Florence-2-large">Florence-2 Large (Text/Image)</option>
710
+ <option value="mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral 8x7B (Text)</option>
711
+ <option value="meta-llama/Llama-2-70b-chat-hf">Llama-2 70B (Chat)</option>
712
+ </select>
713
+ <p style="font-size: 0.8rem; color: var(--text-secondary); margin-top: 8px;">
714
+ 💡 Choose a model. Use VL or Florence for image processing.
715
+ </p>
716
+ </div>
717
+ <div class="form-field">
718
+ <label>👁️ OCR Model (for images):</label>
719
+ <select id="ocrModelSelect">
720
+ <option value="none">None</option>
721
+ <option value="scb10x/typhoon-v1.5x-72b-instruct">Typhoon 1.5x 72B</option>
722
+ <option value="microsoft/trocr-base-printed">TrOCR Base</option>
723
+ </select>
724
+ </div>
725
+ <button id="saveSettingsBtn">💾 Save Settings</button>
726
+ </div>
727
+ <div class="main-content">
728
+ <div class="floating-buttons">
729
+ <button id="settingsToggle" class="floating-btn">
730
+ <span class="material-icons">settings</span>
731
+ </button>
732
+ <button id="fullscreenToggle" class="floating-btn">
733
+ <span class="material-icons">fullscreen</span>
734
+ </button>
735
+ <button id="refreshBtn" class="floating-btn">
736
+ <span class="material-icons">refresh</span>
737
+ </button>
738
+ </div>
739
+
740
+ <div class="mode-toggle">
741
+ <button id="carouselModeBtn" class="active">🎛️ Prompt Editor</button>
742
+ <button id="chatModeBtn">💬 Chat</button>
743
+ <div class="mode-toggle-slider" id="modeToggleSlider"></div>
744
+ </div>
745
+
746
+ <div id="carouselMode">
747
+ <div class="carousel-container">
748
+ <div class="carousel" id="promptCarousel">
749
+ <div class="carousel-card" style="transform: rotateY(0deg) translateZ(500px);">
750
+ <label>🎯 Primary System Prompt:</label>
751
+ <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>
752
+ </div>
753
+ <div class="carousel-card" style="transform: rotateY(60deg) translateZ(500px); opacity: 0.8;">
754
+ <label>👁️ OCR System Prompt:</label>
755
+ <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>
756
+ </div>
757
+ <div class="carousel-card" style="transform: rotateY(120deg) translateZ(500px); opacity: 0.8;">
758
+ <label>💻 Code Template:</label>
759
+ <textarea id="codeTemplate" placeholder="Enter code formatting template...">```javascript
760
+ // Enhanced code implementation
761
+ function solution() {
762
+ // Your optimized code here
763
+ return result;
764
+ }
765
+ ```</textarea>
766
+ </div>
767
+ <div class="carousel-card" style="transform: rotateY(180deg) translateZ(500px); opacity: 0.8;">
768
+ <label>📋 Additional Instructions:</label>
769
+ <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>
770
+ </div>
771
+ <div class="carousel-card" style="transform: rotateY(240deg) translateZ(500px); opacity: 0.8;">
772
+ <label>🚀 Prompt Prefix:</label>
773
+ <textarea id="promptPrefix" placeholder="Enter text to prepend to all prompts...">Please analyze the following request carefully and provide a comprehensive solution:</textarea>
774
+ </div>
775
+ <div class="carousel-card" style="transform: rotateY(300deg) translateZ(500px); opacity: 0.8;">
776
+ <label>✨ Prompt Suffix:</label>
777
+ <textarea id="promptSuffix" placeholder="Enter text to append to all prompts...">Ensure your response is complete, accurate, and includes practical examples where applicable.</textarea>
778
+ </div>
779
+ </div>
780
+ <div class="carousel-controls">
781
+ <button id="prevCard"><span class="material-icons">chevron_left</span></button>
782
+ <button id="nextCard"><span class="material-icons">chevron_right</span></button>
783
+ </div>
784
+ <div class="carousel-indicator" id="carouselIndicator">
785
+ <div class="carousel-dot active" data-index="0"></div>
786
+ <div class="carousel-dot" data-index="1"></div>
787
+ <div class="carousel-dot" data-index="2"></div>
788
+ <div class="carousel-dot" data-index="3"></div>
789
+ <div class="carousel-dot" data-index="4"></div>
790
+ <div class="carousel-dot" data-index="5"></div>
791
+ </div>
792
+ <button id="applyPromptBtn" style="margin-top: 24px;">✅ Apply Prompts & Switch to Chat</button>
793
+ </div>
794
+ </div>
795
+
796
+ <div id="chatMode" style="display: none;">
797
+ <div class="chip-container" id="quickPrompts">
798
+ <span class="chip" data-prompt="Explain this code in detail">🔍 Explain Code</span>
799
+ <span class="chip" data-prompt="Generate a complete function">⚡ Generate Function</span>
800
+ <span class="chip" data-prompt="Debug and fix this issue">🐛 Debug Code</span>
801
+ <span class="chip" data-prompt="Optimize this for performance">🚀 Optimize</span>
802
+ <span class="chip" data-prompt="Add error handling">🛡️ Error Handling</span>
803
+ <span class="chip" data-prompt="Convert to modern syntax">✨ Modernize</span>
804
+ </div>
805
+ <div class="chat-container" id="chatContainer"></div>
806
+ <div class="input-container">
807
+ <button id="attachButton"><span class="material-icons">attach_file</span></button>
808
+ <input type="file" id="fileInput" multiple accept="image/*" style="display: none;">
809
+ <span class="file-name" id="fileName"></span>
810
+ <textarea id="userInput" placeholder="Type your message here... (Shift+Enter for new line)"></textarea>
811
+ <button id="sendButton"><span class="material-icons">send</span></button>
812
+ </div>
813
+ <div class="dropzone" id="dropzone">📁 Drop files here to attach them</div>
814
+ </div>
815
+
816
+ <div class="notification error-message" id="errorMessage">
817
+ <span id="errorText"></span>
818
+ </div>
819
+ <div class="notification success-message" id="successMessage">
820
+ <span id="successText"></span>
821
+ </div>
822
+ </div>
823
+ </div>
824
+
825
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
826
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script>
827
+ <script>
828
+ // Global variables
829
+ let attachedFiles = [];
830
+ let currentCarouselIndex = 0;
831
+ let isLoading = false;
832
+ let isDragging = false;
833
+
834
+ // Initialize the application
835
+ document.addEventListener('DOMContentLoaded', function() {
836
+ loadSettings();
837
+ setupEventListeners();
838
+ setupCarousel();
839
+ setupDropzone();
840
+ hljs.highlightAll();
841
+ });
842
+
843
+ // Settings management
844
+ function loadSettings() {
845
+ const settings = {
846
+ model: localStorage.getItem('selectedModel') || 'Qwen/Qwen2.5-Coder-32B-Instruct',
847
+ ocrModel: localStorage.getItem('selectedOcrModel') || 'none',
848
+ 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.',
849
+ 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.',
850
+ codeTemplate: localStorage.getItem('codeTemplate') || '```javascript\n// Enhanced code implementation\nfunction solution() {\n // Your optimized code here\n return result;\n}\n```',
851
+ 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.',
852
+ promptPrefix: localStorage.getItem('promptPrefix') || 'Please analyze the following request carefully and provide a comprehensive solution:',
853
+ promptSuffix: localStorage.getItem('promptSuffix') || 'Ensure your response is complete, accurate, and includes practical examples where applicable.'
854
+ };
855
+
856
+ document.getElementById('modelSelect').value = settings.model;
857
+ document.getElementById('ocrModelSelect').value = settings.ocrModel;
858
+ document.getElementById('primarySystemPrompt').value = settings.primarySystemPrompt;
859
+ document.getElementById('ocrSystemPrompt').value = settings.ocrSystemPrompt;
860
+ document.getElementById('codeTemplate').value = settings.codeTemplate;
861
+ document.getElementById('additionalInstructions').value = settings.additionalInstructions;
862
+ document.getElementById('promptPrefix').value = settings.promptPrefix;
863
+ document.getElementById('promptSuffix').value = settings.promptSuffix;
864
+ }
865
+
866
+ function saveSettings() {
867
+ localStorage.setItem('selectedModel', document.getElementById('modelSelect').value);
868
+ localStorage.setItem('selectedOcrModel', document.getElementById('ocrModelSelect').value);
869
+ localStorage.setItem('primarySystemPrompt', document.getElementById('primarySystemPrompt').value);
870
+ localStorage.setItem('ocrSystemPrompt', document.getElementById('ocrSystemPrompt').value);
871
+ localStorage.setItem('codeTemplate', document.getElementById('codeTemplate').value);
872
+ localStorage.setItem('additionalInstructions', document.getElementById('additionalInstructions').value);
873
+ localStorage.setItem('promptPrefix', document.getElementById('promptPrefix').value);
874
+ localStorage.setItem('promptSuffix', document.getElementById('promptSuffix').value);
875
+ showNotification('Settings saved successfully!', 'success');
876
+ }
877
+
878
+ // Event listeners setup
879
+ function setupEventListeners() {
880
+ // Mode toggle
881
+ document.getElementById('carouselModeBtn').addEventListener('click', () => switchMode('carousel'));
882
+ document.getElementById('chatModeBtn').addEventListener('click', () => switchMode('chat'));
883
+
884
+ // Settings
885
+ document.getElementById('saveSettingsBtn').addEventListener('click', saveSettings);
886
+ document.getElementById('settingsToggle').addEventListener('click', toggleSettings);
887
+
888
+ // Carousel controls
889
+ document.getElementById('prevCard').addEventListener('click', () => rotateCarousel(-1));
890
+ document.getElementById('nextCard').addEventListener('click', () => rotateCarousel(1));
891
+ document.getElementById('applyPromptBtn').addEventListener('click', applyPromptsAndSwitchToChat);
892
+
893
+ // Chat controls
894
+ document.getElementById('sendButton').addEventListener('click', sendMessage);
895
+ document.getElementById('attachButton').addEventListener('click', () => document.getElementById('fileInput').click());
896
+ document.getElementById('fileInput').addEventListener('change', handleFileSelect);
897
+ document.getElementById('userInput').addEventListener('keydown', handleKeyDown);
898
+
899
+ // Other controls
900
+ document.getElementById('fullscreenToggle').addEventListener('click', toggleFullscreen);
901
+ document.getElementById('refreshBtn').addEventListener('click', refreshApp);
902
+
903
+ // Quick prompts
904
+ document.querySelectorAll('.chip').forEach(chip => {
905
+ chip.addEventListener('click', (e) => {
906
+ const prompt = e.target.getAttribute('data-prompt');
907
+ document.getElementById('userInput').value = prompt;
908
+ document.getElementById('userInput').focus();
909
+ });
910
+ });
911
+
912
+ // Carousel dots
913
+ document.querySelectorAll('.carousel-dot').forEach(dot => {
914
+ dot.addEventListener('click', (e) => {
915
+ const index = parseInt(e.target.getAttribute('data-index'));
916
+ goToCarouselIndex(index);
917
+ });
918
+ });
919
+ }
920
+
921
+ // Mode switching
922
+ function switchMode(mode) {
923
+ const carouselMode = document.getElementById('carouselMode');
924
+ const chatMode = document.getElementById('chatMode');
925
+ const carouselBtn = document.getElementById('carouselModeBtn');
926
+ const chatBtn = document.getElementById('chatModeBtn');
927
+ const slider = document.getElementById('modeToggleSlider');
928
+
929
+ if (mode === 'carousel') {
930
+ carouselMode.style.display = 'block';
931
+ chatMode.style.display = 'none';
932
+ carouselBtn.classList.add('active');
933
+ chatBtn.classList.remove('active');
934
+ slider.style.width = '50%';
935
+ slider.style.left = '4px';
936
+ } else {
937
+ carouselMode.style.display = 'none';
938
+ chatMode.style.display = 'block';
939
+ carouselBtn.classList.remove('active');
940
+ chatBtn.classList.add('active');
941
+ slider.style.width = '50%';
942
+ slider.style.left = '50%';
943
+ }
944
+ }
945
+
946
+ // Carousel functionality
947
+ function setupCarousel() {
948
+ updateCarouselPosition();
949
+ }
950
+
951
+ function rotateCarousel(direction) {
952
+ const totalCards = 6;
953
+ currentCarouselIndex = (currentCarouselIndex + direction + totalCards) % totalCards;
954
+ updateCarouselPosition();
955
+ }
956
+
957
+ function goToCarouselIndex(index) {
958
+ currentCarouselIndex = index;
959
+ updateCarouselPosition();
960
+ }
961
+
962
+ function updateCarouselPosition() {
963
+ const carousel = document.getElementById('promptCarousel');
964
+ const cards = carousel.querySelectorAll('.carousel-card');
965
+ const dots = document.querySelectorAll('.carousel-dot');
966
+
967
+ cards.forEach((card, index) => {
968
+ const angle = (index - currentCarouselIndex) * 60;
969
+ const isActive = index === currentCarouselIndex;
970
+
971
+ card.style.transform = `rotateY(${angle}deg) translateZ(500px)`;
972
+ card.style.opacity = isActive ? '1' : '0.6';
973
+ card.style.zIndex = isActive ? '10' : '1';
974
+ });
975
+
976
+ dots.forEach((dot, index) => {
977
+ dot.classList.toggle('active', index === currentCarouselIndex);
978
+ });
979
+ }
980
+
981
+ function applyPromptsAndSwitchToChat() {
982
+ saveSettings();
983
+ switchMode('chat');
984
+ showNotification('Prompts applied successfully!', 'success');
985
+ }
986
+
987
+ // File handling
988
+ function setupDropzone() {
989
+ const dropzone = document.getElementById('dropzone');
990
+ const chatMode = document.getElementById('chatMode');
991
+
992
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
993
+ chatMode.addEventListener(eventName, preventDefaults, false);
994
+ });
995
+
996
+ function preventDefaults(e) {
997
+ e.preventDefault();
998
+ e.stopPropagation();
999
+ }
1000
+
1001
+ ['dragenter', 'dragover'].forEach(eventName => {
1002
+ chatMode.addEventListener(eventName, () => dropzone.classList.add('active'), false);
1003
+ });
1004
+
1005
+ ['dragleave', 'drop'].forEach(eventName => {
1006
+ chatMode.addEventListener(eventName, () => dropzone.classList.remove('active'), false);
1007
+ });
1008
+
1009
+ chatMode.addEventListener('drop', handleDrop, false);
1010
+ }
1011
+
1012
+ function handleDrop(e) {
1013
+ const dt = e.dataTransfer;
1014
+ const files = dt.files;
1015
+ handleFiles(files);
1016
+ }
1017
+
1018
+ function handleFileSelect(e) {
1019
+ const files = e.target.files;
1020
+ handleFiles(files);
1021
+ }
1022
+
1023
+ function handleFiles(files) {
1024
+ attachedFiles = Array.from(files);
1025
+ updateFileDisplay();
1026
+ }
1027
+
1028
+ function updateFileDisplay() {
1029
+ const fileName = document.getElementById('fileName');
1030
+ if (attachedFiles.length === 0) {
1031
+ fileName.textContent = '';
1032
+ } else if (attachedFiles.length === 1) {
1033
+ fileName.textContent = attachedFiles[0].name;
1034
+ } else {
1035
+ fileName.textContent = `${attachedFiles.length} files selected`;
1036
+ }
1037
+ }
1038
+
1039
+ // Chat functionality
1040
+ function handleKeyDown(e) {
1041
+ if (e.key === 'Enter' && !e.shiftKey) {
1042
+ e.preventDefault();
1043
+ sendMessage();
1044
+ }
1045
+ }
1046
+
1047
+ async function sendMessage() {
1048
+ const userInput = document.getElementById('userInput');
1049
+ const message = userInput.value.trim();
1050
+
1051
+ if (!message && attachedFiles.length === 0) return;
1052
+ if (isLoading) return;
1053
+
1054
+ const chatContainer = document.getElementById('chatContainer');
1055
+
1056
+ // Add user message
1057
+ if (message) {
1058
+ addMessage(message, 'user');
1059
+ }
1060
+
1061
+ // Add file previews
1062
+ if (attachedFiles.length > 0) {
1063
+ for (const file of attachedFiles) {
1064
+ if (file.type.startsWith('image/')) {
1065
+ const imageUrl = URL.createObjectURL(file);
1066
+ addImageMessage(imageUrl, 'user');
1067
+ }
1068
+ }
1069
+ }
1070
+
1071
+ userInput.value = '';
1072
+ setLoading(true);
1073
+
1074
+ try {
1075
+ const response = await callHuggingFaceAPI(message, attachedFiles);
1076
+ addMessage(response, 'ai');
1077
+ } catch (error) {
1078
+ console.error('Error:', error);
1079
+ addMessage('Sorry, there was an error processing your request. Please try again.', 'ai');
1080
+ showNotification('Error: ' + error.message, 'error');
1081
+ } finally {
1082
+ setLoading(false);
1083
+ attachedFiles = [];
1084
+ updateFileDisplay();
1085
+ }
1086
+
1087
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1088
+ }
1089
+
1090
+ async function callHuggingFaceAPI(message, files) {
1091
+ const model = document.getElementById('modelSelect').value;
1092
+ const primaryPrompt = document.getElementById('primarySystemPrompt').value;
1093
+ const prefix = document.getElementById('promptPrefix').value;
1094
+ const suffix = document.getElementById('promptSuffix').value;
1095
+
1096
+ let fullPrompt = `${primaryPrompt}\n\n${prefix}\n\n${message}\n\n${suffix}`;
1097
+
1098
+ // Handle OCR for images if needed
1099
+ if (files.length > 0) {
1100
+ const ocrModel = document.getElementById('ocrModelSelect').value;
1101
+ if (ocrModel !== 'none') {
1102
+ for (const file of files) {
1103
+ if (file.type.startsWith('image/')) {
1104
+ try {
1105
+ const ocrText = await performOCR(file, ocrModel);
1106
+ fullPrompt += `\n\nExtracted text from image: ${ocrText}`;
1107
+ } catch (error) {
1108
+ console.warn('OCR failed:', error);
1109
+ }
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ const response = await fetch(`https://api-inference.huggingface.co/models/${model}`, {
1116
+ method: 'POST',
1117
+ headers: {
1118
+ 'Authorization': 'Bearer hf_your_token_here', // Replace with actual token
1119
+ 'Content-Type': 'application/json',
1120
+ },
1121
+ body: JSON.stringify({
1122
+ inputs: fullPrompt,
1123
+ parameters: {
1124
+ max_new_tokens: 2048,
1125
+ temperature: 0.7,
1126
+ top_p: 0.9,
1127
+ do_sample: true
1128
+ }
1129
+ })
1130
+ });
1131
+
1132
+ if (!response.ok) {
1133
+ throw new Error(`HTTP error! status: ${response.status}`);
1134
+ }
1135
+
1136
+ const data = await response.json();
1137
+
1138
+ if (data.error) {
1139
+ throw new Error(data.error);
1140
+ }
1141
+
1142
+ return data[0]?.generated_text || data.choices?.[0]?.message?.content || 'No response generated';
1143
+ }
1144
+
1145
+ async function performOCR(file, ocrModel) {
1146
+ const formData = new FormData();
1147
+ formData.append('file', file);
1148
+
1149
+ const response = await fetch(`https://api-inference.huggingface.co/models/${ocrModel}`, {
1150
+ method: 'POST',
1151
+ headers: {
1152
+ 'Authorization': 'Bearer hf_your_token_here', // Replace with actual token
1153
+ },
1154
+ body: formData
1155
+ });
1156
+
1157
+ if (!response.ok) {
1158
+ throw new Error(`OCR failed: ${response.status}`);
1159
+ }
1160
+
1161
+ const data = await response.json();
1162
+ return data.generated_text || data.text || 'Could not extract text';
1163
+ }
1164
+
1165
+ function addMessage(content, sender) {
1166
+ const chatContainer = document.getElementById('chatContainer');
1167
+ const messageDiv = document.createElement('div');
1168
+ messageDiv.className = `message ${sender}`;
1169
+
1170
+ if (sender === 'ai') {
1171
+ messageDiv.innerHTML = marked.parse(content);
1172
+ // Re-highlight code blocks
1173
+ messageDiv.querySelectorAll('pre code').forEach(block => {
1174
+ hljs.highlightElement(block);
1175
+ addCodeTools(block.parentElement);
1176
+ });
1177
+ } else {
1178
+ messageDiv.textContent = content;
1179
+ }
1180
+
1181
+ chatContainer.appendChild(messageDiv);
1182
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1183
+ }
1184
+
1185
+ function addImageMessage(imageUrl, sender) {
1186
+ const chatContainer = document.getElementById('chatContainer');
1187
+ const messageDiv = document.createElement('div');
1188
+ messageDiv.className = `message ${sender}`;
1189
+
1190
+ const img = document.createElement('img');
1191
+ img.src = imageUrl;
1192
+ img.className = 'image-preview';
1193
+ img.alt = 'Uploaded image';
1194
+
1195
+ messageDiv.appendChild(img);
1196
+ chatContainer.appendChild(messageDiv);
1197
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1198
+ }
1199
+
1200
+ function addCodeTools(preElement) {
1201
+ const toolsDiv = document.createElement('div');
1202
+ toolsDiv.className = 'code-tools';
1203
+
1204
+ const copyBtn = document.createElement('button');
1205
+ copyBtn.textContent = 'Copy';
1206
+ copyBtn.onclick = () => {
1207
+ navigator.clipboard.writeText(preElement.textContent);
1208
+ showNotification('Code copied to clipboard!', 'success');
1209
+ };
1210
+
1211
+ toolsDiv.appendChild(copyBtn);
1212
+ preElement.style.position = 'relative';
1213
+ preElement.appendChild(toolsDiv);
1214
+ }
1215
+
1216
+ function setLoading(loading) {
1217
+ isLoading = loading;
1218
+ const sendButton = document.getElementById('sendButton');
1219
+ const spinner = sendButton.querySelector('.spinner');
1220
+ const icon = sendButton.querySelector('.material-icons');
1221
+
1222
+ if (loading) {
1223
+ if (!spinner) {
1224
+ const spinnerDiv = document.createElement('div');
1225
+ spinnerDiv.className = 'spinner';
1226
+ sendButton.innerHTML = '';
1227
+ sendButton.appendChild(spinnerDiv);
1228
+ }
1229
+ sendButton.disabled = true;
1230
+ } else {
1231
+ sendButton.innerHTML = '<span class="material-icons">send</span>';
1232
+ sendButton.disabled = false;
1233
+ }
1234
+ }
1235
+
1236
+ // Utility functions
1237
+ function toggleSettings() {
1238
+ const settingsPanel = document.getElementById('settingsPanel');
1239
+ settingsPanel.classList.toggle('collapsed');
1240
+ }
1241
+
1242
+ function toggleFullscreen() {
1243
+ if (!document.fullscreenElement) {
1244
+ document.documentElement.requestFullscreen();
1245
+ } else {
1246
+ document.exitFullscreen();
1247
+ }
1248
+ }
1249
+
1250
+ function refreshApp() {
1251
+ location.reload();
1252
+ }
1253
+
1254
+ function showNotification(message, type) {
1255
+ const notification = document.getElementById(type === 'error' ? 'errorMessage' : 'successMessage');
1256
+ const textElement = document.getElementById(type === 'error' ? 'errorText' : 'successText');
1257
+
1258
+ textElement.textContent = message;
1259
+ notification.style.display = 'block';
1260
+
1261
+ setTimeout(() => {
1262
+ notification.style.display = 'none';
1263
+ }, 3000);
1264
+ }
1265
+ </script>
1266
+ </body>
1267
+ </html>