File size: 4,137 Bytes
7eaced5 | 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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | """
GESDA Knowledge Graph Explorer β Streamlit entry point.
Run with:
streamlit run graphrag_UI/app.py
"""
from __future__ import annotations
import sys
from pathlib import Path
# Ensure graphrag_UI/ is on the path for relative imports inside the package
_HERE = Path(__file__).parent.resolve()
if str(_HERE) not in sys.path:
sys.path.insert(0, str(_HERE))
import streamlit as st
import config # noqa: F401 β bootstraps project paths + loads .env
from config import APP_TITLE, APP_ICON
from db.neo4j_client import get_neo4j_resources, get_graph_summary
from db.vector_client import get_vector_resources
from queries.schema import NODE_COLORS
from ui.styles import inject_css
import ui.tab_vector_search as tab_vs
import ui.tab_hardcoded as tab_hq
import ui.tab_query_builder as tab_qb
# ---------------------------------------------------------------------------
# Page config (must be first Streamlit call)
# ---------------------------------------------------------------------------
st.set_page_config(
page_title=APP_TITLE,
page_icon=APP_ICON,
layout="wide",
initial_sidebar_state="expanded",
)
inject_css()
# ---------------------------------------------------------------------------
# Header
# ---------------------------------------------------------------------------
st.markdown(
"""
<div style="padding: 16px 0 8px 0;">
<span style="font-size:28px; font-weight:800; color:#1a1e2a;">
π¬ GESDA Knowledge Graph Explorer
</span>
</div>
""",
unsafe_allow_html=True,
)
# ---------------------------------------------------------------------------
# Sidebar β connection status
# ---------------------------------------------------------------------------
with st.sidebar:
st.markdown("### Connection")
# Neo4j
summary = get_graph_summary()
if summary.get("connected"):
st.markdown(
'<span class="status-dot ok"></span> **Neo4j** connected',
unsafe_allow_html=True,
)
with st.expander("Graph statistics", expanded=False):
st.metric("Total nodes", f'{summary["total_nodes"]:,}')
st.metric("Total relationships", f'{summary["total_relationships"]:,}')
nt = summary.get("node_types", {})
if nt:
rows = sorted(nt.items(), key=lambda x: x[1], reverse=True)
for label, cnt in rows:
color = NODE_COLORS.get(label, "#888")
st.markdown(
f'<span style="color:{color}; font-size:12px;">β {label}: {cnt:,}</span>',
unsafe_allow_html=True,
)
else:
st.markdown(
f'<span class="status-dot err"></span> **Neo4j** β {summary.get("error", "unavailable")}',
unsafe_allow_html=True,
)
# Vector search
_, _, vec_err = get_vector_resources()
if not vec_err:
st.markdown(
'<span class="status-dot ok"></span> **Vector search** ready',
unsafe_allow_html=True,
)
else:
st.markdown(
'<span class="status-dot warn"></span> **Vector search** unavailable',
unsafe_allow_html=True,
)
with st.expander("Details", expanded=False):
st.caption(vec_err)
st.divider()
st.markdown(
"""
**Tabs**
- **Hardcoded Queries** - examples of graph capabilities and explore the relationships
- **Vector Search** β find nodes using non-jargon language
- **Query Builder** β interactive Cypher builder
""",
unsafe_allow_html=False,
)
st.divider()
st.caption("GESDA Β· EPFL Β· 2026")
# ---------------------------------------------------------------------------
# Main tabs
# ---------------------------------------------------------------------------
tab_hard, tab_vec, tab_build = st.tabs([
"π Hardcoded Queries",
"π Vector Search",
"π οΈ Query Builder",
])
with tab_hard:
tab_hq.render()
with tab_vec:
tab_vs.render()
with tab_build:
tab_qb.render()
|