caarleexx commited on
Commit
62c65cf
·
verified ·
1 Parent(s): 2d9b988

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -108
app.py CHANGED
@@ -1,6 +1,6 @@
1
  # ╔════════════════════════════════════════════════════════════════════════════╗
2
- # ║ PIPELINE v25: ORQUESTRAÇÃO COM UPLOAD DE EVIDÊNCIAS
3
- # ║ Novidade: Upload de arquivos de texto (.txt, .md, .csv) no input
4
  # ╚════════════════════════════════════════════════════════════════════════════╝
5
 
6
  import os
@@ -13,10 +13,12 @@ import google.generativeai as genai
13
 
14
  # ==================== 1. CONFIGURAÇÃO ====================
15
  api_key = os.getenv("GOOGLE_API_KEY", "SUA_API_KEY_AQUI")
16
- genai.configure(api_key=api_key)
17
 
18
- model_flash = genai.GenerativeModel("gemini-flash-latest")
19
- model_pro = genai.GenerativeModel("gemini-pro-latest")
 
 
 
20
 
21
  ARQUIVO_CONFIG = "protocolo.json"
22
 
@@ -29,27 +31,17 @@ def carregar_protocolo_padrao():
29
 
30
  def salvar_protocolo_disco(conteudo_json):
31
  try:
32
- json.loads(conteudo_json) # Valida JSON
33
  with open(ARQUIVO_CONFIG, "w", encoding="utf-8") as f: f.write(conteudo_json)
34
- return "✅ Salvo!"
35
  except Exception as e: return f"❌ Erro: {e}"
36
 
37
  def ler_arquivo_input(arquivo):
38
- """
39
- Lê o conteúdo de um arquivo de texto enviado pelo usuário.
40
- """
41
- if arquivo is None:
42
- return ""
43
-
44
  try:
45
- # Tenta ler como UTF-8
46
  with open(arquivo.name, "r", encoding="utf-8") as f:
47
- conteudo = f.read()
48
- return f"\n\n=== CONTEÚDO DO ARQUIVO ANEXADO ({os.path.basename(arquivo.name)}) ===\n{conteudo}\n=======================================\n"
49
- except UnicodeDecodeError:
50
- return "\n\n[ERRO: O arquivo anexado não é um texto válido ou tem codificação desconhecida.]"
51
- except Exception as e:
52
- return f"\n\n[ERRO AO LER ARQUIVO: {str(e)}]"
53
 
54
  # ==================== 3. ENGINE DE EXECUÇÃO ====================
55
 
@@ -63,16 +55,9 @@ def executar_no(timeline: list, config: dict):
63
  modelo_ativo = model_pro if config.get("modelo") == "pro" else model_flash
64
 
65
  contexto_str = json.dumps(timeline, ensure_ascii=False, indent=2)
66
- prompt_bruto = f"""
67
- --- TIMELINE DO CASO ---
68
- {contexto_str}
69
- ------------------------
70
- AGENTE: {config['nome']}
71
- MISSÃO: {config['missao']}
72
- """
73
 
74
- log_entry = f"\n{'='*40}\n🔶 EXECUTANDO: {config['nome']}\n{'='*40}\n"
75
- log_entry += f"📤 PROMPT:\n{prompt_bruto[:1000]}... [truncado para visualização]\n"
76
 
77
  try:
78
  inicio = time.time()
@@ -80,127 +65,157 @@ MISSÃO: {config['missao']}
80
  output_bruto = response.text
81
  tempo = time.time() - inicio
82
 
83
- log_entry += f"📥 OUTPUT ({tempo:.2f}s):\n{output_bruto}\n"
84
 
85
  if config['tipo_saida'] == 'json': conteudo = limpar_json(output_bruto)
86
  else: conteudo = output_bruto
87
 
88
- return {"role": "assistant", "agent": config['nome'], "content": conteudo}, log_entry
89
 
90
  except Exception as e:
91
- return {"role": "system", "error": str(e)}, log_entry + f"\n❌ ERRO: {str(e)}\n"
92
 
93
- # ==================== 4. ORQUESTRADOR ====================
94
 
95
- def orquestrador(texto_caso, arquivo_anexo, json_protocolo_str):
96
  """
97
- Recebe texto + arquivo, combina ambos e inicia a pipeline.
98
  """
99
- # 1. Processa o arquivo anexado
100
- conteudo_anexo = ler_arquivo_input(arquivo_anexo)
101
-
102
- # 2. Combina Inputs
103
- input_completo = f"{texto_caso}\n{conteudo_anexo}".strip()
104
 
