Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

⚡ CacheCourse

An asynchronous, multi-agent study pipeline that ingests PDF textbooks, maps their structure with Gemini, and warms exam-ready summaries with Groq — modelled on how a CPU cache works.

FastAPI React LangGraph MongoDB Gemini Groq


Table of Contents


What is CacheCourse?

CacheCourse is a full-stack AI study tool that borrows its vocabulary and mental model directly from CPU caching:

CPU Cache concept CacheCourse equivalent
Cold cache (compulsory miss) Section exists but no summary yet
Cache warming Groq is actively generating the summary
Cache hit Summary is ready and served instantly
Memory hierarchy Chapter → Subtopic → Leaf section
Eviction / writeback Re-processing a failed section

You upload a PDF textbook. Gemini reads the entire document and extracts its chapter/subtopic/section hierarchy into a structured JSON tree. Every exam-relevant leaf section is then queued through a LangGraph state machine that calls Groq's llama-3.1-8b-instant to generate:

  • A core concept summary (2–3 sentences)
  • Key definitions as term/definition pairs
  • Critical formulas as a list
  • One high-yield exam question with a model answer

Results are persisted incrementally to MongoDB so the React UI updates in real-time as each section warms — you never wait for the whole document to finish.


How it works

┌─────────────┐     PDF upload      ┌──────────────────┐
┌   Browser   │ ─────────────────▶  │   FastAPI /upload │
│  (React 18) │                     └────────┬─────────┘
└─────────────┘                              │ 202 Accepted (non-blocking)
      ▲                                      │
      │ poll /documents/:id                  ▼
      │ every 5 s                   ┌──────────────────────────────┐
      │                             │  BackgroundTask               │
      │                             │                              │
      │                             │  1. Gemini 2.0 Flash         │
      │                             │     PDF → JSON tree          │
      │                             │     (google-genai SDK)       │
      │                             │                              │
      │                             │  2. LangGraph StateGraph     │
      │                             │     ┌─────────┐             │
      │                             │     │iterator │             │
      │                             │     └────┬────┘             │
      │                             │          │ leaf queue       │
      │                             │     ┌────▼──────────┐      │
      │                             │     │  summarizer   │◀─┐   │
      │                             │     │  (Groq LLM)   │  │   │
      │                             │     └────┬──────────┘  │   │
      │                             │          │ more leaves? │   │
      │                             │          └─────────────┘   │
      │                             │                              │
      │                             │  3. Each leaf → MongoDB     │
      │                             │     cache_status: hit       │
      └─────────────────────────────┴──────────────────────────────┘

System Architecture

The CacheCourse application is split into a decoupled client-server architecture:

  1. Client-Side (React 18 + Vite):

    • Uses react-router-dom for application routing (Landing Page, Auth Forms, Dashboard feeds, and Split-screen Study workspaces).
    • Global states are separated: authentication details live in a standard React Context, while documents, loading states, and current active nodes reside in a high-performance Zustand store (docStore).
    • CSS modules isolate styles for components, preventing stylesheet collisions and supporting micro-animations like the signature cache-hit-reveal animation.
  2. Server-Side API Gateway (FastAPI):

    • Exposes public and protected endpoints behind JWT stateless token-verification routes.
    • Leverages uvicorn as the ASGI application server and uses async database lifespans to initialize collections and create database indexes.
  3. External Integrations & Workers:

    • Google Gemini 2.0 Flash: Processes uploaded PDFs on demand via the modern google-genai SDK to output structural JSON matching the textbook outlines.
    • LangGraph StateGraph: Orchestrates pipeline jobs. It utilizes stateless retry policies with exponential backoffs to query the Groq Llama API to compile chapter summaries, definitions, and formulas.
    • Motor (MongoDB Client): Performs async database executions, indexing user profiles and tracking individual document states, tree outlines, and leaf page content.

Directory Structure & Module Guide

The full codebase is structured as follows. Click on any file path to navigate directly to it in your local workspace:

CacheCourse/
├── server/                  FastAPI backend service
│   ├── app/                 Core application package
│   │   ├── core/            Security & Auth utilities
│   │   │   └── auth.py      JWT logic & password hashing
│   │   ├── models/          Pydantic validation schemas
│   │   │   ├── user.py      Schemas for user registration & login
│   │   │   └── document.py  User document & JSON tree outlines
│   │   ├── services/        External AI provider APIs
│   │   │   └── gemini.py    PDF uploading & structure parsing
│   │   ├── pipeline/        LangGraph orchestration
│   │   │   └── graph.py     State machine, iterator & summarizer nodes
│   │   ├── routers/         FastAPI route endpoints
│   │   │   ├── auth.py      /register and /login endpoints
│   │   │   └── documents.py /upload, document details, & RAG /chat endpoints
│   │   ├── config.py        pydantic-settings environment loader
│   │   └── database.py      Motor async MongoDB connection client
│   │   # Convenience shortcuts (Interface wrappers)
│   │   ├── auth.py          Shortcut to core auth helpers
│   │   ├── models.py        Shortcut to models schemas
│   │   ├── gemini_service.py Shortcut to gemini service
│   │   └── graph.py         Shortcut to LangGraph graph builders
│   └── main.py              FastAPI server creation & database lifespans
│
└── client/                  React frontend application
    └── src/                 Application source code
        ├── lib/             Custom axios network client
        │   └── api.js       Axios instance with JWT interceptors
        ├── context/         Context wrappers
        │   └── AuthContext.jsx React Auth state & session handler
        ├── store/           Zustand state management
        │   └── docStore.js  Zustand document list & upload states
        ├── components/      Reusable UI elements
        │   ├── ProtectedRoute.jsx Guard for private pages
        │   ├── UploadZone.jsx   Drag-and-drop PDF component
        │   ├── UploadZone.module.css Styles for uploads
        │   ├── TreeOutline.jsx  Recursive outlines navigation
        │   ├── TreeOutline.module.css Styles for tree navigation
        │   ├── SummaryPanel.jsx Reveals summaries, definition lists & formulas
        │   ├── SummaryPanel.module.css CSS with custom cache-hit-reveal animation
        │   ├── ChatPanel.jsx   Chat interface panel with textbook assistant
        │   └── ChatPanel.module.css Styles for chatbot panels
        ├── pages/           Router navigation page view roots
        │   ├── LandingPage.jsx  Animated hero landing with SVG schematic tree
        │   ├── LandingPage.module.css Styles for landing page
        │   ├── AuthPage.jsx     Login / Register unified entry form
        │   ├── AuthPage.module.css Styles for auth page
        │   ├── DashboardPage.jsx Displays document feeds and upload zones
        │   ├── DashboardPage.module.css Styles for dashboard page
        │   ├── StudyPage.jsx    Split-screen workspace (tree + details panel + chatbot)
        │   └── StudyPage.module.css Styles for study page
        ├── App.jsx          Application router & paths registry
        ├── App.css          Generic base rules
        ├── index.css        Global CSS containing variables & typography definitions
        └── main.jsx         React app launcher

Module Descriptions & Roles

🔑 Core Security & Schemas

  • server/app/core/auth.py: Handles stateless JWT token encoding, decoding, token expiration, password salting/hashing via passlib[bcrypt], and FastAPI dependency injection (get_current_user) to authenticate incoming HTTP requests.
  • server/app/models/user.py: Validates credentials for registration (UserRegister) and authentication logins (UserLogin).
  • server/app/models/document.py: Represents the recursive nodes of the textbook structure (TreeNode), the document summary metadata (DocumentListItem), and full details containing nested summaries (DocumentOut).

📡 Gateways, Services, and Configuration

  • server/app/config.py: Automatically reads variables from server/.env with pydantic-settings. Config values are validated and cached to prevent redundant disk access.
  • server/app/database.py: Establishes async MongoDB connections using motor.motor_asyncio. Creates unique indexes on application startup (e.g., users.email and documents.user_id).
  • server/app/services/gemini.py: Handles textbook processing using the official google-genai SDK. It uploads the raw PDF to Google AI Studio and invokes Gemini 2.0 Flash with a structured instruction to return a fully formatted outline tree matching the Pydantic structure.
  • server/app/pipeline/graph.py: Implements the stateful StateGraph worker using LangGraph. After the PDF tree structure is created, the graph collects all exam-relevant leaf sections and loops over them, calling the Groq API (llama-3.1-8b-instant) to "warm" each node with structured core concepts, formulas, and mock questions.

