aldohenrique commited on
Commit
c661b4a
·
verified ·
1 Parent(s): a4781c3

Update interface.py

Browse files
Files changed (1) hide show
  1. interface.py +605 -266
interface.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
  import gradio as gr
3
  import uuid
4
  from ai_logic import (
@@ -10,189 +9,427 @@ from ai_logic import (
10
  )
11
 
12
  css_customizado = """
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  .gradio-container {
14
- max-width: 1400px !important;
15
- margin: 0 auto;
16
- width: 99%;
17
- height: 100vh !important;
18
- display: flex;
19
- flex-direction: column;
20
- overflow: hidden;
21
  }
22
- .main-content {
 
 
23
  display: flex;
24
- flex-direction: column;
25
  height: 100vh;
26
- overflow: hidden;
 
 
 
 
 
 
 
 
 
27
  flex-shrink: 0;
28
  }
29
- .titulo-principal {
30
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
 
 
 
 
 
 
 
 
 
 
31
  color: white !important;
32
- padding: 10px !important;
33
- border-radius: 10px !important;
34
- margin-bottom: 10px !important;
35
- text-align: center !important;
36
- flex-shrink: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
- .chat-area {
 
 
39
  flex: 1;
40
  display: flex;
41
  flex-direction: column;
42
- overflow: hidden;
43
- }
44
- .chat-container {
45
- flex: 1;
46
- overflow-y: auto;
47
- margin-bottom: 10px;
48
  }
49
- .input-container {
50
- flex-shrink: 0;
51
- padding: 10px 0;
 
 
 
52
  display: flex;
53
- flex-direction: column;
54
  justify-content: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
- .additional-content {
 
 
 
57
  overflow-y: auto;
58
- padding-top: 20px;
 
 
59
  }
60
- /* Estilos para o chat - Melhorias na legibilidade */
61
  .chatbot {
 
 
62
  height: 100% !important;
63
  max-height: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
- /* Mensagens do usuário */
 
 
 
 
 
 
 
66
  .message.user {
67
- background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important;
68
- color: white !important;
69
- border-radius: 18px 18px 6px 18px !important;
70
- padding: 12px 16px !important;
71
- margin: 8px 0 !important;
72
- font-size: 15px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  line-height: 1.5 !important;
74
- box-shadow: 0 2px 8px rgba(79, 70, 229, 0.3) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  border: none !important;
 
 
 
 
 
 
 
 
76
  }
77
- /* Mensagens do bot */
78
- .message.bot {
79
- background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important;
80
- color: #1e293b !important;
81
- border: 1px solid #e2e8f0 !important;
82
- border-radius: 18px 18px 18px 6px !important;
83
- padding: 16px 20px !important;
84
- margin: 8px 0 !important;
85
- font-size: 15px !important;
86
- line-height: 1.6 !important;
87
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
- /* Estilização para código dentro das mensagens */
 
 
 
 
 
 
 
 
 
 
 
 
90
  .message pre {
91
- background: #1e293b !important;
92
- color: #e2e8f0 !important;
93
  border-radius: 8px !important;
94
  padding: 16px !important;
95
  margin: 12px 0 !important;
96
  overflow-x: auto !important;
97
- font-family: 'Fira Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
98
  font-size: 14px !important;
99
  line-height: 1.5 !important;
100
- border: 1px solid #374151 !important;
101
  }
 
102
  .message code {
103
- background: #e2e8f0 !important;
104
- color: #1e293b !important;
105
  padding: 2px 6px !important;
106
  border-radius: 4px !important;
107
- font-family: 'Fira Code', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
108
- font-size: 13px !important;
109
  }
110
- /* Código inline dentro de pre */
111
  .message pre code {
112
  background: transparent !important;
113
- color: #e2e8f0 !important;
114
  padding: 0 !important;
115
- border-radius: 0 !important;
116
  }
117
- /* Estilos específicos do Gradio para chatbot */
118
- .chatbot .message-wrap {
119
- margin: 8px 0 !important;
 
 
120
  }
121
- .chatbot .message-wrap.user {
122
- justify-content: flex-end !important;
 
123
  }
124
- .chatbot .message-wrap.bot {
125
- justify-content: flex-start !important;
 
 
 
126
  }
127
- /* Melhorias na área de input */
128
- #entrada_usuario textarea {
129
- background: linear-gradient(135deg, #1e293b 0%, #374151 100%) !important;
130
- color: white !important;
131
- font-size: 15px !important;
132
- line-height: 1.5 !important;
133
- border: 2px solid #374151 !important;
134
- border-radius: 12px !important;
135
- padding: 12px 16px !important;
136
- min-height: 60px !important;
137
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
138
  }
139
- #entrada_usuario textarea:focus {
140
- border-color: #4f46e5 !important;
141
- box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1) !important;
 
 
 
 
 
 
142
  }
143
- #entrada_usuario textarea::placeholder {
144
- color: #9ca3af !important;
 
 
 
145
  }
146
- /* Botão de enviar */
147
- .gradio-button.primary {
148
- background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%) !important;
149
- border: none !important;
150
- border-radius: 12px !important;
151
- padding: 12px 24px !important;
152
  font-weight: 600 !important;
153
- font-size: 15px !important;
154
- transition: all 0.2s ease !important;
155
  }
156
- .gradio-button.primary:hover {
157
- transform: translateY(-1px) !important;
158
- box-shadow: 0 4px 12px rgba(79, 70, 229, 0.4) !important;
 
 
159
  }
160
- /* Dropdown do modelo */
161
- .modelo-dropdown {
162
- margin-bottom: 15px !important;
163
  }
164
- .modelo-dropdown .gr-dropdown {
165
- border-radius: 8px !important;
166
- border: 1px solid #d1d5db !important;
 
167
  }
168
- /* Responsividade melhorada */
 
 
 
 
 
169
  @media (max-width: 768px) {
170
- .titulo-principal {
171
- padding: 8px !important;
172
- font-size: 14px !important;
173
  }
174
 
175
- #entrada_usuario textarea {
176
- min-height: 50px !important;
177
- font-size: 16px !important;
 
 
178
  }
179
 
180
- .message.user,
181
- .message.bot {
182
- font-size: 14px !important;
183
- padding: 10px 14px !important;
184
  }
185
 
186
- .message pre {
187
- font-size: 12px !important;
188
- padding: 12px !important;
 
 
 
 
 
 
 
 
 
189
  }
190
  }
191
- /* Animações suaves */
 
192
  .message {
193
- animation: fadeInUp 0.3s ease-out !important;
194
  }
195
- @keyframes fadeInUp {
 
196
  from {
197
  opacity: 0;
198
  transform: translateY(10px);
@@ -202,151 +439,226 @@ css_customizado = """
202
  transform: translateY(0);
203
  }
