aldohenrique commited on
Commit
4d0a94b
·
verified ·
1 Parent(s): 27d5d42

Update interface.py

Browse files
Files changed (1) hide show
  1. interface.py +433 -752
interface.py CHANGED
@@ -17,107 +17,69 @@ css_customizado = """
17
  }
18
 
19
  body {
20
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
21
- background: #ffffff;
22
- color: #374151;
23
  overflow-x: hidden;
24
- height: 100vh;
25
- -webkit-font-smoothing: antialiased;
26
  }
27
 
28
- /* Container principal */
29
  .gradio-container {
30
- background: #ffffff !important;
31
  min-height: 100vh !important;
32
  max-width: 100% !important;
33
  padding: 0 !important;
34
  margin: 0 !important;
35
- height: 100vh !important;
36
- overflow: hidden !important;
37
  }
38
 
39
- /* Layout principal */
40
- .main-layout {
41
  display: flex !important;
42
- height: 100vh !important;
43
- max-height: 100vh !important;
44
- background: #ffffff;
45
  overflow: hidden !important;
46
  position: relative;
47
  }
48
 
49
- /* Sidebar */
50
  .sidebar {
51
- width: 280px;
52
- min-width: 280px;
53
- background: #f7f7f8;
54
- border-right: 1px solid #e5e7eb;
55
- display: flex;
56
- flex-direction: column;
 
 
57
  height: 100vh !important;
58
- overflow: hidden;
59
- transition: all 0.3s ease;
60
  }
61
 
62
  .sidebar-header {
63
- padding: 20px;
64
- border-bottom: 1px solid #e5e7eb;
65
- background: #ffffff;
66
- flex-shrink: 0;
67
- }
68
-
69
- .logo {
70
  display: flex;
71
  align-items: center;
72
- gap: 12px;
73
- margin-bottom: 16px;
74
- }
75
-
76
- .logo-icon {
77
- width: 32px;
78
- height: 32px;
79
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
80
- border-radius: 8px;
81
- display: flex;
82
- align-items: center;
83
- justify-content: center;
84
- color: white;
85
- font-weight: 600;
86
- font-size: 16px;
87
- }
88
-
89
- .logo-text {
90
- font-size: 20px;
91
- font-weight: 700;
92
- color: #111827;
93
  }
94
 
95
  .new-chat-btn {
96
- width: 100%;
97
- background: #ffffff !important;
98
- color: #374151 !important;
99
- border: 1px solid #d1d5db !important;
100
  border-radius: 8px !important;
101
- padding: 12px 16px !important;
102
  font-size: 14px !important;
103
  font-weight: 500 !important;
104
  cursor: pointer !important;
105
  transition: all 0.2s ease !important;
106
- display: flex;
107
- align-items: center;
108
- justify-content: center;
109
- gap: 8px;
110
  }
111
 
112
  .new-chat-btn:hover {
113
- background: #f9fafb !important;
114
- border-color: #9ca3af !important;
115
- }
116
-
117
- .sidebar-content {
118
- flex: 1;
119
- overflow-y: auto;
120
- padding: 16px 20px;
121
  }
122
 
123
  .sidebar-section {
@@ -125,59 +87,52 @@ body {
125
  }
126
 
127
  .sidebar-section h3 {
128
- color: #6b7280;
129
  font-size: 12px;
130
  font-weight: 600;
131
  text-transform: uppercase;
132
- letter-spacing: 0.05em;
133
- margin-bottom: 12px;
134
  }
135
 
136
- /* Chat principal */
137
- .chat-area {
138
  flex: 1;
139
- display: flex;
140
- flex-direction: column;
141
- background: #ffffff;
 
142
  height: 100vh !important;
143
- max-height: 100vh !important;
144
- overflow: hidden;
145
- min-width: 0;
146
  }
147
 
 
148
  .chat-header {
149
- background: #ffffff;
150
- border-bottom: 1px solid #e5e7eb;
151
- padding: 16px 24px;
152
  display: flex;
153
  align-items: center;
154
  justify-content: center;
155
  position: relative;
 
156
  flex-shrink: 0;
157
- height: 60px;
158
- }
159
-
160
- .mobile-menu-btn {
161
- display: none;
162
- background: none;
163
- border: none;
164
- padding: 8px;
165
- cursor: pointer;
166
- position: absolute;
167
- left: 16px;
168
- color: #6b7280;
169
- font-size: 18px;
170
  }
171
 
172
  .chat-title {
173
- color: #111827;
174
  font-size: 16px;
175
  font-weight: 600;
176
  text-align: center;
177
  }
178
 
179
  .chat-title a {
180
- color: #667eea;
181
  text-decoration: none;
182
  }
183
 
@@ -185,125 +140,80 @@ body {
185
  text-decoration: underline;
186
  }
187
 
188
- /* Área de mensagens */
189
- .messages-area {
190
- flex: 1;
191
- overflow: hidden;
192
- display: flex;
193
- flex-direction: column;
194
- min-height: 0;
 
 
 
195
  }
196
 
 
197
  .chatbot {
198
  flex: 1 !important;
199
- min-height: 0 !important;
200
  height: 100% !important;
 
 
201
  background: transparent !important;
202
  border: none !important;
203
- padding: 0 !important;
204
  margin: 0 !important;
 
205
  }
206
 
 
207
  .chatbot > div {
208
  height: 100% !important;
209
- overflow-y: auto !important;
 
210
  overflow-x: hidden !important;
 
211
  scroll-behavior: smooth !important;
212
- padding: 0 !important;
213
- }
214
-
215
- /* Container das mensagens */
216
- .message-container {
217
- max-width: 768px;
218
- margin: 0 auto;
219
- padding: 0 16px;
220
- }
221
-
222
- /* Estilo das mensagens */
223
- .message {
224
- padding: 24px 0;
225
- border-bottom: 1px solid #f3f4f6;
226
- }
227
-
228
- .message:last-child {
229
- border-bottom: none;
230
- }
231
-
232
- .message-content {
233
- display: flex;
234
- gap: 16px;
235
- align-items: flex-start;
236
- }
237
-
238
- .message-avatar {
239
- width: 40px;
240
- height: 40px;
241
- border-radius: 50%;
242
- flex-shrink: 0;
243
- display: flex;
244
- align-items: center;
245
- justify-content: center;
246
- font-size: 18px;
247
- font-weight: 600;
248
- position: relative;
249
- }
250
-
251
- .user-avatar {
252
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
253
- color: white;
254
- }
255
-
256
- .bot-avatar {
257
- background: #f3f4f6;
258
- color: #374151;
259
- border: 2px solid #e5e7eb;
260
- }
261
-
262
- .message-text {
263
- flex: 1;
264
- line-height: 1.6;
265
- font-size: 16px;
266
- color: #374151;
267
- word-wrap: break-word;
268
  }
269
 
270
- .user-message {
271
- background: rgba(102, 126, 234, 0.05);
272
- }
273
-
274
- .bot-message {
275
- background: #ffffff;
276
- }
277
-
278
- /* Área de input */
279
  .input-area {
280
- background: #ffffff;
281
- border-top: 1px solid #e5e7eb;
282
  padding: 24px;
283
- flex-shrink: 0;
 
 
 
 
 
 
284
  }
285
 
286
  .input-container {
287
  max-width: 768px;
288
  margin: 0 auto;
289
  position: relative;
 
 
 
290
  }
291
 
292
  .input-wrapper {
293
- background: #ffffff;
294
- border: 2px solid #e5e7eb;
295
- border-radius: 24px;
296
- padding: 12px 20px;
297
  display: flex;
298
  align-items: flex-end;
299
  gap: 12px;
300
  transition: all 0.2s ease;
301
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
 
302
  }
303
 
304
  .input-wrapper:focus-within {
305
- border-color: #667eea;
306
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
307
  }
308
 
309
  #entrada_usuario {
@@ -313,29 +223,29 @@ body {
313
  #entrada_usuario textarea {
314
  background: transparent !important;
315
  border: none !important;
316
- color: #374151 !important;
317
  font-size: 16px !important;
318
  line-height: 1.5 !important;
319
  resize: none !important;
320
  outline: none !important;
321
  min-height: 24px !important;
322
- max-height: 120px !important;
323
  height: 24px !important;
324
  padding: 0 !important;
325
  margin: 0 !important;
326
- font-family: inherit !important;
327
  }
328
 
329
  #entrada_usuario textarea::placeholder {
330
- color: #9ca3af !important;
331
  }
332
 
333
  .send-button {
334
- width: 40px;
335
- height: 40px;
336
- background: #667eea !important;
337
  border: none !important;
338
- border-radius: 50% !important;
339
  color: white !important;
340
  cursor: pointer !important;
341
  display: flex !important;
@@ -343,94 +253,126 @@ body {
343
  justify-content: center !important;
344
  transition: all 0.2s ease !important;
345
  flex-shrink: 0;
346
- font-size: 18px !important;
347
  }
348
 
349
  .send-button:hover:not(:disabled) {
350
- background: #5a67d8 !important;
351
- transform: scale(1.05);
352
  }
353
 
354
  .send-button:disabled {
355
- background: #d1d5db !important;
356
  cursor: not-allowed !important;
357
- transform: none !important;
358
  }
359
 
360
- /* Dropdown personalizado */
361
- .model-selector {
362
- background: #ffffff !important;
363
- border: 1px solid #d1d5db !important;
364
- border-radius: 8px !important;
365
- padding: 12px 16px !important;
366
- color: #374151 !important;
367
- font-size: 14px !important;
368
- width: 100% !important;
369
- cursor: pointer !important;
370
- transition: all 0.2s ease !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  }
372
 
373
- .model-selector:hover {
374
- border-color: #9ca3af !important;
375
  }
376
 
377
- .model-selector:focus {
378
- border-color: #667eea !important;
379
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
 
 
 
 
 
 
 
 
 
380
  }
381
 
382
- /* Accordions */
383
- .sidebar-accordion {
384
- background: #ffffff !important;
385
- border: 1px solid #e5e7eb !important;
386
  border-radius: 8px !important;
387
  margin-bottom: 16px !important;
388
- overflow: hidden !important;
389
  }
390
 
391
- .sidebar-accordion summary {
392
- background: #f9fafb !important;
393
- color: #374151 !important;
394
- padding: 16px !important;
 
395
  font-weight: 500 !important;
396
- cursor: pointer !important;
397
- border: none !important;
398
- transition: all 0.2s ease !important;
399
  }
400
 
401
- .sidebar-accordion summary:hover {
402
- background: #f3f4f6 !important;
 
403
  }
404
 
405
- .sidebar-accordion[open] summary {
406
- border-bottom: 1px solid #e5e7eb !important;
407
- }
408
-
409
- .sidebar-accordion .gr-panel {
410
- background: #ffffff !important;
411
  padding: 16px !important;
 
412
  }
413
 
414
  /* Estilo para código */
415
  .message pre {
416
- background: #f8fafc !important;
417
- border: 1px solid #e2e8f0 !important;
418
  border-radius: 8px !important;
419
  padding: 16px !important;
420
- margin: 16px 0 !important;
421
  overflow-x: auto !important;
422
- font-family: 'Monaco', 'Menlo', 'SF Mono', 'Consolas', monospace !important;
423
  font-size: 14px !important;
424
  line-height: 1.5 !important;
425
  }
426
 
427
  .message code {
428
- background: #f1f5f9 !important;
429
  padding: 2px 6px !important;
430
  border-radius: 4px !important;
431
- font-family: 'Monaco', 'Menlo', 'SF Mono', 'Consolas', monospace !important;
432
  font-size: 14px !important;
433
- color: #1e293b !important;
434
  }
435
 
436
  .message pre code {
@@ -440,7 +382,7 @@ body {
440
 
441
  /* Links */
442
  .message a {
443
- color: #667eea !important;
444
  text-decoration: none !important;
445
  }
446
 
@@ -450,12 +392,12 @@ body {
450
 
451
  /* Listas */
452
  .message ul, .message ol {
453
- margin: 16px 0 !important;
454
  padding-left: 24px !important;
455
  }
456
 
457
  .message li {
458
- margin: 8px 0 !important;
459
  line-height: 1.6 !important;
460
  }
461
 
@@ -464,78 +406,120 @@ body {
464
  border-collapse: collapse !important;
465
  width: 100% !important;
466
  margin: 16px 0 !important;
467
- background: #ffffff !important;
468
- border: 1px solid #e5e7eb !important;
469
  border-radius: 8px !important;
470
  overflow: hidden !important;
471
  }
472
 
473
  .message th, .message td {
474
- border: 1px solid #e5e7eb !important;
475
  padding: 12px !important;
476
  text-align: left !important;
477
  }
478
 
479
  .message th {
480
- background: #f9fafb !important;
481
  font-weight: 600 !important;
482
- color: #374151 !important;
483
  }
484
 
485
  /* Scrollbar personalizada */
486
  ::-webkit-scrollbar {
487
- width: 6px;
 
488
  }
489
 
490
  ::-webkit-scrollbar-track {
491
- background: #f1f5f9;
492
  }
493
 
494
  ::-webkit-scrollbar-thumb {
495
- background: #cbd5e1;
496
- border-radius: 3px;
497
  }
498
 
499
  ::-webkit-scrollbar-thumb:hover {
500
- background: #94a3b8;
501
  }
502
 
503
- /* Status indicators */
504
- .status-indicator {
505
- font-size: 12px;
506
- padding: 6px 12px;
507
- border-radius: 16px;
508
- font-weight: 500;
509
- display: inline-block;
510
  }
511
 
512
- .status-success {
513
- background: #dcfce7;
514
- color: #166534;
515
- border: 1px solid #bbf7d0;
 
516
  }
517
 
518
- .status-error {
519
- background: #fef2f2;
520
- color: #dc2626;
521
- border: 1px solid #fecaca;
 
522
  }
523
 
524
- .status-warning {
525
- background: #fefbeb;
526
- color: #d97706;
527
- border: 1px solid #fed7aa;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  }
529
 
530
  /* Animações */
531
  .message {
532
- animation: slideIn 0.3s ease-out;
533
  }
534
 
535
- @keyframes slideIn {
536
  from {
537
  opacity: 0;
538
- transform: translateY(20px);
539
  }
540
  to {
541
  opacity: 1;
@@ -543,357 +527,180 @@ body {
543
  }
544
  }
545
 
546
- /* Loading animation */
547
  .loading-indicator {
548
- display: flex;
549
  align-items: center;
550
  gap: 8px;
551
- color: #6b7280;
552
  font-style: italic;
553
  }
554
 
555
  .loading-dots {
556
- display: flex;
557
- gap: 4px;
558
  }
559
 
560
  .loading-dots span {
561
- width: 8px;
562
- height: 8px;
563
- background: #667eea;
564
  border-radius: 50%;
565
- animation: bounce 1.4s ease-in-out infinite both;
566
  }
567
 
568
  .loading-dots span:nth-child(1) { animation-delay: -0.32s; }
569
  .loading-dots span:nth-child(2) { animation-delay: -0.16s; }
570
  .loading-dots span:nth-child(3) { animation-delay: 0s; }
571
 
572
- @keyframes bounce {
573
  0%, 80%, 100% {
574
- transform: scale(0.6);
575
- opacity: 0.5;
576
  }
577
  40% {
578
- transform: scale(1);
579
  opacity: 1;
580
  }
581
  }
582
 
583
- /* Responsividade Mobile */
584
- @media (max-width: 768px) {
585
- .main-layout {
586
- flex-direction: column;
587
- }
588
-
589
- .sidebar {
590
- position: fixed;
591
- top: 0;
592
- left: -280px;
593
- width: 280px;
594
- height: 100vh;
595
- z-index: 1000;
596
- box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
597
- transition: left 0.3s ease;
598
- }
599
-
600
- .sidebar.open {
601
- left: 0;
602
- }
603
-
604
- .sidebar-overlay {
605
- position: fixed;
606
- top: 0;
607
- left: 0;
608
- width: 100%;
609
- height: 100%;
610
- background: rgba(0, 0, 0, 0.5);
611
- z-index: 999;
612
- opacity: 0;
613
- visibility: hidden;
614
- transition: all 0.3s ease;
615
- }
616
-
617
- .sidebar-overlay.active {
618
- opacity: 1;
619
- visibility: visible;
620
- }
621
-
622
- .mobile-menu-btn {
623
- display: block !important;
624
- }
625
-
626
- .chat-area {
627
- width: 100%;
628
- margin-left: 0;
629
- }
630
-
631
- .chat-header {
632
- padding: 16px;
633
- }
634
-
635
- .input-area {
636
- padding: 16px;
637
- }
638
-
639
- .input-wrapper {
640
- padding: 10px 16px;
641
- }
642
-
643
- .message-content {
644
- gap: 12px;
645
- }
646
-
647
- .message-avatar {
648
- width: 36px;
649
- height: 36px;
650
- font-size: 16px;
651
- }
652
-
653
- .message-text {
654
- font-size: 15px;
655
- }
656
-
657
- .send-button {
658
- width: 36px;
659
- height: 36px;
660
- font-size: 16px !important;
661
- }
662
  }
663
 
664
- @media (max-width: 480px) {
665
- .sidebar {
666
- width: 100%;
667
- left: -100%;
668
- }
669
-
670
- .sidebar.open {
671
- left: 0;
672
- }
673
-
674
- .message {
675
- padding: 16px 0;
676
- }
677
-
678
- .input-area {
679
- padding: 12px;
680
- }
681
-
682
- .chat-header {
683
- padding: 12px 16px;
684
- }
685
  }
686
 
687
- /* Dark mode support */
688
- @media (prefers-color-scheme: dark) {
689
- body {
690
- background: #1f2937;
691
- color: #f9fafb;
692
- }
693
-
694
- .gradio-container {
695
- background: #1f2937 !important;
696
- }
697
-
698
- .main-layout {
699
- background: #1f2937;
700
- }
701
-
702
- .sidebar {
703
- background: #111827;
704
- border-right-color: #374151;
705
- }
706
-
707
- .sidebar-header {
708
- background: #1f2937;
709
- border-bottom-color: #374151;
710
- }
711
-
712
- .chat-area {
713
- background: #1f2937;
714
- }
715
-
716
- .chat-header {
717
- background: #1f2937;
718
- border-bottom-color: #374151;
719
- }
720
-
721
- .input-area {
722
- background: #1f2937;
723
- border-top-color: #374151;
724
- }
725
-
726
- .input-wrapper {
727
- background: #374151;
728
- border-color: #4b5563;
729
- }
730
-
731
- #entrada_usuario textarea {
732
- color: #f9fafb !important;
733
- }
734
-
735
- .message-text {
736
- color: #f9fafb;
737
- }
738
  }
739
 
740
- /* Ocultar elementos desnecessários */
741
- .gr-button-lg {
742
- display: none !important;
 
 
 
 
 
 
 
743
  }
744
 
745
- .gr-form {
746
- background: transparent !important;
747
- border: none !important;
748
  }
749
 
750
- /* Ajustes adicionais para melhor UX */
751
- .message-content {
752
- animation: fadeInUp 0.5s ease-out;
753
  }
754
 
755
- @keyframes fadeInUp {
756
- from {
757
- opacity: 0;
758
- transform: translateY(10px);
759
- }
760
- to {
761
- opacity: 1;
762
- transform: translateY(0);
763
- }
764
  }
765
 
766
- /* Hover effects */
767
- .sidebar-section:hover {
768
- transform: translateX(2px);
769
- transition: transform 0.2s ease;
 
 
770
  }
771
 
772
- /* Focus states */
773
- .send-button:focus {
774
- outline: 2px solid #667eea;
775
- outline-offset: 2px;
776
  }
777
 
778
- .model-selector:focus {
779
- outline: none;
 
 
780
  }
781
 
782
- /* Improved accessibility */
783
- @media (prefers-reduced-motion: reduce) {
784
- * {
785
- animation-duration: 0.01ms !important;
786
- animation-iteration-count: 1 !important;
787
- transition-duration: 0.01ms !important;
788
- }
789
  }
790
  """