🔀 Route Controllers

  • server/app/routers/auth.py: Defines the /api/register and /api/login endpoints.
  • server/app/routers/documents.py: Manages documents (uploading PDFs, listing documents, fetching outline detail states) and handles chatbot requests by scanning the pages collection and calling the LLM context.
  • server/main.py: Sets up the FastAPI application context, registers routers, handles CORS validation, and initializes/terminates the database motor client connections.

⚛️ Client Infrastructure & Layouts

  • client/src/lib/api.js: A preconfigured Axios client that intercepts outgoing HTTP requests to append the Authorization: Bearer <token> header if a user is logged in. It also detects 401 Unauthorized responses to clear local storage and redirect the user back to the login screen.
  • client/src/context/AuthContext.jsx: Tracks active user states and sessions, exposing login, register, and logout hooks to the components.
  • client/src/store/docStore.js: A global state store using Zustand. Avoids prop-drilling by managing uploaded documents lists, processing status, and the currently active node details.
  • client/src/pages/LandingPage.jsx: Implements a beautiful drafting-table styled landing page featuring a custom SVG schematic diagram of the cache states (Cold, Warming, Hit) to explain the core CPU-cache analogy.

🧩 Reusable View Components

  • client/src/components/TreeOutline.jsx: Renders a collapsible tree outline of the textbook structure. Highlights the cache state of each node (Cold vs. Warming vs. Hit) and lets users click exam-relevant leaves.
  • client/src/components/SummaryPanel.jsx: Renders summaries, key terms, equations, and mock questions. Uses the cache-hit-reveal animation to transition newly warmed sections into display.
  • client/src/components/ChatPanel.jsx: Renders an inline chat window. Users can ask queries about specific nodes or the whole textbook, generating real-time responses from the RAG engine.
  • client/src/components/UploadZone.jsx: A drag-and-drop zone that handles uploading PDF textbooks to the backend server with dynamic progress bars.

Tech stack

Backend

Layer Technology Purpose
Framework FastAPI 0.115 + uvicorn Async HTTP, dependency injection
Database MongoDB Atlas via motor 3.6 Async document store
Auth PyJWT 2.10 + passlib[bcrypt] Stateless JWT, bcrypt password hashing
Config pydantic-settings 2.6 Typed env var loading with .env support
AI — structure google-genai 1.0 Modern Gemini SDK (not deprecated generativeai)
AI — summaries langchain-groq 0.2 Groq LLM calls via LangChain
Orchestration langgraph 0.2 Stateful multi-node pipeline with RetryPolicy
File upload python-multipart Multipart form parsing

Frontend

Layer Technology Purpose
Framework React 18 + Vite 5 Component UI + fast HMR dev server
Routing react-router-dom v6 Client-side routing with nested routes
HTTP axios 1.7 JWT interceptor, 401 auto-redirect
State React Context + Zustand 5 Auth state (Context), doc state (Zustand)
Icons lucide-react 0.447 Crisp SVG icon set
Fonts Space Grotesk, Inter, JetBrains Mono Display, body, and monospace faces

Prerequisites

Tool Minimum version Notes
Python 3.12+ 3.14 works; uses set | None union syntax
Node.js 18 LTS+ Required for Vite + npm
MongoDB Atlas any Free M0 tier works fine
Gemini API key Google AI Studio → aistudio.google.com
Groq API key console.groq.com

Note: uv is used in the server directory for virtual environment management. If you don't have it, use python -m venv .venv instead.


Environment variables

server/.env

Copy server/.env.exampleserver/.env and fill in every value:

# MongoDB Atlas connection string
MONGODB_URI=mongodb+srv://<user>:<password>@<cluster>.mongodb.net/?retryWrites=true&w=majority

# Database name (created automatically)
DB_NAME=cachecourse

# JWT signing secret — generate with: python -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=change_me_to_a_long_random_string_at_least_32_chars