204
  }
205
- /* Melhorias gerais na tipografia */
206
- .chatbot {
207
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif !important;
 
 
 
 
 
 
 
 
 
 
208
  }
209
- /* Scroll personalizado para o chat */
210
- .chat-container::-webkit-scrollbar {
211
- width: 6px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
- .chat-container::-webkit-scrollbar-track {
214
- background: #f1f5f9;
215
- border-radius: 3px;
 
216
  }
217
- .chat-container::-webkit-scrollbar-thumb {
218
- background: #cbd5e1;
219
- border-radius: 3px;
 
 
220
  }
221
- .chat-container::-webkit-scrollbar-thumb:hover {
222
- background: #94a3b8;
 
 
 
 
223
  }
224
- /* Força aplicação dos estilos */
225
- #component-6 { flex-grow: initial !important; }
226
- #component-7 { flex-grow: initial !important; }
227
- .message-wrap.svelte-gjtrl6 .prose.chatbot.md {
228
- opacity: 1 !important;
 
 
 
 
 
 
229
  }
230
- /* Estilo para links */
231
- .message a {
232
- color: #4f46e5 !important;
233
- text-decoration: underline !important;
234
  }
235
- .message.user a {
236
- color: #e0e7ff !important;
 
 
237
  }
238
- /* Estilo para listas */
239
- .message ul, .message ol {
240
- margin: 12px 0 !important;
241
- padding-left: 20px !important;
242
  }
243
- .message li {
244
- margin: 6px 0 !important;
245
- line-height: 1.6 !important;
 
 
 
 
246
  }
247
- /* Estilo para tabelas */
248
- .message table {
249
- border-collapse: collapse !important;
250
- width: 100% !important;
251
- margin: 12px 0 !important;
252
  }
253
- .message th, .message td {
254
- border: 1px solid #d1d5db !important;
255
- padding: 8px 12px !important;
256
- text-align: left !important;
 
257
  }
258
- .message th {
259
- background: #f8fafc !important;
260
- font-weight: 600 !important;
 
 
261
  }
262
  """
263
 
264
  def criar_interface():
265
- with gr.Blocks(title="Dr. Aldo Henrique - API Externa", theme=gr.themes.Soft(), css=css_customizado) as interface:
266
- session_id_state = gr.State(str(uuid.uuid4())) # Geração do session_id único
267
-
268
- with gr.Column(elem_classes="main-content"):
269
- gr.HTML("""
270
- <div class="titulo-principal">
271
- <h4 style="margin: 0;">🤖 iAldo - Converse com o <a href="https://aldohenrique.com.br/" style="color: white; text-decoration: underline;">Prof. Dr. Aldo Henrique</a></h4>
272
- </div>
273
- """)
274
-
275
- with gr.Column(elem_classes="chat-area"):
276
- with gr.Column(elem_classes="chat-container"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  chatbot = gr.Chatbot(
278
- label="💬 Área do chat",
279
  elem_id="chat",
280
- height="100%",
281
  show_label=False,
282
- container=True,
283
- scale=1,
284
- min_width=160,
285
- visible=True,
286
- elem_classes="chatbot"
287
  )
288
 
289
- with gr.Column(elem_classes="input-container"):
290
- with gr.Row():
291
- modelo_select = gr.Dropdown(
292
- choices=list(MODELS.keys()),
293
- value=DEFAULT_MODEL,
294
- label="🧠 Selecione o Modelo de Pensamento",
295
- elem_classes="modelo-dropdown"
296
- )
297
- with gr.Row():
298
- user_input = gr.Textbox(
299
- show_label=False,
300
- placeholder="Digite sua pergunta e pressione Enter ou clique em Enviar",
301
- lines=2,
302
- elem_id="entrada_usuario",
303
- max_lines=6
304
- )
305
- enviar_btn = gr.Button("Enviar", variant="primary", size="lg")
306
-
307
- with gr.Column(elem_classes="additional-content"):
308
- with gr.Accordion("⚙️ Controle do Conhecimento (RAG)", open=False):
309
- status_rag = gr.Textbox(label="Status do Retreino", interactive=False)
310
- botao_retreinar = gr.Button("🔄 Atualizar Conhecimento do Blog", variant="stop")
311
- download_faiss_file = gr.File(label="Download do Índice FAISS", interactive=False, file_count="single", file_types=[".pkl"])
312
- download_urls_file = gr.File(label="Download das URLs Processadas", interactive=False, file_count="single", file_types=[".pkl"])
313
-
314
- with gr.Accordion("📚 Exemplos de Perguntas", open=False):
315
- gr.Examples(
316
- examples=[
317
- ["Como implementar uma lista ligada em C com todas as operações básicas?", DEFAULT_MODEL],
318
- ["Qual a sua opinião sobre o uso de ponteiros em C++ moderno, baseada no seu blog?", "Mistral 7B (Mais acertivo)"],
319
- ["Resuma o que você escreveu sobre machine learning no seu blog.", "Zephyr 7B (Meio Termo)"],
320
- ],
321
- inputs=[user_input, modelo_select]
322
- )
323
-
324
- with gr.Accordion("🔧 Status da API", open=False):
325
- status_api = gr.Textbox(label="Status dos Modelos", interactive=False, lines=8,
326
- value="Modelos carregados com sucesso! Verifique o console para detalhes.")
327
-
328
- with gr.Accordion("ℹ️ Informações", open=False):
329
- gr.Markdown("""
330
- ### Sobre o Dr. Aldo Henrique:
331
- - **Especialidade**: Linguagens C, Java, Desenvolvimento Web, Inteligência Artificial
332
- - **Conhecimento Adicional**: Conteúdo do blog aldohenrique.com.br
333
- ### Dicas para melhores respostas:
334
- - Faça perguntas específicas sobre o conteúdo do blog para ver o RAG em ação!
335
- - Peça resumos ou opiniões sobre temas que o professor aborda.
336
-
337
- ### Melhorias na Interface:
338
- - **Mensagens do usuário**: Estilo moderno com gradiente azul/roxo
339
- - **Respostas do bot**: Fundo claro com excelente contraste para leitura
340
- - **Códigos**: Syntax highlighting com fundo escuro e fonte monospace
341
- - **Responsivo**: Otimizado para desktop e mobile
342
- """)
343
 
344
  def responder(chat_history, user_msg, modelo, session_id):
345
  if not user_msg.strip():
346
  return chat_history, ""
347
 
348
  # Adiciona a mensagem do usuário ao histórico
349
- chat_history = chat_history + [[user_msg, "🤖 Dr. Aldo Henrique está digitando..."]]
350
  yield chat_history, ""
351
 
352
  try:
@@ -359,22 +671,22 @@ def criar_interface():
359
 
360
  except Exception as e:
361
  # Em caso de erro, mostra uma mensagem amigável
362
- chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro ao processar sua mensagem: {str(e)}"
363
  yield chat_history, ""
364
 
365
- # Eventos de clique e submit
366
  enviar_btn.click(
367
  fn=responder,
368
  inputs=[chatbot, user_input, modelo_select, session_id_state],
369
  outputs=[chatbot, user_input],
370
- show_progress=True
371
  )
372
 
373
  user_input.submit(
374
  fn=responder,
375
  inputs=[chatbot, user_input, modelo_select, session_id_state],
376
  outputs=[chatbot, user_input],
377
- show_progress=True
378
  )
379
 
380
  botao_retreinar.click(
@@ -383,22 +695,39 @@ def criar_interface():
383
  show_progress=True
384
  )
385
 
386
- # Script para focar no input ao carregar a página
387
  gr.HTML("""
388
  <script>
389
- window.addEventListener("load", function() {
390
- const textarea = document.querySelector("#entrada_usuario textarea");
391
- if (textarea) {
392
- setTimeout(() => {
393
- textarea.focus();
394
- // Adiciona evento para redimensionar automaticamente
395
- textarea.addEventListener('input', function() {
396
- this.style.height = 'auto';
397
- this.style.height = this.scrollHeight + 'px';
398
- });
399
- }, 100);
400
- }
401
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  </script>
403
  """)
404
 
@@ -407,14 +736,24 @@ def criar_interface():
407
  def inicializar_sistema_sync():
408
  """Função síncrona para compatibilidade"""
409
  try:
410
- loop = asyncio.get_event_loop()
411
- if loop.is_running():
412
- import concurrent.futures
413
- with concurrent.futures.ThreadPoolExecutor() as executor:
414
- future = executor.submit(asyncio.run, inicializar_sistema_sync()) # Erro: chama a si mesma
415
- return future.result()
416
- else:
417
- return loop.run_until_complete(inicializar_sistema_sync()) # Erro: chama a si mesma
 
 
 
 
 
 
 
 
 
 
418
  except Exception as e:
419
  print(f"Erro na inicialização: {e}")
420
  return False, {}
@@ -429,7 +768,7 @@ def configurar_interface():
429
  if status:
430
  return criar_interface()
431
  else:
432
- error_msg = f"Não foi possível inicializar o sistema: menos de 3 modelos de IA disponíveis. Modelos disponíveis: {', '.join(available_models.keys()) if available_models else 'Nenhum'}"
433
  raise RuntimeError(error_msg)
434
  except Exception as e:
435
  print(f"Erro na configuração da interface: {e}")
@@ -447,4 +786,4 @@ if __name__ == "__main__":
447
  )
448
  except Exception as e:
449
  print(f"Erro ao iniciar a aplicação: {e}")
450
- exit(1)
 
 
1
  import gradio as gr
2
  import uuid
3
  from ai_logic import (
 
9
  )
10
 
11
  css_customizado = """
12
+ /* Reset e configurações básicas */
13
+ * {
14
+ margin: 0;
15
+ padding: 0;
16
+ box-sizing: border-box;
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
+ }
24
+
25
  .gradio-container {
26
+ background: #0f0f23 !important;
27
+ min-height: 100vh !important;
28
+ max-width: 100% !important;
29
+ padding: 0 !important;
30
+ margin: 0 !important;
 
 
31
  }
32
+
33
+ /* Layout principal estilo ChatGPT */
34
+ .main-container {
35
  display: flex;
 
36
  height: 100vh;
37
+ background: #0f0f23;
38
+ }
39
+
40
+ /* Sidebar lateral */
41
+ .sidebar {
42
+ width: 260px;
43
+ background: #171717;
44
+ border-right: 1px solid #2d2d2d;
45
+ padding: 16px;
46
+ overflow-y: auto;
47
  flex-shrink: 0;
48
  }
49
+
50
+ .sidebar-header {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ margin-bottom: 20px;
55
+ padding-bottom: 16px;
56
+ border-bottom: 1px solid #2d2d2d;
57
+ }
58
+
59
+ .new-chat-btn {
60
+ background: #10a37f !important;
61
  color: white !important;
62
+ border: none !important;
63
+ border-radius: 8px !important;
64
+ padding: 8px 12px !important;
65
+ font-size: 14px !important;
66
+ font-weight: 500 !important;
67
+ cursor: pointer !important;
68
+ transition: all 0.2s ease !important;
69
+ }
70
+
71
+ .new-chat-btn:hover {
72
+ background: #0d8f6e !important;
73
+ }
74
+
75
+ .sidebar-section {
76
+ margin-bottom: 24px;
77
+ }
78
+
79
+ .sidebar-section h3 {
80
+ color: #8e8ea0;
81
+ font-size: 12px;
82
+ font-weight: 600;
83
+ text-transform: uppercase;
84
+ letter-spacing: 1px;
85
+ margin-bottom: 8px;
86
  }
87
+
88
+ /* Área principal do chat */
89
+ .chat-main {
90
  flex: 1;
91
  display: flex;
92
  flex-direction: column;
93
+ background: #0f0f23;
94
+ position: relative;
 
 
 
 
95
  }
96
+
97
+ /* Header do chat */
98
+ .chat-header {
99
+ background: #171717;
100
+ border-bottom: 1px solid #2d2d2d;
101
+ padding: 12px 24px;
102
  display: flex;
103
+ align-items: center;
104
  justify-content: center;
105
+ position: relative;
106
+ z-index: 10;
107
+ }
108
+
109
+ .chat-title {
110
+ color: #ffffff;
111
+ font-size: 16px;
112
+ font-weight: 600;
113
+ text-align: center;
114
+ }
115
+
116
+ .chat-title a {
117
+ color: #10a37f;
118
+ text-decoration: none;
119
+ }
120
+
121
+ .chat-title a:hover {
122
+ text-decoration: underline;
123
  }
124
+
125
+ /* Área de mensagens */
126
+ .messages-container {
127
+ flex: 1;
128
  overflow-y: auto;
129
+ padding: 0;
130
+ background: #0f0f23;
131
+ scroll-behavior: smooth;
132
  }
133
+
134
  .chatbot {
135
+ background: transparent !important;
136
+ border: none !important;
137
  height: 100% !important;
138
  max-height: none !important;
139
+ padding: 0 !important;
140
+ }
141
+
142
+ /* Estilo das mensagens - similar ao ChatGPT */
143
+ .message {
144
+ width: 100%;
145
+ padding: 24px 0;
146
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
147
+ }
148
+
149
+ .message-content {
150
+ max-width: 768px;
151
+ margin: 0 auto;
152
+ padding: 0 24px;
153
+ display: flex;
154
+ gap: 16px;
155
+ align-items: flex-start;
156
+ }
157
+
158
+ .message-avatar {
159
+ width: 32px;
160
+ height: 32px;
161
+ border-radius: 50%;
162
+ flex-shrink: 0;
163
+ display: flex;
164
+ align-items: center;
165
+ justify-content: center;
166
+ font-size: 16px;
167
+ font-weight: 600;
168
+ }
169
+
170
+ .user-avatar {
171
+ background: #10a37f;
172
+ color: white;
173
+ }
174
+
175
+ .bot-avatar {
176
+ background: #5436da;
177
+ color: white;
178
  }
179
+
180
+ .message-text {
181
+ flex: 1;
182
+ line-height: 1.7;
183
+ font-size: 16px;
184
+ color: #ffffff;
185
+ }
186
+
187
  .message.user {
188
+ background: rgba(16, 163, 127, 0.05);
189
+ }
190
+
191
+ .message.assistant {
192
+ background: rgba(84, 54, 218, 0.05);
193
+ }
194
+
195
+ /* Área de input inferior */
196
+ .input-area {
197
+ background: #0f0f23;
198
+ padding: 24px;
199
+ border-top: 1px solid #2d2d2d;
200
+ }
201
+
202
+ .input-container {
203
+ max-width: 768px;
204
+ margin: 0 auto;
205
+ position: relative;
206
+ }
207
+
208
+ .input-wrapper {
209
+ background: #2d2d2d;
210
+ border: 1px solid #4d4d4d;
211
+ border-radius: 12px;
212
+ padding: 12px 16px;
213
+ display: flex;
214
+ align-items: flex-end;
215
+ gap: 12px;
216
+ transition: all 0.2s ease;
217
+ }
218
+
219
+ .input-wrapper:focus-within {
220
+ border-color: #10a37f;
221
+ box-shadow: 0 0 0 2px rgba(16, 163, 127, 0.2);
222
+ }
223
+
224
+ #entrada_usuario {
225
+ flex: 1;
226
+ }
227
+
228
+ #entrada_usuario textarea {
229
+ background: transparent !important;
230
+ border: none !important;
231
+ color: #ffffff !important;
232
+ font-size: 16px !important;
233
  line-height: 1.5 !important;
234
+ resize: none !important;
235
+ outline: none !important;
236
+ min-height: 24px !important;
237
+ max-height: 200px !important;
238
+ padding: 0 !important;
239
+ margin: 0 !important;
240
+ }
241
+
242
+ #entrada_usuario textarea::placeholder {
243
+ color: #8e8ea0 !important;
244
+ }
245
+
246
+ .send-button {
247
+ width: 32px;
248
+ height: 32px;
249
+ background: #10a37f !important;
250
  border: none !important;
251
+ border-radius: 6px !important;
252
+ color: white !important;
253
+ cursor: pointer !important;
254
+ display: flex !important;
255
+ align-items: center !important;
256
+ justify-content: center !important;
257
+ transition: all 0.2s ease !important;
258
+ flex-shrink: 0;
259
  }