791
 
792
  def criar_interface():
793
- with gr.Blocks(title="Dr. Aldo Henrique - iAldo AI Assistant", theme=gr.themes.Soft(), css=css_customizado) as interface:
794
  session_id_state = gr.State(str(uuid.uuid4()))
795
 
796
- # Layout principal
797
- with gr.Row(elem_classes="main-layout"):
798
- # Sidebar
799
- with gr.Column(elem_classes="sidebar", scale=0, min_width=280):
800
- # Header da sidebar
801
  gr.HTML("""
802
  <div class="sidebar-header">
803
- <div class="logo">
804
- <div class="logo-icon">🤖</div>
805
- <div class="logo-text">iAldo AI</div>
806
- </div>
807
- <button class="new-chat-btn">
808
- <span>➕</span>
809
- Nova Conversa
810
- </button>
811
  </div>
812
  """)
813
 
814
- # Conteúdo da sidebar
815
- with gr.Column(elem_classes="sidebar-content"):
816
- # Seletor de modelo
817
- with gr.Group():
818
- gr.HTML('<h3>🧠 Modelo de IA</h3>')
819
- modelo_select = gr.Dropdown(
820
- choices=list(MODELS.keys()),
821
- value="Llama 3.2 3B",
822
- label="",
823
- show_label=False,
824
- elem_classes="model-selector",
825
- container=False
826
- )
827
-
828
- # Status da API
829
- with gr.Accordion("🔧 Status do Sistema", open=False, elem_classes="sidebar-accordion"):
830
- status_api = gr.Textbox(
831
- label="",
832
- interactive=False,
833
- lines=3,
834
- show_label=False,
835
- value="✅ Sistema inicializado\n🤖 Modelos carregados\n🔄 Pronto para uso",
836
- container=False
837
- )
838
-
839
- # Configurações
840
- with gr.Accordion("⚙️ Configurações", open=False, elem_classes="sidebar-accordion"):
841
- gr.HTML("""
842
- <div style="font-size: 14px; line-height: 1.6; color: #6b7280;">
843
- <p><strong>💡 Dicas de uso:</strong></p>
844
- <ul style="margin: 8px 0; padding-left: 20px;">
845
- <li>Faça perguntas específicas</li>
846
- <li>Use o RAG para consultar conhecimento</li>
847
- <li>Experimente diferentes modelos</li>
848
- </ul>
849
- </div>
850
- """)
851
-
852
- # Informações
853
- with gr.Accordion("ℹ️ Sobre o Dr. Aldo", open=False, elem_classes="sidebar-accordion"):
854
- gr.HTML("""
855
- <div style="font-size: 14px; line-height: 1.6; color: #6b7280;">
856
- <p><strong>🎓 Especialidades:</strong></p>
857
- <ul style="margin: 8px 0; padding-left: 20px;">
858
- <li>C/C++ & Java</li>
859
- <li>Desenvolvimento Web</li>
860
- <li>Inteligência Artificial</li>
861
- <li>Programação Educacional</li>
862
- </ul>
863
- <p style="margin-top: 12px;">
864
- <strong>🌐 Website:</strong><br>
865
- <a href="https://aldohenrique.com.br/" style="color: #667eea;">aldohenrique.com.br</a>
866
- </p>
867
- </div>
868
- """)
869
 