105
- if not input_completo:
106
- yield "⚠️ Erro: Insira texto ou anexe um arquivo.", "", {}
107
  return
108
 
 
 
 
109
  try:
110
- protocolo = json.loads(json_protocolo_str)
111
- except Exception as e:
112
- yield f"⚠️ Erro no JSON de Configuração: {e}", "", {}
 
113
  return
114
 
115
- # 3. Inicializa
116
- info_anexo = "Sim" if conteudo_anexo else "Não"
117
- logs_totais = f"🚀 INICIANDO (Anexo: {info_anexo})...\n"
118
- timeline = [{"role": "user", "content": input_completo}]
119
- relatorio_final = "⏳ Aguardando..."
120
 
121
- yield logs_totais, relatorio_final, timeline
 
 
122
 
123
- # 4. Loop de Agentes
124
- for config_agente in protocolo:
125
- resultado, log_no = executar_no(timeline, config_agente)
 
 
 
 
 
 
 
 
126
  timeline.append(resultado)
127
- logs_totais += log_no
128
 
129
- if config_agente['tipo_saida'] == 'texto':
130
- relatorio_final = resultado['content']
 
 
131
  else:
132
- relatorio_final = f"⏳ {config_agente['nome']} trabalhando..."
 
133
 
134
- yield logs_totais, relatorio_final, timeline
135
 
136
- logs_totais += "\n🏁 FINALIZADO."
137
- yield logs_totais, relatorio_final, timeline
 
138
 
139
- # ==================== 5. INTERFACE ====================
140
 
141
- def construir_interface():
142
  config_inicial = carregar_protocolo_padrao()
143
 
144
- with gr.Blocks(title="Pipeline v25 - Com Upload", theme=gr.themes.Base()) as app:
145
- gr.Markdown("# 🕵️‍♂️ Pipeline Forense v25: Input Multimodal (Texto + Arquivo)")
146
 
147
  with gr.Tabs():
148
-
149
- # === ABA EXECUÇÃO ===
150
- with gr.TabItem("🚀 Execução"):
 
 
 
 
 
 
 
 
 
151
  with gr.Row():
152
- with gr.Column(scale=1):
153
- inp_caso = gr.Textbox(
154
- label="Instruções / Resumo do Caso",
155
- lines=5,
156
- placeholder="Digite instruções adicionais aqui..."
157
- )
158
- # NOVO COMPONENTE DE UPLOAD
159
- inp_arquivo = gr.File(
160
- label="Anexar Evidências (Texto/Logs/Transcrições)",
161
- file_types=[".txt", ".md", ".csv", ".json"],
162
- file_count="single"
163
  )
164
- btn_executar = gr.Button("⚡ EXECUTAR ANÁLISE COMPLETA", variant="primary", size="lg")
165
-
166
- with gr.Column(scale=1):
167
- out_logs = gr.Textbox(
168
- label="📟 Console de Logs (Raw I/O)",
169
- lines=15,
170
- interactive=False,
171
- elem_id="logs"
172
  )
 
 
 
 
 
 
173
 
174
- gr.Markdown("---")
175
-
176
- with gr.Row():
177
- out_relatorio = gr.Markdown(label="📄 Parecer Final")
178
- out_timeline = gr.JSON(label="🧠 Memória JSON")
179
 
180
- # === ABA CONFIGURAÇÃO ===
181
- with gr.TabItem("⚙️ Configuração (JSON)"):
182
  with gr.Row():
183
- btn_save_config = gr.Button("💾 Salvar Protocolo")
184
- lbl_config = gr.Label()
185
 
186
- editor_json = gr.Code(
187
- label="protocolo.json",
188
- language="json",
189
  value=config_inicial,
190
- lines=20
 
 
191
  )
192
 
193
- btn_save_config.click(salvar_protocolo_disco, editor_json, lbl_config)
194
 
195
- # EVENTO DE EXECUÇÃO
196
- btn_executar.click(
197
- orquestrador,
198
- inputs=[inp_caso, inp_arquivo, editor_json], # Passa Texto + Arquivo + Config
199
- outputs=[out_logs, out_relatorio, out_timeline]
 
 
200
  )
201
 
 
 
 
 
 
 
 
 
 
202
  return app
203
 
204
  if __name__ == "__main__":
205
- print("Iniciando v25...")
206
- construir_interface().launch()
 
1
  # ╔════════════════════════════════════════════════════════════════════════════╗
2
+ # ║ PIPELINE v26: INTERFACE CHAT MODERNIZADA
3
+ # ║ Layout: Chatbot -> Inputs -> DNA (JSON) -> Logs Brutos
4
  # ╚════════════════════════════════════════════════════════════════════════════╝
5
 
6
  import os
 
13
 
14
  # ==================== 1. CONFIGURAÇÃO ====================
15
  api_key = os.getenv("GOOGLE_API_KEY", "SUA_API_KEY_AQUI")
 
16
 
17
+ if api_key:
18
+ genai.configure(api_key=api_key)
19
+
20
+ model_flash = genai.GenerativeModel("gemini-1.5-flash-latest")
21
+ model_pro = genai.GenerativeModel("gemini-1.5-pro-latest")
22
 
23
  ARQUIVO_CONFIG = "protocolo.json"
24
 
 
31
 
32
  def salvar_protocolo_disco(conteudo_json):
33
  try:
34
+ json.loads(conteudo_json)
35
  with open(ARQUIVO_CONFIG, "w", encoding="utf-8") as f: f.write(conteudo_json)
36
+ return "✅ Protocolo Salvo!"
37
  except Exception as e: return f"❌ Erro: {e}"
38
 
39
  def ler_arquivo_input(arquivo):
40
+ if arquivo is None: return ""
 
 
 
 
 
41
  try:
 
42
  with open(arquivo.name, "r", encoding="utf-8") as f:
43
+ return f"\n\n=== ANEXO: {os.path.basename(arquivo.name)} ===\n{f.read()}\n=================\n"
44
+ except: return "\n[Erro ao ler arquivo]"
 
 
 
 
45
 
46
  # ==================== 3. ENGINE DE EXECUÇÃO ====================
47
 
 
55
  modelo_ativo = model_pro if config.get("modelo") == "pro" else model_flash
56
 
57
  contexto_str = json.dumps(timeline, ensure_ascii=False, indent=2)
58
+ prompt_bruto = f"--- TIMELINE ---\n{contexto_str}\n----------------\nAGENTE: {config['nome']}\nMISSÃO: {config['missao']}"
 
 
 
 
 
 
59
 
60
+ log_entry = f"\n🔹 {config['nome']}:\n"
 
61
 
62
  try:
63
  inicio = time.time()
 
65
  output_bruto = response.text
66
  tempo = time.time() - inicio
67
 
68
+ log_entry += f"⏱️ {tempo:.2f}s | INPUT_LEN: {len(prompt_bruto)} | OUTPUT_LEN: {len(output_bruto)}\n"
69
 
70
  if config['tipo_saida'] == 'json': conteudo = limpar_json(output_bruto)
71
  else: conteudo = output_bruto
72
 
73
+ return {"role": "assistant", "agent": config['nome'], "content": conteudo}, log_entry, output_bruto
74
 
75
  except Exception as e:
76
+ return {"role": "system", "error": str(e)}, f"\n❌ ERRO: {str(e)}\n", str(e)
77
 
78
+ # ==================== 4. ORQUESTRADOR (ADAPTADO PARA CHAT) ====================
79
 
80
+ def orquestrador_chat(msg_texto, msg_arquivo, history, json_protocolo):
81
  """
82
+ Gerador que atualiza o Chatbot, o DNA e os Logs passo a passo.
83
  """
84
+ # 1. Preparação
85
+ anexo_str = ler_arquivo_input(msg_arquivo)
86
+ input_total = f"{msg_texto}\n{anexo_str}".strip()
 
 
87
 
88
+ if not input_total:
89
+ yield history, {}, "Por favor, insira texto ou arquivo."
90
  return
91
 
92
+ # Adiciona mensagem do usuário no Chat
93
+ history = history + [[msg_texto + (" [Arquivo Anexado]" if msg_arquivo else ""), None]]
94
+
95
  try:
96
+ protocolo = json.loads(json_protocolo)
97
+ except:
98
+ history[-1][1] = " Erro no JSON de configuração."
99
+ yield history, {}, "Erro JSON"
100
  return
101
 
102
+ # 2. Inicialização
103
+ timeline = [{"role": "user", "content": input_total}]
104
+ logs_brutos = f"🚀 INÍCIO: {datetime.now().strftime('%H:%M:%S')}\n"
 
 
105
 
106
+ # Mostra status inicial no chat
107
+ history[-1][1] = "⏳ Iniciando orquestração..."
108
+ yield history, timeline, logs_brutos
109
 