260
+
261
+ .send-button:hover:not(:disabled) {
262
+ background: #0d8f6e !important;
263
+ }
264
+
265
+ .send-button:disabled {
266
+ background: #4d4d4d !important;
267
+ cursor: not-allowed !important;
268
+ }
269
+
270
+ /* Modelo selector na sidebar */
271
+ .model-selector {
272
+ background: #2d2d2d;
273
+ border: 1px solid #4d4d4d;
274
+ border-radius: 8px;
275
+ padding: 8px 12px;
276
+ color: #ffffff;
277
+ font-size: 14px;
278
+ }
279
+
280
+ /* Accordions na sidebar */
281
+ .sidebar .gr-accordion {
282
+ background: transparent !important;
283
+ border: 1px solid #2d2d2d !important;
284
+ border-radius: 8px !important;
285
+ margin-bottom: 16px !important;
286
+ }
287
+
288
+ .sidebar .gr-accordion summary {
289
+ background: #2d2d2d !important;
290
+ color: #ffffff !important;
291
+ padding: 12px 16px !important;
292
+ border-radius: 8px !important;
293
+ font-weight: 500 !important;
294
  }
295
+
296
+ .sidebar .gr-accordion[open] summary {
297
+ border-bottom: 1px solid #4d4d4d !important;
298
+ border-radius: 8px 8px 0 0 !important;
299
+ }
300
+
301
+ .sidebar .gr-accordion .gr-panel {
302
+ background: #1a1a1a !important;
303
+ padding: 16px !important;
304
+ border-radius: 0 0 8px 8px !important;
305
+ }
306
+
307
+ /* Estilo para código */
308
  .message pre {
309
+ background: #1e1e1e !important;
310
+ border: 1px solid #3e3e3e !important;
311
  border-radius: 8px !important;
312
  padding: 16px !important;
313
  margin: 12px 0 !important;
314
  overflow-x: auto !important;
315
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
316
  font-size: 14px !important;
317
  line-height: 1.5 !important;
 
318
  }
