caarleexx commited on
Commit
75159bd
·
verified ·
1 Parent(s): 39f7c79

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +416 -0
app.py ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import gradio as gr
4
+ import google.generativeai as genai
5
+ from typing import Dict, List, Optional
6
+
7
+ # ==================== CONFIGURAÇÃO DA API GEMINI ====================
8
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY", "SUA_API_KEY_AQUI"))
9
+ counselor_model = genai.GenerativeModel("gemini-flash-latest")
10
+ supervisor_model = genai.GenerativeModel("gemini-flash-latest")
11
+
12
+ # ==================== HISTÓRICOS GLOBAIS ====================
13
+ historico_dialogo: List[Dict] = []
14
+ historico_passo1_clareza: List[Dict] = []
15
+ historico_passo2_proposito: List[Dict] = []
16
+ historico_passo3_motivacao: List[Dict] = []
17
+ historico_passo4_ambiguidade: List[Dict] = []
18
+
19
+ # ==================== CARREGAMENTO DO CONTEXTO FILOSÓFICO ====================
20
+ def carregar_contexto_filosofico(caminho_arquivo: str = "epct0.md") -> Optional[str]:
21
+ """Carrega o arquivo de contexto filosófico (Epicteto) se disponível."""
22
+ try:
23
+ with open(caminho_arquivo, "r", encoding="utf-8") as f:
24
+ print(f"✓ Contexto filosófico '{caminho_arquivo}' carregado com sucesso.")
25
+ return f.read()
26
+ except FileNotFoundError:
27
+ print(f"⚠ AVISO: Arquivo '{caminho_arquivo}' não encontrado. Modo Sábio ficará limitado.")
28
+ return None
29
+
30
+ CONTEXTO_FILOSOFICO = carregar_contexto_filosofico()
31
+
32
+ # ==================== PROMPTS PARA CADA PASSO ====================
33
+
34
+ def prompt_passo1_clareza(historico_dialogo: List[Dict], historico_passo1: List[Dict], input_usuario: str) -> str:
35
+ """Prompt para análise de CLAREZA: Eu entendi o que o usuário quer?"""
36
+ return f"""
37
+ Você é um analisador de CLAREZA em uma pipeline de raciocínio multi-etapa.
38
+
39
+ Sua única tarefa: avaliar se você entendeu claramente o que o usuário está perguntando ou expressando.
40
+
41
+ HISTÓRICO DE DIÁLOGO (perguntas e respostas anteriores):
42
+ {json.dumps(historico_dialogo, indent=2, ensure_ascii=False)}
43
+
44
+ HISTÓRICO DO PASSO 1 (suas análises anteriores de clareza):
45
+ {json.dumps(historico_passo1, indent=2, ensure_ascii=False)}
46
+
47
+ NOVO INPUT DO USUÁRIO:
48
+ "{input_usuario}"
49
+
50
+ INSTRUÇÕES:
51
+ 1. Se este é o primeiro turno ou se o usuário mudou completamente de assunto, analise a clareza do novo input isoladamente.
52
+ 2. Se o usuário está respondendo a uma pergunta sua anterior, reavalie: a clareza aumentou? Ele esclareceu o que você precisava?
53
+ 3. Se o input é ambíguo, vago ou tem múltiplas interpretações possíveis, classifique como confiança "baixa".
54
+ 4. Se você entendeu perfeitamente, classifique como "alta".
55
+
56
+ RETORNE APENAS UM JSON VÁLIDO NO FORMATO:
57
+ {{
58
+ "analise": "Sua análise textual sobre a clareza do input",
59
+ "confianca": "baixa|media|alta",
60
+ "decisao": "prosseguir|pedir_esclarecimento",
61
+ "pergunta_esclarecimento": "Se decisao == pedir_esclarecimento, coloque aqui uma pergunta natural. Caso contrário, null."
62
+ }}
63
+ """
64
+
65
+ def prompt_passo2_proposito(historico_dialogo: List[Dict], historico_passo2: List[Dict], analise_p1: Dict) -> str:
66
+ """Prompt para análise de PROPÓSITO: Para que o usuário quer saber isso?"""
67
+ return f"""
68
+ Você é um analisador de PROPÓSITO em uma pipeline de raciocínio multi-etapa.
69
+
70
+ Sua única tarefa: identificar PARA QUE o usuário está fazendo essa pergunta ou expressando essa ideia.
71
+
72
+ HISTÓRICO DE DIÁLOGO:
73
+ {json.dumps(historico_dialogo, indent=2, ensure_ascii=False)}
74
+
75
+ HISTÓRICO DO PASSO 2 (suas análises anteriores de propósito):
76
+ {json.dumps(historico_passo2, indent=2, ensure_ascii=False)}
77
+
78
+ ANÁLISE DE CLAREZA (PASSO 1):
79
+ {json.dumps(analise_p1, indent=2, ensure_ascii=False)}
80
+
81
+ INSTRUÇÕES:
82
+ 1. Com base no histórico e na análise de clareza, tente inferir o propósito do usuário.
83
+ 2. Exemplos de propósito: "tomar uma decisão", "aprender algo novo", "validar uma crença", "resolver um problema prático", "desabafar".
84
+ 3. Se você tem alta confiança sobre o propósito, classifique como "alta".
85
+ 4. Se não consegue determinar com certeza, classifique como "baixa" ou "media" e considere pedir esclarecimento.
86
+
87
+ RETORNE APENAS UM JSON VÁLIDO NO FORMATO:
88
+ {{
89
+ "analise": "Sua análise textual sobre o propósito",
90
+ "proposito_inferido": "Descrição do propósito ou null se incerto",
91
+ "confianca": "baixa|media|alta",
92
+ "decisao": "prosseguir|pedir_esclarecimento",
93
+ "pergunta_esclarecimento": "Se decisao == pedir_esclarecimento, coloque aqui uma pergunta natural. Caso contrário, null."
94
+ }}
95
+ """
96
+
97
+ def prompt_passo3_motivacao(historico_dialogo: List[Dict], historico_passo3: List[Dict], analise_p2: Dict) -> str:
98
+ """Prompt para análise de MOTIVAÇÃO: Por que isso é importante para o usuário agora?"""
99
+ return f"""
100
+ Você é um analisador de MOTIVAÇÃO em uma pipeline de raciocínio multi-etapa.
101
+
102
+ Sua única tarefa: identificar POR QUE o usuário está interessado nisso agora. O que despertou essa necessidade?
103
+
104
+ HISTÓRICO DE DIÁLOGO:
105
+ {json.dumps(historico_dialogo, indent=2, ensure_ascii=False)}
106
+
107
+ HISTÓRICO DO PASSO 3 (suas análises anteriores de motivação):
108
+ {json.dumps(historico_passo3, indent=2, ensure_ascii=False)}
109
+
110
+ ANÁLISE DE PROPÓSITO (PASSO 2):
111
+ {json.dumps(analise_p2, indent=2, ensure_ascii=False)}
112
+
113
+ INSTRUÇÕES:
114
+ 1. Tente identificar o gatilho emocional, contextual ou situacional que levou o usuário a fazer essa pergunta.
115
+ 2. Exemplos de motivação: "frustração com situação atual", "curiosidade intelectual", "urgência de decisão", "busca por validação", "experiência recente".
116
+ 3. Se você tem alta confiança sobre a motivação, classifique como "alta".
117
+ 4. Se não consegue determinar, classifique como "baixa" ou "media" e considere pedir esclarecimento.
118
+
119
+ RETORNE APENAS UM JSON VÁLIDO NO FORMATO:
120
+ {{
121
+ "analise": "Sua análise textual sobre a motivação",
122
+ "motivacao_inferida": "Descrição da motivação ou null se incerto",
123
+ "confianca": "baixa|media|alta",
124
+ "decisao": "prosseguir|pedir_esclarecimento",
125
+ "pergunta_esclarecimento": "Se decisao == pedir_esclarecimento, coloque aqui uma pergunta natural. Caso contrário, null."
126
+ }}
127
+ """
128
+
129
+ def prompt_passo4_ambiguidade(historico_dialogo: List[Dict], historico_passo4: List[Dict], analise_p3: Dict) -> str:
130
+ """Prompt para análise de AMBIGUIDADE: Existem múltiplos cenários válidos que precisam ser desambiguados?"""
131
+ return f"""
132
+ Você é um analisador de AMBIGUIDADE DE CENÁRIO em uma pipeline de raciocínio multi-etapa.
133
+
134
+ Sua única tarefa: detectar se a pergunta/situação do usuário tem múltiplas interpretações ou cenários válidos que precisam ser esclarecidos antes de dar uma resposta final.
135
+
136
+ HISTÓRICO DE DIÁLOGO:
137
+ {json.dumps(historico_dialogo, indent=2, ensure_ascii=False)}
138
+
139
+ HISTÓRICO DO PASSO 4 (suas análises anteriores de ambiguidade):
140
+ {json.dumps(historico_passo4, indent=2, ensure_ascii=False)}
141
+
142
+ ANÁLISE DE MOTIVAÇÃO (PASSO 3):
143
+ {json.dumps(analise_p3, indent=2, ensure_ascii=False)}
144
+
145
+ INSTRUÇÕES:
146
+ 1. Analise se a resposta pode variar significativamente dependendo de uma perspectiva, contexto ou premissa não explicitada.
147
+ 2. Exemplos de ambiguidade:
148
+ - "Me fale sobre carros" → pode ser engenharia, história, compra, manutenção, esportes...
149
+ - "Como lidar com ansiedade?" → pode ser clínica, filosófica, técnicas práticas, contexto profissional...
150
+ 3. Se há UMA ÚNICA resposta clara e direta possível, classifique confiança como "alta" e decisao "prosseguir_resposta_final".
151
+ 4. Se há múltiplos cenários válidos, classifique confiança como "baixa" e decisao "pedir_esclarecimento".
152
+
153
+ RETORNE APENAS UM JSON VÁLIDO NO FORMATO:
154
+ {{
155
+ "analise": "Sua análise textual sobre possíveis ambiguidades",
156
+ "cenarios_possiveis": ["cenário 1", "cenário 2", ...] ou null se não há ambiguidade,
157
+ "confianca": "baixa|media|alta",
158
+ "decisao": "prosseguir_resposta_final|pedir_esclarecimento",
159
+ "pergunta_esclarecimento": "Se decisao == pedir_esclarecimento, coloque aqui uma pergunta aberta e natural. Caso contrário, null."
160
+ }}
161
+ """
162
+
163
+ def prompt_sintetizador(historico_dialogo: List[Dict], analises: Dict, modo_sabio: bool) -> str:
164
+ """Prompt para SÍNTESE FINAL: gera a resposta textual ao usuário."""
165
+ contexto_filosofico_str = ""
166
+ if modo_sabio and CONTEXTO_FILOSOFICO:
167
+ contexto_filosofico_str = f"""
168
+ --- CONTEXTO FILOSÓFICO (Epicteto) PARA SUA REFLEXÃO INTERNA ---
169
+ {CONTEXTO_FILOSOFICO}
170
+
171
+ IMPORTANTE: Use este contexto como sua bússola interna. NÃO cite Epicteto explicitamente.
172
+ Sua resposta deve soar como um amigo sábio, não como um professor de filosofia.
173
+ Seja conversacional, empático, use humor leve quando apropriado, e empodere o usuário a encontrar suas próprias respostas.
174
+ """
175
+
176
+ return f"""
177
+ Você é um SINTETIZADOR FINAL de uma pipeline de análise conversacional.
178
+
179
+ Sua tarefa: gerar uma resposta textual natural, completa e útil ao usuário, baseada em toda a análise acumulada.
180
+
181
+ HISTÓRICO DE DIÁLOGO COMPLETO:
182
+ {json.dumps(historico_dialogo, indent=2, ensure_ascii=False)}
183
+
184
+ ANÁLISES CONSOLIDADAS DA PIPELINE:
185
+ {json.dumps(analises, indent=2, ensure_ascii=False)}
186
+
187
+ {contexto_filosofico_str}
188
+
189
+ INSTRUÇÕES:
190
+ 1. Se algum dos passos indicou "pedir_esclarecimento", RETORNE APENAS A PERGUNTA DE ESCLARECIMENTO (do passo com menor confiança).
191
+ 2. Se todos os passos indicaram "prosseguir" ou "prosseguir_resposta_final", gere uma resposta completa e bem fundamentada.
192
+ 3. {"Se Modo Sábio estiver ativo, aplique a persona de Amigo Sábio conforme o contexto filosófico acima." if modo_sabio else "Use tom informativo e objetivo."}
193
+ 4. Sua resposta deve ser APENAS o texto final para o usuário. NÃO retorne JSON aqui.
194
+
195
+ RESPOSTA FINAL:
196
+ """
197
+
198
+ # ==================== FUNÇÃO AUXILIAR: CHAMADA AO GEMINI ====================
199
+ def chamada_gemini(model, prompt: str) -> str:
200
+ """Faz chamada à API Gemini e retorna texto de resposta."""
201
+ try:
202
+ response = model.generate_content(prompt)
203
+ return response.text.strip()
204
+ except Exception as e:
205
+ print(f"❌ Erro ao chamar API Gemini: {e}")
206
+ return '{"erro": "Falha na comunicação com o modelo."}'
207
+
208
+ # ==================== FUNÇÃO AUXILIAR: PARSE SEGURO DE JSON ====================
209
+ def parse_json_seguro(texto: str) -> Dict:
210
+ """Tenta extrair JSON de resposta do LLM, mesmo se vier com markdown ou ruído."""
211
+ try:
212
+ # Remove possíveis blocos markdown ``````
213
+ texto = texto.replace("``````", "").strip()
214
+ return json.loads(texto)
215
+ except json.JSONDecodeError as e:
216
+ print(f"⚠ Erro ao parsear JSON: {e}")
217
+ print(f"Texto recebido: {texto}")
218
+ return {"erro": "Resposta inválida do modelo", "texto_original": texto}
219
+
220
+ # ==================== PIPELINE PRINCIPAL ====================
221
+ def processar_turno(mensagem_usuario: str, modo_sabio: bool = False, modo_supervisor: bool = True) -> str:
222
+ """
223
+ Processa um turno completo do usuário através da pipeline fragmentada.
224
+ Retorna a resposta textual final para exibição.
225
+ """
226
+ global historico_dialogo, historico_passo1_clareza, historico_passo2_proposito
227
+ global historico_passo3_motivacao, historico_passo4_ambiguidade
228
+
229
+ # 1. Registrar input do usuário no histórico de diálogo
230
+ historico_dialogo.append({"user": mensagem_usuario, "assistant": None})
231
+
232
+ print("\n" + "="*70)
233
+ print(f"📩 NOVO INPUT DO USUÁRIO: {mensagem_usuario}")
234
+ print("="*70)
235
+
236
+ # 2. PASSO 1: Análise de CLAREZA
237
+ print("\n🔍 PASSO 1: Analisando CLAREZA...")
238
+ prompt1 = prompt_passo1_clareza(historico_dialogo[:-1], historico_passo1_clareza, mensagem_usuario)
239
+ resposta_p1 = chamada_gemini(counselor_model, prompt1)
240
+ analise_p1 = parse_json_seguro(resposta_p1)
241
+ historico_passo1_clareza.append(analise_p1)
242
+ print(f" Confiança: {analise_p1.get('confianca', 'N/A')}")
243
+ print(f" Decisão: {analise_p1.get('decisao', 'N/A')}")
244
+
245
+ # 3. PASSO 2: Análise de PROPÓSITO
246
+ print("\n🎯 PASSO 2: Analisando PROPÓSITO...")
247
+ prompt2 = prompt_passo2_proposito(historico_dialogo[:-1], historico_passo2_proposito, analise_p1)
248
+ resposta_p2 = chamada_gemini(counselor_model, prompt2)
249
+ analise_p2 = parse_json_seguro(resposta_p2)
250
+ historico_passo2_proposito.append(analise_p2)
251
+ print(f" Confiança: {analise_p2.get('confianca', 'N/A')}")
252
+ print(f" Decisão: {analise_p2.get('decisao', 'N/A')}")
253
+
254
+ # 4. PASSO 3: Análise de MOTIVAÇÃO
255
+ print("\n💡 PASSO 3: Analisando MOTIVAÇÃO...")
256
+ prompt3 = prompt_passo3_motivacao(historico_dialogo[:-1], historico_passo3_motivacao, analise_p2)
257
+ resposta_p3 = chamada_gemini(counselor_model, prompt3)
258
+ analise_p3 = parse_json_seguro(resposta_p3)
259
+ historico_passo3_motivacao.append(analise_p3)
260
+ print(f" Confiança: {analise_p3.get('confianca', 'N/A')}")
261
+ print(f" Decisão: {analise_p3.get('decisao', 'N/A')}")
262
+
263
+ # 5. PASSO 4: Análise de AMBIGUIDADE
264
+ print("\n🔀 PASSO 4: Analisando AMBIGUIDADE...")
265
+ prompt4 = prompt_passo4_ambiguidade(historico_dialogo[:-1], historico_passo4_ambiguidade, analise_p3)
266
+ resposta_p4 = chamada_gemini(counselor_model, prompt4)
267
+ analise_p4 = parse_json_seguro(resposta_p4)
268
+ historico_passo4_ambiguidade.append(analise_p4)
269
+ print(f" Confiança: {analise_p4.get('confianca', 'N/A')}")
270
+ print(f" Decisão: {analise_p4.get('decisao', 'N/A')}")
271
+
272
+ # 6. SÍNTESE FINAL
273
+ print("\n✨ SINTETIZANDO RESPOSTA FINAL...")
274
+ analises_consolidadas = {
275
+ "clareza": analise_p1,
276
+ "proposito": analise_p2,
277
+ "motivacao": analise_p3,
278
+ "ambiguidade": analise_p4
279
+ }
280
+
281
+ prompt_final = prompt_sintetizador(historico_dialogo[:-1], analises_consolidadas, modo_sabio)
282
+ resposta_final = chamada_gemini(counselor_model, prompt_final)
283
+
284
+ # 7. SUPERVISÃO (se ativada)
285
+ if modo_supervisor and analise_p4.get('decisao') == 'prosseguir_resposta_final':
286
+ print("\n🔍 MODO SUPERVISOR: Verificando fatos...")
287
+ feedback_supervisor = verificar_fatos(resposta_final)
288
+
289
+ if feedback_supervisor:
290
+ print(" ⚠ Divergências encontradas. Iniciando autocorreção...")
291
+ resposta_final = autocorrigir(resposta_final, feedback_supervisor)
292
+
293
+ # 8. Atualizar histórico de diálogo
294
+ historico_dialogo[-1]["assistant"] = resposta_final
295
+
296
+ print("\n✅ RESPOSTA ENVIADA AO USUÁRIO")
297
+ print("="*70 + "\n")
298
+
299
+ return resposta_final
300
+
301
+ # ==================== FUNÇÕES DE SUPERVISÃO ====================
302
+ def verificar_fatos(texto: str) -> Optional[str]:
303
+ """Verifica fatos no texto usando o modelo Supervisor."""
304
+ prompt_supervisor = f"""
305
+ Você é um Supervisor de IA, um fact-checker rigoroso e objetivo.
306
+
307
+ Sua única tarefa: analisar o texto abaixo em busca de INCORREÇÕES FACTUAIS.
308
+
309
+ - Analise apenas FATOS verificáveis (datas, nomes, estatísticas, conceitos científicos).
310
+ - NÃO analise opiniões, conselhos filosóficos ou estrutura da resposta.
311
+ - Se encontrar divergências factuais com confiança média ou alta, liste-as claramente.
312
+ - Se NÃO encontrar nenhuma divergência factual, responda APENAS: "NODIVERGENCE"
313
+
314
+ TEXTO PARA ANÁLISE:
315
+ {texto}
316
+
317
+ SUA RESPOSTA:
318
+ """
319
+ try:
320
+ resposta = supervisor_model.generate_content(prompt_supervisor)
321
+ if "NODIVERGENCE" in resposta.text:
322
+ print(" ✓ Nenhuma divergência factual encontrada.")
323
+ return None
324
+ else:
325
+ print(f" ⚠ Divergências: {resposta.text[:200]}...")
326
+ return resposta.text
327
+ except Exception as e:
328
+ print(f"❌ Erro no Supervisor: {e}")
329
+ return None
330
+
331
+ def autocorrigir(resposta_original: str, feedback: str) -> str:
332
+ """Solicita autocorreção ao modelo Conselheiro."""
333
+ prompt_correcao = f"""
334
+ Você é um Conselheiro em processo de refinamento.
335
+
336
+ Sua resposta anterior continha uma imprecisão factual identificada pelo Supervisor.
337
+
338
+ SUA RESPOSTA ORIGINAL:
339
+ {resposta_original}
340
+
341
+ FEEDBACK DO SUPERVISOR (CORREÇÃO):
342
+ {feedback}
343
+
344
+ SUA TAREFA:
345
+ 1. Aceite a correção sem ser defensivo.
346
+ 2. Reescreva sua resposta integrando a correção de forma natural.
347
+ 3. Ao final, adicione uma breve "Nota de Refinamento:" explicando a correção.
348
+
349
+ RESPOSTA CORRIGIDA:
350
+ """
351
+ try:
352
+ resposta_corrigida = counselor_model.generate_content(prompt_correcao)
353
+ return resposta_corrigida.text
354
+ except Exception as e:
355
+ print(f"❌ Erro na autocorreção: {e}")
356
+ return resposta_original
357
+
358
+ # ==================== FUNÇÃO PARA LIMPAR HISTÓRICOS ====================
359
+ def resetar_conversa():
360
+ """Reseta todos os históricos para iniciar nova conversa."""
361
+ global historico_dialogo, historico_passo1_clareza, historico_passo2_proposito
362
+ global historico_passo3_motivacao, historico_passo4_ambiguidade
363
+
364
+ historico_dialogo = []
365
+ historico_passo1_clareza = []
366
+ historico_passo2_proposito = []
367
+ historico_passo3_motivacao = []
368
+ historico_passo4_ambiguidade = []
369
+
370
+ print("\n🔄 Históricos resetados. Nova conversa iniciada.\n")
371
+
372
+ # ==================== WRAPPER PARA GRADIO ====================
373
+ def handle_chat(mensagem: str, historico_chat_gradio: List, modo_sabio: bool, modo_supervisor: bool):
374
+ """Wrapper para integração com Gradio ChatInterface."""
375
+
376
+ # Se é nova conversa (histórico vazio), reseta estados internos
377
+ if not historico_chat_gradio:
378
+ resetar_conversa()
379
+
380
+ # Processa turno
381
+ resposta = processar_turno(mensagem, modo_sabio, modo_supervisor)
382
+
383
+ return resposta
384
+
385
+ # ==================== INTERFACE GRADIO ====================
386
+ iface = gr.ChatInterface(
387
+ fn=handle_chat,
388
+ title="🧠 Parceiro de Raciocínio v10 — Pipeline Fragmentada",
389
+ description="""
390
+ Sistema de conversação com análise multi-etapa e memória granular.
391
+
392
+ **Modo Amigo Sábio**: Reflexões filosóficas baseadas em Epicteto (requer epct0.md)
393
+ **Modo Supervisor**: Verificação automática de fatos e autocorreção
394
+ """,
395
+ chatbot=gr.Chatbot(height=600, label="Diálogo"),
396
+ textbox=gr.Textbox(placeholder="O que está na sua cabeça?", container=False, scale=7),
397
+ additional_inputs=[
398
+ gr.Checkbox(label="🧘 Ativar Modo Amigo Sábio (Filosofia)", value=False),
399
+ gr.Checkbox(label="🔍 Ativar Modo Supervisor (Fact-checking)", value=True)
400
+ ],
401
+ theme="soft",
402
+ examples=[
403
+ "Estou confuso sobre qual carreira seguir.",
404
+ "O Monte Everest tem mais de 9.000 metros de altura?",
405
+ "Por que sinto ansiedade antes de apresentações?",
406
+ "Me fale sobre inteligência artificial."
407
+ ],
408
+ cache_examples=False
409
+ )
410
+
411
+ # ==================== EXECUÇÃO ====================
412
+ if __name__ == "__main__":
413
+ print("\n" + "="*70)
414
+ print("🚀 Iniciando Parceiro de Raciocínio v10 - Pipeline Fragmentada")
415
+ print("="*70 + "\n")
416
+ iface.launch()