Danielfonseca1212 commited on
Commit
2c0103c
·
verified ·
1 Parent(s): 3023c1b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +152 -0
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # graph_agent.py — GraphRAG Agent: GPT-4o-mini + Neo4j Cypher
2
+ from openai import OpenAI
3
+ import re
4
+
5
+ SYSTEM_PROMPT = """Você é um agente especialista em Graph Neural Networks para detecção de fraude.
6
+ Você tem acesso a uma base de conhecimento em grafo Neo4j com 5 projetos de GNN.
7
+
8
+ PROJETOS DISPONÍVEIS:
9
+ 1. Sistema Imune Digital — Deep RL (DQN Dueling), 3 agentes especialistas
10
+ 2. HetGNN Fraud — Grafo heterogêneo, HGTConv, 5 tipos de nó
11
+ 3. TGN Fraud Detection — Temporal GNN, memória GRU, stream e-commerce
12
+ 4. DOMINANT — Anomaly detection sem labels (IJCAI 2019)
13
+ 5. GraphSAGE Elliptic — Dataset real Bitcoin, inductive learning
14
+
15
+ SCHEMA DO GRAFO:
16
+ Nós: Projeto, Tecnologia, Conceito, Paper, Metrica
17
+ Arestas:
18
+ (Projeto)-[:USA]->(Tecnologia)
19
+ (Projeto)-[:IMPLEMENTA]->(Conceito)
20
+ (Projeto)-[:REFERENCIA]->(Paper)
21
+ (Projeto)-[:TEM_METRICA]->(Metrica)
22
+ (Projeto)-[:DIFERENTE_DE]->(Projeto)
23
+
24
+ PROPRIEDADES:
25
+ Projeto: nome, descricao, paradigma, dado, url, emoji, ano
26
+ Tecnologia: nome
27
+ Conceito: nome, descricao
28
+ Paper: titulo, autores, venue, modelo
29
+ Metrica: projeto, tipo, valor, dataset
30
+
31
+ Sua tarefa:
32
+ 1. Gerar uma query Cypher para buscar informação relevante no grafo
33
+ 2. A query deve ser eficiente e específica à pergunta
34
+ 3. Retornar APENAS o Cypher, sem explicação, dentro de ```cypher ... ```
35
+
36
+ Exemplos:
37
+ Pergunta: "Quais projetos usam PyTorch Geometric?"
38
+ ```cypher
39
+ MATCH (p:Projeto)-[:USA]->(t:Tecnologia {nome: 'PyTorch Geometric'})
40
+ RETURN p.nome, p.descricao, p.url
41
+ ```
42
+
43
+ Pergunta: "Qual projeto tem maior AUC?"
44
+ ```cypher
45
+ MATCH (p:Projeto)-[:TEM_METRICA]->(m:Metrica {tipo: 'AUC'})
46
+ RETURN p.nome, m.valor, m.dataset
47
+ ORDER BY m.valor DESC
48
+ ```
49
+
50
+ Pergunta: "Me explique o conceito de Inductive Learning"
51
+ ```cypher
52
+ MATCH (c:Conceito {nome: 'Inductive Learning'})<-[:IMPLEMENTA]-(p:Projeto)
53
+ RETURN c.nome, c.descricao, collect(p.nome) AS projetos
54
+ ```"""
55
+
56
+ ANSWER_PROMPT = """Você é Daniel Fonseca, ML Engineer especialista em Graph Neural Networks para detecção de fraude.
57
+ Responda de forma técnica, clara e entusiasmada sobre seus projetos.
58
+
59
+ Contexto do grafo Neo4j:
60
+ {context}
61
+
62
+ Pergunta do usuário: {question}
63
+
64
+ Instruções:
65
+ - Responda em português
66
+ - Seja específico e técnico
67
+ - Cite os projetos relevantes com seus emojis
68
+ - Se tiver URL de projeto, mencione que pode ser acessado no Hugging Face
69
+ - Máximo 4 parágrafos
70
+ - Finalize com uma frase que convide o usuário a explorar mais"""
71
+
72
+
73
+ class GraphRAGAgent:
74
+ def __init__(self, openai_api_key: str, neo4j_driver, neo4j_database: str):
75
+ self.client = OpenAI(api_key=openai_api_key)
76
+ self.driver = neo4j_driver
77
+ self.database = neo4j_database
78
+ self.model = "gpt-4o-mini"
79
+
80
+ def gerar_cypher(self, pergunta: str) -> str:
81
+ """GPT gera Cypher a partir da pergunta em linguagem natural."""
82
+ resp = self.client.chat.completions.create(
83
+ model=self.model,
84
+ messages=[
85
+ {"role": "system", "content": SYSTEM_PROMPT},
86
+ {"role": "user", "content": pergunta}
87
+ ],
88
+ temperature=0.1,
89
+ max_tokens=300,
90
+ )
91
+ texto = resp.choices[0].message.content
92
+ # Extrai o Cypher do bloco de código
93
+ match = re.search(r'```cypher\s*(.*?)\s*```', texto, re.DOTALL)
94
+ if match:
95
+ return match.group(1).strip()
96
+ # Fallback: tenta extrair qualquer bloco de código
97
+ match = re.search(r'```\s*(.*?)\s*```', texto, re.DOTALL)
98
+ if match:
99
+ return match.group(1).strip()
100
+ return texto.strip()
101
+
102
+ def executar_cypher(self, cypher: str) -> list:
103
+ """Executa Cypher no Neo4j e retorna resultados."""
104
+ try:
105
+ with self.driver.session(database=self.database) as session:
106
+ result = session.run(cypher)
107
+ return [dict(record) for record in result]
108
+ except Exception as e:
109
+ return [{"erro": str(e)}]
110
+
111
+ def formatar_contexto(self, resultados: list) -> str:
112
+ """Formata resultados do Neo4j em texto para o LLM."""
113
+ if not resultados:
114
+ return "Nenhum resultado encontrado no grafo."
115
+ if len(resultados) == 1 and "erro" in resultados[0]:
116
+ return f"Erro na query: {resultados[0]['erro']}"
117
+ linhas = []
118
+ for r in resultados[:10]: # max 10 resultados
119
+ linha = " | ".join(f"{k}: {v}" for k, v in r.items() if v is not None)
120
+ linhas.append(linha)
121
+ return "\n".join(linhas)
122
+
123
+ def gerar_resposta(self, pergunta: str, contexto: str) -> str:
124
+ """GPT gera resposta final com base no contexto do grafo."""
125
+ prompt = ANSWER_PROMPT.format(context=contexto, question=pergunta)
126
+ resp = self.client.chat.completions.create(
127
+ model=self.model,
128
+ messages=[{"role": "user", "content": prompt}],
129
+ temperature=0.7,
130
+ max_tokens=600,
131
+ )
132
+ return resp.choices[0].message.content
133
+
134
+ def responder(self, pergunta: str) -> dict:
135
+ """
136
+ Pipeline completo:
137
+ 1. Gera Cypher
138
+ 2. Executa no Neo4j
139
+ 3. Formata contexto
140
+ 4. Gera resposta
141
+ """
142
+ cypher = self.gerar_cypher(pergunta)
143
+ resultados = self.executar_cypher(cypher)
144
+ contexto = self.formatar_contexto(resultados)
145
+ resposta = self.gerar_resposta(pergunta, contexto)
146
+
147
+ return {
148
+ "cypher": cypher,
149
+ "resultados": resultados,
150
+ "contexto": contexto,
151
+ "resposta": resposta,
152
+ }