319
+
320
  .message code {
321
+ background: rgba(255, 255, 255, 0.1) !important;
 
322
  padding: 2px 6px !important;
323
  border-radius: 4px !important;
324
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
325
+ font-size: 14px !important;
326
  }
327
+
328
  .message pre code {
329
  background: transparent !important;
 
330
  padding: 0 !important;
 
331
  }
332
+
333
+ /* Links */
334
+ .message a {
335
+ color: #10a37f !important;
336
+ text-decoration: none !important;
337
  }
338
+
339
+ .message a:hover {
340
+ text-decoration: underline !important;
341
  }
342
+
343
+ /* Listas */
344
+ .message ul, .message ol {
345
+ margin: 12px 0 !important;
346
+ padding-left: 24px !important;
347
  }
348
+
349
+ .message li {
350
+ margin: 6px 0 !important;
351
+ line-height: 1.6 !important;
 
 
 
 
 
 
 
352
  }
353
+
354
+ /* Tabelas */
355
+ .message table {
356
+ border-collapse: collapse !important;
357
+ width: 100% !important;
358
+ margin: 16px 0 !important;
359
+ background: rgba(255, 255, 255, 0.05) !important;
360
+ border-radius: 8px !important;
361
+ overflow: hidden !important;
362
  }
363
+
364
+ .message th, .message td {
365
+ border: 1px solid #3e3e3e !important;
366
+ padding: 12px !important;
367
+ text-align: left !important;
368
  }
