An AI-powered, agentic study companion that turns your own notes into an intelligent tutor.
Upload your documents β start a session β ask questions, generate flashcards, plan your exam schedule, and export revision sheets β all powered by RAG and a multi-node LangGraph pipeline.
π Live Demo Β Β·Β π API Docs Β Β·Β π Architecture
- Upload PDF, DOCX, MD, and TXT files (up to 20MB each)
- Files are stored on Cloudinary β no local disk dependency, production-safe on any free-tier host
- Documents are scoped per subject and per user β full multi-tenancy
- Start a session by selecting one or more documents from your library
- Documents are parsed β chunked β embedded β stored in ChromaDB on session start
- ChromaDB collections are ephemeral β created on start, deleted on end β keeping storage clean
- Query across all loaded documents in natural language
The core of the system is a multi-stage retrieval pipeline that goes beyond simple vector search:
- RAG Node (with Vector Reranking) β performs a two-stage retrieval. It first fetches a large candidate pool using cosine similarity, then passes them through a Cohere Rerank model (via
ContextualCompressionRetriever) to score and extract only the most highly relevant chunks. - Sufficiency Judge β a dedicated Gemini instance evaluates the retrieved context and returns one of three verdicts:
SUFFICIENTβ answers immediately from your notesPARTIALβ pauses and asks you whether to supplement with web search (Tavily) or Gemini's general knowledgeINSUFFICIENTβ same interrupt, letting you choose your fallback
- Human-in-the-loop interrupt β powered by LangGraph's checkpoint + interrupt system; the agent literally pauses its graph execution and waits for your decision before proceeding
The agent classifies every message into one of six intents and routes through different graph branches accordingly:
| Intent | What happens |
|---|---|
rag_query |
Retrieval β Judge β (Fallback?) β Synthesis |
content_generation |
Planner β Flashcard generator / Revision sheet / RAG |
study_planning |
Gap analysis β Study plan builder β Calendar (optional) |
calendar_scheduling |
Direct calendar event builder β Google Calendar |
session_end |
Evaluator β Summary β Save & cleanup |
chitchat |
Direct synthesis |
- Ask the agent to create flashcards on any topic during a session
- Cards are generated by Gemini using your notes as context (RAG-grounded)
- Each card is persisted to MongoDB for easy access
- Dedicated review interface to test your knowledge
- OAuth 2.0 integration β connect your Google account from the app
- Agent can propose a full study schedule based on gap analysis: missing topics get 3 sessions, shallow topics get 2, well-covered topics get 1
- Before creating calendar events, the agent interrupts and shows you the proposed plan for confirmation (human-in-the-loop)
- Events are created directly in your primary Google Calendar
When you end a session, a pipeline runs automatically:
- Evaluator node scores the session: topics covered, depth of discussion, weak moments, and an overall session score
- Summary node generates a concise, human-readable session summary
- Both are persisted to MongoDB and visible in the session history
- Export a beautiful, formatted PDF revision sheet for any subject
- The sheet is generated by the agent (RAG + Gemini) covering all session topics at exam-revision depth
- Rendered with ReportLab β includes topic coverage indicators (β
well covered,
β οΈ needs work, β missing) - Downloadable directly from the UI
- The agent detects the language of queries and translates them to English before embedding search (since the embedding model is English-optimized)
- Translation via the Hugging Face Inference API (NLLB-200)
- Responses are generated in the same language as the user's notes
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js Frontend β
β (App Router Β· TypeScript Β· Tailwind CSS) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β REST API
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββ
β FastAPI Backend β
β β
β /auth /subjects /documents /sessions /chat /flashcards β
β /export /google-oauth β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β LangGraph Agent β β
β β β β
β β router β rag β sufficiency_judge β [interrupt] β β
β β β planner β flashcard_generator β β
β β β gap_analysis β study_plan_builder β calendar β β
β β β evaluator β summary_node β save_node β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββ΄βββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
MongoDB Atlas ChromaDB (local)
(users, subjects, Ephemeral session
documents, sessions, vector collections
flashcards) (created & deleted
per session)
1. Ephemeral vector stores per session Rather than maintaining a single persistent vector index per user, each study session gets its own short-lived ChromaDB collection. This means documents are embedded fresh per session β isolation is perfect, there are no cross-session contamination bugs, and cleanup is trivially simple (delete the collection when the session ends).
2. Sufficiency Judge as a circuit breaker A raw vector similarity score is a poor signal for answer quality. A score of 0.72 might mean the notes are perfect, or it might mean the best chunk you have is only tangentially related. The Sufficiency Judge pattern uses a second LLM call to read both the question and the retrieved context and make a semantic judgment β exactly what a human would do. This drastically reduces hallucinations from answering confidently with bad context.
3. Dual Gemini key separation Two separate Gemini API keys are used: one dedicated to the Sufficiency Judge (a fast, deterministic classification task at temperature=0) and one for all answer synthesis. This prevents a burst of synthesis calls from hitting the judge's rate limit and vice versa.
4. LangGraph interrupts for human-in-the-loop Two points in the graph pause execution and wait for user input:
- After the judge returns
PARTIAL/INSUFFICIENTβ let the user pick fallback strategy - Before creating Google Calendar events β show the proposed plan and wait for confirmation
This is implemented with LangGraph's interrupt_before + MemorySaver checkpointer. The graph state is frozen in memory, the API returns to the client, and when the user responds, the graph resumes from the exact checkpoint.
5. Document storage on Cloudinary as raw assets
Documents are uploaded with resource_type="raw" so Cloudinary treats them as file storage (not image CDN). This bypasses Cloudinary's PDF delivery restrictions that apply to image-type assets. The backend downloads files at session start using an archive API call for authenticated access.
6. Gemini API embeddings (no local model)
Embeddings use Google's gemini-embedding-001 via API rather than a local sentence-transformers model. This eliminates a ~500MB model download on deployment, making the backend compatible with free-tier cloud hosts that have strict RAM and disk limits.
| Layer | Technology |
|---|---|
| API Framework | FastAPI + Uvicorn |
| Agent Orchestration | LangGraph (StateGraph with interrupts) |
| LLM | Google Gemini 2.5 Flash |
| Embeddings | Google Gemini Embedding API (gemini-embedding-001) |
| Vector Reranking | Cohere Rerank API (langchain-cohere) |
| Vector Store | ChromaDB (ephemeral, per-session) |
| Database | MongoDB Atlas (Motor async driver) |
| Document Storage | Cloudinary |
| Web Search Fallback | Tavily Search API |
| PDF Parsing | PyMuPDF (fitz) + pypdf |
| PDF Export | ReportLab |
| Auth | JWT (python-jose) + bcrypt |
| Google OAuth | google-auth + google-api-python-client |
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS |
| HTTP Client | Axios / fetch |
- Email/password registration and login with bcrypt hashing and JWT tokens
- Google OAuth 2.0 β sign in with Google; OAuth tokens are stored encrypted in MongoDB and used for Google Calendar API calls
- All API routes are protected with JWT bearer token authentication
- Rate limiting via SlowAPI on sensitive endpoints
study-agent/
βββ agent/
β βββ graph.py # LangGraph topology definition
β βββ nodes.py # All node implementations
β βββ state.py # AgentState TypedDict
β βββ sufficiency_judge.py # RAG quality evaluator
β βββ tavily_search.py # Web search fallback
β βββ tools.py # search_notes, flashcards, study_plan, etc.
βββ routes/
β βββ auth.py # Register, login
β βββ chat.py # Chat endpoint (drives the LangGraph agent)
β βββ documents.py # Upload, list, delete documents
β βββ sessions.py # Start, end, list sessions
β βββ flashcards.py # List flashcards
β βββ export.py # PDF revision sheet export
β βββ google_oauth.py # Google OAuth flow
βββ db/
β βββ chroma.py # ChromaDB session collection manager
βββ utils/
β βββ embedder.py # Gemini embedding API wrapper
β βββ file_parser.py # PDF/DOCX/MD/TXT β LangChain Documents
β βββ chunker.py # Document chunking strategies
βββ frontend/ # Next.js application
βββ server.py # FastAPI app + lifespan startup
βββ models.py # Pydantic request/response models
βββ cleanup.py # Orphaned session cleanup job
Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.
