caarleexx commited on
Commit
b0c8126
·
verified ·
1 Parent(s): 6e39b29

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -265
app.py CHANGED
@@ -9,327 +9,192 @@ import warnings
9
  import re
10
  warnings.filterwarnings("ignore", category=FutureWarning, module="google.api_core")
11
 
12
- # ============================================================================
13
- # CONFIGURAÇÃO
14
  # ============================================================================
15
  API_KEY = os.getenv("GOOGLE_API_KEY", "sua-chave-aqui")
16
  genai.configure(api_key=API_KEY)
17
  model = genai.GenerativeModel("gemini-2.0-flash")
18
 
19
- TITLE = "# 🚀 Pipeline v10\n**P0-P1 → X1-X2 → P2-P8**"
20
-
21
- # ============================================================================
22
- # LOGGER MELHORADO
23
  # ============================================================================
24
  class Logger:
25
- def __init__(self, verbose=True):
26
- self.verbose = verbose
27
- self.logs = []
28
  def log(self, msg: str, level="INFO"):
29
  timestamp = datetime.now().strftime("%H:%M:%S")
30
- log_msg = f"[{timestamp}] [{level}] {msg}"
31
- self.logs.append(log_msg)
32
- if self.verbose: print(log_msg)
33
 
34
  logger = Logger(verbose=True)
35
 
36
  # ============================================================================
37
- # HELPERS ULTRA ROBUSTOS
38
- # ============================================================================
39
- def processar_anexo(arquivo) -> Tuple[str, str]:
40
- if arquivo is None: return "", "nenhum"
41
  try:
42
  caminho = str(arquivo)
43
- if caminho.lower().endswith('.pdf'):
44
  try:
45
  import PyPDF2
46
  with open(caminho, 'rb') as f:
47
  leitor = PyPDF2.PdfReader(f)
48
- texto = "".join(pagina.extract_text() + "\n" for pagina in leitor.pages[:3])
49
- return texto[:2000], "pdf"
50
- except: return f"[PDF detectado]", "pdf"
51
- elif any(caminho.lower().endswith(ext) for ext in ['.png','.jpg','.jpeg','.gif']):
52
  with open(caminho, 'rb') as f:
53
  return base64.b64encode(f.read()).decode()[:500], "imagem"
54
- return "", "nao_suportado"
55
- except: return "", "erro"
56
 
57
- def construir_prompt_com_anexo(pergunta: str, anexo_conteudo: str, tipo_anexo: str) -> str:
58
- if not anexo_conteudo or tipo_anexo == "nenhum": return pergunta
59
- if tipo_anexo == "pdf": return f"""DOCUMENTO:
60
- {anexo_conteudo[:1800]}
61
- ---
62
- PERGUNTA: {pergunta}"""
63
- return f"""ANEXO VISUAL:
64
- PERGUNTA: {pergunta}"""
65
 
66
- def parse_json_ultra_robusto(texto: str) -> Dict:
67
- """Extrai QUALQUER JSON de texto bagunçado"""
68
- logger.log(f"Parse: {len(texto)} chars", "DEBUG")
69
  if not texto: return {"erro": "vazio"}
70
 
71
- try:
72
- # Regex múltiplos JSONs
73
- matches = re.findall(r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}', texto, re.DOTALL)
74
- for match in matches:
75
- try: return json.loads(match)
76
- except: continue
77
-
78
- # JSON balanceado primeiro
79
- inicio = texto.find('{')
80
- if inicio != -1:
81
- count, i = 1, inicio + 1
82
- while i < len(texto) and count > 0:
83
- if texto[i] == '{': count += 1
84
- elif texto[i] == '}': count -= 1
85
- i += 1
86
- if count == 0: return json.loads(texto[inicio:i])
87
-
88
- # Fallback último JSON
89
- fim = texto.rfind('}')
90
- if fim != -1:
91
- count, i = 1, fim - 1
92
- while i >= 0 and count > 0:
93
- if texto[i] == '}': count += 1
94
- elif texto[i] == '{': count -= 1
95
- i -= 1
96
- if count == 0: return json.loads(texto[i+1:fim+1])
97
-
98
- except Exception as e:
99
- logger.log(f"Parse falhou: {str(e)[:100]}", "ERROR")
100
 
