abdullahalioo commited on
Commit
8fb6c06
·
verified ·
1 Parent(s): 36759db

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -1948
index.html CHANGED
@@ -1,1948 +0,0 @@
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>Orion AI Assistant</title>
7
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
- <style>
9
- .settings-sidebar.active {
10
- transform: translateX(0);
11
- opacity: 1;
12
- }
13
-
14
- .settings-overlay.active {
15
- opacity: 1;
16
- visibility: visible;
17
- }
18
- ::-webkit-scrollbar {
19
- display: none;
20
- }
21
-
22
- * {
23
- -ms-overflow-style: none;
24
- scrollbar-width: none;
25
- }
26
-
27
- :root {
28
- --primary: #6366f1;
29
- --primary-dark: #4f46e5;
30
- --secondary: #f43f5e;
31
- --dark: #1e293b;
32
- --light: #f8fafc;
33
- --gray: #94a3b8;
34
- --success: #10b981;
35
- --warning: #f59e0b;
36
- --error: #ef4444;
37
- --border: #e2e8f0;
38
- --dark-bg: #0f172a;
39
- --dark-text: #e2e8f0;
40
- --dark-border: #334155;
41
- --think-bg: #e5e7eb;
42
- --think-text: #6b7280;
43
- --think-dark-bg: #4b5563;
44
- --think-dark-text: #d1d5db;
45
- }
46
-
47
- * {
48
- margin: 0;
49
- padding: 0;
50
- box-sizing: border-box;
51
- font-family: 'Segoe UI', system-ui, sans-serif;
52
- }
53
-
54
- body {
55
- background-color: #f1f5f9;
56
- color: var(--dark);
57
- min-height: 100vh;
58
- display: flex;
59
- flex-direction: column;
60
- scrollbar-width: none;
61
- position: relative;
62
- }
63
-
64
- body.dark-mode {
65
- background-color: var(--dark-bg);
66
- color: var(--dark-text);
67
- }
68
-
69
- body::-webkit-scrollbar {
70
- display: none;
71
- }
72
-
73
- .app-container {
74
- max-width: 1250px;
75
- width: 100%;
76
- margin: 0 auto;
77
- padding: 1rem;
78
- flex: 1;
79
- display: flex;
80
- flex-direction: column;
81
- }
82
-
83
- header {
84
- display: flex;
85
- justify-content: space-between;
86
- align-items: center;
87
- padding: 0.5rem 0;
88
- margin-bottom: 1rem;
89
- position: relative;
90
- }
91
-
92
- .mobile-menu-btn {
93
- display: none;
94
- background: none;
95
- border: none;
96
- font-size: 1.5rem;
97
- color: var(--dark);
98
- cursor: pointer;
99
- padding: 0.5rem;
100
- }
101
-
102
- .mobile-menu-btn.dark-mode {
103
- color: var(--dark-text);
104
- }
105
-
106
- .logo {
107
- display: flex;
108
- align-items: center;
109
- gap: 0.75rem;
110
- font-weight: 700;
111
- font-size: 1.5rem;
112
- color: var(--primary);
113
- }
114
-
115
- .logo i {
116
- font-size: 1.75rem;
117
- }
118
-
119
- .settings-btn {
120
- background: none;
121
- border: none;
122
- font-size: 1.25rem;
123
- color: var(--dark);
124
- cursor: pointer;
125
- transition: color 0.2s;
126
- padding-right: 7px;
127
- }
128
-
129
- .settings-btn.dark-mode {
130
- color: var(--dark-text);
131
- }
132
-
133
- .settings-btn:hover {
134
- color: var(--primary);
135
- }
136
-
137
- .main-content {
138
- display: flex;
139
- flex: 1;
140
- gap: 1rem;
141
- position: relative;
142
- }
143
-
144
- .sidebar {
145
- width: 250px;
146
- background-color: white;
147
- border-radius: 1rem;
148
- padding: 1rem;
149
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
150
- display: flex;
151
- flex-direction: column;
152
- transition: transform 0.3s ease, opacity 0.3s ease;
153
- }
154
-
155
- .settings-sidebar {
156
- width: 250px;
157
- background-color: white;
158
- border-radius: 1rem;
159
- padding: 1rem;
160
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
161
- display: flex;
162
- flex-direction: column;
163
- transition: transform 0.3s ease, opacity 0.3s ease;
164
- position: fixed;
165
- top: 0;
166
- right: 0;
167
- height: 100vh;
168
- transform: translateX(100%);
169
- opacity: 0;
170
- z-index: 999;
171
- }
172
-
173
- .sidebar.dark-mode, .settings-sidebar.dark-mode {
174
- background-color: var(--dark);
175
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
176
- }
177
-
178
- .sidebar.active, .settings-sidebar.active {
179
- transform: translateX(0);
180
- opacity: 1;
181
- }
182
-
183
- .sidebar-header, .settings-header {
184
- display: flex;
185
- align-items: center;
186
- margin-bottom: 1rem;
187
- position: relative;
188
- gap: 2rem;
189
- }
190
-
191
- .sidebar-title, .settings-title {
192
- font-weight: 600;
193
- font-size: 1rem;
194
- flex-grow: 1;
195
- color: var(--dark);
196
- }
197
-
198
- .sidebar-title.dark-mode, .settings-title.dark-mode {
199
- color: var(--dark-text);
200
- }
201
-
202
- .close-sidebar-btn, .close-settings-btn {
203
- background: none;
204
- border: none;
205
- font-size: 1.25rem;
206
- color: var(--dark);
207
- cursor: pointer;
208
- display: none;
209
- padding: 0.5rem;
210
- }
211
-
212
- .close-sidebar-btn.dark-mode, .close-settings-btn.dark-mode {
213
- color: var(--dark-text);
214
- }
215
-
216
- .close-sidebar-btn:hover, .close-settings-btn:hover {
217
- color: var(--primary);
218
- }
219
-
220
- .new-chat-btn {
221
- background-color: var(--primary);
222
- color: white;
223
- border: none;
224
- border-radius: 0.5rem;
225
- padding: 0.5rem;
226
- cursor: pointer;
227
- transition: background-color 0.2s;
228
- width: 100%;
229
- height: 2rem;
230
- font-size: 1rem;
231
- display: flex;
232
- align-items: center;
233
- justify-content: center;
234
- }
235
-
236
- .new-chat-btn:hover {
237
- background-color: var(--primary-dark);
238
- }
239
-
240
- .chat-list {
241
- flex: 1;
242
- overflow-y: auto;
243
- margin-bottom: 1rem;
244
- }
245
-
246
- .chat-item {
247
- position: relative;
248
- padding: 0.75rem;
249
- border-radius: 0.5rem;
250
- cursor: pointer;
251
- margin-bottom: 0.25rem;
252
- white-space: nowrap;
253
- overflow: hidden;
254
- text-overflow: ellipsis;
255
- transition: background-color 0.2s;
256
- color: var(--dark);
257
- }
258
-
259
- .chat-item:hover {
260
- background-color: #f1f5f9;
261
- }
262
-
263
- .chat-item.active {
264
- background-color: #e0e7ff;
265
- color: var(--primary);
266
- font-weight: 500;
267
- }
268
-
269
- .chat-item.dark-mode {
270
- color: var(--dark-text);
271
- }
272
-
273
- .chat-item.dark-mode:hover {
274
- background-color: var(--dark-border);
275
- }
276
-
277
- .chat-item.active.dark-mode {
278
- background-color: var(--dark-border);
279
- color: var(--dark-text);
280
- font-weight: 500;
281
- }
282
-
283
- .bin-button {
284
- position: absolute;
285
- top: 50%;
286
- right: 10px;
287
- transform: translateY(-50%);
288
- display: flex;
289
- flex-direction: column;
290
- align-items: center;
291
- justify-content: center;
292
- width: 20px;
293
- height: 20px;
294
- border-radius: 5px;
295
- background-color: #f5f5f5;
296
- cursor: pointer;
297
- border: 2px solid var(--primary);
298
- transition-duration: 0.3s;
299
- }
300
-
301
- .bin-button.dark-mode {
302
- background-color: var(--dark-border);
303
- border-color: var(--primary);
304
- }
305
-
306
- .bin-bottom {
307
- width: 7px;
308
- height: 7px;
309
- background-color: var(--primary);
310
- border-radius: 1px;
311
- }
312
-
313
- .bin-top {
314
- width: 8px;
315
- height: 1px;
316
- background-color: var(--primary);
317
- transform-origin: right;
318
- transition-duration: 0.3s;
319
- }
320
-
321
- .bin-button:hover .bin-top {
322
- transform: rotate(45deg);
323
- }
324
-
325
- .bin-button:hover {
326
- background-color: #ffffff;
327
- }
328
-
329
- .bin-button.dark-mode:hover {
330
- background-color: var(--dark-text);
331
- }
332
-
333
- .chat-container {
334
- flex: 1;
335
- display: flex;
336
- flex-direction: column;
337
- background-color: white;
338
- border-radius: 1rem;
339
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
340
- overflow: hidden;
341
- }
342
-
343
- .chat-container.dark-mode {
344
- background-color: var(--dark);
345
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
346
- }
347
-
348
- .chat-messages {
349
- flex: 1;
350
- padding: 1.5rem;
351
- overflow-y: auto;
352
- display: flex;
353
- flex-direction: column;
354
- gap: 1.5rem;
355
- scrollbar-width: none;
356
- }
357
-
358
- .chat-messages::-webkit-scrollbar {
359
- display: none;
360
- }
361
-
362
- .message {
363
- display: flex;
364
- gap: 1rem;
365
- max-width: 80%;
366
- }
367
-
368
- .message-user {
369
- align-self: flex-end;
370
- flex-direction: row-reverse;
371
- }
372
-
373
- .message-ai {
374
- align-self: flex-start;
375
- }
376
-
377
- .avatar {
378
- width: 2.5rem;
379
- height: 2.5rem;
380
- border-radius: 50%;
381
- display: flex;
382
- align-items: center;
383
- justify-content: center;
384
- flex-shrink: 0;
385
- font-size: 1.25rem;
386
- }
387
-
388
- .avatar-user {
389
- background-color: var(--primary);
390
- color: white;
391
- }
392
-
393
- .avatar-ai {
394
- background-color: #e0e7ff;
395
- color: var(--primary);
396
- }
397
-
398
- .message-content {
399
- display: flex;
400
- flex-direction: column;
401
- gap: 0.5rem;
402
- }
403
-
404
- .message-text {
405
- padding: 0.75rem 1rem;
406
- border-radius: 1rem;
407
- line-height: 1.5;
408
- font-size: 0.95rem;
409
- }
410
-
411
- .message-user .message-text {
412
- background-color: var(--primary);
413
- color: white;
414
- border-bottom-right-radius: 0.25rem;
415
- }
416
-
417
- .message-ai .message-text {
418
- background-color: #f8fafc;
419
- border: 1px solid var(--border);
420
- border-bottom-left-radius: 0.25rem;
421
- }
422
-
423
- .message-ai .message-text.dark-mode {
424
- background-color: var(--dark-border);
425
- border-color: var(--dark-border);
426
- color: var(--dark-text);
427
- }
428
-
429
- .message-meta {
430
- display: flex;
431
- align-items: center;
432
- gap: 0.5rem;
433
- font-size: 0.75rem;
434
- color: var(--gray);
435
- }
436
-
437
- .message-ai .message-meta {
438
- justify-content: flex-start;
439
- }
440
-
441
- .message-user .message-meta {
442
- justify-content: flex-end;
443
- }
444
-
445
- .input-container {
446
- padding: 1rem;
447
- border-top: 1px solid var(--border);
448
- background-color: white;
449
- }
450
-
451
- .input-container.dark-mode {
452
- border-top-color: var(--dark-border);
453
- background-color: var(--dark);
454
- }
455
-
456
- .suggestions {
457
- display: flex;
458
- flex-wrap: wrap;
459
- gap: 0.5rem;
460
- margin-bottom: 1rem;
461
- }
462
-
463
- .suggestion-chip {
464
- padding: 0.5rem 0.75rem;
465
- background-color: #f1f5f9;
466
- border-radius: 1rem;
467
- font-size: 0.875rem;
468
- cursor: pointer;
469
- transition: background-color 0.2s;
470
- }
471
-
472
- .suggestion-chip.dark-mode {
473
- background-color: var(--dark-border);
474
- color: var(--dark-text);
475
- }
476
-
477
- .suggestion-chip:hover {
478
- background-color: #e2e8f0;
479
- }
480
-
481
- .suggestion-chip.dark-mode:hover {
482
- background-color: #475569;
483
- }
484
-
485
- .input-box {
486
- display: flex;
487
- gap: 0.5rem;
488
- position: relative;
489
- }
490
-
491
- .input-field {
492
- flex: 1;
493
- padding: 0.75rem 1rem;
494
- border: 1px solid var(--border);
495
- border-radius: 0.75rem;
496
- font-size: 1rem;
497
- outline: none;
498
- transition: border-color 0.2s, box-shadow 0.2s, padding 0.2s;
499
- }
500
-
501
- .input-field.with-image {
502
- padding: 0.75rem 1rem 0.75rem 2.5rem;
503
- }
504
-
505
- .input-field.dark-mode {
506
- border-color: var(--dark-border);
507
- background-color: var(--dark);
508
- color: var(--dark-text);
509
- }
510
-
511
- .input-field:focus {
512
- border-color: var(--primary);
513
- box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
514
- }
515
-
516
- .input-image-preview {
517
- position: absolute;
518
- left: 0.5rem;
519
- top: 50%;
520
- transform: translateY(-50%);
521
- height: 30px;
522
- width: 30px;
523
- object-fit: cover;
524
- border-radius: 4px;
525
- display: none;
526
- }
527
-
528
- .image-remove-icon {
529
- position: absolute;
530
- left: 26px;
531
- top: 6px;
532
- font-size: 12px;
533
- color: var(--error);
534
- background-color: white;
535
- border-radius: 50%;
536
- width: 16px;
537
- height: 16px;
538
- display: none;
539
- align-items: center;
540
- justify-content: center;
541
- cursor: pointer;
542
- transition: background-color 0.2s;
543
- }
544
-
545
- .image-remove-icon.dark-mode {
546
- background-color: var(--dark);
547
- color: var(--error);
548
- }
549
-
550
- .image-remove-icon:hover {
551
- background-color: #f1f5f9;
552
- }
553
-
554
- .image-remove-icon.dark-mode:hover {
555
- background-color: var(--dark-border);
556
- }
557
-
558
- .send-btn {
559
- padding: 0 1.25rem;
560
- background-color: var(--primary);
561
- color: white;
562
- border: none;
563
- border-radius: 0.75rem;
564
- cursor: pointer;
565
- transition: background-color 0.2s;
566
- }
567
-
568
- .send-btn:hover {
569
- background-color: var(--primary-dark);
570
- }
571
-
572
- .send-btn:disabled {
573
- background-color: var(--gray);
574
- cursor: not-allowed;
575
- }
576
-
577
- .action-buttons {
578
- display: flex;
579
- gap: 0.5rem;
580
- margin-top: 0.5rem;
581
- }
582
-
583
- .action-btn {
584
- padding: 0.5rem 0.75rem;
585
- background-color: #f1f5f9;
586
- border: none;
587
- border-radius: 0.5rem;
588
- font-size: 0.875rem;
589
- color: var(--dark);
590
- cursor: pointer;
591
- transition: background-color 0.2s;
592
- display: flex;
593
- align-items: center;
594
- gap: 0.25rem;
595
- }
596
-
597
- .action-btn.dark-mode {
598
- background-color: var(--dark-border);
599
- color: var(--dark-text);
600
- }
601
-
602
- .action-btn:hover {
603
- background-color: #e2e8f0;
604
- }
605
-
606
- .action-btn.dark-mode:hover {
607
- background-color: #475569;
608
- }
609
-
610
- .action-btn i {
611
- font-size: 0.875rem;
612
- }
613
-
614
- .chat-footer {
615
- text-align: center;
616
- padding: 0.5rem;
617
- font-size: 0.875rem;
618
- color: var(--dark);
619
- background-color: white;
620
- border-top: 1px solid var(--border);
621
- }
622
-
623
- .chat-footer.dark-mode {
624
- color: var(--dark-text);
625
- background-color: var(--dark);
626
- border-top-color: var(--dark-border);
627
- }
628
-
629
- .code-block {
630
- position: relative;
631
- background-color: #1e293b;
632
- color: #f8fafc;
633
- border-radius: 0.5rem;
634
- padding: 1rem;
635
- margin: 0.5rem 0;
636
- font-family: 'Courier New', Courier, monospace;
637
- font-size: 0.875rem;
638
- line-height: 1.5;
639
- overflow-x: auto;
640
- }
641
-
642
- .code-block.dark-mode {
643
- background-color: #1e293b;
644
- color: #f8fafc;
645
- }
646
-
647
- .code-block pre {
648
- margin: 0;
649
- white-space: pre-wrap;
650
- word-break: break-word;
651
- }
652
-
653
- .code-block .language-label {
654
- position: absolute;
655
- top: 0.25rem;
656
- right: 0.5rem;
657
- font-size: 0.75rem;
658
- color: #94a3b8;
659
- }
660
-
661
- .copy-btn {
662
- position: absolute;
663
- top: 0.25rem;
664
- right: 0.5rem;
665
- background-color: #334155;
666
- color: white;
667
- border: none;
668
- border-radius: 0.25rem;
669
- padding: 0.25rem 0.5rem;
670
- font-size: 0.75rem;
671
- cursor: pointer;
672
- display: flex;
673
- align-items: center;
674
- gap: 0.25rem;
675
- transition: background-color 0.2s;
676
- }
677
-
678
- .copy-btn:hover {
679
- background-color: #475569;
680
- }
681
-
682
- .copy-btn i {
683
- font-size: 0.75rem;
684
- }
685
-
686
- .typing-indicator {
687
- display: flex;
688
- align-items: center;
689
- gap: 0.3rem;
690
- padding: 0.75rem 1rem;
691
- background-color: #f8fafc;
692
- border: 1px solid var(--border);
693
- border-radius: 1rem;
694
- border-bottom-left-radius: 0.25rem;
695
- max-width: 80%;
696
- align-self: flex-start;
697
- margin: 0.5rem 1.5rem;
698
- }
699
-
700
- .typing-indicator.dark-mode {
701
- background-color: var(--dark-border);
702
- border-color: var(--dark-border);
703
- }
704
-
705
- .typing-dot {
706
- width: 8px;
707
- height: 8px;
708
- background-color: var(--primary);
709
- border-radius: 50%;
710
- animation: typing 1s infinite ease-in-out;
711
- }
712
-
713
- .typing-dot:nth-child(2) {
714
- animation-delay: 0.2s;
715
- }
716
-
717
- .typing-dot:nth-child(3) {
718
- animation-delay: 0.4s;
719
- }
720
-
721
- @keyframes typing {
722
- 0%, 100% {
723
- transform: translateY(0);
724
- opacity: 0.5;
725
- }
726
- 50% {
727
- transform: translateY(-5px);
728
- opacity: 1;
729
- }
730
- }
731
-
732
- .message-text ul,
733
- .message-text ol {
734
- padding-left: 1.5rem;
735
- margin: 0.5rem 0;
736
- }
737
-
738
- .message-text li {
739
- margin-bottom: 0.25rem;
740
- }
741
-
742
- .message-text h1,
743
- .message-text h2,
744
- .message-text h3,
745
- .message-text h4 {
746
- margin: 0.75rem 0 0.5rem 0;
747
- font-weight: 600;
748
- }
749
-
750
- .message-text h1 {
751
- font-size: 1.5rem;
752
- }
753
-
754
- .message-text h2 {
755
- font-size: 1.3rem;
756
- }
757
-
758
- .message-text h3 {
759
- font-size: 1.1rem;
760
- }
761
-
762
- .message-text h4 {
763
- font-size: 1rem;
764
- }
765
-
766
- .message-text p {
767
- margin-bottom: 0.75rem;
768
- line-height: 1.6;
769
- }
770
-
771
- .message-text strong {
772
- font-weight: 600;
773
- }
774
-
775
- .message-text em {
776
- font-style: italic;
777
- }
778
-
779
- .message-text blockquote {
780
- border-left: 3px solid var(--primary);
781
- padding-left: 1rem;
782
- margin: 0.5rem 0;
783
- color: var(--dark);
784
- opacity: 0.8;
785
- }
786
-
787
- .message-text blockquote.dark-mode {
788
- color: var(--dark-text);
789
- }
790
-
791
- .think-block {
792
- background-color: var(--think-bg);
793
- color: var(--think-text);
794
- border-radius: 0.5rem;
795
- padding: 1rem;
796
- margin: 0.5rem 0;
797
- font-size: 0.875rem;
798
- line-height: 1.5;
799
- }
800
-
801
- .think-block.dark-mode {
802
- background-color: var(--think-dark-bg);
803
- color: var(--think-dark-text);
804
- }
805
-
806
- .think-heading {
807
- font-weight: 600;
808
- font-size: 1rem;
809
- color: var(--think-text);
810
- margin-bottom: 0.5rem;
811
- }
812
-
813
- .think-heading.dark-mode {
814
- color: var(--think-dark-text);
815
- }
816
-
817
- .sidebar-overlay, .settings-overlay {
818
- position: fixed;
819
- top: 0;
820
- left: 0;
821
- width: 100%;
822
- height: 100%;
823
- background-color: rgba(0, 0, 0, 0.5);
824
- z-index: 998;
825
- opacity: 0;
826
- visibility: hidden;
827
- transition: opacity 0.3s ease, visibility 0.3s ease;
828
- }
829
-
830
- .sidebar-overlay.active, .settings-overlay.active {
831
- opacity: 1;
832
- visibility: visible;
833
- }
834
-
835
- .settings-section {
836
- margin-bottom: 1.5rem;
837
- }
838
-
839
- .settings-label {
840
- font-weight: 500;
841
- margin-bottom: 0.5rem;
842
- font-size: 0.95rem;
843
- color: var(--dark);
844
- }
845
-
846
- .settings-label.dark-mode {
847
- color: var(--dark-text);
848
- }
849
-
850
- .select-field, .toggle-switch {
851
- width: 100%;
852
- padding: 0.5rem;
853
- border: 1px solid var(--border);
854
- border-radius: 0.5rem;
855
- font-size: 0.9rem;
856
- background-color: #f8fafc;
857
- cursor: pointer;
858
- }
859
-
860
- .select-field.dark-mode, .toggle-switch.dark-mode {
861
- border-color: var(--dark-border);
862
- background-color: var(--dark-border);
863
- color: var(--dark-text);
864
- }
865
-
866
- .toggle-switch {
867
- display: flex;
868
- align-items: center;
869
- justify-content: space-between;
870
- padding: 0.5rem 1rem;
871
- }
872
-
873
- .toggle {
874
- position: relative;
875
- display: inline-block;
876
- width: 40px;
877
- height: 20px;
878
- }
879
-
880
- .toggle input {
881
- opacity: 0;
882
- width: 0;
883
- height: 0;
884
- }
885
-
886
- .slider {
887
- position: absolute;
888
- cursor: pointer;
889
- top: 0;
890
- left: 0;
891
- right: 0;
892
- bottom: 0;
893
- background-color: #ccc;
894
- transition: 0.4s;
895
- border-radius: 20px;
896
- }
897
-
898
- .slider:before {
899
- position: absolute;
900
- content: "";
901
- height: 16px;
902
- width: 16px;
903
- margin: 2px;
904
- bottom: 2px;
905
- background-color: white;
906
- transition: 0.4s;
907
- border-radius: 50%;
908
- }
909
-
910
- input:checked + .slider {
911
- background-color: var(--primary);
912
- }
913
-
914
- input:checked + .slider:before {
915
- transform: translateX(20px);
916
- }
917
-
918
- /* Image Upload Styles */
919
- .image-upload-input {
920
- display: none;
921
- }
922
-
923
- .image-preview {
924
- max-width: 100%;
925
- max-height: 200px;
926
- margin: 0.5rem 0;
927
- border-radius: 0.5rem;
928
- display: none;
929
- }
930
-
931
- .loading {
932
- display: none;
933
- text-align: center;
934
- margin: 0.5rem 0;
935
- }
936
-
937
- .spinner {
938
- border: 4px solid rgba(0, 0, 0, 0.1);
939
- border-radius: 50%;
940
- border-top: 4px solid var(--primary);
941
- width: 20px;
942
- height: 20px;
943
- animation: spin 1s linear infinite;
944
- margin: 0 auto;
945
- }
946
-
947
- @keyframes spin {
948
- 0% { transform: rotate(0deg); }
949
- 100% { transform: rotate(360deg); }
950
- }
951
-
952
- /* Notification Styles */
953
- .notification {
954
- position: fixed;
955
- top: 10px;
956
- left: 50%;
957
- transform: translateX(-50%);
958
- background-color: var(--success);
959
- color: white;
960
- padding: 0.75rem 1.5rem;
961
- border-radius: 0.5rem;
962
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
963
- z-index: 1000;
964
- opacity: 0;
965
- visibility: hidden;
966
- transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease;
967
- }
968
-
969
- .notification.active {
970
- opacity: 1;
971
- visibility: visible;
972
- transform: translateX(-50%) translateY(0);
973
- }
974
-
975
- .notification.dark-mode {
976
- background-color: #059669;
977
- }
978
-
979
- @media (max-width: 768px) {
980
- .app-container {
981
- padding: 0;
982
- }
983
-
984
- .mobile-menu-btn {
985
- display: block;
986
- }
987
-
988
- .main-content {
989
- flex-direction: column;
990
- }
991
-
992
- .sidebar {
993
- position: fixed;
994
- top: 0;
995
- left: 0;
996
- height: 100vh;
997
- z-index: 999;
998
- transform: translateX(-100%);
999
- opacity: 0;
1000
- border-radius: 0;
1001
- box-shadow: none;
1002
- width: 75%;
1003
- background-color: white;
1004
- transition: transform 0.3s ease, opacity 0.3s ease;
1005
- }
1006
-
1007
- .settings-sidebar {
1008
- width: 75%;
1009
- border-radius: 0;
1010
- box-shadow: none;
1011
- transform: translateX(100%);
1012
- }
1013
-
1014
- .sidebar.active, .settings-sidebar.active {
1015
- transform: translateX(0);
1016
- opacity: 1;
1017
- }
1018
-
1019
- .close-sidebar-btn, .close-settings-btn {
1020
- display: block;
1021
- }
1022
-
1023
- .chat-container {
1024
- border-radius: 0;
1025
- }
1026
-
1027
- .message {
1028
- max-width: 90%;
1029
- }
1030
-
1031
- .notification {
1032
- width: 90%;
1033
- text-align: center;
1034
- }
1035
- }
1036
-
1037
- @keyframes fadeIn {
1038
- from {
1039
- opacity: 0;
1040
- transform: translateY(10px);
1041
- }
1042
- to {
1043
- opacity: 1;
1044
- transform: translateY(0);
1045
- }
1046
- }
1047
-
1048
- .message {
1049
- animation: fadeIn 0.3s ease-out;
1050
- }
1051
- </style>
1052
- </head>
1053
- <body>
1054
- <div class="notification" id="notification">Model converted to GPT-4o for image processing</div>
1055
- <div class="app-container">
1056
- <header>
1057
- <button class="mobile-menu-btn">
1058
- <i class="fas fa-bars"></i>
1059
- </button>
1060
- <div class="logo">
1061
- <i class="fas fa-robot"></i>
1062
- <span>Orion AI</span>
1063
- </div>
1064
- <button class="settings-btn" id="settingsBtn">
1065
- <i class="fas fa-cog"></i>
1066
- </button>
1067
- </header>
1068
-
1069
- <div class="sidebar-overlay" id="sidebarOverlay"></div>
1070
- <div class="settings-overlay" id="settingsOverlay"></div>
1071
-
1072
- <div class="main-content">
1073
- <div class="sidebar" id="sidebar">
1074
- <div class="sidebar-header">
1075
- <div class="sidebar-title">Chats</div>
1076
- <button class="new-chat-btn" id="newChatBtn">
1077
- <i>New Chat</i>
1078
- </button>
1079
- <button class="close-sidebar-btn" id="closeSidebarBtn">
1080
- <i class="fas fa-times"></i>
1081
- </button>
1082
- </div>
1083
- <div class="chat-list" id="chatList">
1084
- <!-- Chat items will be added here -->
1085
- </div>
1086
- <div class="chat-footer">
1087
- Created by Abdullah Ali
1088
- </div>
1089
- </div>
1090
-
1091
- <div class="settings-sidebar" id="settingsSidebar">
1092
- <div class="settings-header">
1093
- <div class="settings-title">Settings</div>
1094
- <button class="close-settings-btn" id="closeSettingsBtn">
1095
- <i class="fas fa-times"></i>
1096
- </button>
1097
- </div>
1098
- <div class="settings-section">
1099
- <div class="settings-label">AI Model</div>
1100
- <select class="select-field" id="modelSelect">
1101
- <option value="deepseek/DeepSeek-R1">DeepSeek-R1</option>
1102
- <option value="deepseek/DeepSeek-V3-0324">DeepSeek V3</option>
1103
- <option value="openai/gpt-4.1">OpenAI GPT-4.1</option>
1104
- <option value="openai/gpt-4.1-mini">OpenAI GPT-4.1-mini</option>
1105
- <option value="openai/gpt-4.1-nano">OpenAI GPT-4.1-nano</option>
1106
- <option value="openai/gpt-4o">OpenAI GPT-4o</option>
1107
- <option value="openai/gpt-4o-mini">OpenAI GPT-4o mini</option>
1108
- <option value="openai/o4-mini">OpenAI o4-mini</option>
1109
- <option value="microsoft/Phi-3.5-MoE-instruct">Phi-3.5-MoE instruct (128k)</option>
1110
- <option value="microsoft/Phi-3.5-mini-instruct">Phi-3.5-mini instruct (128k)</option>
1111
- <option value="microsoft/Phi-3.5-vision-instruct">Phi-3.5-vision instruct (128k)</option>
1112
- <option value="microsoft/Phi-3-medium-128k-instruct">Phi-3-medium instruct (128k)</option>
1113
- <option value="microsoft/Phi-3-medium-4k-instruct">Phi-3-medium instruct (4k)</option>
1114
- <option value="microsoft/Phi-3-mini-128k-instruct">Phi-3-mini instruct (128k)</option>
1115
- <option value="microsoft/Phi-3-small-128k-instruct">Phi-3-small instruct (128k)</option>
1116
- <option value="microsoft/Phi-3-small-8k-instruct">Phi-3-small instruct (8k)</option>
1117
- <option value="microsoft/Phi-4">Phi-4</option>
1118
- <option value="microsoft/Phi-4-mini-instruct">Phi-4-mini-instruct</option>
1119
- <option value="microsoft/Phi-4-multimodal-instruct">Phi-4-multimodal-instruct</option>
1120
- <option value="ai21-labs/AI21-Jamba-1.5-Large">AI21 Jamba 1.5 Large</option>
1121
- <option value="ai21-labs/AI21-Jamba-1.5-Mini">AI21 Jamba 1.5 Mini</option>
1122
- <option value="mistral-ai/Codestral-2501">Codestral 25.01</option>
1123
- <option value="cohere/Cohere-command-r">Cohere Command R</option>
1124
- <option value="cohere/Cohere-command-r-08-2024">Cohere Command R 08-2024</option>
1125
- <option value="cohere/Cohere-command-r-plus">Cohere Command R+</option>
1126
- <option value="cohere/Cohere-command-r-plus-08-2024">Cohere Command R+ 08-2024</option>
1127
- <option value="meta/Llama-3.2-11B-Vision-Instruct">Llama-3.2-11B-Vision-Instruct</option>
1128
- <option value="meta/Llama-3.2-90B-Vision-Instruct">Llama-3.2-90B-Vision-Instruct</option>
1129
- <option value="meta/Llama-3.3-70B-Instruct">Llama-3.3-70B-Instruct</option>
1130
- <option value="meta/Llama-4-Maverick-17B-128E-Instruct-FP8">Llama 4 Maverick 17B 128E Instruct FP8</option>
1131
- <option value="meta/Llama-4-Scout-17B-16E-Instruct">Llama 4 Scout 17B 16E Instruct</option>
1132
- <option value="meta/Meta-Llama-3.1-405B-Instruct">Meta-Llama-3.1-405B-Instruct</option>
1133
- <option value="meta/Meta-Llama-3.1-70B-Instruct">Meta-Llama-3.1-70B-Instruct</option>
1134
- <option value="meta/Meta-Llama-3.1-8B-Instruct">Meta-Llama-3.1-8B-Instruct</option>
1135
- <option value="meta/Meta-Llama-3-70B-Instruct">Meta-Llama-3-70B-Instruct</option>
1136
- <option value="meta/Meta-Llama-3-8B-Instruct">Meta-Llama-3-8B-Instruct</option>
1137
- <option value="mistral-ai/Ministral-3B">Ministral 3B</option>
1138
- <option value="mistral-ai/Mistral-Large-2411">Mistral Large 24.11</option>
1139
- <option value="mistral-ai/Mistral-Nemo">Mistral Nemo</option>
1140
- <option value="mistral-ai/Mistral-large-2407">Mistral Large (2407)</option>
1141
- <option value="mistral-ai/Mistral-small">Mistral Small</option>
1142
- <option value="cohere/cohere-command-a">Cohere Command A</option>
1143
- <option value="core42/jais-30b-chat">JAIS 30b Chat</option>
1144
- <option value="mistral-ai/mistral-small-2503">Mistral Small 3.1</option>
1145
- </select>
1146
- </div>
1147
- <div class="settings-section">
1148
- <div class="settings-label">Theme</div>
1149
- <div class="toggle-switch">
1150
- <span>Dark Mode</span>
1151
- <label class="toggle">
1152
- <input type="checkbox" id="darkModeToggle">
1153
- <span class="slider"></span>
1154
- </label>
1155
- </div>
1156
- </div>
1157
- <div class="settings-section">
1158
- <div class="settings-label">Response Tone</div>
1159
- <select class="select-field" id="toneSelect">
1160
- <option value="professional">Professional</option>
1161
- <option value="casual">Casual</option>
1162
- <option value="humorous">Humorous</option>
1163
- </select>
1164
- </div>
1165
- </div>
1166
-
1167
- <div class="chat-container">
1168
- <div class="chat-messages" id="chatMessages">
1169
- <!-- Messages will be inserted here -->
1170
- </div>
1171
- <div class="input-container">
1172
- <div class="suggestions">
1173
- <div class="suggestion-chip">Explain AI in simple terms</div>
1174
- <div class="suggestion-chip">Help with coding</div>
1175
- </div>
1176
- <div class="input-box">
1177
- <img class="input-image-preview" id="inputImagePreview" src="" alt="Image preview">
1178
- <span class="image-remove-icon" id="imageRemoveIcon"><i class="fas fa-times"></i></span>
1179
- <input type="text" class="input-field" id="messageInput" placeholder="Ask me anything..." autocomplete="off">
1180
- <button class="send-btn" id="sendBtn">
1181
- <i class="fas fa-paper-plane"></i>
1182
- </button>
1183
- </div>
1184
- <div class="action-buttons">
1185
- <button class="action-btn" id="imageUploadBtn">
1186
- <i class="fas fa-image"></i>
1187
- Upload Image
1188
- </button>
1189
- <input type="file" class="image-upload-input" id="imageUpload" accept="image/*">
1190
- <button class="action-btn" id="clearChatBtn">
1191
- <i class="fas fa-trash-alt"></i>
1192
- Clear
1193
- </button>
1194
- </div>
1195
- </div>
1196
- </div>
1197
- </div>
1198
- </div>
1199
-
1200
- <script>
1201
- const messageInput = document.getElementById('messageInput');
1202
- const sendBtn = document.getElementById('sendBtn');
1203
- const chatMessages = document.getElementById('chatMessages');
1204
- const clearChatBtn = document.getElementById('clearChatBtn');
1205
- const suggestionChips = document.querySelectorAll('.suggestion-chip');
1206
- const newChatBtn = document.getElementById('newChatBtn');
1207
- const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
1208
- const sidebar = document.getElementById('sidebar');
1209
- const sidebarOverlay = document.getElementById('sidebarOverlay');
1210
- const closeSidebarBtn = document.getElementById('closeSidebarBtn');
1211
- const settingsBtn = document.getElementById('settingsBtn');
1212
- const settingsSidebar = document.getElementById('settingsSidebar');
1213
- const settingsOverlay = document.getElementById('settingsOverlay');
1214
- const closeSettingsBtn = document.getElementById('closeSettingsBtn');
1215
- const darkModeToggle = document.getElementById('darkModeToggle');
1216
- const modelSelect = document.getElementById('modelSelect');
1217
- const toneSelect = document.getElementById('toneSelect');
1218
- const imageUploadBtn = document.getElementById('imageUploadBtn');
1219
- const imageUpload = document.getElementById('imageUpload');
1220
- const notification = document.getElementById('notification');
1221
- const inputImagePreview = document.getElementById('inputImagePreview');
1222
- const imageRemoveIcon = document.getElementById('imageRemoveIcon');
1223
-
1224
- const STORAGE_KEY = 'orionAI_chat';
1225
- const SETTINGS_KEY = 'orionAI_settings';
1226
- let chats = [];
1227
- let currentChatId = null;
1228
- let currentAiMessageDiv = null;
1229
- let isMobileSidebarOpen = false;
1230
- let isMobileSettingsOpen = false;
1231
- let uploadedImage = null;
1232
-
1233
- document.addEventListener('DOMContentLoaded', () => {
1234
- initApp();
1235
- if (messageInput) messageInput.focus();
1236
- });
1237
-
1238
- function initApp() {
1239
- loadChats();
1240
- if (chats.length === 0) {
1241
- createNewChat();
1242
- } else {
1243
- loadChat(chats[0].id);
1244
- }
1245
- renderChatList();
1246
- setupEventListeners();
1247
- checkMobileView();
1248
- window.addEventListener('resize', checkMobileView);
1249
- loadSettings();
1250
- }
1251
-
1252
- function showNotification(message) {
1253
- if (!notification) {
1254
- console.warn('Notification element not found');
1255
- return;
1256
- }
1257
- notification.textContent = message;
1258
- notification.classList.add('active', document.body.classList.contains('dark-mode') ? 'dark-mode' : '');
1259
- setTimeout(() => {
1260
- notification.classList.remove('active', 'dark-mode');
1261
- }, 3000);
1262
- }
1263
-
1264
- function checkMobileView() {
1265
- if (window.innerWidth <= 768) {
1266
- if (!isMobileSidebarOpen) {
1267
- sidebar.classList.remove('active');
1268
- sidebarOverlay.classList.remove('active');
1269
- }
1270
- if (!isMobileSettingsOpen) {
1271
- settingsSidebar.classList.remove('active');
1272
- settingsOverlay.classList.remove('active');
1273
- }
1274
- } else {
1275
- sidebar.classList.remove('active');
1276
- sidebarOverlay.classList.remove('active');
1277
- settingsSidebar.classList.remove('active');
1278
- settingsOverlay.classList.remove('active');
1279
- isMobileSidebarOpen = false;
1280
- isMobileSettingsOpen = false;
1281
- }
1282
- }
1283
-
1284
- function toggleMobileSidebar() {
1285
- isMobileSidebarOpen = !isMobileSidebarOpen;
1286
- sidebar.classList.toggle('active', isMobileSidebarOpen);
1287
- sidebarOverlay.classList.toggle('active', isMobileSidebarOpen);
1288
- if (isMobileSidebarOpen && isMobileSettingsOpen) {
1289
- toggleMobileSettings();
1290
- }
1291
- }
1292
-
1293
- function toggleMobileSettings() {
1294
- isMobileSettingsOpen = !isMobileSettingsOpen;
1295
- settingsSidebar.classList.toggle('active', isMobileSettingsOpen);
1296
- settingsOverlay.classList.toggle('active', isMobileSettingsOpen);
1297
- if (isMobileSettingsOpen && isMobileSidebarOpen) {
1298
- toggleMobileSidebar();
1299
- }
1300
- }
1301
-
1302
- function setupEventListeners() {
1303
- if (!sendBtn) console.warn('Send button not found');
1304
- else sendBtn.addEventListener('click', sendMessage);
1305
-
1306
- if (!messageInput) console.warn('Message input not found');
1307
- else messageInput.addEventListener('keypress', (e) => {
1308
- if (e.key === 'Enter' && !e.shiftKey) {
1309
- e.preventDefault();
1310
- sendMessage();
1311
- }
1312
- });
1313
-
1314
- if (!clearChatBtn) console.warn('Clear chat button not found');
1315
- else clearChatBtn.addEventListener('click', clearCurrentChat);
1316
-
1317
- if (!newChatBtn) console.warn('New chat button not found');
1318
- else newChatBtn.addEventListener('click', createNewChat);
1319
-
1320
- if (!suggestionChips) console.warn('Suggestion chips not found');
1321
- else suggestionChips.forEach(chip => {
1322
- chip.addEventListener('click', () => {
1323
- if (messageInput) {
1324
- messageInput.value = chip.textContent;
1325
- removeImage();
1326
- messageInput.focus();
1327
- sendMessage();
1328
- }
1329
- });
1330
- });
1331
-
1332
- if (!imageUploadBtn) console.warn('Image upload button not found');
1333
- else imageUploadBtn.addEventListener('click', () => {
1334
- if (imageUpload) imageUpload.click();
1335
- });
1336
-
1337
- if (!imageUpload) console.warn('Image upload input not found');
1338
- else imageUpload.addEventListener('change', handleImageUpload);
1339
-
1340
- if (!imageRemoveIcon) console.warn('Image remove icon not found');
1341
- else imageRemoveIcon.addEventListener('click', removeImage);
1342
-
1343
- if (!window) console.warn('Window object not found');
1344
- else window.addEventListener('beforeunload', () => {
1345
- saveChats();
1346
- saveSettings();
1347
- });
1348
-
1349
- if (!mobileMenuBtn) console.warn('Mobile menu button not found');
1350
- else mobileMenuBtn.addEventListener('click', toggleMobileSidebar);
1351
-
1352
- if (!sidebarOverlay) console.warn('Sidebar overlay not found');
1353
- else sidebarOverlay.addEventListener('click', toggleMobileSidebar);
1354
-
1355
- if (!closeSidebarBtn) console.warn('Close sidebar button not found');
1356
- else closeSidebarBtn.addEventListener('click', toggleMobileSidebar);
1357
-
1358
- if (!settingsBtn) console.warn('Settings button not found');
1359
- else settingsBtn.addEventListener('click', toggleMobileSettings);
1360
-
1361
- if (!settingsOverlay) console.warn('Settings overlay not found');
1362
- else settingsOverlay.addEventListener('click', toggleMobileSettings);
1363
-
1364
- if (!closeSettingsBtn) console.warn('Close settings button not found');
1365
- else closeSettingsBtn.addEventListener('click', toggleMobileSettings);
1366
-
1367
- if (!darkModeToggle) console.warn('Dark mode toggle not found');
1368
- else darkModeToggle.addEventListener('change', toggleDarkMode);
1369
-
1370
- if (!modelSelect) console.warn('Model select not found');
1371
- else modelSelect.addEventListener('change', saveSettings);
1372
-
1373
- if (!toneSelect) console.warn('Tone select not found');
1374
- else toneSelect.addEventListener('change', saveSettings);
1375
- }
1376
-
1377
- function handleImageUpload() {
1378
- if (!imageUpload || !imageUpload.files || !imageUpload.files[0]) return;
1379
-
1380
- const file = imageUpload.files[0];
1381
- if (!file.type.startsWith('image/')) {
1382
- alert('Please upload an image file.');
1383
- return;
1384
- }
1385
- const reader = new FileReader();
1386
- reader.onload = function(e) {
1387
- uploadedImage = e.target.result;
1388
- if (inputImagePreview) {
1389
- inputImagePreview.src = uploadedImage;
1390
- inputImagePreview.style.display = 'block';
1391
- }
1392
- if (imageRemoveIcon) {
1393
- imageRemoveIcon.style.display = 'flex';
1394
- }
1395
- if (messageInput) {
1396
- messageInput.classList.add('with-image');
1397
- messageInput.placeholder = 'Ask a question about the uploaded image...';
1398
- }
1399
- if (modelSelect) {
1400
- modelSelect.value = 'openai/gpt-4o';
1401
- saveSettings();
1402
- }
1403
- showNotification('Model converted to GPT-4o for image processing');
1404
- if (messageInput) messageInput.focus();
1405
- };
1406
- reader.readAsDataURL(file);
1407
- }
1408
-
1409
- function removeImage() {
1410
- uploadedImage = null;
1411
- if (inputImagePreview) {
1412
- inputImagePreview.src = '';
1413
- inputImagePreview.style.display = 'none';
1414
- }
1415
- if (imageRemoveIcon) {
1416
- imageRemoveIcon.style.display = 'none';
1417
- }
1418
- if (messageInput) {
1419
- messageInput.classList.remove('with-image');
1420
- messageInput.placeholder = 'Ask me anything...';
1421
- }
1422
- if (imageUpload) imageUpload.value = '';
1423
- if (modelSelect) {
1424
- const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY) || '{}');
1425
- modelSelect.value = settings.model || 'deepseek/DeepSeek-R1';
1426
- saveSettings();
1427
- }
1428
- }
1429
-
1430
- function loadChats() {
1431
- try {
1432
- const savedChats = localStorage.getItem(STORAGE_KEY);
1433
- if (savedChats) {
1434
- chats = JSON.parse(savedChats);
1435
- chats = chats.filter(chat => chat.id && chat.title && Array.isArray(chat.messages));
1436
- chats.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
1437
- }
1438
- } catch (e) {
1439
- console.error('Failed to load chats:', e);
1440
- chats = [];
1441
- }
1442
- }
1443
-
1444
- function saveChats() {
1445
- try {
1446
- localStorage.setItem(STORAGE_KEY, JSON.stringify(chats));
1447
- } catch (e) {
1448
- console.error('Failed to save chats:', e);
1449
- if (e.name === 'QuotaExceededError') {
1450
- alert('Storage is full. Clearing old chats.');
1451
- chats = chats.slice(0, 10);
1452
- saveChats();
1453
- }
1454
- }
1455
- }
1456
-
1457
- function loadSettings() {
1458
- const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY) || '{}');
1459
- if (settings.darkMode) {
1460
- document.body.classList.add('dark-mode');
1461
- if (darkModeToggle) darkModeToggle.checked = true;
1462
- updateDarkModeClasses(true);
1463
- }
1464
- if (settings.model && modelSelect) {
1465
- modelSelect.value = settings.model;
1466
- }
1467
- if (settings.tone && toneSelect) {
1468
- toneSelect.value = settings.tone;
1469
- }
1470
- }
1471
-
1472
- function saveSettings() {
1473
- const settings = {
1474
- darkMode: darkModeToggle ? darkModeToggle.checked : false,
1475
- model: modelSelect ? modelSelect.value : 'deepseek/DeepSeek-R1',
1476
- tone: toneSelect ? toneSelect.value : 'professional'
1477
- };
1478
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
1479
- }
1480
-
1481
- function toggleDarkMode() {
1482
- const isDarkMode = darkModeToggle ? darkModeToggle.checked : false;
1483
- document.body.classList.toggle('dark-mode', isDarkMode);
1484
- updateDarkModeClasses(isDarkMode);
1485
- if (imageRemoveIcon) {
1486
- imageRemoveIcon.classList.toggle('dark-mode', isDarkMode);
1487
- }
1488
- saveSettings();
1489
- }
1490
-
1491
- function updateDarkModeClasses(isDarkMode) {
1492
- const elements = document.querySelectorAll(
1493
- '.sidebar, .settings-sidebar, .mobile-menu-btn, .settings-btn, ' +
1494
- '.chat-container, .input-container, .suggestion-chip, .input-field, ' +
1495
- '.action-btn, .chat-footer, .typing-indicator, .chat-item, ' +
1496
- '.bin-button, .sidebar-title, .settings-title, .settings-label, ' +
1497
- '.select-field, .toggle-switch, .message-text, .message-text blockquote, ' +
1498
- '.think-block, .think-heading'
1499
- );
1500
- elements.forEach(el => {
1501
- el.classList.toggle('dark-mode', isDarkMode);
1502
- });
1503
- }
1504
-
1505
- function createNewChat() {
1506
- const newChat = {
1507
- id: Date.now().toString(),
1508
- title: 'New Chat',
1509
- messages: [],
1510
- createdAt: new Date().toISOString(),
1511
- updatedAt: new Date().toISOString()
1512
- };
1513
- chats.unshift(newChat);
1514
- saveChats();
1515
- loadChat(newChat.id);
1516
- renderChatList();
1517
-
1518
- if (window.innerWidth <= 768) {
1519
- toggleMobileSidebar();
1520
- }
1521
- }
1522
-
1523
- function loadChat(chatId) {
1524
- const chat = chats.find(c => c.id === chatId);
1525
- if (!chat) return;
1526
-
1527
- currentChatId = chatId;
1528
- if (chatMessages) chatMessages.innerHTML = '';
1529
-
1530
- if (chat.messages.length === 0) {
1531
- addMessage('ai', `Hello! I'm Orion AI, your advanced assistant. How can I help you today?`, false);
1532
- } else {
1533
- chat.messages.forEach(msg => {
1534
- addMessage(msg.sender, msg.text, false, false, msg.image);
1535
- });
1536
- }
1537
-
1538
- document.querySelectorAll('.chat-item').forEach(item => {
1539
- item.classList.toggle('active', item.dataset.chatId === chatId);
1540
- });
1541
-
1542
- scrollToBottom();
1543
- }
1544
-
1545
- function renderChatList() {
1546
- if (!chatList) return;
1547
- chatList.innerHTML = '';
1548
- chats.forEach(chat => {
1549
- const chatItem = document.createElement('div');
1550
- chatItem.className = `chat-item ${chat.id === currentChatId ? 'active' : ''} ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1551
- chatItem.dataset.chatId = chat.id;
1552
-
1553
- const chatTitle = document.createElement('span');
1554
- chatTitle.textContent = chat.title;
1555
- chatTitle.style.flex = '1';
1556
- chatItem.appendChild(chatTitle);
1557
-
1558
- const deleteBtn = document.createElement('div');
1559
- deleteBtn.className = `bin-button ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1560
- deleteBtn.innerHTML = `
1561
- <div class="bin-top"></div>
1562
- <div class="bin-bottom"></div>
1563
- `;
1564
- deleteBtn.addEventListener('click', (e) => {
1565
- e.stopPropagation();
1566
- deleteChat(chat.id);
1567
- });
1568
- chatItem.appendChild(deleteBtn);
1569
-
1570
- chatItem.addEventListener('click', () => {
1571
- loadChat(chat.id);
1572
- if (window.innerWidth <= 768) {
1573
- toggleMobileSidebar();
1574
- }
1575
- });
1576
- chatList.appendChild(chatItem);
1577
- });
1578
- }
1579
-
1580
- function deleteChat(chatId) {
1581
- const chatIndex = chats.findIndex(chat => chat.id === chatId);
1582
- if (chatIndex !== -1) {
1583
- chats.splice(chatIndex, 1);
1584
- saveChats();
1585
- renderChatList();
1586
- if (currentChatId === chatId) {
1587
- if (chats.length > 0) {
1588
- loadChat(chats[0].id);
1589
- } else {
1590
- createNewChat();
1591
- }
1592
- }
1593
- }
1594
- }
1595
-
1596
- function updateChatTitle(messageText) {
1597
- const chat = chats.find(c => c.id === currentChatId);
1598
- if (!chat || chat.title !== 'New Chat') return;
1599
-
1600
- const cleanText = messageText.replace(/[^\w\s]/gi, '').replace(/\s+/g, ' ').trim();
1601
- const newTitle = cleanText.length > 30 ? cleanText.substring(0, 30) + '...' : cleanText;
1602
-
1603
- if (newTitle.trim().length > 0) {
1604
- chat.title = newTitle;
1605
- chat.updatedAt = new Date().toISOString();
1606
- saveChats();
1607
- renderChatList();
1608
- }
1609
- }
1610
-
1611
- function addMessage(sender, text, saveToHistory = true, isStreaming = false, image = null) {
1612
- const messageDiv = document.createElement('div');
1613
- messageDiv.className = `message message-${sender}`;
1614
-
1615
- const avatarDiv = document.createElement('div');
1616
- avatarDiv.className = `avatar avatar-${sender}`;
1617
- avatarDiv.innerHTML = sender === 'ai' ? '<i class="fas fa-robot"></i>' : '<i class="fas fa-user"></i>';
1618
-
1619
- const contentDiv = document.createElement('div');
1620
- contentDiv.className = 'message-content';
1621
-
1622
- const textDiv = document.createElement('div');
1623
- textDiv.className = `message-text ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1624
-
1625
- if (isStreaming) {
1626
- textDiv.textContent = text;
1627
- } else {
1628
- processMessageText(text, textDiv);
1629
- }
1630
-
1631
- if (image && sender === 'user') {
1632
- const imgPreview = document.createElement('img');
1633
- imgPreview.className = 'image-preview';
1634
- imgPreview.src = image;
1635
- imgPreview.style.display = 'block';
1636
- textDiv.insertBefore(imgPreview, textDiv.firstChild);
1637
- }
1638
-
1639
- const metaDiv = document.createElement('div');
1640
- metaDiv.className = 'message-meta';
1641
- const timeSpan = document.createElement('span');
1642
- timeSpan.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
1643
-
1644
- if (sender === 'ai') {
1645
- const modelSpan = document.createElement('span');
1646
- modelSpan.textContent = modelSelect ? modelSelect.value.split('/').pop() : 'Unknown Model';
1647
- metaDiv.appendChild(modelSpan);
1648
- }
1649
- metaDiv.appendChild(timeSpan);
1650
-
1651
- contentDiv.appendChild(textDiv);
1652
- contentDiv.appendChild(metaDiv);
1653
- messageDiv.appendChild(avatarDiv);
1654
- messageDiv.appendChild(contentDiv);
1655
- if (chatMessages) chatMessages.appendChild(messageDiv);
1656
-
1657
- if (isStreaming) {
1658
- currentAiMessageDiv = textDiv;
1659
- }
1660
-
1661
- scrollToBottom();
1662
-
1663
- if (saveToHistory && currentChatId) {
1664
- const chat = chats.find(c => c.id === currentChatId);
1665
- if (chat) {
1666
- chat.messages.push({
1667
- sender,
1668
- text,
1669
- image: image || null,
1670
- timestamp: new Date().toISOString()
1671
- });
1672
- chat.updatedAt = new Date().toISOString();
1673
- saveChats();
1674
- if (sender === 'user') {
1675
- updateChatTitle(text);
1676
- }
1677
- }
1678
- }
1679
- }
1680
-
1681
- function processMessageText(text, container) {
1682
- const isDeepSeekR1 = modelSelect ? modelSelect.value === 'deepseek/DeepSeek-R1' : false;
1683
- const parts = text.split(/(```[\s\S]*?```|<\s*think\s*>[\s\S]*?<\s*\/think\s*>)/gi);
1684
-
1685
- parts.forEach(part => {
1686
- if (!part.trim()) return;
1687
-
1688
- if (part.match(/^```[\s\S]*?```$/)) {
1689
- const codeContent = part.slice(3, -3).trim();
1690
- const languageMatch = codeContent.match(/^(\w+)\n/);
1691
- let language = '';
1692
- let code = codeContent;
1693
-
1694
- if (languageMatch) {
1695
- language = languageMatch[1];
1696
- code = codeContent.slice(language.length).trim();
1697
- }
1698
-
1699
- const codeBlock = document.createElement('div');
1700
- codeBlock.className = `code-block ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1701
-
1702
- const pre = document.createElement('pre');
1703
- pre.textContent = code;
1704
-
1705
- if (language) {
1706
- const langLabel = document.createElement('div');
1707
- langLabel.className = 'language-label';
1708
- langLabel.textContent = language;
1709
- codeBlock.appendChild(langLabel);
1710
- }
1711
-
1712
- const copyBtn = document.createElement('button');
1713
- copyBtn.className = 'copy-btn';
1714
- copyBtn.innerHTML = '<i class="far fa-copy"></i> Copy';
1715
- copyBtn.setAttribute('aria-label', 'Copy code to clipboard');
1716
- copyBtn.addEventListener('click', async () => {
1717
- try {
1718
- await navigator.clipboard.writeText(code);
1719
- copyBtn.innerHTML = '<i class="fas fa-check"></i> Copied!';
1720
- copyBtn.style.backgroundColor = '#10b981';
1721
- copyBtn.setAttribute('aria-label', 'Code copied');
1722
- setTimeout(() => {
1723
- copyBtn.innerHTML = '<i class="far fa-copy"></i> Copy';
1724
- copyBtn.style.backgroundColor = '#334155';
1725
- copyBtn.setAttribute('aria-label', 'Copy code to clipboard');
1726
- }, 2000);
1727
- } catch (err) {
1728
- console.error('Failed to copy:', err);
1729
- copyBtn.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Error';
1730
- copyBtn.style.backgroundColor = '#ef4444';
1731
- setTimeout(() => {
1732
- copyBtn.innerHTML = '<i class="far fa-copy"></i> Copy';
1733
- copyBtn.style.backgroundColor = '#334155';
1734
- copyBtn.setAttribute('aria-label', 'Copy code to clipboard');
1735
- }, 2000);
1736
- }
1737
- });
1738
-
1739
- codeBlock.appendChild(pre);
1740
- codeBlock.appendChild(copyBtn);
1741
- container.appendChild(codeBlock);
1742
- } else if (isDeepSeekR1 && part.match(/^<\s*think\s*>[\s\S]*?<\s*\/think\s*>$/i)) {
1743
- const thinkContent = part.replace(/^<\s*think\s*>([\s\S]*?)<\s*\/think\s*>$/i, '$1').trim();
1744
- const thinkBlock = document.createElement('div');
1745
- thinkBlock.className = `think-block ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1746
-
1747
- const heading = document.createElement('div');
1748
- heading.className = `think-heading ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1749
- heading.textContent = 'Thinking';
1750
- thinkBlock.appendChild(heading);
1751
-
1752
- const contentDiv = document.createElement('div');
1753
- contentDiv.innerHTML = formatText(thinkContent);
1754
- thinkBlock.appendChild(contentDiv);
1755
-
1756
- container.appendChild(thinkBlock);
1757
- } else {
1758
- const textNode = document.createElement('div');
1759
- textNode.innerHTML = formatText(part);
1760
- container.appendChild(textNode);
1761
- }
1762
- });
1763
- }
1764
-
1765
- function formatText(text) {
1766
- return text
1767
- .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
1768
- .replace(/\*(.*?)\*/g, '<em>$1</em>')
1769
- .replace(/^# (.*$)/gm, '<h1>$1</h1>')
1770
- .replace(/^## (.*$)/gm, '<h2>$1</h2>')
1771
- .replace(/^### (.*$)/gm, '<h3>$1</h3>')
1772
- .replace(/^#### (.*$)/gm, '<h4>$1</h4>')
1773
- .replace(/^\> (.*$)/gm, '<blockquote class="' + (document.body.classList.contains('dark-mode') ? 'dark-mode' : '') + '">$1</blockquote>')
1774
- .replace(/\n/g, '<br>')
1775
- .replace(/^\s*-\s(.*$)/gm, '<li>$1</li>')
1776
- .replace(/^\s*\*\s(.*$)/gm, '<li>$1</li>')
1777
- .replace(/^\s*\d+\.\s(.*$)/gm, '<li>$1</li>');
1778
- }
1779
-
1780
- function addTypingIndicator() {
1781
- const typingDiv = document.createElement('div');
1782
- typingDiv.className = `typing-indicator ${document.body.classList.contains('dark-mode') ? 'dark-mode' : ''}`;
1783
- typingDiv.innerHTML = `
1784
- <div class="typing-dot"></div>
1785
- <div class="typing-dot"></div>
1786
- <div class="typing-dot"></div>
1787
- `;
1788
- if (chatMessages) chatMessages.appendChild(typingDiv);
1789
- scrollToBottom();
1790
- return typingDiv;
1791
- }
1792
-
1793
- function removeTypingIndicator(typingDiv) {
1794
- if (typingDiv && typingDiv.parentNode) {
1795
- typingDiv.parentNode.removeChild(typingDiv);
1796
- }
1797
- }
1798
-
1799
- async function sendMessage() {
1800
- const message = messageInput ? messageInput.value.trim() : '';
1801
- if (!message && !uploadedImage) return;
1802
-
1803
- if (uploadedImage && !message) {
1804
- alert('Please enter a question about the uploaded image.');
1805
- return;
1806
- }
1807
-
1808
- addMessage('user', message, true, false, uploadedImage);
1809
- if (messageInput) {
1810
- messageInput.value = '';
1811
- messageInput.placeholder = 'Ask me anything...';
1812
- messageInput.classList.remove('with-image');
1813
- }
1814
- if (inputImagePreview) inputImagePreview.style.display = 'none';
1815
- if (imageRemoveIcon) imageRemoveIcon.style.display = 'none';
1816
- if (sendBtn) sendBtn.disabled = true;
1817
- if (imageUpload) imageUpload.value = '';
1818
- const tempImage = uploadedImage;
1819
- uploadedImage = null;
1820
-
1821
- const typingIndicator = addTypingIndicator();
1822
- const minAnimationTime = 500;
1823
- const animationStart = Date.now();
1824
-
1825
- try {
1826
- let result = '';
1827
- if (tempImage) {
1828
- const blob = await fetch(tempImage).then(res => res.blob());
1829
- const formData = new FormData();
1830
- formData.append('image', blob, 'uploaded_image.jpg');
1831
- formData.append('question', message);
1832
- formData.append('model', modelSelect ? modelSelect.value : 'openai/gpt-4o');
1833
-
1834
- const response = await fetch('https://abdullahalioo-vision.hf.space/process-image', {
1835
- method: 'POST',
1836
- body: formData
1837
- });
1838
-
1839
- if (!response.ok) {
1840
- const errorText = await response.text();
1841
- throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
1842
- }
1843
-
1844
- const elapsed = Date.now() - animationStart;
1845
- if (elapsed < minAnimationTime) {
1846
- await new Promise(resolve => setTimeout(resolve, minAnimationTime - elapsed));
1847
- }
1848
-
1849
- const data = await response.json();
1850
- result = data.response || JSON.stringify(data, null, 2);
1851
-
1852
- removeTypingIndicator(typingIndicator);
1853
- addMessage('ai', result, true, false);
1854
-
1855
- } else {
1856
- let endpoint = `https://abdullahalioo-wow.hf.space/generate?model=${modelSelect ? modelSelect.value : 'deepseek/DeepSeek-R1'}&prompt=${encodeURIComponent(message)}`;
1857
-
1858
- if ((modelSelect ? modelSelect.value : '') === 'deepseek/DeepSeek-R1') {
1859
- endpoint = 'https://abdullahalioo-deepseek.hf.space/generate?prompt=' + encodeURIComponent(message);
1860
- }
1861
-
1862
- const response = await fetch(endpoint, {
1863
- method: 'POST',
1864
- headers: {
1865
- 'Accept': 'application/json',
1866
- }
1867
- });
1868
-
1869
- if (!response.ok) {
1870
- const errorText = await response.text();
1871
- throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
1872
- }
1873
-
1874
- const elapsed = Date.now() - animationStart;
1875
- if (elapsed < minAnimationTime) {
1876
- await new Promise(resolve => setTimeout(resolve, minAnimationTime - elapsed));
1877
- }
1878
-
1879
- const reader = response.body.getReader();
1880
- const decoder = new TextDecoder();
1881
-
1882
- removeTypingIndicator(typingIndicator);
1883
- addMessage('ai', '', true, true);
1884
-
1885
- while (true) {
1886
- const { done, value } = await reader.read();
1887
- if (done) break;
1888
-
1889
- const chunk = decoder.decode(value, { stream: true });
1890
- result += chunk;
1891
-
1892
- if (currentAiMessageDiv) {
1893
- currentAiMessageDiv.textContent = result;
1894
- }
1895
- scrollToBottom();
1896
- }
1897
-
1898
- if (currentAiMessageDiv) {
1899
- currentAiMessageDiv.innerHTML = '';
1900
- processMessageText(result, currentAiMessageDiv);
1901
- }
1902
-
1903
- const chat = chats.find(c => c.id === currentChatId);
1904
- if (chat) {
1905
- chat.messages[chat.messages.length - 1].text = result;
1906
- saveChats();
1907
- }
1908
- }
1909
-
1910
- } catch (error) {
1911
- console.error('Error:', error);
1912
- const elapsed = Date.now() - animationStart;
1913
- if (elapsed < minAnimationTime) {
1914
- await new Promise(resolve => setTimeout(resolve, minAnimationTime - elapsed));
1915
- }
1916
- removeTypingIndicator(typingIndicator);
1917
- if (currentAiMessageDiv) {
1918
- currentAiMessageDiv.textContent = 'Error: ' + error.message;
1919
- } else {
1920
- addMessage('ai', 'Error: ' + error.message, true);
1921
- }
1922
- } finally {
1923
- if (sendBtn) sendBtn.disabled = false;
1924
- currentAiMessageDiv = null;
1925
- }
1926
- }
1927
-
1928
- function clearCurrentChat() {
1929
- if (!currentChatId) return;
1930
-
1931
- const chat = chats.find(c => c.id === currentChatId);
1932
- if (chat) {
1933
- chat.messages = [];
1934
- chat.updatedAt = new Date().toISOString();
1935
- saveChats();
1936
- }
1937
-
1938
- if (chatMessages) chatMessages.innerHTML = '';
1939
- addMessage('ai', `Hello! I'm Orion AI, your advanced assistant. How can I help you today?`, false);
1940
- removeImage();
1941
- }
1942
-
1943
- function scrollToBottom() {
1944
- if (chatMessages) chatMessages.scrollTop = chatMessages.scrollHeight;
1945
- }
1946
- </script>
1947
- </body>
1948
- </html>