OOSC 4.0 — Problem Statement 2: AI for Equitable Education Access
PATHSHALA is a grounded AI learning system built around one idea: a student's question deserves an answer that can be checked, not just believed. Every explanation PATHSHALA gives is retrieved from real textbook material and cited by source and page — the same standard you'd expect from a good tutor, not a chatbot guessing in the dark.
It ships three connected agents, not three disconnected demos:
| Agent | What it does |
|---|---|
| 🔍 Grounded Doubt-Solving Agent | Answers a student's question using retrieval-augmented generation over an indexed textbook corpus, with visible citations (source file + page + exact snippet) and a confidence score. |
| 📝 Adaptive Practice Generator | Generates MCQ practice questions from the same corpus, auto-targeting whichever topic the student is currently weakest in, at a difficulty that follows their live mastery score. |
| 📊 Teacher-Facing Insight Agent | Turns every doubt and every practice attempt into a class-wide topic heatmap and a ranked "needs attention" list — so a teacher can see who's struggling before the next test does. |
They share one database, one mastery model, and one corpus — a student's practice history is what makes their next practice round adaptive, and what makes them show up on their teacher's dashboard. Nothing here is a disconnected point solution.
Quickstart • Why RAG • Architecture • Judging Criteria • Team
The distinction matters and it's checkable in under a minute:
- Ask PATHSHALA a question. The answer arrives with citations — the
exact
.txtfile (or PDF + page number, once you load real textbook PDFs) the answer was pulled from, and a verbatim snippet. - Embeddings run locally, via
sentence-transformers— no API call, no cost, works offline. Only the final answer synthesis calls an LLM, and that call is instructed to answer strictly from the retrieved context, not from what it memorized during training. - Ask something outside the corpus and PATHSHALA says so — it does
not fabricate an answer to look useful. Try it: ask about a topic
that isn't in
backend/app/data/corpus/and you'll get an honest "not found" rather than a hallucination.
This is what "citations to source" in the problem brief actually means in a shipped system, and it's the single easiest thing for a judge to verify live.
React frontend (Vite, JS)
│ HTTP requests, JWT in the Authorization header
▼
FastAPI backend
│
├── Routers auth · doubts · practice · insights · corpus
│ │
│ ▼
└── Services rag_service → ChromaDB (local vector store,
persisted to disk)
llm_service → Groq (free tier) or Anthropic
— one provider-agnostic adapter,
generation only, not retrieval
mastery_service → SQLite / Postgres
(users, mastery, attempts, doubts)
(A boxed version of this same diagram is in the accompanying setup guide document, verified page-by-page against a rendered PDF export.)
Zero-cost by default. SQLite and ChromaDB are both local files — no
managed database, no hosted vector DB subscription. The default LLM
provider is Groq's free tier, so the entire stack — auth, retrieval,
mastery tracking, the teacher dashboard, and generation — can run at
zero cost. Anthropic is supported as a drop-in alternative; switch with
one environment variable (LLM_PROVIDER) and nothing else in the
codebase changes, since every LLM call is routed through a single
provider-agnostic adapter in app/services/llm_service.py.
users— student or teacher, with role-gated access.doubts— every question asked, its answer, and its citations (stored as JSON so the full provenance trail is queryable later).practice_questions/attempts— generated questions and what the student answered, with correctness and timing.topic_mastery— one row per (student, subject, topic), holding an exponential moving average of correctness. This is the join between "what a student got wrong" and "what the teacher dashboard shows" and "what gets asked next" — seebackend/app/services/mastery_service.pyfor the exact update rule.
- ChromaDB over a linear similarity scan — a real ANN vector index, the same category of tool used in production RAG systems, rather than a keyword-match demo dressed up as AI.
- Local embeddings, API-only generation — retrieval keeps working even if the LLM API key or quota runs out; only the final synthesis step needs it. Keeps the zero-cost story honest.
- Paragraph-aware chunking with overlap — avoids losing context at
chunk boundaries (see
_chunk_textinrag_service.py). - Strict JSON-contract prompting for question generation — the LLM is told to return only a JSON array; the parser defensively strips stray markdown fences and falls back to regex extraction if the model wraps its output in prose anyway.
- EMA mastery over running accuracy — recent performance counts more than performance from weeks ago, and it's O(1) to update per attempt — the teacher dashboard stays fast as usage grows instead of re-scanning every historical attempt.
- Provider-agnostic LLM adapter — one function (
_complete()) normalizes Groq's and Anthropic's different request shapes, so the four call sites in the app never branch on provider.
pathshala/
├── backend/
│ ├── app/
│ │ ├── main.py FastAPI app, router wiring
│ │ ├── config.py All settings, loaded from .env
│ │ ├── database.py SQLAlchemy engine/session
│ │ ├── models/
│ │ │ ├── models.py ORM: User, Doubt, PracticeQuestion, Attempt, TopicMastery
│ │ │ └── schemas.py Pydantic request/response contracts
│ │ ├── routers/
│ │ │ ├── auth.py Signup / login
│ │ │ ├── doubts.py Grounded Doubt-Solving Agent
│ │ │ ├── practice.py Adaptive Practice Generator
│ │ │ ├── insights.py Teacher-Facing Insight Agent
│ │ │ └── corpus.py Corpus (re)ingestion, teacher-only
│ │ ├── services/
│ │ │ ├── rag_service.py Chunking, embedding, retrieval (ChromaDB)
│ │ │ ├── llm_service.py Provider-agnostic LLM adapter (Groq / Anthropic)
│ │ │ └── mastery_service.py EMA mastery tracking, weak-topic queries
│ │ ├── utils/
│ │ │ ├── security.py Password hashing (bcrypt), JWT
│ │ │ └── deps.py Auth dependencies (get_current_user, require_teacher)
│ │ └── data/
│ │ └── corpus/ Subject-organized source material (see below)
│ ├── scripts/
│ │ ├── ingest_corpus.py CLI: rebuild the vector index
│ │ └── seed_demo_users.py CLI: create demo teacher/student accounts
│ ├── requirements.txt
│ └── .env.example
├── frontend/
│ ├── src/
│ │ ├── pages/
│ │ │ ├── AuthPage.jsx Login / signup, with one-click demo fill
│ │ │ ├── DoubtsPage.jsx Ask-a-doubt UI with citation "margin notes"
│ │ │ ├── PracticePage.jsx Adaptive MCQ practice flow
│ │ │ └── TeacherDashboard.jsx Class heatmap + attention list
│ │ ├── components/TopNav.jsx
│ │ ├── AuthContext.jsx Session state (JWT in sessionStorage)
│ │ ├── api.js Typed fetch client for the backend
│ │ ├── App.jsx Routing, role-based landing page
│ │ └── styles.css Design tokens ("ruled textbook page" system)
│ ├── package.json
│ └── .env.example
├── demo_video_script.md Timed 3-speaker script for the submission video
└── README.md You are here
Requirements: Python 3.11+, Node 18+, a free Groq API key (or an Anthropic key, if you have credits).
cd backend
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .envEdit .env — default provider is Groq (free tier):
LLM_PROVIDER=groq
GROQ_API_KEY=gsk_... # get one free at https://console.groq.com/keysOr switch to Anthropic if you have credits:
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
LLM_MODEL=claude-sonnet-4-6Everything else has a working zero-cost default. Then:
python scripts/seed_demo_users.py # creates teacher@pathshala.demo / student@pathshala.demo, password: demo1234
python scripts/ingest_corpus.py # indexes backend/app/data/corpus/ into the local vector store
uvicorn app.main:app --reload --port 8000Backend is now live at http://localhost:8000. Interactive API docs
(auto-generated by FastAPI) are at http://localhost:8000/docs — useful
for judges who want to poke the API directly without the frontend.
In a second terminal:
cd frontend
npm install
cp .env.example .env.local # default already points at localhost:8000
npm run devFrontend is now live at http://localhost:5173.
Use the demo accounts seeded in step 1 (password demo1234 for both), or
sign up fresh from the UI:
teacher@pathshala.demo— lands on the class dashboard.student@pathshala.demo— lands on the ask-a-doubt page.
- As the student, ask: "Why do passengers fall forward when a bus stops suddenly?" (subject: Physics). Watch the citation appear underneath, pointing at the exact source passage.
- Go to Practice, leave the topic blank on your first round (type "Newton's First Law" to seed it), answer a couple of questions — deliberately get one wrong.
- Generate practice again with the topic blank. Notice it auto-selects the topic you got wrong, at an easier difficulty.
- Log in as the teacher. The class heatmap and the "needs attention" list now reflect that attempt in real time.
The repo ships with three original, hand-written subject notes (Physics —
Newton's Laws, Mathematics — Quadratic Equations, Biology —
Photosynthesis) under backend/app/data/corpus/<Subject>/ so the
prototype is fully runnable and demoable out of the box with zero setup.
To point PATHSHALA at real open-licensed textbook content (e.g. NCERT, which publishes textbooks under an open license for educational use):
- Download the relevant chapter PDFs.
- Drop them into
backend/app/data/corpus/<Subject>/(create the subject folder if it doesn't exist — the folder name becomes thesubjecttag used everywhere in the app). - Re-run
python scripts/ingest_corpus.py, or hit Rebuild knowledge base on the teacher dashboard — ingestion is idempotent, so re-running it is always safe.
Both .pdf (page-numbered citations) and .txt (source-only citations)
are supported.
Zero-cost hosting is possible in the same spirit as local dev:
- Backend — Render or Railway free tier. Set
GROQ_API_KEY(orANTHROPIC_API_KEY) andJWT_SECRETas environment variables. SQLite works for a demo; for anything beyond that, setDATABASE_URLto a managed Postgres instance (e.g. a free-tier Supabase or Neon database) — the code requires no changes, SQLAlchemy handles both identically. - Frontend — Vercel or Netlify free tier. Set
VITE_API_BASE_URLto the deployed backend URL. - Vector store — ChromaDB persists to a local disk directory
(
app/data/chroma_store/). On most free-tier hosts this directory is ephemeral across deploys — re-run ingestion after each deploy, or mount a persistent volume if the host supports one.
If no live link is available at judging time, the local-run instructions above are complete and sufficient — every step has been verified against a real running instance of both servers.
Being direct about these matters more than pretending they don't exist:
- Schema migrations — tables are created via
Base.metadata.create_all()on startup, fine for a hackathon timeline but a real deployment needs Alembic for versioned migrations. - Topic labels are LLM-generated free text, not a fixed taxonomy — two questions on the same concept could get slightly different topic strings (e.g. "Newton's First Law" vs "Newton's 1st Law of Motion"), which would fragment mastery tracking. A production version would normalize against a fixed syllabus topic list per subject.
- Practice generation retrieves the top-K chunks for a topic every time, which tends to pull the same passages when the same topic is requested, reducing novelty across repeated practice rounds. The fix is to remember which chunks were already used per student and vary retrieval away from them.
- No offline/low-bandwidth mode yet — relevant for the same under-resourced-school context this problem statement targets. A production version would cache the last N answers client-side and support a low-data mode.
- Single-language demo corpus —
preferred_languageis already wired through the schema and the prompt (respected byllm_service.synthesize_grounded_answer), but the demo corpus itself is English-only. Multilingual answers work today for any language the LLM supports, but retrieval quality across languages depends on how multilingual the underlying embedding model is, whichall-MiniLM-L6-v2only partially is. Swapping to a multilingual embedding model (e.g.paraphrase-multilingual-MiniLM-L12-v2) is a one-line config change for real multilingual deployment. - Groq free-tier rate limits — fine for a live demo, but tight compared to paid tiers. If you're stress-testing with large batch sizes during development, you may see occasional 429s; not a defect in the app.
| Criterion | Where |
|---|---|
| Innovation | Grounded RAG (not prompt-stuffed) doubt-solving with visible, checkable citations; mastery-driven adaptive difficulty; teacher dashboard fed by the same signal as the student experience — one coherent loop, not three demos. |
| Technical implementation | backend/app/services/rag_service.py (real vector search), mastery_service.py (EMA update rule), llm_service.py (provider-agnostic adapter), role-gated JWT auth, defensive LLM-output parsing. |
| Feasibility | Runs today on a laptop with a free-tier deploy path; zero infra cost beyond generation, and even that defaults to a free tier. |
| Scalability | ChromaDB + SQLite swap cleanly to a managed vector DB + Postgres with no code changes beyond DATABASE_URL — see Deploying. |
| Code quality | Typed Pydantic schemas end-to-end, service/router separation, inline rationale comments at every non-obvious design decision (not just what the code does, but why). |
| Documentation | This file, plus the accompanying setup guide document. |
| Presentation | See demo_video_script.md for the recommended 3-speaker walkthrough structure. |
Built by [FORNAX] — PSIT, Kanpur — for OOSC 4.0.
| Name | Focus area |
|---|---|
| [Siddhima Tiwari] | Backend / RAG pipeline |
| [Chandni Singh] | Frontend / product design |
| [Devansh Singh] | Data model / mastery logic / demo |
MIT — see LICENSE. Free to use, modify, and build on.