101
- return {"erro": "parse_falhou", "fallback": texto[:200]}
102
-
103
- def chamar_gemini_json(prompt_base: str, temperatura=0.4, max_tokens=1500) -> Dict:
104
- prompt = f"""{prompt_base}
105
-
106
- ---
107
-
108
- **JSON PURO OBRIGATÓRIO**
109
- SEM TEXTO EXTRA. APENAS:
110
- {{"chave": "valor"}}"""
111
 
 
 
 
 
112
  try:
113
- response = model.generate_content(prompt,
114
  generation_config=genai.types.GenerationConfig(
115
- temperature=temperatura,
116
- max_output_tokens=max_tokens))
117
- logger.log(f"Gemini OK: {len(response.text)} chars", "DEBUG")
118
- return parse_json_ultra_robusto(response.text or "")
119
  except Exception as e:
120
- logger.log(f"API erro: {str(e)}", "ERROR")
121
  return {"erro": str(e)}
122
 
123
- def historico_compacto(historico: List) -> str:
124
- if not historico: return "PRIMEIRO"
125
- return "\n".join([str(msg).split("\n")[0][:80] for msg in historico[-2:]])
126
-
127
- def criar_dna() -> Dict:
128
- return {
129
- "historico_chat": [],
130
- "historico_passos": {f"passo{i}": [] for i in range(10)},
131
- "memoria": {"resumo": ""},
132
- "meta": {"turnos": 0}
133
- }
134
-
135
  # ============================================================================
136
- # PASSOS P0-P1 (ANTIGOS)
137
- # ============================================================================
138
- def passo_0_aluno(pergunta: str, historico: List) -> Dict:
139
- logger.log("🧠 P0-ALUNO", "TASK")
140
- prompt = f"""P0-ALUNO TELEGRÁFICO
141
- HISTÓRICO: {historico_compacto(historico)}
142
- PERGUNTA: {pergunta}
143
-
144
- {{"relacao": "continua|nova|corrige", "peso_hist": "alto|medio|baixo"}}"""
145
- return chamar_gemini_json(prompt)
146
-
147
- def passo_1_triagem(pergunta: str, p0: Dict, historico: List) -> Dict:
148
- logger.log("📊 P1-TRIAGEM", "TASK")
149
- prompt = f"""P1-TRIAGEM TELEGRÁFICO
150
- P0: {json.dumps(p0)}
151
- PERGUNTA: {pergunta}
152
 
153
- {{"tipo": "factual|subjetiva|aberta",
154
- "confianca": "alta|media|baixa",
155
- "fatos": ["fato1", "fato2"]}}"""
156
- return chamar_gemini_json(prompt)
157
 
158
  # ============================================================================