870
  # Área principal do chat
871
- with gr.Column(elem_classes="chat-area", scale=1):
872
  # Header do chat
873
  gr.HTML("""
874
  <div class="chat-header">
875
- <button class="mobile-menu-btn" onclick="toggleSidebar()">☰</button>
876
  <div class="chat-title">
877
- 💬 Conversando com <a href="https://aldohenrique.com.br/" target="_blank">Prof. Dr. Aldo Henrique</a>
878
  </div>
879
  </div>
880
  """)
881
 
882
- # Área das mensagens
883
- with gr.Column(elem_classes="messages-area"):
884
  chatbot = gr.Chatbot(
885
  label="",
886
  elem_id="chat",
887
  show_label=False,
888
  container=False,
889
  elem_classes="chatbot",
890
- avatar_images=(
891
- "https://api.dicebear.com/7.x/avataaars/svg?seed=user&backgroundColor=667eea",
892
- "https://api.dicebear.com/7.x/bottts/svg?seed=aldo&backgroundColor=f3f4f6"
893
- ),
894
  bubble_full_width=False,
895
- height="100%",
896
- show_copy_button=True
897
  )
898
 
899
  # Área de input
@@ -902,44 +709,35 @@ def criar_interface():
902
  with gr.Column(elem_classes="input-wrapper", scale=1):