369
+
370
+ .message th {
371
+ background: rgba(255, 255, 255, 0.1) !important;
 
 
 
372
  font-weight: 600 !important;
 
 
373
  }
374
+
375
+ /* Scrollbar personalizada */
376
+ ::-webkit-scrollbar {
377
+ width: 8px;
378
+ height: 8px;
379
  }
380
+
381
+ ::-webkit-scrollbar-track {
382
+ background: #1a1a1a;
383
  }
384
+
385
+ ::-webkit-scrollbar-thumb {
386
+ background: #4d4d4d;
387
+ border-radius: 4px;
388
  }
389
+
390
+ ::-webkit-scrollbar-thumb:hover {
391
+ background: #6d6d6d;
392
+ }
393
+
394
+ /* Responsive */
395
  @media (max-width: 768px) {
396
+ .main-container {
397
+ flex-direction: column;
 
398
  }
399
 
400
+ .sidebar {
401
+ width: 100%;
402
+ height: auto;
403
+ border-right: none;
404
+ border-bottom: 1px solid #2d2d2d;
405
  }
406
 
407
+ .message-content {
408
+ padding: 0 16px;
409
+ gap: 12px;
 
410
  }
411
 
412
+ .message-avatar {
413
+ width: 28px;
414
+ height: 28px;
415
+ font-size: 14px;
416
+ }
417
+
418
+ .input-area {
419
+ padding: 16px;
420
+ }
421
+
422
+ .message-text {
423
+ font-size: 15px;
424
  }
425
  }
