aldohenrique commited on
Commit
39248e1
·
verified ·
1 Parent(s): b3b7474

Update interface.py

Browse files
Files changed (1) hide show
  1. interface.py +585 -270
interface.py CHANGED
@@ -8,295 +8,570 @@ from ai_logic import (
8
  inicializar_sistema
9
  )
10
 
11
- def criar_interface():
12
- css = """
13
- @import url('https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css');
14
- body {
15
- font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
16
- background-color: #f5f5f5;
17
- color: #1f2937;
18
- margin: 0;
19
- height: 100vh;
20
- overflow: hidden;
21
- }
22
- .gradio-container {
23
- max-width: 100% !important;
24
- height: 100vh !important;
25
- padding: 0 !important;
26
- margin: 0 !important;
27
- overflow: hidden !important;
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  .main-container {
30
- display: flex;
31
- height: 100vh;
32
- max-height: 100vh;
33
- overflow: hidden;
34
  }
 
35
  .sidebar {
36
- width: 280px;
37
- background-color: #ffffff;
38
- border-right: 1px solid #e5e7eb;
39
- padding: 1.5rem;
40
- overflow-y: auto;
41
- flex-shrink: 0;
42
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
43
  }
 
44
  .chat-main {
45
- flex: 1;
46
- display: flex;
47
- flex-direction: column;
48
- background-color: #f5f5f5;
49
- height: 100vh;
50
- overflow: hidden;
51
- }
52
- .chat-header {
53
- background-color: #ffffff;
54
- border-bottom: 1px solid #e5e7eb;
55
- padding: 1rem 1.5rem;
56
- text-align: center;
57
- flex-shrink: 0;
58
  }
 
59
  .messages-container {
60
- flex: 1;
61
- overflow-y: auto;
62
- padding: 1.5rem;
63
- background-color: #f5f5f5;
64
- scroll-behavior: smooth;
65
  }
 
66
  .input-area {
67
- background-color: #ffffff;
68
- border-top: 1px solid #e5e7eb;
69
- padding: 1rem 1.5rem;
70
- flex-shrink: 0;
71
- }
72
- .input-container {
73
- max-width: 800px;
74
- margin: 0 auto;
75
- display: flex;
76
- align-items: center;
77
- gap: 0.5rem;
78
- }
79
- .input-wrapper {
80
- flex: 1;
81
- background-color: #f3f4f6;
82
- border: 1px solid #d1d5db;
83
- border-radius: 0.5rem;
84
- padding: 0.75rem;
85
- display: flex;
86
- align-items: center;
87
- transition: all 0.2s ease;
88
- }
89
- .input-wrapper:focus-within {
90
- border-color: #3b82f6;
91
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
92
- }
93
- #entrada_usuario textarea {
94
- background: transparent !important;
95
- border: none !important;
96
- color: #1f2937 !important;
97
- font-size: 1rem !important;
98
- line-height: 1.5 !important;
99
- resize: none !important;
100
- outline: none !important;
101
- width: 100% !important;
102
- min-height: 24px !important;
103
- max-height: 80px !important;
104
- overflow-y: auto !important;
105
- }
106
- #entrada_usuario textarea::placeholder {
107
- color: #6b7280 !important;
108
- }
109
- .send-button {
110
- background-color: #3b82f6 !important;
111
- color: white !important;
112
- border: none !important;
113
- border-radius: 0.375rem !important;
114
- padding: 0.5rem !important;
115
- cursor: pointer !important;
116
- transition: background-color 0.2s ease !important;
117
- }
118
- .send-button:hover:not(:disabled) {
119
- background-color: #2563eb !important;
120
- }
121
- .send-button:disabled {
122
- background-color: #9ca3af !important;
123
- cursor: not-allowed !important;
124
- }
125
- .message {
126
- margin-bottom: 1.5rem;
127
- display: flex;
128
- gap: 0.75rem;
129
- max-width: 800px;
130
- margin-left: auto;
131
- margin-right: auto;
132
- }
133
- .message.user .message-content {
134
- background-color: #dbeafe;
135
- border-radius: 0.5rem 0.5rem 0 0.5rem;
136
- padding: 0.75rem 1rem;
137
- }
138
- .message.assistant .message-content {
139
- background-color: #ffffff;
140
- border: 1px solid #e5e7eb;
141
- border-radius: 0.5rem 0.5rem 0.5rem 0;
142
- padding: 0.75rem 1rem;
143
- box-shadow: 0 1px 2px rgba(0,0,0,0.05);
144
- }
145
  .message-text {
146
- font-size: 1rem;
147
- line-height: 1.5;
148
- }
149
- .model-selector {
150
- width: 100%;
151
- padding: 0.5rem;
152
- border-radius: 0.375rem;
153
- border: 1px solid #d1d5db;
154
- background-color: #f9fafb;
155
- }
156
- .accordion {
157
- border: 1px solid #e5e7eb !important;
158
- border-radius: 0.375rem !important;
159
- margin-bottom: 1rem !important;
160
- background-color: #f9fafb !important;
161
- }
162
- .accordion summary {
163
- padding: 0.75rem !important;
164
- font-weight: 500 !important;
165
- cursor: pointer !important;
166
- }
167
- .accordion[open] summary {
168
- border-bottom: 1px solid #e5e7eb !important;
169
- }
170
- .accordion .gr-panel {
171
- padding: 1rem !important;
172
- }
173
- pre, code {
174
- font-family: 'Fira Code', monospace !important;
175
- background-color: #1f2937 !important;
176
- color: #f9fafb !important;
177
- border-radius: 0.375rem !important;
178
- padding: 0.75rem !important;
179
- }
180
- pre {
181
- overflow-x: auto;
182
- }
183
- code {
184
- padding: 0.2rem 0.4rem !important;
185
- }
186
- a {
187
- color: #3b82f6 !important;
188
- text-decoration: none !important;
189
- }
190
- a:hover {
191
- text-decoration: underline !important;
192
- }
193
- @media (max-width: 768px) {
194
- .main-container {
195
- flex-direction: column;
196
- }
197
- .sidebar {
198
- width: 100%;
199
- height: auto;
200
- max-height: 200px;
201
- border-right: none;
202
- border-bottom: 1px solid #e5e7eb;
203
- }
204
- .chat-main {
205
- height: calc(100vh - 200px);
206
- }
207
- .messages-container {
208
- padding: 1rem;
209
- }
210
- .input-area {
211
- padding: 0.75rem;
212
- }
213
- .message {
214
- margin-bottom: 1rem;
215
- }
216
  }
217
- .loading-indicator {
218
- color: #6b7280;
219
- font-style: italic;
220
- display: flex;
221
- align-items: center;
222
- gap: 0.5rem;
223
- }
224
- .loading-dots span {
225
- width: 0.25rem;
226
- height: 0.25rem;
227
- background-color: #6b7280;
228
- border-radius: 50%;
229
- animation: pulse 1.4s ease-in-out infinite;
230
- }
231
- .loading-dots span:nth-child(1) { animation-delay: -0.32s; }
232
- .loading-dots span:nth-child(2) { animation-delay: -0.16s; }
233
- .loading-dots span:nth-child(3) { animation-delay: 0s; }
234
- @keyframes pulse {
235
- 0%, 80%, 100% { opacity: 0.3; }
236
- 40% { opacity: 1; }
237
- }
238
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
- with gr.Blocks(title="Dr. Aldo Henrique - iAldo AI Assistant", css=css) as interface:
 
 
 
 
 
 
 
 
241
  session_id_state = gr.State(str(uuid.uuid4()))
242
 
243
  with gr.Row(elem_classes="main-container"):
 
244
  with gr.Column(elem_classes="sidebar", scale=0, min_width=280):
245
  gr.HTML("""
