{"repo": "abhishek007-pixel/multi-agent-study-assistant", "files": {"app.py": {"e6678690291649d5969780b61bf702d9560f4834": {"t": 1785674394.530545, "n": 4895, "h": "f427fca1c11924fd", "c": "\"\"\"Streamlit UI + LangGraph entry point.\"\"\"\n\nimport os\nimport tempfile\n\nimport groq\nimport streamlit as st\nfrom dotenv import load_dotenv\n\nfrom graph.study_graph import study_graph\nfrom memory.bm25_store import BM25Store\nfrom memory.vector_store import build_vector_store, load_documents_from_file, split_documents\n\n_ROOT = os.path.abspath(os.path.dirname(__file__))\n_ENV_PATH = os.path.join(_ROOT, \".env\")\nload_dotenv(_ENV_PATH, override=True)\n\n\ndef _groq_key_configured() -> bool:\n k = (os.getenv(\"GROQ_API_KEY\") or \"\").strip().strip(\"\\ufeff\")\n return bool(k) and \"your_groq_api_key\" not in k.lower()\n\n\nst.set_page_config(page_title=\"AI Study Assistant\", page_icon=\"๐ŸŽ“\", layout=\"centered\")\nst.title(\"๐ŸŽ“ AI Study Assistant\")\nst.caption(\"LangGraph Multi-Agent ยท BM25 + FAISS + Cross-Encoder RAG\")\n\nif not _groq_key_configured():\n st.warning(\n \"Add a valid `GROQ_API_KEY` in `.env` at the project root (no quotes, no spaces). \"\n \"Create a key at https://console.groq.com โ€” then save `.env` and use **Rerun** in the Streamlit menu.\"\n )\n\nif \"messages\" not in st.session_state:\n st.session_state.messages = []\nif \"vs\" not in st.session_state:\n st.session_state.vs = None\nif \"bm25_store\" not in st.session_state:\n st.session_state.bm25_store = None\nif \"current_file\" not in st.session_state:\n st.session_state.current_file = None\n\nwith st.sidebar:\n st.header(\"๐Ÿ“š Study Materials\")\n uploaded_file = st.file_uploader(\"Upload a PDF to study\", type=[\"pdf\"])\n\n if st.button(\"๐Ÿ—‘๏ธ Clear Memory & Start Over\"):\n st.session_state.vs = None\n st.session_state.bm25_store = None\n st.session_state.messages = []\n st.session_state.current_file = None\n st.success(\"Session memory cleared.\")\n\n st.markdown(\"---\")\n st.markdown(\"**Session status:**\")\n if st.session_state.vs is not None:\n st.success(\"Document loaded โœ“\")\n else:\n st.warning(\"No document loaded\")\n\n\ndef ingest_uploaded_pdf(uploaded_file) -> None:\n \"\"\"Save upload to temp file โ†’ load โ†’ chunk โ†’ FAISS + BM25 from same chunks.\"\"\"\n with tempfile.NamedTemporaryFile(delete=False, suffix=\".pdf\") as tmp:\n tmp.write(uploaded_file.getbuffer())\n tmp_path = tmp.name\n\n try:\n docs = load_documents_from_file(tmp_path)\n finally:\n os.remove(tmp_path)\n\n chunks = split_documents(docs)\n st.session_state.vs = build_vector_store(chunks)\n st.session_state.bm25_store = BM25Store(chunks)\n st.session_state.current_file = getattr(uploaded_file, \"file_id\", None) or (\n uploaded_file.name,\n uploaded_file.size,\n )\n\n\nif uploaded_file is not None:\n file_key = getattr(uploaded_file, \"file_id\", None) or (\n uploaded_file.name,\n uploaded_file.size,\n )\n if st.session_state.current_file != file_key:\n with st.spinner(\"Building vector memory and cross-encoder index...\"):\n ingest_uploaded_pdf(uploaded_file)\n st.sidebar.success(f\"Loaded: {uploaded_file.name}\")\nelse:\n if st.session_state.current_file is not None:\n st.session_state.vs = None\n st.session_state.bm25_store = None\n st.session_state.current_file = None\n st.sidebar.info(\"Upload a PDF for deep RAG, or just chat with the Fast Agent!\")\n\nfor msg in st.session_state.messages:\n with st.chat_message(msg[\"role\"]):\n st.markdown(msg[\"content\"])\n\nif query := st.chat_input(\"E.g. 'Teach me photosynthesis and test me'\"):\n st.session_state.messages.append({\"role\": \"user\", \"content\": query})\n with st.chat_message(\"user\"):\n st.markdown(query)\n\n with st.chat_message(\"assistant\"):\n with st.spinner(\"Agents orchestrating...\"):\n final = \"\"\n try:\n result = study_graph.invoke(\n {\n \"query\": query,\n \"intent\": \"\",\n \"context\": \"\",\n \"explanation\": \"\",\n \"quiz\": \"\",\n \"final_output\": \"\",\n \"vector_store\": st.session_state.vs,\n \"bm25_store\": st.session_state.bm25_store,\n }\n )\n final = result[\"final_output\"]\n except groq.AuthenticationError:\n final = (\n \"**Invalid Groq API key (401).** Fix `.env`: use a fresh key from \"\n \"[Groq Console](https://console.groq.com), one line `GROQ_API_KEY=gsk_...`, \"\n \"no quotes or spaces, save the file, then **Rerun** the app.\"\n )\n st.error(final)\n except Exception as e:\n final = f\"**Unexpected error:** {e}\"\n st.error(final)\n else:\n st.markdown(final)\n\n if final:\n st.session_state.messages.append({\"role\": \"assistant\", \"content\": final})\n"}}}}