426
+
427
+ /* Animações */
428
  .message {
429
+ animation: fadeIn 0.3s ease-out;
430
  }
431
+
432
+ @keyframes fadeIn {
433
  from {
434
  opacity: 0;
435
  transform: translateY(10px);
 
439
  transform: translateY(0);
440
  }
441
  }
442
+
443
+ /* Estado de carregamento */
444
+ .loading-indicator {
445
+ display: inline-flex;
446
+ align-items: center;
447
+ gap: 8px;
448
+ color: #8e8ea0;
449
+ font-style: italic;
450
+ }
451
+
452
+ .loading-dots {
453
+ display: inline-flex;
454
+ gap: 2px;
455
  }
456
+
457
+ .loading-dots span {
458
+ width: 4px;
459
+ height: 4px;
460
+ background: #8e8ea0;
461
+ border-radius: 50%;
462
+ animation: pulse 1.4s ease-in-out infinite both;
463
+ }
464
+
465
+ .loading-dots span:nth-child(1) { animation-delay: -0.32s; }
466
+ .loading-dots span:nth-child(2) { animation-delay: -0.16s; }
467
+ .loading-dots span:nth-child(3) { animation-delay: 0s; }
468
+
469
+ @keyframes pulse {
470
+ 0%, 80%, 100% {
471
+ opacity: 0.3;
472
+ }
473
+ 40% {
474
+ opacity: 1;
475
+ }
476
  }
477
+
478
+ /* Ocultar elementos desnecessários do Gradio */
479
+ .gr-button-lg {
480
+ display: none !important;
481
  }
482
+
483
+ /* Customizar os componentes específicos */
484
+ .gr-textbox {
485
+ background: transparent !important;
486
+ border: none !important;
487
  }
488
+
489
+ .gr-dropdown {
490
+ background: #2d2d2d !important;
491
+ border: 1px solid #4d4d4d !important;
492
+ border-radius: 8px !important;
493
+ color: #ffffff !important;
494
  }
495
+
496
+ /* Botões personalizados */
497
+ .control-button {
498
+ background: #2d2d2d !important;
499
+ color: #ffffff !important;
500
+ border: 1px solid #4d4d4d !important;
501
+ border-radius: 8px !important;
502
+ padding: 8px 16px !important;
503
+ font-size: 14px !important;
504
+ cursor: pointer !important;
505
+ transition: all 0.2s ease !important;
506
  }
