caarleexx commited on
Commit
66274bb
Β·
verified Β·
1 Parent(s): 8a6fb22

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -62
app.py CHANGED
@@ -1,6 +1,5 @@
1
  # ╔════════════════════════════════════════════════════════════════════════════╗
2
- # β•‘ PIPELINE v40: FRAGMENTAÇÃO + VISΓƒO PAGINADA + ORQUESTRAÇÃO EM ABAS β•‘
3
- # β•‘ Upload de PDF β†’ fragmentos β†’ PAGINADOR_VISUAL β†’ confext_upload JSON β•‘
4
  # β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
5
 
6
  import os
@@ -27,15 +26,10 @@ ARQUIVO_CONFIG = "protocolo_fragmentacao_visao-3.json"
27
  # ==================== 2. UTILIDADES ====================
28
 
29
  def carregar_protocolo():
30
- """
31
- Carrega o protocolo JSON de agentes.
32
- Se nΓ£o existir, usa o protocolo bΓ‘sico de PAGINADOR_VISUAL.
33
- """
34
  try:
35
  with open(ARQUIVO_CONFIG, "r", encoding="utf-8") as f:
36
  return f.read()
37
  except:
38
- # fallback: protocolo mΓ­nimo de visΓ£o paginada
39
  return json.dumps([
40
  {
41
  "nome": "PAGINADOR_VISUAL",
@@ -54,9 +48,6 @@ def carregar_protocolo():
54
  ], ensure_ascii=False, indent=2)
55
 
56
  def salvar_protocolo(conteudo):
57
- """
58
- Salva o JSON de protocolo apΓ³s validar sintaxe.
59
- """
60
  try:
61
  json.loads(conteudo)
62
  with open(ARQUIVO_CONFIG, "w", encoding="utf-8") as f:
@@ -65,13 +56,17 @@ def salvar_protocolo(conteudo):
65
  except:
66
  return "❌ Erro JSON"
67
 
68
- # --------- DIVISΓƒO BURRA: PDF EM BLOCOS DE 5 PÁGINAS ---------
 
 
 
 
69
 
70
  def ler_anexo_e_fragmentar(arquivo, paginas_por_fragmento=5):
71
  """
72
- DIVISÃO BURRA:
73
- - Se PDF: cria fragmentos de metadados indicando blocos de pΓ‘ginas.
74
- - Se texto: devolve um ΓΊnico fragmento marcador.
75
  """
76
  if arquivo is None:
77
  return [], ""
@@ -83,7 +78,6 @@ def ler_anexo_e_fragmentar(arquivo, paginas_por_fragmento=5):
83
 
84
  anexo_info = f"[PDF: {os.path.basename(filename)}]"
85
 
86
- # Se nΓ£o for PDF, tratamos como arquivo texto simples
87
  if not filename.lower().endswith(".pdf"):
88
  return [f"[ARQUIVO_TEXTO: {os.path.basename(filename)}]"], anexo_info
89
 
@@ -96,12 +90,18 @@ def ler_anexo_e_fragmentar(arquivo, paginas_por_fragmento=5):
96
  start = i + 1
97
  end = min(i + paginas_por_fragmento, total_pages)
98
 
99
- # Aqui o fragmento Γ© apenas um cabeΓ§alho + marcador
 
 
 
 
 
 
 
100
  fragment = (
101
  f"=== FRAG {i//paginas_por_fragmento + 1} "
102
  f"(PÁGS {start}-{end}/{total_pages}) ===\n"
103
- f"[PAGINADOR: vocΓͺ estΓ‘ vendo pΓ‘ginas {start}-{end}. "
104
- f"Extraia JSON pagina/transcricao_fiel/descricao_visual.]"
105
  )
106
  fragments.append(fragment)
107
 
@@ -112,11 +112,6 @@ def ler_anexo_e_fragmentar(arquivo, paginas_por_fragmento=5):
112
  # ==================== 3. ENGINE DE EXECUÇÃO ====================
113
 
114
  def executar_no(timeline, config, fragmento_input=None):
115
- """
116
- Executa um nΓ³ (agente) do protocolo.
117
- - Se fragmento_input for fornecido, ele Γ© o INPUT PARA O AGENTE.
118
- - Caso contrΓ‘rio, o input Γ© o JSON da timeline inteira.
119
- """
120
  modelo = model_pro if config.get("modelo") == "pro" else model_flash
121
 
122
  if fragmento_input is not None:
@@ -136,13 +131,16 @@ def executar_no(timeline, config, fragmento_input=None):
136
  try:
137
  inicio = time.time()
138
  resp = modelo.generate_content(prompt)
139
- out = resp.text
140
  tempo = time.time() - inicio
141
 
142
  if config["tipo_saida"] == "json":
143
- # limpeza mΓ­nima de cercas de cΓ³digo
144
  cleaned = out.strip().replace("``````", "")
145
- content = json.loads(cleaned)
 
 
 
 
146
  else:
147
  content = out
148
 
@@ -154,21 +152,12 @@ def executar_no(timeline, config, fragmento_input=None):
154
  # ==================== 4. ORQUESTRADOR ====================
155
 
156
  def orquestrador(texto, arquivo, history, json_config, confext_state):
157
- """
158
- Pipeline:
159
- 1) Se houver arquivo, faz divisΓ£o burra + visΓ£o PAGINADOR_VISUAL por fragmento.
160
- - Resultado consolidado em confext_upload (state) por pΓ‘gina.
161
- 2) Timeline recebe um nΓ³ de sistema com esse confext_upload.
162
- 3) Protocolos adicionais (se existirem alΓ©m do PAGINADOR_VISUAL) usam sΓ³ esse contexto.
163
- """
164
- # 1. FragmentaΓ§Γ£o
165
  fragmentos, anexo_info = ler_anexo_e_fragmentar(arquivo)
166
 
167
  if not texto and not fragmentos:
168
  yield history, {}, "⚠️ Sem input ou erro ao ler arquivo.", confext_state
169
  return
170
 
171
- # 2. Setup inicial
172
  history = history + [[texto + (" πŸ“Ž" if arquivo else ""), None]]
173
 
174
  try:
@@ -181,38 +170,36 @@ def orquestrador(texto, arquivo, history, json_config, confext_state):
181
  timeline = [{"role": "user", "content": texto}]
182
  logs = f"πŸš€ START: {datetime.now().strftime('%H:%M:%S')}\n"
183
 
184
- # Estrutura interna de contexto de anexos
185
  confext_upload = {
186
  "arquivo": os.path.basename(getattr(arquivo, "name", "sem_arquivo"))
187
  if arquivo else None,
188
  "meta": anexo_info,
189
- "paginas": [] # cada item: {pagina, transcricao_fiel, descricao_visual}
190
  }
191
 
192
  if fragmentos:
193
- logs += f"πŸ“Ž PDF dividido: {len(fragmentos)} fragmentos burros.\n"
194
  history[-1][1] = "⏳ Fragmentando + visΓ£o paginada..."
195
  yield history, timeline, logs, confext_upload
196
 
197
- # 3. PASSO DE VISÃO PAGINADA (PAGINADOR_VISUAL)
198
- # Espera-se que seja o primeiro (ΓΊnico) agente, mas tratamos genericamente.
199
  if protocolo and fragmentos:
200
- cfg_visao = protocolo[0] # usamos apenas o primeiro como PAGINADOR_VISUAL
 
201
 
202
  for i, fragmento in enumerate(fragmentos):
203
- history[-1][1] = (
204
- f"πŸ‘οΈ {cfg_visao['nome']} frag {i+1}/{len(fragmentos)}..."
205
- )
206
  yield history, timeline, logs, confext_upload
207
 
208
  res, log_add, raw = executar_no(timeline, cfg_visao, fragmento_input=fragmento)
209
  logs += log_add + "\n"
 
210
 
211
  if "error" in res:
212
- logs += f"❌ Erro frag {i+1}: {res['error']}\n"
213
  continue
214
 
215
- # res['content'] deve ser lista JSON de pΓ‘ginas [{pagina, transcricao_fiel, descricao_visual}, ...]
216
  try:
217
  paginas_res = res["content"]
218
  if isinstance(paginas_res, dict):
@@ -220,21 +207,18 @@ def orquestrador(texto, arquivo, history, json_config, confext_state):
220
  for p in paginas_res:
221
  confext_upload["paginas"].append(p)
222
  except Exception as e:
223
- logs += f"❌ Erro ao incorporar pÑginas do frag {i+1}: {e}\n"
224
 
225
- logs += "βœ… VisΓ΅es paginadas completas.\n"
226
 
227
- # 4. Injeta confext_upload na timeline como nΓ³ de sistema
228
  timeline.append({
229
  "role": "system",
230
  "agent": "CONFEXT_UPLOAD",
231
  "content": confext_upload
232
  })
233
 
234
- # 5. Se existirem passos adicionais alΓ©m do PAGINADOR_VISUAL, executa-os sequencialmente
235
- final_response = ""
236
- # pula o primeiro passo se ele Γ© o PAGINADOR_VISUAL
237
  restante = protocolo[1:] if protocolo else []
 
238
 
239
  for cfg in restante:
240
  history[-1][1] = f"βš™οΈ {cfg['nome']}..."
@@ -251,14 +235,13 @@ def orquestrador(texto, arquivo, history, json_config, confext_state):
251
  yield history, timeline, logs, confext_upload
252
 
253
  if not restante and not texto:
254
- # se nΓ£o hΓ‘ mais agentes e nΓ£o houve prompt, sΓ³ confirma prΓ©-processamento
255
- history[-1][1] = "βœ… PDF processado. Pronto para perguntas usando contexto interno."
256
  final_response = history[-1][1]
257
 
258
- logs += "βœ… FIM.\n"
259
  yield history, timeline, logs, confext_upload
260
 
261
- # ==================== 5. UI LIMPA ====================
262
 
263
  def ui_clean():
264
  css = """
@@ -272,7 +255,6 @@ def ui_clean():
272
  confext_state = gr.State(value=None)
273
 
274
  with gr.Tabs():
275
- # === ABA 1: CHAT / INVESTIGADOR ===
276
  with gr.Tab("πŸ’¬ Investigador"):
277
  chatbot = gr.Chatbot(
278
  label="",
@@ -301,21 +283,18 @@ def ui_clean():
301
  btn_send = gr.Button("Enviar", variant="primary", size="sm")
302
 
303
  file_status = gr.Markdown("", visible=True)
304
- # Mostra nome do arquivo ao subir
305
  file_in.upload(
306
  lambda x: f"πŸ“Ž Anexo recebido: {os.path.basename(getattr(x, 'name', x))}",
307
  inputs=file_in,
308
  outputs=file_status,
309
  )
310
 
311
- # === ABA 2: DEPURAÇÃO ===
312
  with gr.Tab("πŸ•΅οΈ DepuraΓ§Γ£o"):
313
  with gr.Row():
314
  out_dna = gr.JSON(label="DNA (Timeline)")
315
  out_logs = gr.Textbox(label="Logs do Sistema", lines=20)
316
  confext_view = gr.JSON(label="confext_upload")
317
 
318
- # === ABA 3: CONFIG ===
319
  with gr.Tab("βš™οΈ Config"):
320
  with gr.Row():
321
  btn_save = gr.Button("Salvar Config")
@@ -323,9 +302,7 @@ def ui_clean():
323
  code_json = gr.Code(value=config_init, language="json", label=ARQUIVO_CONFIG)
324
  btn_save.click(salvar_protocolo, code_json, lbl_save)
325
 
326
- # === TRIGGERS ===
327
  def _orq_wrapper(texto, arquivo, history, json_cfg, confext_old):
328
- # delega para o orquestrador, passando state antigo
329
  for h, dna, logs, confext_new in orquestrador(texto, arquivo, history, json_cfg, confext_old):
330
  yield h, dna, logs, confext_new
331
 
 
1
  # ╔════════════════════════════════════════════════════════════════════════════╗
2
+ # β•‘ PIPELINE v41: FRAGMENTAÇÃO + VISΓƒO PAGINADA + CONFEXT_UPLOAD β•‘
 
3
  # β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
4
 
5
  import os
 
26
  # ==================== 2. UTILIDADES ====================
27
 
28
  def carregar_protocolo():
 
 
 
 
29
  try:
30
  with open(ARQUIVO_CONFIG, "r", encoding="utf-8") as f:
31
  return f.read()
32
  except:
 
33
  return json.dumps([
34
  {
35
  "nome": "PAGINADOR_VISUAL",
 
48
  ], ensure_ascii=False, indent=2)
49
 
50
  def salvar_protocolo(conteudo):
 
 
 
51
  try:
52
  json.loads(conteudo)
53
  with open(ARQUIVO_CONFIG, "w", encoding="utf-8") as f:
 
56
  except:
57
  return "❌ Erro JSON"
58
 
59
+ def log_point(msg, logs):
60
+ ts = datetime.now().strftime("%H:%M:%S")
61
+ return logs + f"[{ts}] {msg}\n"
62
+
63
+ # --------- DIVISÃO BURRA COM TEXTO REAL ---------
64
 
65
  def ler_anexo_e_fragmentar(arquivo, paginas_por_fragmento=5):
66
  """
67
+ Se PDF: lΓͺ texto das pΓ‘ginas e cria fragmentos com blocos de atΓ© N pΓ‘ginas.
68
+ Cada fragmento contΓ©m o texto bruto dessas pΓ‘ginas.
69
+ Se nΓ£o for PDF: devolve um marcador simples.
70
  """
71
  if arquivo is None:
72
  return [], ""
 
78
 
79
  anexo_info = f"[PDF: {os.path.basename(filename)}]"
80
 
 
81
  if not filename.lower().endswith(".pdf"):
82
  return [f"[ARQUIVO_TEXTO: {os.path.basename(filename)}]"], anexo_info
83
 
 
90
  start = i + 1
91
  end = min(i + paginas_por_fragmento, total_pages)
92
 
93
+ bloco_texto = ""
94
+ for p in range(i, end):
95
+ try:
96
+ t = reader.pages[p].extract_text() or ""
97
+ except Exception as e:
98
+ t = f"\n[ERRO_EXTRACT_PAG_{p+1}: {e}]\n"
99
+ bloco_texto += f"\n=== PAGINA {p+1}/{total_pages} ===\n{t}\n"
100
+
101
  fragment = (
102
  f"=== FRAG {i//paginas_por_fragmento + 1} "
103
  f"(PÁGS {start}-{end}/{total_pages}) ===\n"
104
+ f"{bloco_texto.strip()}"
 
105
  )
106
  fragments.append(fragment)
107
 
 
112
  # ==================== 3. ENGINE DE EXECUÇÃO ====================
113
 
114
  def executar_no(timeline, config, fragmento_input=None):
 
 
 
 
 
115
  modelo = model_pro if config.get("modelo") == "pro" else model_flash
116
 
117
  if fragmento_input is not None:
 
131
  try:
132
  inicio = time.time()
133
  resp = modelo.generate_content(prompt)
134
+ out = resp.text or ""
135
  tempo = time.time() - inicio
136
 
137
  if config["tipo_saida"] == "json":
 
138
  cleaned = out.strip().replace("``````", "")
139
+ try:
140
+ content = json.loads(cleaned)
141
+ except Exception as e:
142
+ content = []
143
+ log += f" [ERRO JSON: {e}]"
144
  else:
145
  content = out
146
 
 
152
  # ==================== 4. ORQUESTRADOR ====================
153
 
154
  def orquestrador(texto, arquivo, history, json_config, confext_state):
 
 
 
 
 
 
 
 
155
  fragmentos, anexo_info = ler_anexo_e_fragmentar(arquivo)
156
 
157
  if not texto and not fragmentos:
158
  yield history, {}, "⚠️ Sem input ou erro ao ler arquivo.", confext_state
159
  return
160
 
 
161
  history = history + [[texto + (" πŸ“Ž" if arquivo else ""), None]]
162
 
163
  try:
 
170
  timeline = [{"role": "user", "content": texto}]
171
  logs = f"πŸš€ START: {datetime.now().strftime('%H:%M:%S')}\n"
172
 
 
173
  confext_upload = {
174
  "arquivo": os.path.basename(getattr(arquivo, "name", "sem_arquivo"))
175
  if arquivo else None,
176
  "meta": anexo_info,
177
+ "paginas": []
178
  }
179
 
180
  if fragmentos:
181
+ logs = log_point(f"PDF dividido em {len(fragmentos)} fragmentos.", logs)
182
  history[-1][1] = "⏳ Fragmentando + visΓ£o paginada..."
183
  yield history, timeline, logs, confext_upload
184
 
185
+ # PASSO PAGINADOR_VISUAL (se existir)
 
186
  if protocolo and fragmentos:
187
+ cfg_visao = protocolo[0]
188
+ logs = log_point(f"Usando agente de visΓ£o: {cfg_visao['nome']}", logs)
189
 
190
  for i, fragmento in enumerate(fragmentos):
191
+ history[-1][1] = f"πŸ‘οΈ {cfg_visao['nome']} frag {i+1}/{len(fragmentos)}..."
192
+ logs = log_point(f"Enviando frag {i+1}", logs)
 
193
  yield history, timeline, logs, confext_upload
194
 
195
  res, log_add, raw = executar_no(timeline, cfg_visao, fragmento_input=fragmento)
196
  logs += log_add + "\n"
197
+ logs = log_point(f"Resposta bruta frag {i+1}: {raw[:160]!r}", logs)
198
 
199
  if "error" in res:
200
+ logs = log_point(f"Erro no frag {i+1}: {res['error']}", logs)
201
  continue
202
 
 
203
  try:
204
  paginas_res = res["content"]
205
  if isinstance(paginas_res, dict):
 
207
  for p in paginas_res:
208
  confext_upload["paginas"].append(p)
209
  except Exception as e:
210
+ logs = log_point(f"Falha ao anexar pΓ‘ginas do frag {i+1}: {e}", logs)
211
 
212
+ logs = log_point("VisΓ£o paginada concluΓ­da.", logs)
213
 
 
214
  timeline.append({
215
  "role": "system",
216
  "agent": "CONFEXT_UPLOAD",
217
  "content": confext_upload
218
  })
219
 
 
 
 
220
  restante = protocolo[1:] if protocolo else []
221
+ final_response = ""
222
 
223
  for cfg in restante:
224
  history[-1][1] = f"βš™οΈ {cfg['nome']}..."
 
235
  yield history, timeline, logs, confext_upload
236
 
237
  if not restante and not texto:
238
+ history[-1][1] = "βœ… PDF processado. Pronto para perguntas usando confext_upload."
 
239
  final_response = history[-1][1]
240
 
241
+ logs = log_point("FIM.", logs)
242
  yield history, timeline, logs, confext_upload
243
 
244
+ # ==================== 5. UI ====================
245
 
246
  def ui_clean():
247
  css = """
 
255
  confext_state = gr.State(value=None)
256
 
257
  with gr.Tabs():
 
258
  with gr.Tab("πŸ’¬ Investigador"):
259
  chatbot = gr.Chatbot(
260
  label="",
 
283
  btn_send = gr.Button("Enviar", variant="primary", size="sm")
284
 
285
  file_status = gr.Markdown("", visible=True)
 
286
  file_in.upload(
287
  lambda x: f"πŸ“Ž Anexo recebido: {os.path.basename(getattr(x, 'name', x))}",
288
  inputs=file_in,
289
  outputs=file_status,
290
  )
291
 
 
292
  with gr.Tab("πŸ•΅οΈ DepuraΓ§Γ£o"):
293
  with gr.Row():
294
  out_dna = gr.JSON(label="DNA (Timeline)")
295
  out_logs = gr.Textbox(label="Logs do Sistema", lines=20)
296
  confext_view = gr.JSON(label="confext_upload")
297
 
 
298
  with gr.Tab("βš™οΈ Config"):
299
  with gr.Row():
300
  btn_save = gr.Button("Salvar Config")
 
302
  code_json = gr.Code(value=config_init, language="json", label=ARQUIVO_CONFIG)
303
  btn_save.click(salvar_protocolo, code_json, lbl_save)
304
 
 
305
  def _orq_wrapper(texto, arquivo, history, json_cfg, confext_old):
 
306
  for h, dna, logs, confext_new in orquestrador(texto, arquivo, history, json_cfg, confext_old):
307
  yield h, dna, logs, confext_new
308