rwayz commited on
Commit
2afa395
·
verified ·
1 Parent(s): 1674c1d

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -452
app.py DELETED
@@ -1,452 +0,0 @@
1
- """
2
- AgentGraph - Aplicação principal com interface Gradio e LangGraph
3
- """
4
- import asyncio
5
- import logging
6
- import gradio as gr
7
- import tempfile
8
- import os
9
- from typing import List, Tuple, Optional, Dict
10
- from PIL import Image
11
-
12
- from graphs.main_graph import initialize_graph, get_graph_manager
13
- from utils.config import (
14
- AVAILABLE_MODELS,
15
- DEFAULT_MODEL,
16
- GRADIO_SHARE,
17
- GRADIO_PORT,
18
- validate_config,
19
- is_langsmith_enabled,
20
- LANGSMITH_PROJECT
21
- )
22
- from utils.object_manager import get_object_manager
23
-
24
- # Configuração de logging
25
- logging.basicConfig(
26
- level=logging.INFO,
27
- format='%(asctime)s - %(levelname)s - %(message)s'
28
- )
29
-
30
- # Variáveis globais
31
- graph_manager = None
32
- show_history_flag = False
33
-
34
- async def initialize_app():
35
- """Inicializa a aplicação"""
36
- global graph_manager
37
-
38
- try:
39
- # Valida configurações
40
- validate_config()
41
-
42
- # Inicializa o grafo
43
- graph_manager = await initialize_graph()
44
-
45
- # Informa sobre o status do LangSmith
46
- if is_langsmith_enabled():
47
- logging.info(f"✅ LangSmith habilitado - Projeto: '{LANGSMITH_PROJECT}'")
48
- logging.info("🔍 Traces serão enviados para LangSmith automaticamente")
49
- else:
50
- logging.info("ℹ️ LangSmith não configurado - Executando sem observabilidade")
51
-
52
- logging.info("Aplicação inicializada com sucesso")
53
- return True
54
-
55
- except Exception as e:
56
- logging.error(f"Erro ao inicializar aplicação: {e}")
57
- return False
58
-
59
- def run_async(coro):
60
- """Executa corrotina de forma síncrona"""
61
- try:
62
- loop = asyncio.get_event_loop()
63
- except RuntimeError:
64
- loop = asyncio.new_event_loop()
65
- asyncio.set_event_loop(loop)
66
-
67
- return loop.run_until_complete(coro)
68
-
69
- def chatbot_response(user_input: str, selected_model: str, advanced_mode: bool = False) -> Tuple[str, Optional[str]]:
70
- """
71
- Processa resposta do chatbot usando LangGraph
72
-
73
- Args:
74
- user_input: Entrada do usuário
75
- selected_model: Modelo LLM selecionado
76
- advanced_mode: Se deve usar refinamento avançado
77
-
78
- Returns:
79
- Tupla com (resposta_texto, caminho_imagem_grafico)
80
- """
81
- global graph_manager
82
-
83
- if not graph_manager:
84
- return "❌ Sistema não inicializado. Tente recarregar a página.", None
85
-
86
- try:
87
- # Processa query através do LangGraph
88
- result = run_async(graph_manager.process_query(
89
- user_input=user_input,
90
- selected_model=selected_model,
91
- advanced_mode=advanced_mode
92
- ))
93
-
94
- response_text = result.get("response", "Erro ao processar resposta")
95
- graph_image_path = None
96
-
97
- # Verifica se foi gerado um gráfico
98
- if result.get("graph_generated", False) and result.get("graph_image_id"):
99
- graph_image_path = save_graph_image_to_temp(result["graph_image_id"])
100
-
101
- # Adiciona informação sobre o gráfico na resposta
102
- if graph_image_path:
103
- graph_type = result.get("graph_type", "gráfico")
104
- response_text += f"\n\n📊 **Gráfico gerado**: {graph_type.replace('_', ' ').title()}"
105
-
106
- return response_text, graph_image_path
107
-
108
- except Exception as e:
109
- error_msg = f"Erro no chatbot: {e}"
110
- logging.error(error_msg)
111
- logging.error(f"Detalhes do erro: {type(e).__name__}: {str(e)}")
112
- return error_msg, None
113
-
114
- def save_graph_image_to_temp(graph_image_id: str) -> Optional[str]:
115
- """
116
- Salva imagem do gráfico em arquivo temporário para exibição no Gradio
117
-
118
- Args:
119
- graph_image_id: ID da imagem no ObjectManager
120
-
121
- Returns:
122
- Caminho do arquivo temporário ou None se falhar
123
- """
124
- try:
125
- obj_manager = get_object_manager()
126
- graph_image = obj_manager.get_object(graph_image_id)
127
-
128
- if graph_image and isinstance(graph_image, Image.Image):
129
- # Cria arquivo temporário
130
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
131
- graph_image.save(temp_file.name, format='PNG')
132
- temp_file.close()
133
-
134
- logging.info(f"[GRADIO] Gráfico salvo em: {temp_file.name}")
135
- return temp_file.name
136
-
137
- except Exception as e:
138
- logging.error(f"[GRADIO] Erro ao salvar gráfico: {e}")
139
-
140
- return None
141
-
142
- def handle_csv_upload(file) -> str:
143
- """
144
- Processa upload de arquivo CSV
145
-
146
- Args:
147
- file: Arquivo enviado pelo Gradio
148
-
149
- Returns:
150
- Mensagem de feedback
151
- """
152
- global graph_manager
153
-
154
- if not graph_manager:
155
- return "❌ Sistema não inicializado."
156
-
157
- if not file:
158
- return "❌ Nenhum arquivo selecionado."
159
-
160
- try:
161
- # Log detalhado do arquivo recebido
162
- logging.info(f"[UPLOAD] Arquivo recebido: {file}")
163
- logging.info(f"[UPLOAD] Nome do arquivo: {file.name}")
164
- logging.info(f"[UPLOAD] Tipo do arquivo: {type(file)}")
165
-
166
- # Verifica se o arquivo existe
167
- import os
168
- if not os.path.exists(file.name):
169
- return f"❌ Arquivo não encontrado: {file.name}"
170
-
171
- # Verifica se é um arquivo CSV
172
- if not file.name.lower().endswith('.csv'):
173
- return "❌ Por favor, selecione um arquivo CSV válido."
174
-
175
- # Verifica o tamanho do arquivo
176
- file_size = os.path.getsize(file.name)
177
- file_size_mb = file_size / (1024 * 1024)
178
- file_size_gb = file_size / (1024 * 1024 * 1024)
179
-
180
- if file_size_gb >= 1:
181
- size_str = f"{file_size_gb:.2f} GB"
182
- else:
183
- size_str = f"{file_size_mb:.2f} MB"
184
-
185
- logging.info(f"[UPLOAD] Tamanho do arquivo: {file_size} bytes ({size_str})")
186
-
187
- if file_size == 0:
188
- return "❌ O arquivo está vazio."
189
-
190
- if file_size > 5 * 1024 * 1024 * 1024: # 5GB
191
- return "❌ Arquivo muito grande. Máximo permitido: 5GB."
192
-
193
- # Aviso para arquivos grandes
194
- if file_size_mb > 100:
195
- logging.info(f"[UPLOAD] Arquivo grande detectado ({size_str}). Processamento pode demorar...")
196
- return f"⏳ Processando arquivo grande ({size_str}). Aguarde..."
197
-
198
- # Processa upload através do LangGraph
199
- logging.info(f"[UPLOAD] Iniciando processamento do arquivo: {file.name}")
200
- result = run_async(graph_manager.handle_csv_upload(file.name))
201
-
202
- logging.info(f"[UPLOAD] Resultado do processamento: {result}")
203
- return result.get("message", "Erro no upload")
204
-
205
- except Exception as e:
206
- error_msg = f"❌ Erro ao processar upload: {e}"
207
- logging.error(error_msg)
208
- logging.error(f"[UPLOAD] Detalhes do erro: {type(e).__name__}: {str(e)}")
209
- import traceback
210
- logging.error(f"[UPLOAD] Traceback: {traceback.format_exc()}")
211
- return error_msg
212
-
213
- def reset_system() -> str:
214
- """
215
- Reseta o sistema ao estado inicial
216
-
217
- Returns:
218
- Mensagem de feedback
219
- """
220
- global graph_manager
221
-
222
- if not graph_manager:
223
- return "❌ Sistema não inicializado."
224
-
225
- try:
226
- # Reseta sistema através do LangGraph
227
- result = run_async(graph_manager.reset_system())
228
-
229
- return result.get("message", "Erro no reset")
230
-
231
- except Exception as e:
232
- error_msg = f"❌ Erro ao resetar sistema: {e}"
233
- logging.error(error_msg)
234
- return error_msg
235
-
236
- def toggle_advanced_mode(enabled: bool) -> str:
237
- """
238
- Alterna modo avançado
239
-
240
- Args:
241
- enabled: Se deve habilitar modo avançado
242
-
243
- Returns:
244
- Mensagem de status
245
- """
246
- global graph_manager
247
-
248
- if not graph_manager:
249
- return "❌ Sistema não inicializado."
250
-
251
- return graph_manager.toggle_advanced_mode(enabled)
252
-
253
- def toggle_history():
254
- """Alterna exibição do histórico"""
255
- global show_history_flag, graph_manager
256
-
257
- show_history_flag = not show_history_flag
258
-
259
- if show_history_flag and graph_manager:
260
- return graph_manager.get_history()
261
- else:
262
- return {}
263
-
264
- def respond(message: str, chat_history: List[Dict[str, str]], selected_model: str, advanced_mode: bool):
265
- """
266
- Função de resposta para o chatbot Gradio
267
-
268
- Args:
269
- message: Mensagem do usuário
270
- chat_history: Histórico do chat (formato messages)
271
- selected_model: Modelo selecionado
272
- advanced_mode: Modo avançado habilitado
273
-
274
- Returns:
275
- Tupla com (mensagem_vazia, histórico_atualizado, imagem_grafico)
276
- """
277
- if not message.strip():
278
- return "", chat_history, None
279
-
280
- # Processa resposta
281
- response, graph_image_path = chatbot_response(message, selected_model, advanced_mode)
282
-
283
- # Atualiza histórico no formato messages
284
- chat_history.append({"role": "user", "content": message})
285
- chat_history.append({"role": "assistant", "content": response})
286
-
287
- return "", chat_history, graph_image_path
288
-
289
- def handle_csv_and_clear_chat(file):
290
- """
291
- Processa CSV e limpa chat
292
-
293
- Args:
294
- file: Arquivo CSV
295
-
296
- Returns:
297
- Tupla com (feedback, chat_limpo, grafico_limpo)
298
- """
299
- feedback = handle_csv_upload(file)
300
- return feedback, [], gr.update(visible=False)
301
-
302
- def reset_all():
303
- """
304
- Reseta tudo e limpa interface
305
-
306
- Returns:
307
- Tupla com (feedback, chat_limpo, arquivo_limpo, grafico_limpo)
308
- """
309
- feedback = reset_system()
310
- return feedback, [], None, gr.update(visible=False)
311
-
312
- # Interface Gradio
313
- def create_interface():
314
- """Cria interface Gradio"""
315
-
316
- # CSS customizado para pequeno espaçamento lateral
317
- custom_css = """
318
- .gradio-container {
319
- padding: 20px 30px !important;
320
- }
321
- """
322
-
323
- with gr.Blocks(theme=gr.themes.Soft(), css=custom_css) as demo:
324
-
325
- with gr.Row():
326
- with gr.Column(scale=1):
327
- gr.Markdown("## Configurações")
328
- model_selector = gr.Dropdown(list(AVAILABLE_MODELS.keys()), value=DEFAULT_MODEL, label="")
329
- csv_file = gr.File(file_types=[".csv"], label="")
330
- upload_feedback = gr.Markdown()
331
- advanced_checkbox = gr.Checkbox(label="Refinar Resposta")
332
-
333
- # Status do LangSmith
334
- if is_langsmith_enabled():
335
- gr.Markdown(f"🔍 **LangSmith**: Ativo")
336
- else:
337
- gr.Markdown("🔍 **LangSmith**: Desabilitado")
338
-
339
- reset_btn = gr.Button("Resetar")
340
-
341
- with gr.Column(scale=4):
342
- gr.Markdown("## Agent86")
343
- chatbot = gr.Chatbot(
344
- height=600,
345
- show_label=False,
346
- container=True,
347
- type="messages"
348
- )
349
-
350
- msg = gr.Textbox(placeholder="Digite sua pergunta aqui...", lines=1, label="")
351
- btn = gr.Button("Enviar", variant="primary")
352
- history_btn = gr.Button("Histórico", variant="secondary")
353
- history_output = gr.JSON()
354
-
355
- # Componente para exibir gráficos - posicionado após histórico
356
- graph_image = gr.Image(
357
- label="📊 Visualização de Dados",
358
- visible=False,
359
- height=500, # Altura maior para ocupar mais espaço
360
- show_label=True,
361
- container=True,
362
- interactive=False,
363
- show_download_button=True
364
- )
365
-
366
- download_file = gr.File(visible=False)
367
-
368
- # Event handlers (usando as funções originais do sistema)
369
- def handle_response_with_graph(message, chat_history, model, advanced):
370
- """Wrapper para lidar com resposta e gráfico"""
371
- empty_msg, updated_history, graph_path = respond(message, chat_history, model, advanced)
372
-
373
- # Controla visibilidade do componente de gráfico
374
- if graph_path:
375
- return empty_msg, updated_history, gr.update(value=graph_path, visible=True)
376
- else:
377
- return empty_msg, updated_history, gr.update(visible=False)
378
-
379
- msg.submit(
380
- handle_response_with_graph,
381
- inputs=[msg, chatbot, model_selector, advanced_checkbox],
382
- outputs=[msg, chatbot, graph_image]
383
- )
384
-
385
- btn.click(
386
- handle_response_with_graph,
387
- inputs=[msg, chatbot, model_selector, advanced_checkbox],
388
- outputs=[msg, chatbot, graph_image]
389
- )
390
-
391
- csv_file.change(
392
- handle_csv_and_clear_chat,
393
- inputs=csv_file,
394
- outputs=[upload_feedback, chatbot, graph_image]
395
- )
396
-
397
- reset_btn.click(
398
- reset_all,
399
- outputs=[upload_feedback, chatbot, csv_file, graph_image]
400
- )
401
-
402
- advanced_checkbox.change(
403
- toggle_advanced_mode,
404
- inputs=advanced_checkbox,
405
- outputs=[]
406
- )
407
-
408
- history_btn.click(
409
- toggle_history,
410
- outputs=history_output
411
- )
412
-
413
- return demo
414
-
415
- async def main():
416
- """Função principal"""
417
- # Inicializa aplicação
418
- success = await initialize_app()
419
-
420
- if not success:
421
- logging.error("Falha na inicialização. Encerrando aplicação.")
422
- return
423
-
424
- # Cria e lança interface
425
- demo = create_interface()
426
-
427
- # Tenta diferentes portas se a padrão estiver ocupada
428
- ports_to_try = [GRADIO_PORT, 7861, 7862, 7863, 7864, 0] # 0 = porta automática
429
-
430
- for port in ports_to_try:
431
- try:
432
- logging.info(f"Tentando iniciar interface Gradio na porta {port}")
433
- demo.launch(
434
- share=GRADIO_SHARE,
435
- server_port=port if port != 0 else None,
436
- show_error=True,
437
- quiet=False
438
- )
439
- break # Se chegou aqui, deu certo
440
- except OSError as e:
441
- if "Cannot find empty port" in str(e) and port != ports_to_try[-1]:
442
- logging.warning(f"Porta {port} ocupada, tentando próxima...")
443
- continue
444
- else:
445
- logging.error(f"Erro ao iniciar servidor: {e}")
446
- raise
447
- except Exception as e:
448
- logging.error(f"Erro inesperado ao iniciar interface: {e}")
449
- raise
450
-
451
- if __name__ == "__main__":
452
- run_async(main())