507
+
508
+ .control-button:hover {
509
+ background: #3d3d3d !important;
510
+ border-color: #6d6d6d !important;
511
  }
512
+
513
+ .control-button.primary {
514
+ background: #10a37f !important;
515
+ border-color: #10a37f !important;
516
  }
517
+
518
+ .control-button.primary:hover {
519
+ background: #0d8f6e !important;
 
520
  }
521
+
522
+ /* Status indicators */
523
+ .status-indicator {
524
+ font-size: 12px;
525
+ padding: 4px 8px;
526
+ border-radius: 4px;
527
+ font-weight: 500;
528
  }
529
+
530
+ .status-success {
531
+ background: rgba(16, 163, 127, 0.2);
532
+ color: #10a37f;
533
+ border: 1px solid rgba(16, 163, 127, 0.3);
534
  }
535
+
536
+ .status-error {
537
+ background: rgba(239, 68, 68, 0.2);
538
+ color: #ef4444;
539
+ border: 1px solid rgba(239, 68, 68, 0.3);
540
  }
541
+
542
+ .status-warning {
543
+ background: rgba(245, 158, 11, 0.2);
544
+ color: #f59e0b;
545
+ border: 1px solid rgba(245, 158, 11, 0.3);
546
  }
547
  """
548
 
549
  def criar_interface():
550
+ with gr.Blocks(title="Dr. Aldo Henrique - iAldo AI Assistant", theme=gr.themes.Base(), css=css_customizado) as interface:
551
+ session_id_state = gr.State(str(uuid.uuid4()))
552
+
553
+ with gr.Row(elem_classes="main-container"):
554
+ # Sidebar esquerda
555
+ with gr.Column(elem_classes="sidebar", scale=0, min_width=260):
556
+ gr.HTML("""
557
+ <div class="sidebar-header">
558
+ <h2 style="color: #10a37f; font-size: 18px; font-weight: 600;">iAldo AI</h2>
559
+ </div>
560
+ """)
561
+
562
+ # Seletor de modelo
563
+ with gr.Group():
564
+ gr.HTML('<h3 style="color: #8e8ea0; font-size: 12px; font-weight: 600; text-transform: uppercase; margin-bottom: 8px;">🧠 Modelo de IA</h3>')
565
+ modelo_select = gr.Dropdown(
566
+ choices=list(MODELS.keys()),
567
+ value=DEFAULT_MODEL,
568
+ label="",
569
+ show_label=False,
570
+ elem_classes="model-selector",
571
+ container=False
572
+ )
573
+
574
+ # Controles RAG
575
+ with gr.Accordion("⚙️ Conhecimento (RAG)", open=False, elem_classes="sidebar-section"):
576
+ status_rag = gr.Textbox(label="Status", interactive=False, show_label=False,
577
+ placeholder="Status do retreino...")
578
+ botao_retreinar = gr.Button("🔄 Atualizar", elem_classes="control-button primary", size="sm")
579
+ download_faiss_file = gr.File(label="📁 Índice FAISS", interactive=False,
580
+ file_count="single", file_types=[".pkl"])
581
+ download_urls_file = gr.File(label="📁 URLs", interactive=False,
582
+ file_count="single", file_types=[".pkl"])
583
+
584
+ # Exemplos
585
+ with gr.Accordion("💡 Exemplos", open=False, elem_classes="sidebar-section"):
586
+ gr.Examples(
587
+ examples=[
588
+ ["Como implementar uma lista ligada em C com todas as operações básicas?", DEFAULT_MODEL],
589
+ ["Qual a sua opinião sobre o uso de ponteiros em C++ moderno?", "Mistral 7B (Mais acertivo)"],
590
+ ["Resuma o que você escreveu sobre machine learning no seu blog.", "Zephyr 7B (Meio Termo)"],
591
+ ],
592
+ inputs=[gr.Textbox(visible=False), modelo_select],
593
+ label=""
594
+ )
595
+
596
+ # Status da API
597
+ with gr.Accordion("🔧 Status API", open=False, elem_classes="sidebar-section"):
598
+ status_api = gr.Textbox(label="", interactive=False, lines=4, show_label=False,
599
+ value="✅ Modelos carregados com sucesso!")
600
+
601
+ # Informações
602
+ with gr.Accordion("ℹ️ Sobre", open=False, elem_classes="sidebar-section"):
603
+ gr.Markdown("""
604
+ **Dr. Aldo Henrique**
605
+
606
+ • Especialista em C/C++, Java
607
+ • Desenvolvimento Web & IA
608
+ • Conteúdo: aldohenrique.com.br
609
+
610
+ **Dicas:**
611
+ • Faça perguntas específicas
612
+ • Use o RAG para consultar o blog
613
+ • Experimente diferentes modelos
614
+ """)
615
+
616
+ # Área principal do chat
617
+ with gr.Column(elem_classes="chat-main", scale=1):
618
+ # Header do chat
619
+ gr.HTML("""
620
+ <div class="chat-header">
621
+ <div class="chat-title">
622
+ 🤖 Conversando com <a href="https://aldohenrique.com.br/" target="_blank">Prof. Dr. Aldo Henrique</a>
623
+ </div>
624
+ </div>
625
+ """)
626
+
627
+ # Área de mensagens
628
+ with gr.Column(elem_classes="messages-container"):
629
  chatbot = gr.Chatbot(
630
+ label="",
631
  elem_id="chat",
632
+ height="calc(100vh - 200px)",
633
  show_label=False,
634
+ container=False,
635
+ elem_classes="chatbot",
636
+ avatar_images=("👤", "🤖"),
637
+ bubble_full_width=False
 
638
  )
639
 
640
+ # Área de input
641
+ with gr.Column(elem_classes="input-area"):
642
+ with gr.Row(elem_classes="input-container"):
643
+ with gr.Column(elem_classes="input-wrapper", scale=1):
644
+ user_input = gr.Textbox(
645
+ show_label=False,
646
+ placeholder="Digite sua mensagem aqui...",
647
+ lines=1,
648
+ elem_id="entrada_usuario",
649
+ max_lines=10,
650
+ container=False,
651
+ scale=1
652
+ )
653
+ # Botão de envio oculto (será substituído por JavaScript)
654
+ enviar_btn = gr.Button("➤", variant="primary", size="sm", elem_classes="send-button")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
 
656
  def responder(chat_history, user_msg, modelo, session_id):
657
  if not user_msg.strip():
658
  return chat_history, ""
659
 
660
  # Adiciona a mensagem do usuário ao histórico
661
+ chat_history = chat_history + [[user_msg, "🤔 Dr. Aldo está pensando..."]]
662
  yield chat_history, ""
663
 
664
  try:
 
671
 
672
  except Exception as e:
673
  # Em caso de erro, mostra uma mensagem amigável
674
+ chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro: {str(e)}"
675
  yield chat_history, ""
676
 
677
+ # Eventos
678
  enviar_btn.click(
679
  fn=responder,
680
  inputs=[chatbot, user_input, modelo_select, session_id_state],
681
  outputs=[chatbot, user_input],
682
+ show_progress=False
683
  )
684
 
685
  user_input.submit(
686
  fn=responder,
687
  inputs=[chatbot, user_input, modelo_select, session_id_state],
688
  outputs=[chatbot, user_input],
689
+ show_progress=False
690
  )
691
 
692
  botao_retreinar.click(
 
695
  show_progress=True
696
  )
697
 
698
+ # JavaScript para melhorar a UX
699
  gr.HTML("""
