ArduinoYuri commited on
Commit
bff91d0
·
verified ·
1 Parent(s): faf41ff

Create workflow.py

Browse files
Files changed (1) hide show
  1. workflow.py +87 -0
workflow.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # workflow.py
2
+
3
+ import pandas as pd
4
+ from typing import Any
5
+ from pydantic import ConfigDict
6
+
7
+ from llama_index.core import Settings
8
+ from llama_index.core.workflow import Workflow, Event, StartEvent as BaseStartEvent, StopEvent, step
9
+ from llama_index.llms.groq import Groq
10
+
11
+ # Importações de nossos módulos locais
12
+ from config import pandas_prompt_str, instruction_str, RESPONSE_SYNTHESIS_PROMPT_STR
13
+ from utils import descricao_colunas, limpar_codigo_pandas
14
+
15
+ # --- MODELOS DE EVENTOS DO WORKFLOW ---
16
+ class StartEvent(BaseStartEvent):
17
+ query: str
18
+ df: pd.DataFrame
19
+ model_config = ConfigDict(arbitrary_types_allowed=True)
20
+
21
+ class CodeEvent(Event):
22
+ pandas_prompt: str; query: str; df: pd.DataFrame
23
+ model_config = ConfigDict(arbitrary_types_allowed=True)
24
+
25
+ class OutputEvent(Event):
26
+ pandas_code: str; query: str; df: pd.DataFrame
27
+ model_config = ConfigDict(arbitrary_types_allowed=True)
28
+
29
+ class ExecutedEvent(Event):
30
+ pandas_code: str; pandas_output: Any; query: str; df: pd.DataFrame
31
+ model_config = ConfigDict(arbitrary_types_allowed=True)
32
+
33
+ # --- CLASSE WORKFLOW PRINCIPAL ---
34
+ class PandasWorkflow(Workflow):
35
+ @step
36
+ async def iniciar_processamento(self, ev: StartEvent) -> CodeEvent:
37
+ colunas_info = descricao_colunas(ev.df)
38
+ prompt_text = pandas_prompt_str.format(
39
+ colunas_detalhes=colunas_info, df_str=ev.df.head(5).to_string(),
40
+ instruction_str=instruction_str, query_str=ev.query
41
+ )
42
+ return CodeEvent(pandas_prompt=prompt_text, query=ev.query, df=ev.df)
43
+
44
+ @step
45
+ async def gerar_codigo(self, ev: CodeEvent) -> OutputEvent:
46
+ response = await Settings.llm.acomplete(ev.pandas_prompt)
47
+ codigo_limpo = limpar_codigo_pandas(str(response).strip())
48
+ print(f"✅ Código gerado: {codigo_limpo}")
49
+ return OutputEvent(pandas_code=codigo_limpo, query=ev.query, df=ev.df)
50
+
51
+ @step
52
+ async def executar_codigo(self, ev: OutputEvent) -> ExecutedEvent:
53
+ try:
54
+ resultado = eval(ev.pandas_code, {"__builtins__": {}}, {"df": ev.df, "pd": pd})
55
+ except Exception as e:
56
+ resultado = f"Erro ao executar o código: {str(e)}"
57
+ return ExecutedEvent(
58
+ pandas_code=ev.pandas_code, pandas_output=resultado,
59
+ query=ev.query, df=ev.df
60
+ )
61
+
62
+ @step
63
+ async def finalizar_e_sintetizar(self, ev: ExecutedEvent) -> StopEvent:
64
+ if isinstance(ev.pandas_output, str) and "Erro" in ev.pandas_output:
65
+ resposta_final = f"Não foi possível processar: {ev.pandas_output}"
66
+ else:
67
+ prompt = RESPONSE_SYNTHESIS_PROMPT_STR.format(
68
+ query_str=ev.query, pandas_instructions=ev.pandas_code,
69
+ pandas_output=str(ev.pandas_output)
70
+ )
71
+ response = await Settings.llm.acomplete(prompt)
72
+ resposta_final = str(response).strip()
73
+ return StopEvent(result={"resposta_final": resposta_final})
74
+
75
+ # --- FUNÇÃO DE EXECUÇÃO ---
76
+ async def executar_consulta(query: str, df_local: pd.DataFrame):
77
+ if df_local is None: return {"resposta_final": "Erro: DataFrame não carregado."}
78
+ if not query.strip(): return {"resposta_final": "Erro: Consulta vazia."}
79
+ try:
80
+ wf = PandasWorkflow()
81
+ resultado_final = await wf.run(query=query, df=df_local)
82
+ if not isinstance(resultado_final, dict):
83
+ raise TypeError(f"Workflow retornou tipo inesperado: {type(resultado_final)}")
84
+ return resultado_final
85
+ except Exception as e:
86
+ import traceback; traceback.print_exc()
87
+ return {"resposta_final": f"Erro crítico no workflow: {str(e)}"}