# Google AI Studio key (for Gemini 2.0 Flash)
GEMINI_API_KEY=your_gemini_api_key_here

# Groq Cloud key (for llama-3.1-8b-instant)
GROQ_API_KEY=your_groq_api_key_here

# Maximum allowed PDF size in megabytes
MAX_PDF_SIZE_MB=50
Variable Required Default Description
MONGODB_URI Atlas connection string
DB_NAME cachecourse MongoDB database name
SECRET_KEY 32+ char random string for JWT signing
GEMINI_API_KEY Google AI Studio API key
GROQ_API_KEY Groq Cloud API key
MAX_PDF_SIZE_MB 50 Upload size limit

client/.env

# Base URL for the FastAPI backend (no trailing slash)
VITE_API_BASE_URL=http://localhost:8000

In development the Vite proxy (vite.config.js) forwards /api requests to http://localhost:8000, so this variable is only needed for production builds.


Installation

Backend setup

# 1. Navigate to server directory
cd server

# 2. Create and activate virtual environment
uv venv
.venv\Scripts\activate        # Windows
# source .venv/bin/activate   # macOS / Linux

# 3. Install all dependencies
pip install -r requirements.txt

# 4. Create your env file
copy .env.example .env        # Windows
# cp .env.example .env        # macOS / Linux

# 5. Fill in your real values in .env

requirements.txt (all pinned)

fastapi==0.115.5
uvicorn[standard]==0.32.1
motor==3.6.0
pydantic==2.10.3
pydantic-settings==2.6.1
PyJWT==2.10.1
passlib[bcrypt]==1.7.4
bcrypt==4.2.1
python-multipart==0.0.18
langgraph==0.2.60
langchain-core==0.3.27
langchain-groq==0.2.3
langchain-google-genai==2.0.8
google-genai==1.0.0
groq==0.13.0
pymongo==4.10.1

Frontend setup

# 1. Navigate to client directory
cd client

# 2. Install Node dependencies
npm install

# 3. (Optional) set env vars for local dev
copy .env.local.example .env.local   # or just edit .env.local directly

package.json key dependencies

{
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.26.2",
    "axios": "^1.7.7",
    "lucide-react": "^0.447.0",
    "zustand": "^5.0.0"
  }
}

Running the application

Development (two terminals)

Terminal 1 — Backend

cd server
.venv\Scripts\activate
uvicorn main:app --reload --port 8000

The API is now live at http://localhost:8000. Interactive docs at http://localhost:8000/docs.

Terminal 2 — Frontend

cd client
npm run dev

The React app is now at http://localhost:5173. The Vite proxy forwards all /api/* requests to the FastAPI server, so there are no CORS issues in dev.

Production

# Backend — run without --reload, behind a reverse proxy (nginx / Caddy)
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

# Frontend — build static assets, serve from CDN or reverse proxy
cd client
npm run build        # outputs to client/dist/

API reference

All protected routes require the Authorization: Bearer <token> header.

Auth

Method Endpoint Auth Body Response
POST /api/register { email, password } { access_token, token_type, user_id, email }
POST /api/login { email, password } { access_token, token_type, user_id, email }

Documents

Method Endpoint Auth Body Response
POST /api/upload multipart/form-data (field: file) { document_id, status } — 202 Accepted
GET /api/documents DocumentListItem[] (no tree_data)
GET /api/documents/:id Full DocumentOut with tree_data
POST /api/documents/:id/chat { message: string, history: ChatMessage[] } { response: string, citations: string }

Health

Method Endpoint Response
GET /health { "status": "ok" }

Document status values

Status Meaning
processing_structure Gemini is reading the PDF and extracting the hierarchy
processing_summaries LangGraph is warming leaf sections with Groq
complete All exam-relevant sections have been summarized
failed An unrecoverable error occurred (see error field)

Database schema

Collection: users

{
  "_id": "ObjectId",
  "email": "string (unique indexed)",
  "hashed_password": "string (bcrypt)",
  "created_at": "ISODate"
}

Collection: documents

