Spaces:
Sleeping
Sleeping
| # app/ui_streamlit.py | |
| import os, json | |
| from pathlib import Path | |
| import streamlit as st | |
| from app.main import get_env, ensure_index_exists | |
| from app.search import search | |
| # Streamlit config should be the first Streamlit call | |
| st.set_page_config(page_title="Grants Discovery RAG", layout="wide") | |
| # Environment + index | |
| _env = get_env() | |
| ensure_index_exists(_env) | |
| # ---------- helpers ---------- | |
| def _dedup_records(rows): | |
| seen, out = set(), [] | |
| for r in rows or []: | |
| k = r.get("id") or r.get("url") or r.get("title") | |
| if not k or k in seen: | |
| continue | |
| seen.add(k) | |
| out.append(r) | |
| return out | |
| # ---------- end helpers ---------- | |
| # ---------- optional diagnostics ---------- | |
| with st.expander("Diagnostics (optional)", expanded=False): | |
| idx = Path(_env["INDEX_DIR"]) | |
| st.write("INDEX_DIR:", str(idx)) | |
| st.write("faiss.index exists:", (idx / "faiss.index").exists()) | |
| st.write("meta.json exists:", (idx / "meta.json").exists()) | |
| if (idx / "meta.json").exists(): | |
| try: | |
| meta = json.loads((idx / "meta.json").read_text()) | |
| st.write("meta.json count:", len(meta)) | |
| st.write("meta head:", [{"id": m.get("id"), "title": m.get("title")} for m in meta[:2]]) | |
| except Exception as e: | |
| st.error(f"Failed to read meta.json: {e!r}") | |
| try: | |
| demo = search("transportation", _env, top_k=3, filters={}) | |
| st.write("sample search('transportation') results:", len(demo)) | |
| if demo: | |
| st.write(demo[:3]) | |
| except Exception as e: | |
| st.error(f"search() raised: {e!r}") | |
| # ---------- end diagnostics ---------- | |
| st.title("Grants Discovery RAG (Capacity Building)") | |
| preset = st.radio( | |
| "Quick topic:", | |
| ["General", "Elderly", "Prison Ministry", "Evangelism", "Vehicles/Transport", "FTA 5310"], | |
| horizontal=True | |
| ) | |
| default_q = { | |
| "General": "capacity building", | |
| "Elderly": "capacity building for seniors and aging services", | |
| "Prison Ministry": "capacity building for reentry and prison ministry", | |
| "Evangelism": "capacity building for faith and community outreach", | |
| "Vehicles/Transport": "capacity building transportation vehicles vans buses mobility", | |
| "FTA 5310": "5310 Enhanced Mobility Seniors Individuals with Disabilities", | |
| }.get(preset, "capacity building") | |
| # --- controls --- | |
| q = st.text_input("Search query", value=default_q) | |
| # No defaults -> no filtering unless the user selects something | |
| geo = st.multiselect("Geo filter (optional)", options=["US", "MD", "MA"], default=[]) | |
| categories = st.multiselect( | |
| "Category filter (optional)", | |
| options=["capacity_building", "elderly", "prison_ministry", "evangelism", "transportation", "vehicle"], | |
| default=[] | |
| ) | |
| top_k = st.slider("Results", 5, 50, 15) | |
| # Build filters only when selected | |
| filters = {} | |
| if geo: | |
| filters["geo"] = geo | |
| if categories: | |
| filters["categories"] = categories # <- use 'categories' key (not 'cats') | |
| col1, col2 = st.columns([1, 1]) | |
| with col1: | |
| if st.button("Search"): | |
| try: | |
| results = search(q, _env, top_k=top_k, filters=filters) | |
| results = _dedup_records(results) | |
| st.session_state["results"] = results | |
| except Exception as e: | |
| st.error(str(e)) | |
| with col2: | |
| if st.button("Export Results to CSV"): | |
| results = st.session_state.get("results", []) | |
| if not results: | |
| st.warning("No results to export. Run a search first.") | |
| else: | |
| os.makedirs(_env["EXPORT_DIR"], exist_ok=True) | |
| out_path = os.path.join(_env["EXPORT_DIR"], "results.csv") | |
| import pandas as pd | |
| pd.DataFrame(results).to_csv(out_path, index=False) | |
| st.success(f"Exported to {out_path}") | |
| st.markdown("---") | |
| results = st.session_state.get("results", []) | |
| if results: | |
| st.caption(f"Results: {len(results)}") | |
| for r in results: | |
| title = r.get("title", "(no title)") | |
| url = r.get("url", "") | |
| cats = r.get("categories") or r.get("cats") or [] | |
| geo_tags = r.get("geo") or [] | |
| st.markdown(f"### {title}") | |
| st.write(f"**Source:** {r.get('source','')} | **Geo:** {', '.join(geo_tags) if isinstance(geo_tags, list) else geo_tags} | **Categories:** {', '.join(cats) if isinstance(cats, list) else cats}") | |
| if url and not url.startswith("http"): | |
| st.caption("Note: This item may display an ID or number instead of a full link. Open on Grants.gov if needed.") | |
| st.write(f"[Open Link]({url}) \nScore: {r.get('score', 0):.3f}") | |
| st.markdown("---") | |
| else: | |
| st.info("Enter a query and click Search.") | |