Spaces:
Sleeping
Sleeping
Create graph_tools.py
Browse files- genesis/graph_tools.py +119 -0
genesis/graph_tools.py
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# genesis/graph_tools.py
|
2 |
+
import os
|
3 |
+
import logging
|
4 |
+
from neo4j import GraphDatabase, basic_auth
|
5 |
+
|
6 |
+
# =========================
|
7 |
+
# CONFIG
|
8 |
+
# =========================
|
9 |
+
NEO4J_URI = os.getenv("NEO4J_URI")
|
10 |
+
NEO4J_USER = os.getenv("NEO4J_USER")
|
11 |
+
NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD")
|
12 |
+
|
13 |
+
driver = None
|
14 |
+
|
15 |
+
# =========================
|
16 |
+
# INIT CONNECTION
|
17 |
+
# =========================
|
18 |
+
def init_driver():
|
19 |
+
"""Initialize Neo4j driver if credentials are set."""
|
20 |
+
global driver
|
21 |
+
if NEO4J_URI and NEO4J_USER and NEO4J_PASSWORD:
|
22 |
+
try:
|
23 |
+
driver = GraphDatabase.driver(
|
24 |
+
NEO4J_URI,
|
25 |
+
auth=basic_auth(NEO4J_USER, NEO4J_PASSWORD)
|
26 |
+
)
|
27 |
+
logging.info("[Neo4j] Connected successfully.")
|
28 |
+
except Exception as e:
|
29 |
+
logging.error(f"[Neo4j] Connection failed: {e}")
|
30 |
+
driver = None
|
31 |
+
else:
|
32 |
+
logging.info("[Neo4j] No URI/user/password set β skipping connection.")
|
33 |
+
driver = None
|
34 |
+
|
35 |
+
# Call on import
|
36 |
+
init_driver()
|
37 |
+
|
38 |
+
def is_connected():
|
39 |
+
"""Check if driver is active and ready."""
|
40 |
+
return driver is not None and hasattr(driver, "session")
|
41 |
+
|
42 |
+
# =========================
|
43 |
+
# QUERY FUNCTIONS
|
44 |
+
# =========================
|
45 |
+
def run_query(cypher, params=None):
|
46 |
+
"""Run a read/write Cypher query safely."""
|
47 |
+
if not is_connected():
|
48 |
+
logging.warning("[Neo4j] No active connection β returning empty result.")
|
49 |
+
return []
|
50 |
+
try:
|
51 |
+
with driver.session() as session:
|
52 |
+
return list(session.run(cypher, params or {}))
|
53 |
+
except Exception as e:
|
54 |
+
logging.error(f"[Neo4j] Query failed: {e}")
|
55 |
+
return []
|
56 |
+
|
57 |
+
def write_data(cypher, params=None):
|
58 |
+
"""Write data to Neo4j (CREATE/MERGE)."""
|
59 |
+
if not is_connected():
|
60 |
+
logging.warning("[Neo4j] No active connection β skipping write.")
|
61 |
+
return False
|
62 |
+
try:
|
63 |
+
with driver.session() as session:
|
64 |
+
session.run(cypher, params or {})
|
65 |
+
return True
|
66 |
+
except Exception as e:
|
67 |
+
logging.error(f"[Neo4j] Write failed: {e}")
|
68 |
+
return False
|
69 |
+
|
70 |
+
# =========================
|
71 |
+
# BULK GRAPH CREATION
|
72 |
+
# =========================
|
73 |
+
def save_graph_data(nodes, edges):
|
74 |
+
"""
|
75 |
+
Save nodes and edges to Neo4j.
|
76 |
+
nodes: list of dicts {id, label, type}
|
77 |
+
edges: list of dicts {source, target, type}
|
78 |
+
"""
|
79 |
+
if not is_connected():
|
80 |
+
logging.warning("[Neo4j] No active connection β skipping graph save.")
|
81 |
+
return False
|
82 |
+
|
83 |
+
try:
|
84 |
+
with driver.session() as session:
|
85 |
+
# Create nodes
|
86 |
+
for node in nodes:
|
87 |
+
session.run(
|
88 |
+
"""
|
89 |
+
MERGE (n:Entity {id: $id})
|
90 |
+
SET n.label = $label, n.type = $type
|
91 |
+
""",
|
92 |
+
node
|
93 |
+
)
|
94 |
+
# Create edges
|
95 |
+
for edge in edges:
|
96 |
+
session.run(
|
97 |
+
"""
|
98 |
+
MATCH (a:Entity {id: $source})
|
99 |
+
MATCH (b:Entity {id: $target})
|
100 |
+
MERGE (a)-[r:RELATION {type: $type}]->(b)
|
101 |
+
""",
|
102 |
+
edge
|
103 |
+
)
|
104 |
+
logging.info("[Neo4j] Graph data saved successfully.")
|
105 |
+
return True
|
106 |
+
except Exception as e:
|
107 |
+
logging.error(f"[Neo4j] Error saving graph data: {e}")
|
108 |
+
return False
|
109 |
+
|
110 |
+
# =========================
|
111 |
+
# CLEANUP
|
112 |
+
# =========================
|
113 |
+
def close_driver():
|
114 |
+
"""Close Neo4j driver."""
|
115 |
+
global driver
|
116 |
+
if driver:
|
117 |
+
driver.close()
|
118 |
+
driver = None
|
119 |
+
logging.info("[Neo4j] Connection closed.")
|