{
  "_id": "ObjectId",
  "user_id": "string (indexed)",
  "pdf_name": "string",
  "upload_date": "ISODate",
  "status": "processing_structure | processing_summaries | complete | failed",
  "error": "string | null",
  "tree_data": [
    {
      "id": "string (unique within doc)",
      "title": "string",
      "level": 1,
      "page_start": 1,
      "page_end": 24,
      "is_exam_relevant": true,
      "cache_status": "cold | warming | hit",
      "summary": null,
      "children": [
        {
          "id": "string",
          "title": "string",
          "level": 2,
          "page_start": 3,
          "page_end": 10,
          "is_exam_relevant": true,
          "cache_status": "hit",
          "summary": {
            "core_concept": "string",
            "key_definitions": [{ "term": "string", "definition": "string" }],
            "critical_formulas": ["string"],
            "exam_question": {
              "question": "string",
              "answer": "string"
            }
          },
          "children": []
        }
      ]
    }
  ]
}

Indexes created automatically on startup: users.email (unique), documents.user_id.


LangGraph pipeline

The pipeline lives in server/app/pipeline/graph.py and runs entirely in the background after upload.

                    ┌──────────────┐
    START ─────────▶│   iterator   │
                    └──────┬───────┘
                           │ Walk tree, collect all
                           │ is_exam_relevant=true leaves
                           │ Set status = processing_summaries
                           ▼
                    ┌──────────────┐   queue not empty
                    │  summarizer  │◀──────────────────┐
                    │  (Groq LLM)  │                   │
                    └──────┬───────┘                   │
                           │                           │
                     ┌─────▼──────┐        ┌──────────┴──────────┐
                     │  complete? │──yes──▶│  complete node      │
                     └─────┬──────┘        │  status = complete  │
                           │ no            │  or failed          │
                           └───────────────┘         │
                                                      ▼
                                                     END

RetryPolicy (on summarizer node)

RetryPolicy(
    max_attempts=5,
    initial_interval=2.0,   # seconds before first retry
    backoff_factor=2.0,     # doubles each retry: 2 → 4 → 8 → 16 → 32 s
    max_interval=60.0,      # caps at 60 s
    retry_on=Exception,     # catches 429, 5xx, timeouts, JSON parse errors
)

Groq prompt schema (structured JSON output)

{
  "core_concept": "2–3 sentence explanation",
  "key_definitions": [{ "term": "...", "definition": "..." }],
  "critical_formulas": ["formula or principle as plain string"],
  "exam_question": {
    "question": "high-yield exam question",
    "answer": "model answer"
  }
}

Academic Chatbot and RAG Engine

The chatbot feature inside the Study Workspace allows users to hold dynamic, context-aware conversations with their uploaded documents.

RAG System Design & Workflow

 ┌──────────────┐     Post Chat Message     ┌────────────────────────┐
 │   Browser    │ ────────────────────────▶ │ POST /documents/:id/   │
 │ (ChatPanel)  │                           │ chat                   │
 └──────────────┘                           └───────────┬────────────┘
        ▲                                               │
        │                                               │ 1. Fetch PDF pages
        │                                               ▼
        │                                   ┌────────────────────────┐
        │                                   │    MongoDB database    │
        │                                   └───────────┬────────────┘
        │                                               │
        │                                               │ 2. Scrape matching context
        │                                               ▼
        │                                   ┌────────────────────────┐
        │                                   │  BM25-like Scorer      │
        │                                   │  (Term overlaps)       │
        │                                   └───────────┬────────────┘
        │                                               │
        │                                               │ 3. Build detailed prompt
        │                                               ▼
        │                                   ┌────────────────────────┐
        │                                   │ Groq Llama 3.3 (70B)   │
        │                                   └───────────┬────────────┘
        │                                               │
        │ 5. Returns formatted response & citations     │ 4. Fallback (if Groq fails)
        │                                               ▼
        └─────────────────────────────────────────────── Gemini 2.5 Flash
  1. Retrieval: When a query is made, the backend fetches the stored raw text pages of the document from the MongoDB collection.
  2. Scoring & Context Formulation: It scores each page using a simple, token-overlap BM25-like matcher:
    • Excludes short words (< 4 chars).
    • Counts match frequencies of each term.
    • Slices the top 5 most relevant pages and formats them as standard context blocks.
  3. Agent Framing: The chatbot agent acts as an encouraging, empathetic, and thorough academic mentor. It uses positive reinforcement to comfort the student, and outputs detailed structural markdown (including lists, bold sections, and citations like pp. 12, 15).
  4. Resilient Gateway Execution:
    • Primary Model: llama-3.3-70b-versatile on Groq (temperature 0.4, max tokens 2048).
    • Fallback Model: gemini-2.5-flash on Google Gemini (triggered if Groq meets rate limits or network issues).