159
- # NOVOS PASSOS X1-X2
160
- # ============================================================================
161
- def passo_x1_perguntas_necessarias(pergunta: str, p1: Dict, historico: List) -> Dict:
162
- """X1: Quais perguntas precisamos responder antes dos cenários?"""
163
- logger.log("❓ X1-PERGUNTAS NECESSÁRIAS", "TASK")
164
- prompt = f"""X1-PERGUNTAS CRÍTICAS TELEGRÁFICO
165
- P1: {json.dumps(p1)}
166
- CONTEXTO: {historico_compacto(historico)}
167
- PERGUNTA PRINCIPAL: {pergunta}
168
-
169
- LACUNAS FACTUAIS/SUBJETIVAS:
170
- {{"perguntas": [
171
- {{"texto": "pergunta curta", "necessidade": "alta|media|baixa", "relevancia": "alta|media"}}
172
- ]}}"""
173
- return chamar_gemini_json(prompt)
174
-
175
- def passo_x2_resolver_perguntas(pergunta: str, p1: Dict, x1: Dict, historico: List) -> Dict:
176
- """X2: Responde as perguntas levantadas com confiança/conflito"""
177
- logger.log("✅ X2-RESOLVER PERGUNTAS", "TASK")
178
- perguntas = x1.get("perguntas", [])
179
- prompt = f"""X2-RESOLUÇÃO TELEGRÁFICO
180
- P1: {json.dumps(p1)}
181
- PERGUNTAS X1: {json.dumps(perguntas)}
182
- CONTEXTO: {historico_compacto(historico)}
183
 
184
- PARA CADA PERGUNTA:
185
- {{"respostas": [
186
- {{"pergunta": "texto original",
187
- "resposta": "curta direta",
188
- "confianca": "alta|media|baixa",
189
- "conflito": "alto|medio|baixo",
190
- "razao": "1-2 palavras"}}
191
- ]}}"""
192
- return chamar_gemini_json(prompt, max_tokens=2000)
193
 
194
- # ============================================================================
195
- # PASSOS P2-P8 (MELHORADOS COM X1-X2)
196
- # ============================================================================
197
- def passo_2_cenarios(pergunta: str, p1: Dict, x1: Dict, x2: Dict, historico: List) -> Dict:
198
- logger.log("🎯 P2-CENÁRIOS (com X1-X2)", "TASK")
199
- prompt = f"""P2-CENÁRIOS TELEGRÁFICO
200
- P1: {json.dumps(p1)}
201
- X1-PERGUNTAS: {json.dumps(x1)}
202
- X2-RESPOSTAS: {json.dumps(x2)}
203
- PERGUNTA: {pergunta}
204
 
205
- {{"cenarios": {{"provaveis": [{{"id": "C1", "desc": "curto"}}],
206
- "improvaveis": [{{"id": "C2", "desc": "curto"}}]}},
207
- "total": 2}}"""
208
- return chamar_gemini_json(prompt)
209
 
210
- def passo_3_isolar_cenarios(p2: Dict) -> Dict:
211
- logger.log("🔍 P3-ISOLAR", "TASK")
212
- exploracoes = []
213
- for tipo in ['provaveis', 'improvaveis']:
214
- for c in p2.get('cenarios', {}).get(tipo, [])[:2]:
215
- prompt = f"""P3-ISOLAR: {c.get('id')}
216
- {{"id": "{c.get('id')}", "solucao": "direta", "balanco": "positivo|negativo"}}"""
217
- exploracoes.append(chamar_gemini_json(prompt))
218
- return {"isolados": exploracoes}
219
 
220
- def passo_4_cruzar_validacoes(p1: Dict, p2: Dict, p3: Dict, x2: Dict) -> Dict:
221
- logger.log(" P4-VALIDAR", "TASK")
222
- prompt = f"""P4-VALIDAR TELEGRÁFICO
223
- {{"confiancas": [{{"fato": "X", "origem": "X1|X2|P3", "nivel": "alta|baixa"}}]}}"""
224
- return chamar_gemini_json(prompt)
 
 
225
 
226
- def passo_5_lacunas_finais(p1: Dict, p4: Dict) -> Dict:
227
- logger.log("🚨 P5-LACUNAS FINAIS", "TASK")
228
- prompt = f"""P5-LACUNAS RESTANTES
229
- {{"lacunas": [{{"texto": "curto", "critica": "sim|nao"}}],
230
- "decisao": "continuar|parar"}}"""
231
- return chamar_gemini_json(prompt)
232
 
233
- def passo_6_ponderar(p2: Dict, p4: Dict, p5: Dict) -> Dict:
234
- logger.log("⚖️ P6-PONDERAR", "TASK")
235
- prompt = f"""P6-DECISÃO FINAL
236
- {{"vencedor": "C1", "peso": "0.8", "razao": "curta"}}"""
237
- return chamar_gemini_json(prompt)
238
 
239
- def passo_7_sintetizar(p6: Dict) -> Dict:
240
- logger.log("✍️ P7-SINTETIZAR", "TASK")
241
- prompt = f"""P7-PROSA NATURAL
242
- P6: {json.dumps(p6)}
243
 
244
- {{"resposta": "texto fluido completo"}}"""
245
- return chamar_gemini_json(prompt, temperatura=0.7, max_tokens=2500)
 
246
 
247
- def passo_8_verificar(p7: Dict) -> Dict:
248
- logger.log("🔍 P8-FINAL", "TASK")
249
- prompt = f"""P8-VERIFICAÇÃO
250
- {{"factual": "ok", "logica": "ok", "etica": "ok",
251
- "final": "texto aprovado"}}"""
252
- return chamar_gemini_json(prompt)
253
 
254
  # ============================================================================
255
- # ORQUESTADOR PRINCIPAL v10
256
- # ============================================================================
257
- def processar_pipeline(pergunta: str, historico: List, arquivo_anexo=None, dna=None) -> Tuple[str, List, Dict]:
258
- if dna is None or not isinstance(dna, dict):
259
- dna = criar_dna()
260
 
261
- logger.log(f"🚀 v10: {pergunta[:50]}", "START")
262
- if not pergunta.strip(): return "Pergunta inválida", historico, dna
263
 
264
- anexo_c, tipo_a = processar_anexo(arquivo_anexo)
265
- pergunta_final = construir_prompt_com_anexo(pergunta, anexo_c, tipo_a)
266
 
267
- try:
268
- # P0-P1
269
- p0 = passo_0_aluno(pergunta_final, historico)
270
- p1 = passo_1_triagem(pergunta_final, p0, historico)
271
-
272
- # NOVOS X1-X2
273
- x1 = passo_x1_perguntas_necessarias(pergunta_final, p1, historico)
274
- x2 = passo_x2_resolver_perguntas(pergunta_final, p1, x1, historico)
275
-
276
- # P2 usa X1-X2
277
- p2 = passo_2_cenarios(pergunta_final, p1, x1, x2, historico)
278
- if p2.get("decisao") == "parar":
279
- return x1.get("perguntas", ["Esclareça"]), historico, dna
280
-
281
- # P3-P8 fluxo normal
282
- p3 = passo_3_isolar_cenarios(p2)
283
- p4 = passo_4_cruzar_validacoes(p1, p2, p3, x2)
284
- p5 = passo_5_lacunas_finais(p1, p4)
285
-
286
- if p5.get("decisao") == "parar":
287
- return "Lacuna crítica", historico, dna
288
-
289
- p6 = passo_6_ponderar(p2, p4, p5)
290
- p7 = passo_7_sintetizar(p6)
291
- p8 = passo_8_verificar(p7)
292
-
293
- resposta = p8.get("final", p7.get("resposta", "Erro"))
294
- novo_hist = historico + [{"role": "user", "content": pergunta},
295
- {"role": "assistant", "content": resposta}]
296
-
297
- dna["historico_chat"].append({"u": pergunta, "a": resposta})
298
- dna["meta"]["turnos"] += 1
299
-
300
- return resposta, novo_hist, dna
301
-
302
- except Exception as e:
303
- logger.log(f"ERRO v10: {str(e)}", "ERROR")
304
- return f"Erro: {str(e)}", historico, dna
305
 
306
  # ============================================================================
307
- # INTERFACE
308
- # ============================================================================
309
- def chat_interface(msg: str, hist: List, anexo=None, dna_json: str="{}") -> Tuple[List, str, str, None]:
310
- try: dna = json.loads(dna_json) if dna_json else {}
311
  except: dna = {}
312
-
313
- resp, novo_hist, dna_new = processar_pipeline(msg, hist, anexo, dna)
314
- return novo_hist, "", json.dumps(dna_new, indent=2), None
315
 
316
  if __name__ == "__main__":
317
- with gr.Blocks(title="Pipeline v10", theme=gr.themes.Soft()) as demo:
318
- gr.Markdown(TITLE + "\n**X1-Perguntas → X2-Resolução → Cenários Aprofundados**")
319
-
320
  with gr.Row():
321
- with gr.Column(scale=2):
322
- chat = gr.Chatbot(height=550, type="messages")
323
- dna_view = gr.Code(label="DNA", language="json", lines=12)
324
- with gr.Column(scale=1):
325
- input_txt = gr.Textbox(label="Pergunta", lines=3, scale=2)
326
- file_up = gr.File(label="Anexo", file_types=[".pdf",".png",".jpg"])
327
- btn_go = gr.Button("🚀 v10", variant="primary")
328
 
329
- btn_go.click(chat_interface, [input_txt, chat, file_up, dna_view],
330
- [chat, input_txt, dna_view, file_up])
331
- input_txt.submit(chat_interface, [input_txt, chat, file_up, dna_view],
332
- [chat, input_txt, dna_view, file_up])
333
-
334
- demo.launch(server_name="0.0.0.0", server_port=7860)
335
 
 
 
9
  import re
10
  warnings.filterwarnings("ignore", category=FutureWarning, module="google.api_core")
11
 
 
 
12
  # ============================================================================
13
  API_KEY = os.getenv("GOOGLE_API_KEY", "sua-chave-aqui")
14
  genai.configure(api_key=API_KEY)
15
  model = genai.GenerativeModel("gemini-2.0-flash")
16
 
 
 
 
 
17
  # ============================================================================
18
  class Logger:
19
+ def __init__(self, verbose=True): self.verbose = verbose; self.logs = []
 
 
20
  def log(self, msg: str, level="INFO"):
21
  timestamp = datetime.now().strftime("%H:%M:%S")
22
+ print(f"[{timestamp}] [{level}] {msg}")
 
 
23
 
24
  logger = Logger(verbose=True)
25
 
26
  # ============================================================================
27
+ def processar_anexo(arquivo):
28
+ if not arquivo: return "", "nenhum"
 
 
29
  try:
30
  caminho = str(arquivo)
31
+ if caminho.endswith('.pdf'):
32
  try:
33
  import PyPDF2
34
  with open(caminho, 'rb') as f:
35
  leitor = PyPDF2.PdfReader(f)
36
+ return "".join(p.extract_text()+"\n" for p in leitor.pages[:3])[:2000], "pdf"
37
+ except: return "[PDF]", "pdf"
38
+ if any(caminho.endswith(x) for x in ['.png','.jpg','.jpeg']):
 
39
  with open(caminho, 'rb') as f:
40
  return base64.b64encode(f.read()).decode()[:500], "imagem"
41
+ except: pass
42
+ return "", "erro"
43
 
44
+ def construir_prompt(pergunta: str, anexo: str, tipo: str):
45
+ if not anexo: return pergunta
46
+ return f"ANEXO {tipo.upper()}:\n{anexo}\n\nPERGUNTA: {pergunta}"
 
 
 
 
 
47
 
48
+ # ============================================================================
49
+ def PARSER_SIMPLES(texto: str) -> Dict:
50
+ """PARSER ULTRA SIMPLES - PEGA PRIMEIRO JSON"""
51
  if not texto: return {"erro": "vazio"}
52
 
53
+ # 1. Regex simples
54
+ match = re.search(r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}', texto)
55
+ if match:
56
+ try: return json.loads(match.group(0))
57
+ except: pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ # 2. Primeiro { até último }
60
+ ini = texto.find('{')
61
+ fim = texto.rfind('}')
62
+ if ini >= 0 and fim > ini:
63
+ try: return json.loads(texto[ini:fim+1])
64
+ except: pass
 
 
 
 
65
 
66
+ return {"erro": texto[:100]}
67
+
68
+ def gemini_json(prompt: str, temp=0.4, tokens=1500) -> Dict:
69
+ prompt += "\n\n**JSON PURO. SEM TEXTO.**"
70
  try:
71
+ resp = model.generate_content(prompt,
72
  generation_config=genai.types.GenerationConfig(
73
+ temperature=temp, max_output_tokens=tokens))
74
+ raw = resp.text or ""
75
+ logger.log(f"RAW({len(raw)}): {raw[:200]}...", "RAW")
76
+ return PARSER_SIMPLES(raw)
77
  except Exception as e:
78
+ logger.log(f"API ERRO: {e}", "ERROR")
79
  return {"erro": str(e)}
80
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  # ============================================================================
82
+ def criar_dna(): return {
83
+ "chat": [],
84
+ "passos": {f"p{i}": [] for i in range(10)},
85
+ "meta": {"turnos": 0}
86
+ }
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ def hist_compacto(hist: List):
89
+ return "\n".join([str(h).split("\n")[0][:60] for h in hist[-2:]] or ["PRIMEIRO"])
 
 
90
 
91
  # ============================================================================
92
+ # PASSOS
93
+ def p0_aluno(pergunta: str, hist: List):
94
+ logger.log("🧠 P0", "TASK")
95
+ return gemini_json(f"P0\nHIST: {hist_compacto(hist)}\nQ: {pergunta}\n{{\"relacao\": \"nova|continua\", \"peso\": \"alto|medio\"}}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ def p1_triagem(pergunta: str, p0: Dict, hist: List):
98
+ logger.log("📊 P1", "TASK")
99
+ return gemini_json(f"P1\nP0: {json.dumps(p0)}\nQ: {pergunta}\n{{\"tipo\": \"factual|subjetiva\", \"conf\": \"alta|baixa\"}}")
 
 
 
 
 
 
100
 
101
+ def x1_perguntas(pergunta: str, p1: Dict, hist: List):
102
+ logger.log("❓ X1", "TASK")
103
+ return gemini_json(f"X1\nP1: {json.dumps(p1)}\nQ: {pergunta}\n{{\"perguntas\": [{{\"t\": \"pergunta\", \"nec\": \"alta|baixa\"}}]}}")
 
 
 
 
 
 
 
104
 
105
+ def x2_respostas(pergunta: str, p1: Dict, x1: Dict, hist: List):
106
+ logger.log(" X2", "TASK")
107
+ return gemini_json(f"X2\nP1: {json.dumps(p1)}\nX1: {json.dumps(x1)}\n{{\"respostas\": [{{\"p\": \"pergunta\", \"r\": \"resposta\", \"conf\": \"alta\"}}]}}")
 
108
 
109
+ def p2_cenarios(pergunta: str, p1: Dict, x1: Dict, x2: Dict, hist: List):
110
+ logger.log("🎯 P2", "TASK")
111
+ return gemini_json(f"P2\nP1: {json.dumps(p1)}\nX1: {json.dumps(x1)}\nX2: {json.dumps(x2)}\n{{\"cen\": {{\"prov\": [{{\"id\": \"C1\"}}], \"imp\": [{{\"id\": \"C2\"}}]}}}}")
 
 
 
 
 
 
112
 
113
+ def p3_isolar(p2: Dict):
114
+ logger.log("🔍 P3", "TASK")
115
+ res = []
116
+ for tipo in ['prov', 'imp']:
117
+ for c in p2.get('cen', {}).get(tipo, [])[:1]:
118
+ res.append(gemini_json(f"P3-{c.get('id')}\n{{\"id\": \"{c.get('id')}\", \"sol\": \"direta\"}}"))
119
+ return {"isol": res}
120
 
121
+ def p4_validar(p1: Dict, p2: Dict, p3: Dict):
122
+ logger.log(" P4", "TASK")
123
+ return gemini_json(f"P4\n{{\"conf\": [{{\"f\": \"fato\", \"n\": \"alta\"}}]}}")
 
 
 
124
 
125
+ def p5_lacunas(p1: Dict, p4: Dict):
126
+ logger.log("🚨 P5", "TASK")
127
+ return gemini_json(f"P5\n{{\"lac\": [{{\"t\": \"lacuna\", \"c\": \"sim\"}}], \"dec\": \"cont|par\"}}")
 
 
128
 
129
+ def p6_ponderar(p2: Dict, p4: Dict, p5: Dict):
130
+ logger.log("⚖️ P6", "TASK")
131
+ return gemini_json(f"P6\n{{\"win\": \"C1\", \"peso\": 0.8}}")
 
132
 
133
+ def p7_sintetizar(p6: Dict):
134
+ logger.log("✍️ P7", "TASK")
135
+ return gemini_json(f"P7\nP6: {json.dumps(p6)}\n{{\"resp\": \"texto final\"}}", temp=0.7, tokens=2000)
136
 
137
+ def p8_verificar(p7: Dict):
138
+ logger.log("🔍 P8", "TASK")
139
+ return gemini_json(f"P8\n{{\"ok\": true, \"final\": \"aprovado\"}}")
 
 
 
140
 
141
  # ============================================================================
142
+ def processar(pergunta: str, hist: List, anexo=None, dna=None):
143
+ if dna is None: dna = criar_dna()
144
+ logger.log(f"🚀 {pergunta[:40]}", "START")
 
 
145
 
146
+ if not pergunta.strip(): return "Pergunta inválida", hist, dna
 
147
 
148
+ a_c, a_t = processar_anexo(anexo)
149
+ q = construir_prompt(pergunta, a_c, a_t)
150
 
151
+ # PIPELINE
152
+ p0 = p0_aluno(q, hist)
153
+ p1 = p1_triagem(q, p0, hist)
154
+ x1 = x1_perguntas(q, p1, hist)
155
+ x2 = x2_respostas(q, p1, x1, hist)
156
+
157
+ p2 = p2_cenarios(q, p1, x1, x2, hist)
158
+ if p2.get("dec") == "par": return "Esclareça", hist, dna
159
+
160
+ p3 = p3_isolar(p2)
161
+ p4 = p4_validar(p1, p2, p3)
162
+ p5 = p5_lacunas(p1, p4)
163
+
164
+ if p5.get("dec") == "par": return "Lacuna", hist, dna
165
+
166
+ p6 = p6_ponderar(p2, p4, p5)
167
+ p7 = p7_sintetizar(p6)
168
+ p8 = p8_verificar(p7)
169
+
170
+ resp = p8.get("final") or p7.get("resp") or "Erro"
171
+ novo_hist = hist + [{"role": "user", "content": pergunta}, {"role": "assistant", "content": resp}]
172
+
173
+ dna["chat"].append({"u": pergunta, "a": resp})
174
+ dna["meta"]["turnos"] += 1
175
+
176
+ return resp, novo_hist, dna
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
  # ============================================================================
179
+ def chat(msg: str, hist: List, anexo=None, dna_j: str="{}"):
180
+ try: dna = json.loads(dna_j)
 
 
181
  except: dna = {}
182
+ r, nh, nd = processar(msg, hist, anexo, dna)
183
+ return nh, "", json.dumps(nd, indent=2)
 
184
 
185
  if __name__ == "__main__":
186
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
187
+ gr.Markdown("# 🚀 v10 X1-X2")
 
188
  with gr.Row():
189
+ with gr.Column(2):
190
+ c = gr.Chatbot(height=500)
191
+ dj = gr.Code(label="DNA", language="json")
192
+ with gr.Column(1):
193
+ i = gr.Textbox(label="Pergunta", lines=3)
194
+ f = gr.File(file_types=[".pdf", ".png", ".jpg"])
195
+ b = gr.Button("GO", variant="primary")
196
 
197
+ b.click(chat, [i,c,f,dj], [c,i,dj,f])
198
+ i.submit(chat, [i,c,f,dj], [c,i,dj,f])
 
 
 
 
199
 
200
+ demo.launch(server_name="0.0.0.0", port=7860)