246
- <div class="flex items-center justify-between mb-6">
247
- <h2 class="text-xl font-semibold text-blue-600">iAldo AI</h2>
 
248
  </div>
249
  """)
 
250
  with gr.Group():
251
- gr.HTML('<h3 class="text-sm font-semibold text-gray-500 uppercase mb-2">🧠 Modelo de IA</h3>')
252
  modelo_select = gr.Dropdown(
253
  choices=list(MODELS.keys()),
254
  value="Llama 3.2 3B",
 
255
  show_label=False,
256
  elem_classes="model-selector",
257
  container=False
258
  )
259
- with gr.Accordion("🔧 Status API", open=False, elem_classes="accordion"):
260
- status_api = gr.Textbox(
261
- value="✅ Modelos carregados com sucesso!",
262
- interactive=False,
263
- lines=4,
264
- show_label=False
265
- )
266
- with gr.Accordion("ℹ️ Sobre", open=False, elem_classes="accordion"):
267
- gr.Markdown("""
268
- **Dr. Aldo Henrique**
269
 
270
- - Especialista em C/C++, Java
271
- - Desenvolvimento Web & IA
272
- - Conteúdo: [aldohenrique.com.br](https://aldohenrique.com.br/)
273
 
 
 
 
 
 
 
 
 
274
  **Dicas:**
275
- - Faça perguntas específicas
276
- - Use o RAG para consultar o blog
277
- - Experimente diferentes modelos
278
  """)
279
 
 
280
  with gr.Column(elem_classes="chat-main", scale=1):
281
  gr.HTML("""
282
  <div class="chat-header">
283
- <div class="text-lg font-semibold text-gray-800">
284
- 🤖 Conversando com <a href="https://aldohenrique.com.br/" target="_blank" class="text-blue-600">Prof. Dr. Aldo Henrique</a>
285
  </div>
286
  </div>
287
  """)
 
288
  with gr.Column(elem_classes="messages-container"):
289
  chatbot = gr.Chatbot(
 
 
290
  show_label=False,
291
  container=False,
292
  elem_classes="chatbot",
293
- avatar_images=(
294
- "https://cdn-icons-png.flaticon.com/256/9055/9055398.png",
295
- "https://cdn.iconscout.com/icon/premium/png-256-thumb/robo-97-415007.png"
296
- ),
297
  bubble_full_width=False,
298
  height="100%"
299
  )
 
300
  with gr.Column(elem_classes="input-area"):
301
  with gr.Row(elem_classes="input-container"):
302
  with gr.Column(elem_classes="input-wrapper", scale=1):
@@ -304,21 +579,25 @@ def criar_interface():
304
  show_label=False,
305
  placeholder="Digite sua mensagem aqui...",
306
  lines=1,
307
- max_lines=3,
308
  elem_id="entrada_usuario",
309
- container=False
 
 
310
  )
311
- enviar_btn = gr.Button("➤", variant="primary", elem_classes="send-button")
312
 
313
  def responder(chat_history, user_msg, modelo, session_id):
314
  if not user_msg.strip():
315
  return chat_history, ""
316
- chat_history = chat_history + [[user_msg, '<div class="loading-indicator">🤔 Dr. Aldo está pensando... <span class="loading-dots"><span></span><span></span><span></span></span></div>']]
 
317
  yield chat_history, ""
 
318
  try:
319
  resposta_final = responder_como_aldo(session_id, user_msg, modelo)
320
  chat_history[-1][1] = resposta_final
321
  yield chat_history, ""
 
322
  except Exception as e:
323
  chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro: {str(e)}"
324
  yield chat_history, ""
@@ -329,6 +608,7 @@ def criar_interface():
329
  outputs=[chatbot, user_input],
330
  show_progress=False
331
  )
 
332
  user_input.submit(
333
  fn=responder,
334
  inputs=[chatbot, user_input, modelo_select, session_id_state],
@@ -338,29 +618,64 @@ def criar_interface():
338
 
339
  gr.HTML("""
340
  <script>
341
- document.addEventListener('DOMContentLoaded', () => {
342
- const textarea = document.querySelector("#entrada_usuario textarea");
343
- if (textarea) {
344
- textarea.style.height = "auto";
345
- textarea.style.overflowY = "hidden";
346
- const adjustHeight = () => {
347
- textarea.style.height = "auto";
348
- textarea.style.height = Math.min(textarea.scrollHeight, 80) + "px";
349
- };
350
- textarea.addEventListener('input', adjustHeight);
351
- textarea.addEventListener('paste', () => setTimeout(adjustHeight, 0));
352
- setTimeout(() => textarea.focus(), 300);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  }
354
-
355
- const messagesContainer = document.querySelector('.messages-container');
356
- if (messagesContainer) {
357
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
358
- const observer = new MutationObserver(() => {
359
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
360
- });
361
- observer.observe(messagesContainer, { childList: true, subtree: true });
362
  }
363
- });
 
 
364
  </script>
365
  """)
366
 
@@ -382,11 +697,11 @@ def inicializar_sistema_sync():
382
  return asyncio.run(inicializar_sistema())
383
  except Exception as e:
384
  print(f"Erro na inicialização: {e}")
385
- return False, {}
386
 
387
  def configurar_interface():
388
  try:
389
- status, available_models = inicializar_sistema_sync()
390
  if status:
391
  return criar_interface()
392
  else:
 
8
  inicializar_sistema
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: var(--bg-primary);
22
+ color: var(--text-primary);
23
+ line-height: 1.5;
24
+ overflow: hidden;
25
+ }
26
+
27
+ /* Variáveis para tema claro e escuro */
28
+ :root {
29
+ --bg-primary: #ffffff;
30
+ --bg-secondary: #f4f4f5;
31
+ --bg-input: #f9fafb;
32
+ --text-primary: #111827;
33
+ --text-secondary: #6b7280;
34
+ --accent: #3b82f6;
35
+ --accent-hover: #2563eb;
36
+ --border: #e5e7eb;
37
+ --message-user-bg: #e0f2fe;
38
+ --message-bot-bg: #f3f4f6;
39
+ }
40
+
41
+ @media (prefers-color-scheme: dark) {
42
+ :root {
43
+ --bg-primary: #0f0f23;
44
+ --bg-secondary: #1f1f38;
45
+ --bg-input: #2d2d4a;
46
+ --text-primary: #ffffff;
47
+ --text-secondary: #9ca3af;
48
+ --accent: #60a5fa;
49
+ --accent-hover: #3b82f6;
50
+ --border: #2d2d4a;
51
+ --message-user-bg: #1e40af;
52
+ --message-bot-bg: #1f2937;
53
+ }
54
+ }
55
+
56
+ .gradio-container {
57
+ background: var(--bg-primary) !important;
58
+ min-height: 100vh !important;
59
+ max-width: 100% !important;
60
+ padding: 0 !important;
61
+ margin: 0 !important;
62
+ overflow: hidden !important;
63
+ }
64
+
65
+ /* Layout principal */
66
+ .main-container {
67
+ display: flex;
68
+ height: 100vh;
69
+ max-height: 100vh;
70
+ background: var(--bg-primary);
71
+ overflow: hidden;
72
+ }
73
+
74
+ /* Sidebar */
75
+ .sidebar {
76
+ width: 280px;
77
+ min-width: 280px;
78
+ background: var(--bg-secondary);
79
+ border-right: 1px solid var(--border);
80
+ padding: 16px;
81
+ overflow-y: auto;
82
+ height: 100vh;
83
+ flex-shrink: 0;
84
+ }
85
+
86
+ .sidebar-header {
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ padding: 12px 0;
91
+ margin-bottom: 16px;
92
+ border-bottom: 1px solid var(--border);
93
+ }
94
+
95
+ .new-chat-btn {
96
+ background: var(--accent) !important;
97
+ color: #ffffff !important;
98
+ border: none !important;
99
+ border-radius: 8px !important;
100
+ padding: 8px 16px !important;
101
+ font-size: 14px !important;
102
+ font-weight: 500 !important;
103
+ cursor: pointer !important;
104
+ transition: background 0.2s ease !important;
105
+ }
106
+
107
+ .new-chat-btn:hover {
108
+ background: var(--accent-hover) !important;
109
+ }
110
+
111
+ .sidebar-section h3 {
112
+ color: var(--text-secondary);
113
+ font-size: 12px;
114
+ font-weight: 600;
115
+ text-transform: uppercase;
116
+ letter-spacing: 0.5px;
117
+ margin-bottom: 12px;
118
+ }
119
+
120
+ /* Área principal */
121
+ .chat-main {
122
+ flex: 1;
123
+ display: flex;
124
+ flex-direction: column;
125
+ background: var(--bg-primary);
126
+ height: 100vh;
127
+ overflow: hidden;
128
+ }
129
+
130
+ .chat-header {
131
+ background: var(--bg-secondary);
132
+ border-bottom: 1px solid var(--border);
133
+ padding: 12px 24px;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: space-between;
137
+ flex-shrink: 0;
138
+ height: 60px;
139
+ }
140
+
141
+ .chat-title {
142
+ color: var(--text-primary);
143
+ font-size: 16px;
144
+ font-weight: 600;
145
+ }
146
+
147
+ .chat-title a {
148
+ color: var(--accent);
149
+ text-decoration: none;
150
+ }
151
+
152
+ .chat-title a:hover {
153
+ text-decoration: underline;
154
+ }
155
+
156
+ /* Área de mensagens */
157
+ .messages-container {
158
+ flex: 1;
159
+ min-height: 0;
160
+ overflow: hidden;
161
+ position: relative;
162
+ }
163
+
164
+ .chatbot {
165
+ flex: 1;
166
+ min-height: 0;
167
+ height: 100%;
168
+ overflow: hidden;
169
+ background: transparent !important;
170
+ border: none !important;
171
+ padding: 0 !important;
172
+ margin: 0 !important;
173
+ }
174
+
175
+ .chatbot > div {
176
+ height: 100%;
177
+ overflow-y: auto;
178
+ padding: 16px 24px;
179
+ scroll-behavior: smooth;
180
+ }
181
+
182
+ /* Área de input */
183
+ .input-area {
184
+ background: var(--bg-primary);
185
+ padding: 16px 24px;
186
+ border-top: 1px solid var(--border);
187
+ flex-shrink: 0;
188
+ height: 100px;
189
+ max-height: 100px;
190
+ }
191
+
192
+ .input-container {
193
+ max-width: 800px;
194
+ margin: 0 auto;
195
+ display: flex;
196
+ align-items: center;
197
+ }
198
+
199
+ .input-wrapper {
200
+ background: var(--bg-input);
201
+ border: 1px solid var(--border);
202
+ border-radius: 12px;
203
+ padding: 12px 16px;
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 12px;
207
+ width: 100%;
208
+ transition: border-color 0.2s ease;
209
+ }
210
+
211
+ .input-wrapper:focus-within {
212
+ border-color: var(--accent);
213
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
214
+ }
215
+
216
+ #entrada_usuario textarea {
217
+ background: transparent !important;
218
+ border: none !important;
219
+ color: var(--text-primary) !important;
220
+ font-size: 16px !important;
221
+ line-height: 1.5 !important;
222
+ resize: none !important;
223
+ outline: none !important;
224
+ min-height: 24px !important;
225
+ max-height: 48px !important;
226
+ height: 24px !important;
227
+ padding: 0 !important;
228
+ margin: 0 !important;
229
+ overflow-y: auto !important;
230
+ width: 100% !important;
231
+ }
232
+
233
+ #entrada_usuario textarea::placeholder {
234
+ color: var(--text-secondary) !important;
235
+ }
236
+
237
+ .send-button {
238
+ width: 36px;
239
+ height: 36px;
240
+ background: var(--accent) !important;
241
+ border: none !important;
242
+ border-radius: 8px !important;
243
+ color: #ffffff !important;
244
+ cursor: pointer !important;
245
+ display: flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ transition: background 0.2s ease;
249
+ }
250
+
251
+ .send-button:hover:not(:disabled) {
252
+ background: var(--accent-hover) !important;
253
+ }
254
+
255
+ .send-button:disabled {
256
+ background: var(--text-secondary) !important;
257
+ cursor: not-allowed !important;
258
+ }
259
+
260
+ /* Estilo das mensagens */
261
+ .message {
262
+ padding: 12px 0;
263
+ border-bottom: 1px solid var(--border);
264
+ animation: fadeIn 0.3s ease-out;
265
+ }
266
+
267
+ .message-content {
268
+ max-width: 800px;
269
+ margin: 0 auto;
270
+ padding: 0 24px;
271
+ display: flex;
272
+ gap: 12px;
273
+ align-items: flex-start;
274
+ }
275
+
276
+ .message-avatar {
277
+ width: 36px;
278
+ height: 36px;
279
+ border-radius: 50%;
280
+ flex-shrink: 0;
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ font-size: 18px;
285
+ font-weight: 600;
286
+ }
287
+
288
+ .user-avatar {
289
+ background: var(--accent);
290
+ color: #ffffff;
291
+ }
292
+
293
+ .bot-avatar {
294
+ background: #6b7280;
295
+ color: #ffffff;
296
+ }
297
+
298
+ .message-text {
299
+ flex: 1;
300
+ line-height: 1.6;
301
+ font-size: 16px;
302
+ color: var(--text-primary);
303
+ }
304
+
305
+ .message.user {
306
+ background: var(--message-user-bg);
307
+ }
308
+
309
+ .message.assistant {
310
+ background: var(--message-bot-bg);
311
+ }
312
+
313
+ /* Estilo para código */
314
+ .message pre {
315
+ background: var(--bg-secondary) !important;
316
+ border: 1px solid var(--border) !important;
317
+ border-radius: 8px !important;
318
+ padding: 12px !important;
319
+ margin: 12px 0 !important;
320
+ overflow-x: auto !important;
321
+ font-family: 'JetBrains Mono', monospace !important;
322
+ font-size: 14px !important;
323
+ }
324
+
325
+ .message code {
326
+ background: rgba(0, 0, 0, 0.05) !important;
327
+ padding: 2px 6px !important;
328
+ border-radius: 4px !important;
329
+ font-family: 'JetBrains Mono', monospace !important;
330
+ }
331
+
332
+ .message pre code {
333
+ background: transparent !important;
334
+ padding: 0 !important;
335
+ }
336
+
337
+ /* Links */
338
+ .message a {
339
+ color: var(--accent) !important;
340
+ text-decoration: none !important;
341
+ }
342
+
343
+ .message a:hover {
344
+ text-decoration: underline !important;
345
+ }
346
+
347
+ /* Listas */
348
+ .message ul, .message ol {
349
+ margin: 12px 0 !important;
350
+ padding-left: 24px !important;
351
+ }
352
+
353
+ .message li {
354
+ margin: 6px 0 !important;
355
+ }
356
+
357
+ /* Tabelas */
358
+ .message table {
359
+ border-collapse: collapse !important;
360
+ width: 100% !important;
361
+ margin: 16px 0 !important;
362
+ background: var(--bg-secondary) !important;
363
+ border-radius: 8px !important;
364
+ }
365
+
366
+ .message th, .message td {
367
+ border: 1px solid var(--border) !important;
368
+ padding: 12px !important;
369
+ text-align: left !important;
370
+ }
371
+
372
+ .message th {
373
+ background: rgba(0, 0, 0, 0.05) !important;
374
+ font-weight: 600 !important;
375
+ }
376
+
377
+ /* Scrollbar */
378
+ ::-webkit-scrollbar {
379
+ width: 6px;
380
+ }
381
+
382
+ ::-webkit-scrollbar-track {
383
+ background: var(--bg-secondary);
384
+ }
385
+
386
+ ::-webkit-scrollbar-thumb {
387
+ background: var(--text-secondary);
388
+ border-radius: 3px;
389
+ }
390
+
391
+ ::-webkit-scrollbar-thumb:hover {
392
+ background: var(--accent);
393
+ }
394
+
395
+ /* Responsividade */
396
+ @media (max-width: 768px) {
397
  .main-container {
398
+ flex-direction: column;
 
 
 
399
  }
400
+
401
  .sidebar {
402
+ width: 100%;
403
+ height: 180px;
404
+ max-height: 180px;
405
+ border-right: none;
406
+ border-bottom: 1px solid var(--border);
 
 
407
  }
408
+
409
  .chat-main {
410
+ height: calc(100vh - 180px);
 
 
 
 
 
 
 
 
 
 
 
 
411
  }
412
+
413
  .messages-container {
414
+ max-height: calc(100vh - 280px);
 
 
 
 
415
  }
416
+
417
  .input-area {
418
+ padding: 12px 16px;
419
+ height: 80px;
420
+ max-height: 80px;
421
+ }
422
+
423
+ .message-content {
424
+ padding: 0 16px;
425
+ gap: 10px;
426
+ }
427
+
428
+ .message-avatar {
429
+ width: 32px;
430
+ height: 32px;
431
+ font-size: 16px;
432
+ }
433
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434
  .message-text {
435
+ font-size: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
+ }
438
+
439
+ /* Animações */
440
+ @keyframes fadeIn {
441
+ from { opacity: 0; transform: translateY(8px); }
442
+ to { opacity: 1; transform: translateY(0); }
443
+ }
444
+
445
+ /* Loading */
446
+ .loading-indicator {
447
+ display: flex;
448
+ align-items: center;
449
+ gap: 6px;
450
+ color: var(--text-secondary);
451
+ font-style: italic;
452
+ }
453
+
454
+ .loading-dots span {
455
+ width: 5px;
456
+ height: 5px;
457
+ background: var(--text-secondary);
458
+ border-radius: 50%;
459
+ animation: pulse 1.2s ease-in-out infinite;
460
+ }
461
+
462
+ .loading-dots span:nth-child(1) { animation-delay: -0.24s; }
463
+ .loading-dots span:nth-child(2) { animation-delay: -0.12s; }
464
+ .loading-dots span:nth-child(3) { animation-delay: 0s; }
465
+
466
+ @keyframes pulse {
467
+ 0%, 80%, 100% { opacity: 0.3; }
468
+ 40% { opacity: 1; }
469
+ }
470
+
471
+ /* Gradio components */
472
+ .gr-textbox, .gr-dropdown {
473
+ background: transparent !important;
474
+ border: none !important;
475
+ color: var(--text-primary) !important;
476
+ }
477
+
478
+ .gr-dropdown {
479
+ background: var(--bg-input) !important;
480
+ border: 1px solid var(--border) !important;
481
+ border-radius: 8px !important;
482
+ }
483
+
484
+ .gr-accordion {
485
+ background: transparent !important;
486
+ border: 1px solid var(--border) !important;
487
+ border-radius: 8px !important;
488
+ }
489
+
490
+ .gr-accordion summary {
491
+ background: var(--bg-input) !important;
492
+ color: var(--text-primary) !important;
493
+ padding: 12px !important;
494
+ border-radius: 8px !important;
495
+ }
496
+
497
+ .gr-accordion[open] summary {
498
+ border-bottom: 1px solid var(--border) !important;
499
+ border-radius: 8px 8px 0 0 !important;
500
+ }
501
 
502
+ .gr-accordion .gr-panel {
503
+ background: var(--bg-secondary) !important;
504
+ padding: 12px !important;
505
+ border-radius: 0 0 8px 8px !important;
506
+ }
507
+ """
508
+
509
+ def criar_interface():
510
+ with gr.Blocks(title="Dr. Aldo Henrique - iAldo AI Assistant", theme=gr.themes.Base(), css=css_customizado) as interface:
511
  session_id_state = gr.State(str(uuid.uuid4()))
512
 
513
  with gr.Row(elem_classes="main-container"):
514
+ # Sidebar
515
  with gr.Column(elem_classes="sidebar", scale=0, min_width=280):
516
  gr.HTML("""
517
+ <div class="sidebar-header">
518
+ <h2 style="color: var(--accent); font-size: 20px; font-weight: 600;">iAldo AI</h2>
519
+ <button class="new-chat-btn">Novo Chat</button>
520
  </div>
521
  """)
522
+
523
  with gr.Group():
524
+ gr.HTML('<h3>🧠 Modelo de IA</h3>')
525
  modelo_select = gr.Dropdown(
526
  choices=list(MODELS.keys()),
527
  value="Llama 3.2 3B",
528
+ label="",
529
  show_label=False,
530
  elem_classes="model-selector",
531
  container=False
532
  )
 
 
 
 
 
 
 
 
 
 
533
 
534
+ with gr.Accordion("🔧 Status API", open=False, elem_classes="sidebar-section"):
535
+ status_api = gr.Textbox(label="", interactive=False, lines=4, show_label=False,
536
+ value="✅ Modelos carregados com sucesso!")
537
 
538
+ with gr.Accordion("ℹ️ Sobre", open=False, elem_classes="sidebar-section"):
539
+ gr.Markdown("""
540
+ **Dr. Aldo Henrique**
541
+
542
+ • Especialista em C/C++, Java
543
+ • Desenvolvimento Web & IA
544
+ • Conteúdo: aldohenrique.com.br
545
+
546
  **Dicas:**
547
+ Faça perguntas específicas
548
+ Use o RAG para consultar o blog
549
+ Experimente diferentes modelos
550
  """)
551
 
552
+ # Área principal
553
  with gr.Column(elem_classes="chat-main", scale=1):
554
  gr.HTML("""
555
  <div class="chat-header">
556
+ <div class="chat-title">
557
+ 🤖 Conversando com <a href="https://aldohenrique.com.br/" target="_blank">Prof. Dr. Aldo Henrique</a>
558
  </div>
559
  </div>
560
  """)
561
+
562
  with gr.Column(elem_classes="messages-container"):
563
  chatbot = gr.Chatbot(
564
+ label="",
565
+ elem_id="chat",
566
  show_label=False,
567
  container=False,
568
  elem_classes="chatbot",
569
+ avatar_images=("https://cdn-icons-png.flaticon.com/256/9055/9055398.png",
570
+ "https://cdn.iconscout.com/icon/premium/png-256-thumb/robo-97-415007.png"),
 
 
571
  bubble_full_width=False,
572
  height="100%"
573
  )
574
+
575
  with gr.Column(elem_classes="input-area"):
576
  with gr.Row(elem_classes="input-container"):
577
  with gr.Column(elem_classes="input-wrapper", scale=1):
 
579
  show_label=False,
580
  placeholder="Digite sua mensagem aqui...",
581
  lines=1,
 
582
  elem_id="entrada_usuario",
583
+ max_lines=2,
584
+ container=False,
585
+ scale=1
586
  )