110
+ # 3. Loop de Agentes
111
+ relatorio_acumulado = ""
112
+
113
+ for config in protocolo:
114
+ # Atualiza status no chat
115
+ history[-1][1] = f"⚙️ {config['nome']} está pensando..."
116
+ yield history, timeline, logs_brutos
117
+
118
+ # Executa
119
+ resultado, log_meta, raw_out = executar_no(timeline, config)
120
+
121
  timeline.append(resultado)
122
+ logs_totais = logs_brutos + log_meta + f"OUTPUT RAW:\n{raw_out[:200]}...\n" # Log resumido
123
 
124
+ # Se for o passo final (Texto), exibe no chat. Se não, mantém loading.
125
+ if config['tipo_saida'] == 'texto':
126
+ relatorio_acumulado = resultado['content']
127
+ history[-1][1] = relatorio_acumulado
128
  else:
129
+ # Mostra progresso no DNA
130
+ pass
131
 
132
+ yield history, timeline, logs_totais
133
 
134
+ # Finalização
135
+ logs_totais += "\n✅ FIM."
136
+ yield history, timeline, logs_totais
137
 
138
+ # ==================== 5. INTERFACE UI (V26) ====================
139
 
140
+ def ui_v26():
141
  config_inicial = carregar_protocolo_padrao()
142
 
143
+ with gr.Blocks(title="Pipeline v26 - Chat", theme=gr.themes.Soft()) as app:
 
144
 
145
  with gr.Tabs():
146
+ # === ABA 1: CHATBOT (PRINCIPAL) ===
147
+ with gr.TabItem("💬 Investigador Chat"):
148
+
149
+ # 1. O Chatbot (Topo)
150
+ chatbot = gr.Chatbot(
151
+ label="Diálogo Forense",
152
+ height=550,
153
+ show_copy_button=True,
154
+ avatar_images=(None, "⚖️") # Opcional: ícones
155
+ )
156
+
157
+ # 2. Área de Input (Meio)
158
  with gr.Row():
159
+ with gr.Column(scale=8):
160
+ txt_input = gr.Textbox(
161
+ show_label=False,
162
+ placeholder="Digite o caso aqui ou anexe um arquivo...",
163
+ lines=2,
164
+ container=False
 
 
 
 
 
165
  )
166
+ with gr.Column(scale=1, min_width=50):
167
+ file_btn = gr.File(
168
+ label="📎",
169
+ file_count="single",
170
+ type="filepath",
171
+ scale=1,
172
+ min_width=50
 
173
  )
174
+ with gr.Column(scale=1, min_width=80):
175
+ send_btn = gr.Button("Enviar", variant="primary", scale=1, min_width=80)
176
+
177
+ # 3. O DNA (Abaixo)
178
+ gr.Markdown("### 🧬 DNA da Análise (Timeline JSON)")
179
+ out_dna = gr.JSON(label="Estrutura de Raciocínio")
180
 
181
+ # 4. Logs (Acordeão para não poluir)
182
+ with gr.Accordion("🛠️ Logs Brutos do Sistema (Debug)", open=False):
183
+ out_logs = gr.Textbox(label="Terminal Output", lines=10)
 
 
184
 
185
+ # === ABA 2: CONFIGURAÇÃO (JSON) ===
186
+ with gr.TabItem("⚙️ Configurar Protocolo"):
187
  with gr.Row():
188
+ save_btn = gr.Button("💾 Salvar Alterações")
189
+ status_lbl = gr.Label(show_label=False)
190
 
191
+ json_editor = gr.Code(
 
 
192
  value=config_inicial,
193
+ language="json",
194
+ label="protocolo.json",
195
+ lines=25
196
  )
197
 
198
+ save_btn.click(salvar_protocolo_disco, json_editor, status_lbl)
199
 
200
+ # === CONEXÕES ===
201
+
202
+ # Enviar via Botão
203
+ send_btn.click(
204
+ orquestrador_chat,
205
+ inputs=[txt_input, file_btn, chatbot, json_editor],
206
+ outputs=[chatbot, out_dna, out_logs]
207
  )
208
 
209
+ # Enviar via Enter
210
+ txt_input.submit(
211
+ orquestrador_chat,
212
+ inputs=[txt_input, file_btn, chatbot, json_editor],
213
+ outputs=[chatbot, out_dna, out_logs]
214
+ )
215
+
216
+ # Limpar input após envio (opcional, requer função extra, mantendo simples por agora)
217
+
218
  return app
219
 
220
  if __name__ == "__main__":
221
+ ui_v26().launch()