700
  <script>
701
+ // Auto-resize textarea
702
+ function setupAutoResize() {
703
+ const textarea = document.querySelector("#entrada_usuario textarea");
704
+ if (textarea) {
705
+ textarea.style.minHeight = "24px";
706
+ textarea.addEventListener('input', function() {
707
+ this.style.height = 'auto';
708
+ const newHeight = Math.min(this.scrollHeight, 200);
709
+ this.style.height = newHeight + 'px';
710
+ });
711
+
712
+ // Focus on load
713
+ setTimeout(() => textarea.focus(), 100);
714
+ }
715
+ }
716
+
717
+ // Scroll to bottom when new message is added
718
+ function scrollToBottom() {
719
+ const chatContainer = document.querySelector(".chatbot");
720
+ if (chatContainer) {
721
+ chatContainer.scrollTop = chatContainer.scrollHeight;
722
+ }
723
+ }
724
+
725
+ // Initialize when page loads
726
+ document.addEventListener("DOMContentLoaded", setupAutoResize);
727
+ window.addEventListener("load", setupAutoResize);
728
+
729
+ // Re-setup after Gradio updates
730
+ setInterval(setupAutoResize, 1000);
731
  </script>
732
  """)
733
 
 
736
  def inicializar_sistema_sync():
737
  """Função síncrona para compatibilidade"""
738
  try:
739
+ import asyncio
740
+
741
+ # Tenta obter o loop atual
742
+ try:
743
+ loop = asyncio.get_event_loop()
744
+ if loop.is_running():
745
+ # Se já está rodando, cria uma nova thread
746
+ import concurrent.futures
747
+ with concurrent.futures.ThreadPoolExecutor() as executor:
748
+ future = executor.submit(lambda: asyncio.run(inicializar_sistema()))
749
+ return future.result()
750
+ else:
751
+ # Se não está rodando, executa normalmente
752
+ return loop.run_until_complete(inicializar_sistema())
753
+ except RuntimeError:
754
+ # Se não há loop, cria um novo
755
+ return asyncio.run(inicializar_sistema())
756
+
757
  except Exception as e:
758
  print(f"Erro na inicialização: {e}")
759
  return False, {}
 
768
  if status:
769
  return criar_interface()
770
  else:
771
+ error_msg = f"Sistema não inicializado: menos de 3 modelos disponíveis. Modelos: {', '.join(available_models.keys()) if available_models else 'Nenhum'}"
772
  raise RuntimeError(error_msg)
773
  except Exception as e:
774
  print(f"Erro na configuração da interface: {e}")
 
786
  )
787
  except Exception as e:
788
  print(f"Erro ao iniciar a aplicação: {e}")
789
+ exit(1)