from pathlib import Path import streamlit as st from src.pipeline import ingest, query def render_ui(): st.title("Neo4j GraphRAG Engine") st.markdown( "Ingest documents, extract entities and relationships into Neo4j, " "embed into Pinecone, and query via hybrid retrieval (vector + graph)." ) tab1, tab2 = st.tabs(["Query", "Ingest Documents"]) with tab1: q = st.text_input("Ask a question about your documents:", key="query_input") if st.button("Search", type="primary", disabled=not q): with st.spinner("Running hybrid retrieval..."): try: result = query(q) st.session_state["query_result"] = result except Exception as e: st.error(f"Query failed: {e}") if "query_result" in st.session_state: r = st.session_state["query_result"] st.subheader("Answer") st.write(r.answer) with st.expander("Vector Context (top chunks)"): for i, ctx in enumerate(r.vector_context[:5]): st.caption(f"Chunk {i + 1}") st.text(ctx[:500]) with st.expander("Graph Context (connected entities)"): for ctx in r.graph_context[:20]: st.write(f"- {ctx}") with tab2: docs_path = st.text_input("Documents directory", value="data/sample_docs") if st.button("Ingest", type="secondary"): _run_ingestion(docs_path) _render_sample_docs() def _render_sample_docs(): docs_dir = Path("data/sample_docs") if not docs_dir.exists(): return md_files = sorted(docs_dir.glob("*.md")) txt_files = sorted(docs_dir.glob("*.txt")) files = md_files + txt_files if not files: return st.divider() st.subheader("Source Documents") for f in files: content = f.read_text(encoding="utf-8") escaped = content.replace("&", "&").replace("<", "<").replace(">", ">") html = ( f"