903
  user_input = gr.Textbox(
904
  show_label=False,
905
- placeholder="Digite sua mensagem aqui... (Shift+Enter para nova linha)",
906
  lines=1,
907
  elem_id="entrada_usuario",
908
- max_lines=5,
909
  container=False,
910
- scale=1,
911
- autofocus=True
912
  )
 
913
  enviar_btn = gr.Button("➤", variant="primary", size="sm", elem_classes="send-button")
914
 
915
- # Overlay para mobile
916
- gr.HTML("""
917
- <div class="sidebar-overlay" onclick="toggleSidebar()"></div>
918
- """)
919
-
920
  def responder(chat_history, user_msg, modelo, session_id):
921
  if not user_msg.strip():
922
  return chat_history, ""
923
 
924
- # Adiciona a mensagem do usuário
925
- chat_history = chat_history + [[user_msg, None]]
926
  yield chat_history, ""
927
 
928
  try:
929
- # Simula typing indicator
930
- chat_history[-1][1] = "✨ Dr. Aldo está analisando sua pergunta..."
931
- yield chat_history, ""
932
-
933
- # Obtem a resposta
934
  resposta_final = responder_como_aldo(session_id, user_msg, modelo)
935
 
936
- # Atualiza com a resposta final
937
  chat_history[-1][1] = resposta_final
938
  yield chat_history, ""
939
 
940
  except Exception as e:
941
- error_msg = f"❌ **Ops! Algo deu errado**\n\nDesculpe, encontrei um problema ao processar sua mensagem:\n\n`{str(e)}`\n\nTente novamente ou reformule sua pergunta."
942
- chat_history[-1][1] = error_msg
943
  yield chat_history, ""
944
 
945
  # Eventos
@@ -957,161 +755,86 @@ def criar_interface():
957
  show_progress=False
958
  )
959
 
960
- # JavaScript para funcionalidades avançadas
961
  gr.HTML("""
962
  <script>
963
  (function() {
964
  let initialized = false;
965
 
966
- function initializeInterface() {
967
  if (initialized) return;
968
  initialized = true;
969
 
970
- // Auto-resize do textarea
971
- const textarea = document.querySelector("#entrada_usuario textarea");
972
- if (textarea) {
973
- function autoResize() {
974
- textarea.style.height = "24px";
975
- const newHeight = Math.min(textarea.scrollHeight, 120);
976
- textarea.style.height = Math.max(newHeight, 24) + "px";
977
- }
978
-
979
- textarea.addEventListener('input', autoResize);
980
- textarea.addEventListener('paste', () => setTimeout(autoResize, 10));
981
-
982
- // Foco automático
983
- setTimeout(() => textarea.focus(), 500);
984
  }
985
 
986
- // Scroll automático para última mensagem
987
- function scrollToBottom() {
988
- const chatContainer = document.querySelector(".chatbot > div");
989
- if (chatContainer) {
990
- chatContainer.scrollTop = chatContainer.scrollHeight;
991
- }
992
  }
993
 
994
- // Observer para novas mensagens
995
- const chatbot = document.querySelector(".chatbot");
996
- if (chatbot) {
997
- const observer = new MutationObserver(scrollToBottom);
998
- observer.observe(chatbot, { childList: true, subtree: true });
999
  }
1000
 
1001
- // Atalhos de teclado
1002
- document.addEventListener('keydown', function(e) {
1003
- // Ctrl/Cmd + Enter para enviar
1004
- if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
1005
- const sendBtn = document.querySelector('.send-button');
1006
- if (sendBtn && !sendBtn.disabled) {
1007
- sendBtn.click();
1008
- }
1009
- }
1010
-
1011
- // Esc para focar no input
1012
- if (e.key === 'Escape') {
1013
- const textarea = document.querySelector("#entrada_usuario textarea");
1014
- if (textarea) textarea.focus();
1015
- }
1016
- });
1017
-
1018
- console.log("Interface moderna inicializada com sucesso!");
1019
- }
1020
-
1021
- // Função para toggle da sidebar no mobile
1022
- window.toggleSidebar = function() {
1023
- const sidebar = document.querySelector('.sidebar');
1024
- const overlay = document.querySelector('.sidebar-overlay');
1025
 
1026
- if (sidebar && overlay) {
1027
- const isOpen = sidebar.classList.contains('open');
 
 
 
 
 
 
1028
 
1029
- if (isOpen) {
1030
- sidebar.classList.remove('open');
1031
- overlay.classList.remove('active');
1032
- } else {
1033
- sidebar.classList.add('open');
1034
- overlay.classList.add('active');
 
 
 
 
 
1035
  }
 
 
 
 
1036
  }
1037
- };
1038
-
1039
- // Função para nova conversa
1040
- window.newChat = function() {
1041
- const chatbot = document.querySelector('.chatbot');
1042
- if (chatbot) {
1043
- // Limpa o chat (implementar conforme necessário)
1044
- console.log("Nova conversa iniciada");
1045
- }
1046
- };
1047
-
1048
- // Detecta mudanças de tema do sistema
1049
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
1050
- mediaQuery.addListener(function(e) {
1051
- document.body.classList.toggle('dark-mode', e.matches);
1052
- });
1053
-
1054
- // Aplicar tema inicial
1055
- if (mediaQuery.matches) {
1056
- document.body.classList.add('dark-mode');
1057
  }
1058
 
1059
- // Inicialização
1060
  if (document.readyState === 'loading') {
1061
- document.addEventListener('DOMContentLoaded', initializeInterface);
1062
  } else {
1063
- setTimeout(initializeInterface, 100);
1064
- }
1065
-
1066
- // Garantir inicialização
1067
- setTimeout(initializeInterface, 1000);
1068
- setTimeout(initializeInterface, 2000);
1069
-
1070
- // Melhorar performance do scroll
1071
- let scrollTimeout;
1072
- function optimizedScrollToBottom() {
1073
- if (scrollTimeout) clearTimeout(scrollTimeout);
1074
- scrollTimeout = setTimeout(() => {
1075
- const chatContainer = document.querySelector(".chatbot > div");
1076
- if (chatContainer) {
1077
- chatContainer.scrollTo({
1078
- top: chatContainer.scrollHeight,
1079
- behavior: 'smooth'
1080
- });
1081
- }
1082
- }, 100);
1083
- }
1084
-
1085
- // Observer otimizado para mensagens
1086
- const chatObserver = new MutationObserver(function(mutations) {
1087
- let shouldScroll = false;
1088
- mutations.forEach(function(mutation) {
1089
- if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
1090
- shouldScroll = true;
1091
- }
1092
- });
1093
- if (shouldScroll) {
1094
- optimizedScrollToBottom();
1095
- }
1096
- });
1097
-
1098
- // Iniciar observer quando chatbot estiver disponível
1099
- function startChatObserver() {
1100
- const chatbot = document.querySelector(".chatbot");
1101
- if (chatbot) {
1102
- chatObserver.observe(chatbot, {
1103
- childList: true,
1104
- subtree: true,
1105
- attributes: false,
1106
- characterData: false
1107
- });
1108
- } else {
1109
- setTimeout(startChatObserver, 500);
1110
- }
1111
  }
1112
 
1113
- startChatObserver();
1114
-
 
1115
  })();
1116
  </script>
1117
  """)
@@ -1145,72 +868,30 @@ def inicializar_sistema_sync():
1145
 
1146
  def configurar_interface():
1147
  """
1148
- Configura a interface Gradio moderna com design inspirado no ChatGPT.
1149
- Lança uma exceção se o sistema não puder ser inicializado adequadamente.
1150
  """
1151
  try:
1152
- print("🚀 Inicializando sistema iAldo AI...")
1153
- status, available_models = inicializar_sistema_sync()
1154
-
1155
- if status and len(available_models) >= 1: # Relaxado para pelo menos 1 modelo
1156
- print(f"✅ Sistema inicializado com {len(available_models)} modelo(s)")
1157
- print(f"📋 Modelos disponíveis: {', '.join(available_models.keys())}")
1158
  return criar_interface()
1159
  else:
1160
- error_msg = f"Sistema não inicializado adequadamente. Modelos disponíveis: {list(available_models.keys()) if available_models else 'Nenhum'}"
1161
- print(error_msg)
1162
  raise RuntimeError(error_msg)
1163
  except Exception as e:
1164
- print(f"💥 Erro na configuração da interface: {e}")
1165
  raise
1166
 
1167
- # Função adicional para melhor experiência do usuário
1168
- def criar_mensagem_boas_vindas():
1169
- """Cria uma mensagem de boas-vindas personalizada"""
1170
- return """
1171
- 👋 **Olá! Seja bem-vindo ao iAldo AI!**
1172
-
1173
- Sou uma IA baseada no conhecimento do **Prof. Dr. Aldo Henrique**, especialista em:
1174
-
1175
- • 💻 **Programação:** C/C++, Java, Python
1176
- • 🌐 **Desenvolvimento Web:** Frontend e Backend
1177
- • 🤖 **Inteligência Artificial:** Machine Learning, Deep Learning
1178
- • 📚 **Educação:** Ensino de programação e tecnologia
1179
-
1180
- **Como posso te ajudar hoje?**
1181
-
1182
- 💡 *Dica: Use Ctrl+Enter para enviar mensagens rapidamente!*
1183
- """
1184
-
1185
  if __name__ == "__main__":
1186
  try:
1187
- print("🌟 Iniciando iAldo AI - Interface Moderna")
1188
- print("=" * 50)
1189
-
1190
  app = configurar_interface()
1191
-
1192
- print("🎯 Interface configurada com sucesso!")
1193
- print("📱 Design responsivo: ✅")
1194
- print("🎨 Tema moderno: ✅")
1195
- print("⚡ Performance otimizada: ✅")
1196
- print("=" * 50)
1197
-
1198
  app.launch(
1199
  server_name="0.0.0.0",
1200
  server_port=7860,
1201
  share=False,
1202
  debug=False,
1203
- show_error=True,
1204
- favicon_path=None,
1205
- show_tips=False,
1206
- enable_queue=True,
1207
- max_threads=40
1208
  )
1209
-
1210
  except Exception as e:
1211
- print(f"💥 Erro crítico ao iniciar a aplicação: {e}")
1212
- print("\n🔧 Sugestões para resolver:")
1213
- print("1. Verifique se todos os modelos estão configurados")
1214
- print("2. Confirme se o módulo 'ai_logic' está disponível")
1215
- print("3. Verifique as dependências do sistema")
1216
  exit(1)
 
17
  }
18
 
19
  body {
20
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
21
+ background: #0f0f23;
22
+ color: #ffffff;
23
  overflow-x: hidden;
 
 
24
  }
25
 
 
26
  .gradio-container {
27
+ background: #0f0f23 !important;
28
  min-height: 100vh !important;
29
  max-width: 100% !important;
30
  padding: 0 !important;
31
  margin: 0 !important;
32
+ overflow-x: hidden !important;
33
+ height: 100vh !important; /* FORÇA altura fixa */
34
  }
35
 
36
+ /* CRÍTICO: Layout principal com altura fixa absoluta */
37
+ .main-container {
38
  display: flex !important;
39
+ height: 100vh !important;
40
+ max-height: 100vh !important; /* Impede crescimento */
41
+ background: #0f0f23;
42
  overflow: hidden !important;
43
  position: relative;
44
  }
45
 
46
+ /* Sidebar lateral com altura fixa */
47
  .sidebar {
48
+ width: 260px;
49
+ min-width: 260px;
50
+ max-width: 260px;
51
+ background: #171717;
52
+ border-right: 1px solid #2d2d2d;
53
+ padding: 16px;
54
+ overflow-y: auto;
55
+ flex-shrink: 0;
56
  height: 100vh !important;
57
+ max-height: 100vh !important;
 
58
  }
59
 
60
  .sidebar-header {
 
 
 
 
 
 
 
61
  display: flex;
62
  align-items: center;
63
+ justify-content: space-between;
64
+ margin-bottom: 20px;
65
+ padding-bottom: 16px;
66
+ border-bottom: 1px solid #2d2d2d;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  .new-chat-btn {
70
+ background: #10a37f !important;
71
+ color: white !important;
72
+ border: none !important;
 
73
  border-radius: 8px !important;
74
+ padding: 8px 12px !important;
75
  font-size: 14px !important;
76
  font-weight: 500 !important;
77
  cursor: pointer !important;
78
  transition: all 0.2s ease !important;
 
 
 
 
79
  }
80
 
81
  .new-chat-btn:hover {
82
+ background: #0d8f6e !important;
 
 
 
 
 
 
 
83
  }
84
 
85
  .sidebar-section {
 
87
  }
88
 
89
  .sidebar-section h3 {
90
+ color: #8e8ea0;
91
  font-size: 12px;
92
  font-weight: 600;
93
  text-transform: uppercase;
94
+ letter-spacing: 1px;
95
+ margin-bottom: 8px;
96
  }
97
 
98
+ /* CRÍTICO: Área principal com altura controlada */
99
+ .chat-main {
100
  flex: 1;
101
+ display: flex !important;
102
+ flex-direction: column !important;
103
+ background: #0f0f23;
104
+ position: relative;
105
  height: 100vh !important;
106
+ max-height: 100vh !important; /* IMPEDE CRESCIMENTO */
107
+ overflow: hidden !important;
108
+ min-height: 0; /* Permite encolhimento */
109
  }
110
 
111
+ /* Header do chat com altura fixa */
112
  .chat-header {
113
+ background: #171717;
114
+ border-bottom: 1px solid #2d2d2d;
115
+ padding: 12px 24px;
116
  display: flex;
117
  align-items: center;
118
  justify-content: center;
119
  position: relative;
120
+ z-index: 10;
121
  flex-shrink: 0;
122
+ height: 60px !important; /* Altura fixa */
123
+ min-height: 60px !important;
124
+ max-height: 60px !important;
 
 
 
 
 
 
 
 
 
 
125
  }
126
 
127
  .chat-title {
128
+ color: #ffffff;
129
  font-size: 16px;
130
  font-weight: 600;
131
  text-align: center;
132
  }
133
 
134
  .chat-title a {
135
+ color: #10a37f;
136
  text-decoration: none;
137
  }
138
 
 
140
  text-decoration: underline;
141
  }
142
 
143
+ /* SOLUÇÃO PRINCIPAL: Container de mensagens com altura calculada */
144
+ .messages-container {
145
+ flex: 1 !important; /* Ocupa espaço disponível */
146
+ display: flex !important;
147
+ flex-direction: column !important;
148
+ background: #0f0f23;
149
+ min-height: 0 !important; /* PERMITE ENCOLHIMENTO */
150
+ max-height: calc(100vh - 180px) !important; /* Altura máxima calculada (total - header - input) */
151
+ overflow: hidden !important;
152
+ position: relative !important;
153
  }
154
 
155
+ /* CRÍTICO: Chatbot com scroll controlado */
156
  .chatbot {
157
  flex: 1 !important;
158
+ min-height: 0 !important; /* PERMITE ENCOLHIMENTO */
159
  height: 100% !important;
160
+ max-height: 100% !important; /* NÃO ULTRAPASSA O CONTAINER */
161
+ overflow: hidden !important; /* Container não faz scroll */
162
  background: transparent !important;
163
  border: none !important;
164
+ padding: 0 !important; /* Remove padding que pode causar overflow */
165
  margin: 0 !important;
166
+ position: relative !important;
167
  }
168
 
169
+ /* Container interno com scroll */
170
  .chatbot > div {
171
  height: 100% !important;
172
+ max-height: 100% !important;
173
+ overflow-y: auto !important; /* APENAS ESTE DIV FAZ SCROLL */
174
  overflow-x: hidden !important;
175
+ padding: 16px 24px !important; /* Padding interno */
176
  scroll-behavior: smooth !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  }
178
 
179
+ /* CRÍTICO: Área de input com altura fixa */
 
 
 
 
 
 
 
 
180
  .input-area {
181
+ background: #0f0f23;
 
182
  padding: 24px;
183
+ border-top: 1px solid #2d2d2d;
184
+ flex-shrink: 0 !important; /* NUNCA ENCOLHE */
185
+ position: relative;
186
+ z-index: 20;
187
+ height: 120px !important; /* Altura fixa para area do input */
188
+ min-height: 120px !important;
189
+ max-height: 120px !important;
190
  }
191
 
192
  .input-container {
193
  max-width: 768px;
194
  margin: 0 auto;
195
  position: relative;
196
+ height: 100%;
197
+ display: flex;
198
+ align-items: center;
199
  }
200
 
201
  .input-wrapper {
202
+ background: #2d2d2d;
203
+ border: 1px solid #4d4d4d;
204
+ border-radius: 12px;
205
+ padding: 12px 16px;
206
  display: flex;
207
  align-items: flex-end;
208
  gap: 12px;
209
  transition: all 0.2s ease;
210
+ width: 100%;
211
+ max-height: 72px; /* Altura máxima do wrapper de input */
212
  }
213
 
214
  .input-wrapper:focus-within {
215
+ border-color: #10a37f;
216
+ box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.2);
217
  }
218
 
219
  #entrada_usuario {
 
223
  #entrada_usuario textarea {
224
  background: transparent !important;
225
  border: none !important;
226
+ color: #ffffff !important;
227
  font-size: 16px !important;
228
  line-height: 1.5 !important;
229
  resize: none !important;
230
  outline: none !important;
231
  min-height: 24px !important;
232
+ max-height: 48px !important; /* Reduzido para não afetar layout */
233
  height: 24px !important;
234
  padding: 0 !important;
235
  margin: 0 !important;
236
+ overflow-y: auto !important;
237
  }
238
 
239
  #entrada_usuario textarea::placeholder {
240
+ color: #8e8ea0 !important;
241
  }
242
 
243
  .send-button {
244
+ width: 32px;
245
+ height: 32px;
246
+ background: #10a37f !important;
247
  border: none !important;
248
+ border-radius: 6px !important;
249
  color: white !important;
250
  cursor: pointer !important;
251
  display: flex !important;
 
253
  justify-content: center !important;
254
  transition: all 0.2s ease !important;
255
  flex-shrink: 0;
 
256
  }
257
 
258
  .send-button:hover:not(:disabled) {
259
+ background: #0d8f6e !important;
 
260
  }
261
 
262
  .send-button:disabled {
263
+ background: #4d4d4d !important;
264
  cursor: not-allowed !important;
 
265
  }
266
 
267
+ /* Estilo das mensagens */
268
+ .message {
269
+ width: 100%;
270
+ padding: 16px 0;
271
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
272
+ }
273
+
274
+ .message-content {
275
+ max-width: 768px;
276
+ margin: 0 auto;
277
+ padding: 0 24px;
278
+ display: flex;
279
+ gap: 16px;
280
+ align-items: flex-start;
281
+ }
282
+
283
+ .message-avatar {
284
+ width: 32px;
285
+ height: 32px;
286
+ border-radius: 50%;
287
+ flex-shrink: 0;
288
+ display: flex;
289
+ align-items: center;
290
+ justify-content: center;
291
+ font-size: 16px;
292
+ font-weight: 600;
293
+ }
294
+
295
+ .user-avatar {
296
+ background: #10a37f;
297
+ color: white;
298
+ }
299
+
300
+ .bot-avatar {
301
+ background: #5436da;
302
+ color: white;
303
+ }
304
+
305
+ .message-text {
306
+ flex: 1;
307
+ line-height: 1.7;
308
+ font-size: 16px;
309
+ color: #ffffff;
310
  }
311
 
312
+ .message.user {
313
+ background: rgba(16, 163, 127, 0.05);
314
  }
315
 
316
+ .message.assistant {
317
+ background: rgba(84, 54, 218, 0.05);
318
+ }
319
+
320
+ /* Modelo selector na sidebar */
321
+ .model-selector {
322
+ background: #2d2d2d;
323
+ border: 1px solid #4d4d4d;
324
+ border-radius: 8px;
325
+ padding: 8px 12px;
326
+ color: #ffffff;
327
+ font-size: 14px;
328
  }
329
 
330
+ /* Accordions na sidebar */
331
+ .sidebar .gr-accordion {
332
+ background: transparent !important;
333
+ border: 1px solid #2d2d2d !important;
334
  border-radius: 8px !important;
335
  margin-bottom: 16px !important;
 
336
  }
337
 
338
+ .sidebar .gr-accordion summary {
339
+ background: #2d2d2d !important;
340
+ color: #ffffff !important;
341
+ padding: 12px 16px !important;
342
+ border-radius: 8px !important;
343
  font-weight: 500 !important;
 
 
 
344
  }
345
 
346
+ .sidebar .gr-accordion[open] summary {
347
+ border-bottom: 1px solid #4d4d4d !important;
348
+ border-radius: 8px 8px 0 0 !important;
349
  }
350
 
351
+ .sidebar .gr-accordion .gr-panel {
352
+ background: #1a1a1a !important;
 
 
 
 
353
  padding: 16px !important;
354
+ border-radius: 0 0 8px 8px !important;
355
  }
356
 
357
  /* Estilo para código */
358
  .message pre {
359
+ background: #1e1e1e !important;
360
+ border: 1px solid #3e3e3e !important;
361
  border-radius: 8px !important;
362
  padding: 16px !important;
363
+ margin: 12px 0 !important;
364
  overflow-x: auto !important;
365
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
366
  font-size: 14px !important;
367
  line-height: 1.5 !important;
368
  }
369
 
370
  .message code {
371
+ background: rgba(255, 255, 255, 0.1) !important;
372
  padding: 2px 6px !important;
373
  border-radius: 4px !important;
374
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
375
  font-size: 14px !important;
 
376
  }
377
 
378
  .message pre code {
 
382
 
383
  /* Links */
384
  .message a {
385
+ color: #10a37f !important;
386
  text-decoration: none !important;
387
  }
388
 
 
392
 
393
  /* Listas */
394
  .message ul, .message ol {
395
+ margin: 12px 0 !important;
396
  padding-left: 24px !important;
397
  }
398
 
399
  .message li {
400
+ margin: 6px 0 !important;
401
  line-height: 1.6 !important;
402
  }
403
 
 
406
  border-collapse: collapse !important;
407
  width: 100% !important;
408
  margin: 16px 0 !important;
409
+ background: rgba(255, 255, 255, 0.05) !important;
 
410
  border-radius: 8px !important;
411
  overflow: hidden !important;
412
  }