Frontend design system

Color palette

Token Hex Usage
--bg-void #05060a Page background
--bg-deep #0b0d14 Header, sidebar
--bg-surface #181c2a Cards, inputs
--accent-plasma #6c63ff Primary CTA, active states
--accent-hit #00e5a0 Cache hit indicator, formulas
--accent-warm #f59e0b Warming / in-progress state
--accent-cold #475569 Cold / unprocessed indicator
--accent-danger #ef4444 Error states

Typography

Role Font Usage
Display Space Grotesk Headings, brand name, section titles
Body Inter Paragraphs, labels, UI copy
Mono JetBrains Mono Badges, metadata, formulas, hints

Signature interaction: cache-hit reveal

When a leaf section finishes processing and the user clicks it, the summary panel plays cache-hit-reveal — a scale-up + glow animation that mimics data appearing in L1 cache. Every other animation in the UI is deliberately restrained to keep this moment memorable.

@keyframes cache-hit-reveal {
  0%   { opacity: 0; transform: scale(0.95); box-shadow: none; }
  60%  { box-shadow: 0 0 20px rgba(0, 229, 160, 0.2); }
  100% { opacity: 1; transform: scale(1); }
}

Accessibility

  • All interactive elements have id attributes, aria-label, and aria-expanded/aria-current where applicable
  • Keyboard navigation supported across the tree outline and auth forms
  • prefers-reduced-motion media query disables all animations globally when enabled

Cache status model

Upload complete
     │
     ▼
 [cold] ─────── Gemini extracts tree ──────▶ tree_data written to MongoDB
                                                       │
                                            LangGraph picks up leaf
                                                       │
                                                       ▼
                                                 [warming]   ← set before Groq call
                                                       │
                                              Groq returns JSON
                                                       │
                                                       ▼
                                                  [hit] ───▶ summary saved, UI updates

The frontend polls GET /api/documents/:id every 5 seconds while the document is in a processing state and updates the tree outline indicators in real-time without a full page reload.


Rate limiting and retries

Provider Model Default TPM Mitigation
Groq llama-3.1-8b-instant 6 000 tokens/min (free tier) LangGraph RetryPolicy with exponential backoff
Gemini gemini-2.5-flash 15 RPM (free tier) Single call per upload; no retry needed for structure extraction

For high-volume deployments, switch the Groq node to use a langchain_groq model with langchain_core's built-in rate-limit aware callbacks, or route through LiteLLM for provider-agnostic load balancing.


Security

  • Passwords hashed with bcrypt (cost factor 12 via passlib default) — raw passwords are never logged or stored
  • JWTs are signed with HS256 and expire in 7 days by default (ACCESS_TOKEN_EXPIRE_MINUTES=10080)
  • The SECRET_KEY must be at least 32 random bytes — generate one with:
    python -c "import secrets; print(secrets.token_hex(32))"
  • MongoDB queries always filter by user_id to prevent cross-user data access
  • PDF size is capped at MAX_PDF_SIZE_MB (default 50 MB) before bytes are read into memory
  • CORS is locked to localhost:5173 and localhost:3000 in development — tighten to your production origin before deploying
  • .env is in .gitignore — never commit real credentials

Contributing

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/my-change
  3. Make your changes — keep backend and frontend concerns separated
  4. Run the server: uvicorn main:app --reload and verify the /docs UI
  5. Run the client: npm run dev and verify your UI changes
  6. Open a pull request with a clear description of what changed and why

Built with ⚡ FastAPI · 🧠 LangGraph · 🤖 Gemini + Groq · ⚛️ React

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages