Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -252,31 +252,50 @@ h1, h2, h3 { font-family: 'IBM Plex Sans', sans-serif; font-weight: 600; }
|
|
| 252 |
# ─────────────────────────────────────────────
|
| 253 |
# NEO4J CONNECTION
|
| 254 |
# ─────────────────────────────────────────────
|
| 255 |
-
|
| 256 |
-
def get_neo4j_driver():
|
| 257 |
-
# Try secrets first, then env vars, then hardcoded fallback
|
| 258 |
uri = (st.secrets.get("NEO4J_URI") or os.getenv("NEO4J_URI") or "neo4j+s://e3b8c8ec.databases.neo4j.io")
|
| 259 |
user = (st.secrets.get("NEO4J_USERNAME") or os.getenv("NEO4J_USERNAME") or "e3b8c8ec")
|
| 260 |
password = (st.secrets.get("NEO4J_PASSWORD") or os.getenv("NEO4J_PASSWORD") or "")
|
| 261 |
database = (st.secrets.get("NEO4J_DATABASE") or os.getenv("NEO4J_DATABASE") or "e3b8c8ec")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
user
|
| 266 |
-
password = password.strip().strip('"').strip("'")
|
| 267 |
-
database = database.strip().strip('"').strip("'")
|
| 268 |
-
|
| 269 |
if not password:
|
| 270 |
st.sidebar.warning("NEO4J_PASSWORD not set in Secrets.")
|
| 271 |
-
return None
|
| 272 |
try:
|
| 273 |
-
driver = GraphDatabase.driver(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
driver.verify_connectivity()
|
| 275 |
-
driver
|
| 276 |
-
return driver
|
| 277 |
except Exception as e:
|
| 278 |
st.sidebar.error(f"Neo4j error: {e}")
|
| 279 |
-
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
|
| 281 |
@st.cache_resource
|
| 282 |
def get_groq_client():
|
|
@@ -361,7 +380,7 @@ MERGE (a5)-[:TRANSACTION {amount:2.00, type:'card_test'}]->(m3)
|
|
| 361 |
"""
|
| 362 |
|
| 363 |
def seed_database(driver):
|
| 364 |
-
with
|
| 365 |
for stmt in SEED_CYPHER.strip().split(';'):
|
| 366 |
stmt = stmt.strip()
|
| 367 |
if stmt:
|
|
@@ -408,7 +427,8 @@ Respond ONLY with a valid JSON object, no markdown, no explanation:
|
|
| 408 |
# ─────────────────────────────────────────────
|
| 409 |
def run_cypher(driver, cypher: str):
|
| 410 |
try:
|
| 411 |
-
|
|
|
|
| 412 |
result = session.run(cypher)
|
| 413 |
records = [dict(r) for r in result]
|
| 414 |
return records, None
|
|
@@ -504,7 +524,8 @@ def build_graph_html(driver, limit=60):
|
|
| 504 |
"Customer": "#42A5F5", "Account": "#69F0AE", "Device": "#FFD54F",
|
| 505 |
"IP": "#FF6B6B", "Merchant": "#CE93D8",
|
| 506 |
}
|
| 507 |
-
|
|
|
|
| 508 |
nodes_q = "MATCH (n) RETURN n, labels(n) AS lbl LIMIT $limit"
|
| 509 |
edges_q = "MATCH (a)-[r]->(b) RETURN id(a) AS src, id(b) AS tgt, type(r) AS rel, r LIMIT $limit"
|
| 510 |
|
|
@@ -558,10 +579,10 @@ with st.sidebar:
|
|
| 558 |
st.markdown("---")
|
| 559 |
st.markdown("**⚙️ Connections**")
|
| 560 |
|
| 561 |
-
driver = get_neo4j_driver()
|
| 562 |
groq_client = get_groq_client()
|
| 563 |
|
| 564 |
-
neo4j_ok = driver is not None
|
| 565 |
groq_ok = groq_client is not None
|
| 566 |
|
| 567 |
st.markdown(f"{'🟢' if neo4j_ok else '🔴'} Neo4j Aura {'Connected' if neo4j_ok else 'Not connected'}")
|
|
|
|
| 252 |
# ─────────────────────────────────────────────
|
| 253 |
# NEO4J CONNECTION
|
| 254 |
# ─────────────────────────────────────────────
|
| 255 |
+
def _get_neo4j_creds():
|
|
|
|
|
|
|
| 256 |
uri = (st.secrets.get("NEO4J_URI") or os.getenv("NEO4J_URI") or "neo4j+s://e3b8c8ec.databases.neo4j.io")
|
| 257 |
user = (st.secrets.get("NEO4J_USERNAME") or os.getenv("NEO4J_USERNAME") or "e3b8c8ec")
|
| 258 |
password = (st.secrets.get("NEO4J_PASSWORD") or os.getenv("NEO4J_PASSWORD") or "")
|
| 259 |
database = (st.secrets.get("NEO4J_DATABASE") or os.getenv("NEO4J_DATABASE") or "e3b8c8ec")
|
| 260 |
+
return (
|
| 261 |
+
uri.strip().strip('"').strip("'"),
|
| 262 |
+
user.strip().strip('"').strip("'"),
|
| 263 |
+
password.strip().strip('"').strip("'"),
|
| 264 |
+
database.strip().strip('"').strip("'"),
|
| 265 |
+
)
|
| 266 |
|
| 267 |
+
@st.cache_resource
|
| 268 |
+
def get_neo4j_driver():
|
| 269 |
+
uri, user, password, database = _get_neo4j_creds()
|
|
|
|
|
|
|
|
|
|
| 270 |
if not password:
|
| 271 |
st.sidebar.warning("NEO4J_PASSWORD not set in Secrets.")
|
| 272 |
+
return None, None
|
| 273 |
try:
|
| 274 |
+
driver = GraphDatabase.driver(
|
| 275 |
+
uri, auth=(user, password),
|
| 276 |
+
max_connection_lifetime=200,
|
| 277 |
+
keep_alive=True,
|
| 278 |
+
)
|
| 279 |
driver.verify_connectivity()
|
| 280 |
+
return driver, database
|
|
|
|
| 281 |
except Exception as e:
|
| 282 |
st.sidebar.error(f"Neo4j error: {e}")
|
| 283 |
+
return None, None
|
| 284 |
+
|
| 285 |
+
def get_session(driver, database):
|
| 286 |
+
"""Always get a fresh session, reconnecting if needed."""
|
| 287 |
+
try:
|
| 288 |
+
return driver.session(database=database)
|
| 289 |
+
except Exception:
|
| 290 |
+
# Driver is defunct — clear cache and rebuild
|
| 291 |
+
get_neo4j_driver.clear()
|
| 292 |
+
uri, user, password, database = _get_neo4j_creds()
|
| 293 |
+
new_driver = GraphDatabase.driver(
|
| 294 |
+
uri, auth=(user, password),
|
| 295 |
+
max_connection_lifetime=200,
|
| 296 |
+
keep_alive=True,
|
| 297 |
+
)
|
| 298 |
+
return new_driver.session(database=database)
|
| 299 |
|
| 300 |
@st.cache_resource
|
| 301 |
def get_groq_client():
|
|
|
|
| 380 |
"""
|
| 381 |
|
| 382 |
def seed_database(driver):
|
| 383 |
+
with get_session(driver, "e3b8c8ec") as session:
|
| 384 |
for stmt in SEED_CYPHER.strip().split(';'):
|
| 385 |
stmt = stmt.strip()
|
| 386 |
if stmt:
|
|
|
|
| 427 |
# ─────────────────────────────────────────────
|
| 428 |
def run_cypher(driver, cypher: str):
|
| 429 |
try:
|
| 430 |
+
_, database = get_neo4j_driver()
|
| 431 |
+
with get_session(driver, database or "e3b8c8ec") as session:
|
| 432 |
result = session.run(cypher)
|
| 433 |
records = [dict(r) for r in result]
|
| 434 |
return records, None
|
|
|
|
| 524 |
"Customer": "#42A5F5", "Account": "#69F0AE", "Device": "#FFD54F",
|
| 525 |
"IP": "#FF6B6B", "Merchant": "#CE93D8",
|
| 526 |
}
|
| 527 |
+
_, database = get_neo4j_driver()
|
| 528 |
+
with get_session(driver, database or "e3b8c8ec") as session:
|
| 529 |
nodes_q = "MATCH (n) RETURN n, labels(n) AS lbl LIMIT $limit"
|
| 530 |
edges_q = "MATCH (a)-[r]->(b) RETURN id(a) AS src, id(b) AS tgt, type(r) AS rel, r LIMIT $limit"
|
| 531 |
|
|
|
|
| 579 |
st.markdown("---")
|
| 580 |
st.markdown("**⚙️ Connections**")
|
| 581 |
|
| 582 |
+
driver, _db = get_neo4j_driver()
|
| 583 |
groq_client = get_groq_client()
|
| 584 |
|
| 585 |
+
neo4j_ok = driver is not None and _db is not None
|
| 586 |
groq_ok = groq_client is not None
|
| 587 |
|
| 588 |
st.markdown(f"{'🟢' if neo4j_ok else '🔴'} Neo4j Aura {'Connected' if neo4j_ok else 'Not connected'}")
|