-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstreamlit_app.py
More file actions
104 lines (88 loc) · 3.18 KB
/
streamlit_app.py
File metadata and controls
104 lines (88 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import streamlit as st
import os
from dotenv import load_dotenv
from neo4j import GraphDatabase
from google import genai
# ---- Load environment variables ----
load_dotenv()
client = genai.Client()
URI = os.getenv("NEO4J_URI")
USERNAME = os.getenv("NEO4J_USERNAME")
PASSWORD = os.getenv("NEO4J_PASSWORD")
# ---- Neo4j connection helper ----
def run_cypher(cypher_query):
with GraphDatabase.driver(URI, auth=(USERNAME, PASSWORD)) as driver:
with driver.session() as session:
result = session.run(cypher_query)
data = result.data()
# If the query returns only one column, extract the values
if data and len(data[0].keys()) == 1:
key = list(data[0].keys())[0]
values = [row[key] for row in data]
else:
values = data
return values
# ---- LLM helper: Generate Cypher ----
def generate_cypher(user_question):
prompt = f"""
You are an AI that converts natural language questions into Cypher queries.
IMPORTANT RULES:
- Output ONLY the Cypher query.
- Follow the schema, relationships, and properties.
- No explanation, no markdown, no code blocks, no extra text, no backticks.
- The query must return only string values.
- The last line MUST be a RETURN <string property> expression.
Schema:
(:Movie)-[:IN_GENRE]->(:Genre)
(:Person)-[:DIRECTED]->(:Movie)
(:Person)-[:ACTED_IN]->(:Movie)
Relationships:
"ACTED_IN"
"DIRECTED"
"PRODUCED"
"WROTE"
"FOLLOWS"
"REVIEWED"
Properties:
"Movie.title"
"Movie.released"
"Movie.tagline"
"Person.name"
"Person.born"
User question: "{user_question}"
Return ONLY the Cypher query.
"""
response = client.models.generate_content(model="gemini-2.5-flash", contents=prompt)
cypher_query = response.text.strip("```").strip()
return cypher_query
# ---- LLM helper: Summarize results ----
def summarize_results(user_question, values):
prompt = f"""
You are an AI assistant. Summarize database results concisely.
User question: "{user_question}"
Database result: "{values}"
Write all the values with a short, clear explanation (1-2 lines).
"""
response = client.models.generate_content(model="gemini-2.5-flash", contents=prompt)
return response.text.strip("```").strip()
# ---- Streamlit UI ----
st.title("🎬 Movie Graph Assistant")
st.write("Ask questions about the movies. The system generates Cypher, queries Neo4j, and gives concise answer.")
user_question = st.text_area("Ask your question:")
if st.button("Submit"):
if not user_question.strip():
st.warning("Please enter a question.")
else:
# Step 1: Generate Cypher
cypher_query = generate_cypher(user_question)
st.code(cypher_query, language="cypher")
# Step 2: Run query on Neo4j
try:
values = run_cypher(cypher_query)
st.success("Query executed successfully!")
st.write("Raw Output:", values)
except Exception as e:
st.error(f"Query execution failed: {e}")
values = None
summary = summarize_results(user_question, values)
st.markdown(f"**Answer:** {summary}")