413
 
414
  .message th, .message td {
415
+ border: 1px solid #3e3e3e !important;
416
  padding: 12px !important;
417
  text-align: left !important;
418
  }
419
 
420
  .message th {
421
+ background: rgba(255, 255, 255, 0.1) !important;
422
  font-weight: 600 !important;
 
423
  }
424
 
425
  /* Scrollbar personalizada */
426
  ::-webkit-scrollbar {
427
+ width: 8px;
428
+ height: 8px;
429
  }
430
 
431
  ::-webkit-scrollbar-track {
432
+ background: #1a1a1a;
433
  }
434
 
435
  ::-webkit-scrollbar-thumb {
436
+ background: #4d4d4d;
437
+ border-radius: 4px;
438
  }
439
 
440
  ::-webkit-scrollbar-thumb:hover {
441
+ background: #6d6d6d;
442
  }
443
 
444
+ /* CRÍTICO: CSS para componentes Gradio específicos */
445
+ .gr-column:has(.messages-container) {
446
+ flex: 1 !important;
447
+ min-height: 0 !important;
448
+ max-height: calc(100vh - 180px) !important;
449
+ overflow: hidden !important;
 
450
  }
451
 
452
+ .gr-column:has(.input-area) {
453
+ flex-shrink: 0 !important;
454
+ height: 120px !important;
455
+ min-height: 120px !important;
456
+ max-height: 120px !important;
457
  }
458
 
459
+ /* Força o container principal do gradio */
460
+ .gradio-container > .gr-column {
461
+ height: 100vh !important;
462
+ max-height: 100vh !important;
463
+ overflow: hidden !important;
464
  }
465
 
466
+ /* Responsive */
467
+ @media (max-width: 768px) {
468
+ .main-container {
469
+ flex-direction: column;
470
+ height: 100vh !important;
471
+ max-height: 100vh !important;
472
+ }
473
+
474
+ .sidebar {
475
+ width: 100%;
476
+ height: 200px !important;
477
+ max-height: 200px !important;
478
+ min-height: 200px !important;
479
+ border-right: none;
480
+ border-bottom: 1px solid #2d2d2d;
481
+ }
482
+
483
+ .chat-main {
484
+ height: calc(100vh - 200px) !important;
485
+ max-height: calc(100vh - 200px) !important;
486
+ }
487
+
488
+ .messages-container {
489
+ max-height: calc(100vh - 320px) !important;
490
+ }
491
+
492
+ .message-content {
493
+ padding: 0 16px;
494
+ gap: 12px;
495
+ }
496
+
497
+ .message-avatar {
498
+ width: 28px;
499
+ height: 28px;
500
+ font-size: 14px;
501
+ }
502
+
503
+ .input-area {
504
+ padding: 16px;
505
+ height: 100px !important;
506
+ max-height: 100px !important;
507
+ }
508
+
509
+ .message-text {
510
+ font-size: 15px;
511
+ }
512
  }
513
 
514
  /* Animações */
515
  .message {
516
+ animation: fadeIn 0.3s ease-out;
517
  }
518
 
519
+ @keyframes fadeIn {
520
  from {
521
  opacity: 0;
522
+ transform: translateY(10px);
523
  }
524
  to {
525
  opacity: 1;
 
527
  }
528
  }
529
 
530
+ /* Estado de carregamento */
531
  .loading-indicator {
532
+ display: inline-flex;
533
  align-items: center;
534
  gap: 8px;
535
+ color: #8e8ea0;
536
  font-style: italic;
537
  }
538
 
539
  .loading-dots {
540
+ display: inline-flex;
541
+ gap: 2px;
542
  }
543
 
544
  .loading-dots span {
545
+ width: 4px;
546
+ height: 4px;
547
+ background: #8e8ea0;
548
  border-radius: 50%;
549
+ animation: pulse 1.4s ease-in-out infinite both;
550
  }
551
 
552
  .loading-dots span:nth-child(1) { animation-delay: -0.32s; }
553
  .loading-dots span:nth-child(2) { animation-delay: -0.16s; }
554
  .loading-dots span:nth-child(3) { animation-delay: 0s; }
555
 
556
+ @keyframes pulse {
557
  0%, 80%, 100% {
558
+ opacity: 0.3;
 
559
  }
560
  40% {
 
561
  opacity: 1;
562
  }
563
  }
564
 
565
+ /* Ocultar elementos desnecessários do Gradio */
566
+ .gr-button-lg {
567
+ display: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  }
569
 
570
+ /* Customizar os componentes específicos */
571
+ .gr-textbox {
572
+ background: transparent !important;
573
+ border: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
574
  }
575
 
576
+ .gr-dropdown {
577
+ background: #2d2d2d !important;
578
+ border: 1px solid #4d4d4d !important;
579
+ border-radius: 8px !important;
580
+ color: #ffffff !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  }
582
 
583
+ /* Botões personalizados */
584
+ .control-button {
585
+ background: #2d2d2d !important;
586
+ color: #ffffff !important;
587
+ border: 1px solid #4d4d4d !important;
588
+ border-radius: 8px !important;
589
+ padding: 8px 16px !important;
590
+ font-size: 14px !important;
591
+ cursor: pointer !important;
592
+ transition: all 0.2s ease !important;
593
  }
594
 
595
+ .control-button:hover {
596
+ background: #3d3d3d !important;
597
+ border-color: #6d6d6d !important;
598
  }
599
 
600
+ .control-button.primary {
601
+ background: #10a37f !important;
602
+ border-color: #10a37f !important;
603
  }
604
 
605
+ .control-button.primary:hover {
606
+ background: #0d8f6e !important;
 
 
 
 
 
 
 
607
  }
608
 
609
+ /* Status indicators */
610
+ .status-indicator {
611
+ font-size: 12px;
612
+ padding: 4px 8px;
613
+ border-radius: 4px;
614
+ font-weight: 500;
615
  }
616
 
617
+ .status-success {
618
+ background: rgba(16, 163, 127, 0.2);
619
+ color: #10a37f;
620
+ border: 1px solid rgba(16, 163, 127, 0.3);
621
  }
622
 
623
+ .status-error {
624
+ background: rgba(239, 68, 68, 0.2);
625
+ color: #ef4444;
626
+ border: 1px solid rgba(239, 68, 68, 0.3);
627
  }
628
 
629
+ .status-warning {
630
+ background: rgba(245, 158, 11, 0.2);
631
+ color: #f59e0b;
632
+ border: 1px solid rgba(245, 158, 11, 0.3);
 
 
 
633
  }
634
  """
635
 
636
  def criar_interface():
637
+ with gr.Blocks(title="Dr. Aldo Henrique - iAldo AI Assistant", theme=gr.themes.Base(), css=css_customizado) as interface:
638
  session_id_state = gr.State(str(uuid.uuid4()))
639
 
640
+ with gr.Row(elem_classes="main-container"):
641
+ # Sidebar esquerda
642
+ with gr.Column(elem_classes="sidebar", scale=0, min_width=260):
 
 
643
  gr.HTML("""
644
  <div class="sidebar-header">
645
+ <h2 style="color: #10a37f; font-size: 18px; font-weight: 600;">iAldo AI</h2>
 
 
 
 
 
 
 
646
  </div>
647
  """)
648
 
649
+ # Seletor de modelo
650
+ with gr.Group():
651
+ gr.HTML('<h3 style="color: #8e8ea0; font-size: 12px; font-weight: 600; text-transform: uppercase; margin-bottom: 8px;">🧠 Modelo de IA</h3>')
652
+ modelo_select = gr.Dropdown(
653
+ choices=list(MODELS.keys()),
654
+ value="Llama 3.2 3B",
655
+ label="",
656
+ show_label=False,
657
+ elem_classes="model-selector",
658
+ container=False
659
+ )
660
+
661
+ # Status da API
662
+ with gr.Accordion("🔧 Status API", open=False, elem_classes="sidebar-section"):
663
+ status_api = gr.Textbox(label="", interactive=False, lines=4, show_label=False,
664
+ value=" Modelos carregados com sucesso!")
665
+
666
+ # Informações
667
+ with gr.Accordion("ℹ️ Sobre", open=False, elem_classes="sidebar-section"):
668
+ gr.Markdown("""
669
+ **Dr. Aldo Henrique**
670
+
671
+ • Especialista em C/C++, Java
672
+ • Desenvolvimento Web & IA
673
+ • Conteúdo: aldohenrique.com.br
674
+
675
+ **Dicas:**
676
+ • Faça perguntas específicas
677
+ Use o RAG para consultar o blog
678
+ Experimente diferentes modelos
679
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
 
681
  # Área principal do chat
682
+ with gr.Column(elem_classes="chat-main", scale=1):
683
  # Header do chat
684
  gr.HTML("""
685
  <div class="chat-header">
 
686
  <div class="chat-title">
687
+ 🤖 Conversando com <a href="https://aldohenrique.com.br/" target="_blank">Prof. Dr. Aldo Henrique</a>
688
  </div>
689
  </div>
690
  """)
691
 
692
+ # Área de mensagens
693
+ with gr.Column(elem_classes="messages-container"):
694
  chatbot = gr.Chatbot(
695
  label="",
696
  elem_id="chat",
697
  show_label=False,
698
  container=False,
699
  elem_classes="chatbot",
700
+ avatar_images=("https://cdn-icons-png.flaticon.com/256/9055/9055398.png",
701
+ "https://cdn.iconscout.com/icon/premium/png-256-thumb/robo-97-415007.png"),
 
 
702
  bubble_full_width=False,
703
+ height="100%" # Força altura 100%
 
704
  )
705
 
706
  # Área de input
 
709
  with gr.Column(elem_classes="input-wrapper", scale=1):
710
  user_input = gr.Textbox(
711
  show_label=False,
712
+ placeholder="Digite sua mensagem aqui...",
713
  lines=1,
714
  elem_id="entrada_usuario",
715
+ max_lines=3, # Reduzido para não expandir muito
716
  container=False,
717
+ scale=1
 
718
  )
719
+ # Botão de envio oculto (será substituído por JavaScript)
720
  enviar_btn = gr.Button("➤", variant="primary", size="sm", elem_classes="send-button")
721
 
 
 
 
 
 
722
  def responder(chat_history, user_msg, modelo, session_id):
723
  if not user_msg.strip():
724
  return chat_history, ""
725
 
726
+ # Adiciona a mensagem do usuário ao histórico
727
+ chat_history = chat_history + [[user_msg, "🤔 Dr. Aldo está pensando..."]]
728
  yield chat_history, ""
729
 
730
  try:
731
+ # Obtem a resposta do modelo
 
 
 
 
732
  resposta_final = responder_como_aldo(session_id, user_msg, modelo)
733
 
734
+ # Atualiza o histórico com a resposta final
735
  chat_history[-1][1] = resposta_final
736
  yield chat_history, ""
737
 
738
  except Exception as e:
739
+ # Em caso de erro, mostra uma mensagem amigável
740
+ chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro: {str(e)}"
741
  yield chat_history, ""
742
 
743
  # Eventos
 
755
  show_progress=False
756
  )
757
 
758
+ # JavaScript otimizado e simplificado
759
  gr.HTML("""
760
  <script>
761
  (function() {
762
  let initialized = false;
763
 
764
+ function initLayout() {
765
  if (initialized) return;
766
  initialized = true;
767
 
768
+ // Força layout fixo imediatamente
769
+ const mainContainer = document.querySelector('.main-container');
770
+ if (mainContainer) {
771
+ mainContainer.style.height = '100vh';
772
+ mainContainer.style.maxHeight = '100vh';
773
+ mainContainer.style.overflow = 'hidden';
 
 
 
 
 
 
 
 
774
  }
775
 
776
+ const chatMain = document.querySelector('.chat-main');
777
+ if (chatMain) {
778
+ chatMain.style.height = '100vh';
779
+ chatMain.style.maxHeight = '100vh';
780
+ chatMain.style.display = 'flex';
781
+ chatMain.style.flexDirection = 'column';
782
  }
783
 
784
+ const messagesContainer = document.querySelector('.messages-container');
785
+ if (messagesContainer) {
786
+ messagesContainer.style.flex = '1';
787
+ messagesContainer.style.minHeight = '0';
788
+ messagesContainer.style.overflow = 'hidden';
789
  }
790
 
791
+ const inputArea = document.querySelector('.input-area');
792
+ if (inputArea) {
793
+ inputArea.style.flexShrink = '0';
794
+ inputArea.style.height = '120px';
795
+ inputArea.style.maxHeight = '120px';
796
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
 
798
+ // Configuração do textarea
799
+ const textarea = document.querySelector("#entrada_usuario textarea");
800
+ if (textarea) {
801
+ textarea.style.height = "24px";
802
+ textarea.style.minHeight = "24px";
803
+ textarea.style.maxHeight = "48px"; // Limitado para não quebrar layout
804
+ textarea.style.resize = "none";
805
+ textarea.style.overflowY = "hidden";
806
 
807
+ // Auto-resize limitado
808
+ function autoResize() {
809
+ textarea.style.height = "24px";
810
+ const newHeight = Math.min(textarea.scrollHeight, 48);
811
+ textarea.style.height = Math.max(newHeight, 24) + "px";
812
+
813
+ if (textarea.scrollHeight > 48) {
814
+ textarea.style.overflowY = "auto";
815
+ } else {
816
+ textarea.style.overflowY = "hidden";
817
+ }
818
  }
819
+
820
+ textarea.addEventListener('input', autoResize);
821
+ textarea.addEventListener('paste', () => setTimeout(autoResize, 0));
822
+ setTimeout(() => textarea.focus(), 300);
823
  }
824
+
825
+ console.log("Layout fixo inicializado");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
826
  }
827
 
828
+ // Executa quando DOM estiver pronto
829
  if (document.readyState === 'loading') {
830
+ document.addEventListener('DOMContentLoaded', initLayout);
831
  } else {
832
+ setTimeout(initLayout, 100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
833
  }
834
 
835
+ // Reforça o layout depois que o Gradio terminar de carregar
836
+ setTimeout(initLayout, 1000);
837
+ setTimeout(initLayout, 2000);
838
  })();
839
  </script>
840
  """)
 
868
 
869
  def configurar_interface():
870
  """
871
+ Configura a interface Gradio apenas se o sistema for inicializado com pelo menos 3 modelos disponíveis.
872
+ Lança uma exceção com a lista de modelos disponíveis se a inicialização falhar.
873
  """
874
  try:
875
+ status, available_models = inicializar_sistema()
876
+ if status:
 
 
 
 
877
  return criar_interface()
878
  else:
879
+ error_msg = f"Sistema não inicializado: menos de 3 modelos disponíveis. Modelos: {', '.join(available_models.keys()) if available_models else 'Nenhum'}"
 
880
  raise RuntimeError(error_msg)
881
  except Exception as e:
882
+ print(f"Erro na configuração da interface: {e}")
883
  raise
884
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
885
  if __name__ == "__main__":
886
  try:
 
 
 
887
  app = configurar_interface()
 
 
 
 
 
 
 
888
  app.launch(
889
  server_name="0.0.0.0",
890
  server_port=7860,
891
  share=False,
892
  debug=False,
893
+ show_error=True
 
 
 
 
894
  )
 
895
  except Exception as e:
896
+ print(f"Erro ao iniciar a aplicação: {e}")
 
 
 
 
897
  exit(1)