rwayz commited on
Commit
13847c9
·
1 Parent(s): ba9dc0b

Delete graphs

Browse files
Files changed (1) hide show
  1. graphs/main_graph.py +0 -490
graphs/main_graph.py DELETED
@@ -1,490 +0,0 @@
1
- """
2
- Grafo principal do LangGraph para o AgentGraph
3
- """
4
- import logging
5
- from typing import Dict, Any, Optional
6
- from langgraph.graph import StateGraph, END
7
- from langgraph.checkpoint.memory import MemorySaver
8
-
9
- from nodes.agent_node import AgentState, should_refine_response, should_generate_graph
10
- from nodes.csv_processing_node import csv_processing_node
11
- from nodes.database_node import (
12
- create_database_from_dataframe_node,
13
- load_existing_database_node,
14
- get_database_sample_node
15
- )
16
- from nodes.query_node import (
17
- validate_query_input_node,
18
- prepare_query_context_node,
19
- process_user_query_node
20
- )
21
- from nodes.refinement_node import (
22
- refine_response_node,
23
- format_final_response_node
24
- )
25
- from nodes.cache_node import (
26
- check_cache_node,
27
- cache_response_node,
28
- update_history_node
29
- )
30
- from nodes.graph_selection_node import graph_selection_node
31
- from nodes.graph_generation_node import graph_generation_node
32
- from nodes.custom_nodes import CustomNodeManager
33
- from agents.sql_agent import SQLAgentManager
34
- from agents.tools import CacheManager
35
- from utils.database import create_sql_database
36
- from utils.config import get_active_csv_path, SQL_DB_PATH
37
- from utils.object_manager import get_object_manager
38
-
39
- class AgentGraphManager:
40
- """
41
- Gerenciador principal do grafo LangGraph
42
- """
43
-
44
- def __init__(self):
45
- self.graph = None
46
- self.app = None
47
- self.cache_manager = CacheManager()
48
- self.custom_node_manager = CustomNodeManager()
49
- self.object_manager = get_object_manager()
50
- self.engine = None
51
- self.sql_agent = None
52
- self.db = None
53
- # IDs para objetos não-serializáveis
54
- self.agent_id = None
55
- self.engine_id = None
56
- self.db_id = None
57
- self.cache_id = None
58
- self._initialize_system()
59
- self._build_graph()
60
-
61
- def _initialize_system(self):
62
- """Inicializa o sistema com banco e agente padrão"""
63
- try:
64
- # Para inicialização síncrona, vamos usar load_existing_database_node de forma síncrona
65
- # ou criar uma versão síncrona temporária
66
- import os
67
- from sqlalchemy import create_engine
68
-
69
- # Verifica se banco existe
70
- if os.path.exists(SQL_DB_PATH):
71
- # Carrega banco existente
72
- self.engine = create_engine(f"sqlite:///{SQL_DB_PATH}")
73
- db = create_sql_database(self.engine)
74
- logging.info("Banco existente carregado")
75
- else:
76
- # Cria novo banco usando função síncrona temporária
77
- csv_path = get_active_csv_path()
78
- self.engine = self._create_engine_sync(csv_path)
79
- db = create_sql_database(self.engine)
80
- logging.info("Novo banco criado")
81
-
82
- # Armazena banco de dados
83
- self.db = db
84
- self.db_id = self.object_manager.store_database(db)
85
-
86
- # Cria agente SQL
87
- self.sql_agent = SQLAgentManager(db)
88
-
89
- # Armazena objetos no gerenciador
90
- self.agent_id = self.object_manager.store_sql_agent(self.sql_agent, self.db_id)
91
- self.engine_id = self.object_manager.store_engine(self.engine)
92
- self.cache_id = self.object_manager.store_cache_manager(self.cache_manager)
93
-
94
- logging.info("Sistema inicializado com sucesso")
95
-
96
- except Exception as e:
97
- logging.error(f"Erro ao inicializar sistema: {e}")
98
- raise
99
-
100
- def _create_engine_sync(self, csv_path: str):
101
- """Cria engine de forma síncrona para inicialização"""
102
- import pandas as pd
103
- from sqlalchemy import create_engine
104
- from sqlalchemy.types import DateTime, Integer, Float
105
-
106
- # Lê CSV
107
- df = pd.read_csv(csv_path, sep=';')
108
-
109
- # Processamento básico de tipos
110
- sql_types = {}
111
- for col in df.columns:
112
- if df[col].dtype == 'object':
113
- # Tenta converter para datetime
114
- try:
115
- pd.to_datetime(df[col], errors='raise')
116
- df[col] = pd.to_datetime(df[col])
117
- sql_types[col] = DateTime
118
- except:
119
- # Mantém como texto
120
- pass
121
- elif df[col].dtype in ['int64', 'int32']:
122
- sql_types[col] = Integer
123
- elif df[col].dtype in ['float64', 'float32']:
124
- sql_types[col] = Float
125
-
126
- # Cria engine e salva dados
127
- engine = create_engine(f"sqlite:///{SQL_DB_PATH}")
128
- df.to_sql("tabela", engine, index=False, if_exists="replace", dtype=sql_types)
129
-
130
- logging.info(f"Banco criado com {len(df)} registros")
131
- return engine
132
-
133
- def _build_graph(self):
134
- """Constrói o grafo LangGraph com nova arquitetura"""
135
- try:
136
- # Cria o StateGraph
137
- workflow = StateGraph(AgentState)
138
-
139
- # Adiciona nós de validação e preparação
140
- workflow.add_node("validate_input", validate_query_input_node)
141
- workflow.add_node("check_cache", check_cache_node)
142
- workflow.add_node("prepare_context", prepare_query_context_node)
143
- workflow.add_node("get_db_sample", get_database_sample_node)
144
-
145
- # Adiciona nós de processamento
146
- workflow.add_node("process_query", process_user_query_node)
147
-
148
- # Adiciona nós de gráficos
149
- workflow.add_node("graph_selection", graph_selection_node)
150
- workflow.add_node("graph_generation", graph_generation_node)
151
-
152
- # Adiciona nós de refinamento
153
- workflow.add_node("refine_response", refine_response_node)
154
- workflow.add_node("format_response", format_final_response_node)
155
-
156
- # Adiciona nós de cache e histórico
157
- workflow.add_node("cache_response", cache_response_node)
158
- workflow.add_node("update_history", update_history_node)
159
-
160
- # Define ponto de entrada
161
- workflow.set_entry_point("validate_input")
162
-
163
- # Fluxo principal
164
- workflow.add_edge("validate_input", "check_cache")
165
-
166
- # Condicional para cache hit
167
- workflow.add_conditional_edges(
168
- "check_cache",
169
- lambda state: "update_history" if state.get("cache_hit") else "prepare_context"
170
- )
171
-
172
- workflow.add_edge("prepare_context", "get_db_sample")
173
- workflow.add_edge("get_db_sample", "process_query")
174
-
175
- # Condicional para gráficos (após AgentSQL)
176
- workflow.add_conditional_edges(
177
- "process_query",
178
- should_generate_graph,
179
- {
180
- "graph_selection": "graph_selection",
181
- "refine_response": "refine_response",
182
- "cache_response": "cache_response"
183
- }
184
- )
185
-
186
- # Fluxo dos gráficos
187
- workflow.add_edge("graph_selection", "graph_generation")
188
-
189
- # Após geração de gráfico, vai para refinamento ou cache
190
- workflow.add_conditional_edges(
191
- "graph_generation",
192
- should_refine_response,
193
- {
194
- "refine_response": "refine_response",
195
- "cache_response": "cache_response"
196
- }
197
- )
198
-
199
- workflow.add_edge("refine_response", "format_response")
200
- workflow.add_edge("format_response", "cache_response")
201
- workflow.add_edge("cache_response", "update_history")
202
- workflow.add_edge("update_history", END)
203
-
204
- # Compila o grafo
205
- memory = MemorySaver()
206
- self.app = workflow.compile(checkpointer=memory)
207
-
208
- logging.info("Grafo LangGraph construído com sucesso")
209
-
210
- except Exception as e:
211
- logging.error(f"Erro ao construir grafo: {e}")
212
- raise
213
-
214
- async def process_query(
215
- self,
216
- user_input: str,
217
- selected_model: str = "GPT-4o-mini",
218
- advanced_mode: bool = False,
219
- thread_id: str = "default"
220
- ) -> Dict[str, Any]:
221
- """
222
- Processa uma query do usuário através do grafo
223
-
224
- Args:
225
- user_input: Entrada do usuário
226
- selected_model: Modelo LLM selecionado
227
- advanced_mode: Se deve usar refinamento avançado
228
- thread_id: ID da thread para checkpoint
229
-
230
- Returns:
231
- Resultado do processamento
232
- """
233
- try:
234
- # Verifica se precisa recriar agente SQL com modelo diferente
235
- current_sql_agent = self.object_manager.get_sql_agent(self.agent_id)
236
- if current_sql_agent and current_sql_agent.model_name != selected_model:
237
- logging.info(f"Recriando agente SQL com modelo {selected_model}")
238
-
239
- # Recupera banco de dados associado ao agente
240
- db_id = self.object_manager.get_db_id_for_agent(self.agent_id)
241
- if db_id:
242
- db = self.object_manager.get_database(db_id)
243
- if db:
244
- new_sql_agent = SQLAgentManager(db, selected_model)
245
- self.agent_id = self.object_manager.store_sql_agent(new_sql_agent, db_id)
246
- logging.info(f"Agente SQL recriado com sucesso para modelo {selected_model}")
247
- else:
248
- logging.error("Banco de dados não encontrado para recriar agente")
249
- else:
250
- logging.error("ID do banco de dados não encontrado para o agente")
251
-
252
- # Prepara estado inicial com IDs serializáveis
253
- initial_state = {
254
- "user_input": user_input,
255
- "selected_model": selected_model,
256
- "response": "",
257
- "advanced_mode": advanced_mode,
258
- "execution_time": 0.0,
259
- "error": None,
260
- "intermediate_steps": [],
261
- "db_sample_dict": {},
262
- # IDs para recuperar objetos não-serializáveis
263
- "agent_id": self.agent_id,
264
- "engine_id": self.engine_id,
265
- "db_id": self.db_id,
266
- "cache_id": self.cache_id,
267
- # Campos relacionados a gráficos
268
- "query_type": "sql_query", # Será atualizado pela detecção
269
- "sql_query_extracted": None,
270
- "graph_type": None,
271
- "graph_data": None,
272
- "graph_image_id": None,
273
- "graph_generated": False,
274
- "graph_error": None
275
- }
276
-
277
- # Executa o grafo
278
- config = {"configurable": {"thread_id": thread_id}}
279
- result = await self.app.ainvoke(initial_state, config=config)
280
-
281
- logging.info(f"Query processada com sucesso: {user_input[:50]}...")
282
- return result
283
-
284
- except Exception as e:
285
- error_msg = f"Erro ao processar query: {e}"
286
- logging.error(error_msg)
287
- return {
288
- "user_input": user_input,
289
- "response": error_msg,
290
- "error": error_msg,
291
- "execution_time": 0.0
292
- }
293
-
294
- async def handle_csv_upload(self, file_path: str) -> Dict[str, Any]:
295
- """
296
- Processa upload de CSV usando nova arquitetura de nós
297
-
298
- Args:
299
- file_path: Caminho do arquivo CSV
300
-
301
- Returns:
302
- Resultado do upload
303
- """
304
- try:
305
- # Etapa 1: Processa CSV
306
- csv_state = {
307
- "file_path": file_path,
308
- "success": False,
309
- "message": "",
310
- "csv_data_sample": {},
311
- "column_info": {},
312
- "processing_stats": {}
313
- }
314
-
315
- csv_result = await csv_processing_node(csv_state)
316
-
317
- if not csv_result["success"]:
318
- return csv_result
319
-
320
- # Etapa 2: Cria banco de dados
321
- db_state = csv_result.copy()
322
- db_result = await create_database_from_dataframe_node(db_state)
323
-
324
- if not db_result["success"]:
325
- return db_result
326
-
327
- # Etapa 3: Atualiza sistema
328
- if db_result["success"]:
329
- # Atualiza IDs dos objetos
330
- self.engine_id = db_result["engine_id"]
331
- self.db_id = db_result["db_id"]
332
-
333
- # Cria novo agente SQL
334
- new_engine = self.object_manager.get_engine(self.engine_id)
335
- new_db = self.object_manager.get_database(self.db_id)
336
- new_sql_agent = SQLAgentManager(new_db)
337
-
338
- # Atualiza agente
339
- self.agent_id = self.object_manager.store_sql_agent(new_sql_agent, self.db_id)
340
-
341
- # Limpa cache
342
- cache_manager = self.object_manager.get_cache_manager(self.cache_id)
343
- if cache_manager:
344
- cache_manager.clear_cache()
345
-
346
- logging.info("[UPLOAD] Sistema atualizado com novo CSV")
347
-
348
- return db_result
349
-
350
- except Exception as e:
351
- error_msg = f"❌ Erro no upload de CSV: {e}"
352
- logging.error(error_msg)
353
- return {
354
- "success": False,
355
- "message": error_msg
356
- }
357
-
358
- async def reset_system(self) -> Dict[str, Any]:
359
- """
360
- Reseta o sistema ao estado inicial
361
-
362
- Returns:
363
- Resultado do reset
364
- """
365
- try:
366
- # Usa nó de reset customizado
367
- state = {
368
- "success": False,
369
- "message": "",
370
- "engine_id": self.engine_id,
371
- "agent_id": self.agent_id,
372
- "cache_id": self.cache_id
373
- }
374
-
375
- result = await self.custom_node_manager.execute_node("system_reset", state)
376
-
377
- # Se reset foi bem-sucedido, atualiza IDs
378
- if result.get("success"):
379
- self.engine_id = result.get("engine_id", self.engine_id)
380
- self.agent_id = result.get("agent_id", self.agent_id)
381
- # Cache ID permanece o mesmo, apenas é limpo
382
-
383
- logging.info("[RESET] Sistema resetado com sucesso")
384
-
385
- return result
386
-
387
- except Exception as e:
388
- error_msg = f"❌ Erro ao resetar sistema: {e}"
389
- logging.error(error_msg)
390
- return {
391
- "success": False,
392
- "message": error_msg
393
- }
394
-
395
- def toggle_advanced_mode(self, enabled: bool) -> str:
396
- """
397
- Alterna modo avançado
398
-
399
- Args:
400
- enabled: Se deve habilitar modo avançado
401
-
402
- Returns:
403
- Mensagem de status
404
- """
405
- message = "Modo avançado ativado." if enabled else "Modo avançado desativado."
406
- logging.info(f"[MODO AVANÇADO] {'Ativado' if enabled else 'Desativado'}")
407
- return message
408
-
409
- def get_history(self) -> list:
410
- """
411
- Retorna histórico de conversas
412
-
413
- Returns:
414
- Lista com histórico
415
- """
416
- return self.cache_manager.get_history()
417
-
418
- def clear_cache(self):
419
- """Limpa cache do sistema"""
420
- self.cache_manager.clear_cache()
421
- logging.info("Cache limpo")
422
-
423
- async def get_system_info(self) -> Dict[str, Any]:
424
- """
425
- Obtém informações do sistema
426
-
427
- Returns:
428
- Informações do sistema
429
- """
430
- state = {
431
- "engine": self.engine,
432
- "sql_agent": self.sql_agent,
433
- "cache_manager": self.cache_manager
434
- }
435
-
436
- result = await self.custom_node_manager.execute_node("system_info", state)
437
- return result.get("system_info", {})
438
-
439
- async def validate_system(self) -> Dict[str, Any]:
440
- """
441
- Valida o estado do sistema
442
-
443
- Returns:
444
- Resultado da validação
445
- """
446
- state = {
447
- "engine": self.engine,
448
- "sql_agent": self.sql_agent,
449
- "cache_manager": self.cache_manager
450
- }
451
-
452
- result = await self.custom_node_manager.execute_node("system_validation", state)
453
- return result.get("validation", {})
454
-
455
- # Instância global do gerenciador
456
- _graph_manager: Optional[AgentGraphManager] = None
457
-
458
- def get_graph_manager() -> AgentGraphManager:
459
- """
460
- Retorna instância singleton do gerenciador de grafo
461
-
462
- Returns:
463
- AgentGraphManager
464
- """
465
- global _graph_manager
466
- if _graph_manager is None:
467
- _graph_manager = AgentGraphManager()
468
- return _graph_manager
469
-
470
- async def initialize_graph() -> AgentGraphManager:
471
- """
472
- Inicializa o grafo principal
473
-
474
- Returns:
475
- AgentGraphManager inicializado
476
- """
477
- try:
478
- manager = get_graph_manager()
479
-
480
- # Valida sistema
481
- validation = await manager.validate_system()
482
- if not validation.get("overall_valid", False):
483
- logging.warning("Sistema não passou na validação completa")
484
-
485
- logging.info("Grafo principal inicializado e validado")
486
- return manager
487
-
488
- except Exception as e:
489
- logging.error(f"Erro ao inicializar grafo: {e}")
490
- raise