587
+ enviar_btn = gr.Button("➤", variant="primary", size="sm", elem_classes="send-button")
588
 
589
  def responder(chat_history, user_msg, modelo, session_id):
590
  if not user_msg.strip():
591
  return chat_history, ""
592
+
593
+ chat_history = chat_history + [[user_msg, "🤔 Dr. Aldo está pensando..."]]
594
  yield chat_history, ""
595
+
596
  try:
597
  resposta_final = responder_como_aldo(session_id, user_msg, modelo)
598
  chat_history[-1][1] = resposta_final
599
  yield chat_history, ""
600
+
601
  except Exception as e:
602
  chat_history[-1][1] = f"❌ Desculpe, ocorreu um erro: {str(e)}"
603
  yield chat_history, ""
 
608
  outputs=[chatbot, user_input],
609
  show_progress=False
610
  )
611
+
612
  user_input.submit(
613
  fn=responder,
614
  inputs=[chatbot, user_input, modelo_select, session_id_state],
 
618
 
619
  gr.HTML("""
620
  <script>
621
+ (function() {
622
+ let initialized = false;
623
+
624
+ function initLayout() {
625
+ if (initialized) return;
626
+ initialized = true;
627
+
628
+ const mainContainer = document.querySelector('.main-container');
629
+ if (mainContainer) {
630
+ mainContainer.style.height = '100vh';
631
+ mainContainer.style.maxHeight = '100vh';
632
+ mainContainer.style.overflow = 'hidden';
633
+ }
634
+
635
+ const chatMain = document.querySelector('.chat-main');
636
+ if (chatMain) {
637
+ chatMain.style.height = '100vh';
638
+ chatMain.style.maxHeight = '100vh';
639
+ chatMain.style.display = 'flex';
640
+ chatMain.style.flexDirection = 'column';
641
+ }
642
+
643
+ const messagesContainer = document.querySelector('.messages-container');
644
+ if (messagesContainer) {
645
+ messagesContainer.style.flex = '1';
646
+ messagesContainer.style.minHeight = '0';
647
+ messagesContainer.style.overflow = 'hidden';
648
+ }
649
+
650
+ const textarea = document.querySelector("#entrada_usuario textarea");
651
+ if (textarea) {
652
+ textarea.style.height = "24px";
653
+ textarea.style.minHeight = "24px";
654
+ textarea.style.maxHeight = "48px";
655
+ textarea.style.resize = "none";
656
+ textarea.style.overflowY = "hidden";
657
+
658
+ function autoResize() {
659
+ textarea.style.height = "24px";
660
+ const newHeight = Math.min(textarea.scrollHeight, 48);
661
+ textarea.style.height = Math.max(newHeight, 24) + "px";
662
+ textarea.style.overflowY = textarea.scrollHeight > 48 ? "auto" : "hidden";
663
+ }
664
+
665
+ textarea.addEventListener('input', autoResize);
666
+ textarea.addEventListener('paste', () => setTimeout(autoResize, 0));
667
+ setTimeout(() => textarea.focus(), 300);
668
+ }
669
  }
670
+
671
+ if (document.readyState === 'loading') {
672
+ document.addEventListener('DOMContentLoaded', initLayout);
673
+ } else {
674
+ setTimeout(initLayout, 100);
 
 
 
675
  }
676
+
677
+ setTimeout(initLayout, 1000);
678
+ })();
679
  </script>
680
  """)
681
 
 
697
  return asyncio.run(inicializar_sistema())
698
  except Exception as e:
699
  print(f"Erro na inicialização: {e}")
700
+ return False, {}
701
 
702
  def configurar_interface():
703
  try:
704
+ status, available_models = inicializar_sistema()
705
  if status:
706
  return criar_interface()
707
  else: