A role-based, source-grounded AI course assistant for university project courses. Professors create courses, upload materials, and invite students. Students ask AI questions inside module workspaces and get citation-backed answers from course documents.
| Name | GitHub | Responsibilities |
|---|---|---|
| Dipesh Gupta | dgupta98 |
Backend architecture, RAG pipeline, LLM integration (Anthropic Claude), embedding service, ChromaDB persistence, demo seed pipeline, cloud deployment (Render + Vercel), CI/CD, Docker setup, E2E tests, README |
| Rahul Reddy Chitla | rchitla62 |
Frontend features (settings navigation, user icon routing), test suite maintenance, FastAPI/httpx compatibility fixes, frontend startup improvements |
| Anand Kumar | akuma579 |
Settings pages (professor + student), password strength checklist, profile UI, professor dashboard course card UI |
| Vishesh Reddy Lekkala | vlekkal3 |
Document ingestion integration (post-upload RAG trigger) |
Repo: https://github.com/dgupta98/SER594-Team5-CourseCopilotAI
| Service | URL |
|---|---|
| Frontend (Vercel) | https://coursecopilotai.vercel.app/ |
| Backend API (Render) | https://ser594-team5-coursecopilotai.onrender.com |
| API Docs (Swagger) | https://ser594-team5-coursecopilotai.onrender.com/docs |
See the Cloud Deployment section for deployment instructions.
- Docker Desktop (latest stable)
- Docker Compose v2 (
docker compose) - Git
- Node.js and npm (optional on host — required only for host-side frontend build/test)
- An Anthropic API key (set
ANTHROPIC_API_KEYin.env)
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, React 19, TypeScript, Tailwind CSS |
| Backend | FastAPI (Python 3.11+), SQLAlchemy, SQLite |
| Auth | JWT (PyJWT), bcrypt |
| Vector Store | ChromaDB (Docker service locally; embedded mode on Render) |
| LLM | Anthropic Claude (claude-haiku-4-5-20251001) |
| Embeddings | fastembed (BAAI/bge-small-en-v1.5, ONNX — no torch) |
| Document Parsing | PyMuPDF, python-docx |
| Containerization | Docker, Docker Compose |
git clone https://github.com/dgupta98/SER594-Team5-CourseCopilotAI.git
cd SER594-Team5-CourseCopilotAI
cp .env.example .envEdit .env and set your Anthropic API key:
ANTHROPIC_API_KEY=sk-ant-...
./start.sh --buildThis builds Docker images and starts all services. Takes 2–3 minutes the first time.
| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:8000 |
| API Docs (Swagger) | http://localhost:8000/docs |
| ChromaDB | http://localhost:8001 |
./start.sh # start all services (fast, no rebuild)
./stop.sh # stop all services
./start.sh --build # rebuild images (needed after requirements.txt or package.json changes)┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Next.js │─────▶│ FastAPI │─────▶│ SQLite │
│ Frontend │ │ Backend │ │ Database │
│ :3000 │ │ :8000 │ └─────────────┘
└─────────────┘ └──────────────┘
│
├─────▶ ChromaDB :8001 (vector store, Docker-only)
│ OR embedded ChromaDB (Render / no Docker)
│
└─────▶ Anthropic Claude API (LLM)
ChromaDB runs as a separate Docker service locally (port 8001). When CHROMA_HOST is empty the backend uses ChromaDB in embedded persistent mode — no separate service needed (used on Render).
- JWT Auth — validates token from
Authorization: Bearerheader or cookie; attaches user to request state - Request Logging — structured JSON logs with method, path, user_id, status, and duration_ms
- Security Headers — X-Content-Type-Options, X-Frame-Options: DENY, HSTS
- Rate Limiting — 100 req/min general; 10 req/min for
/chat/ask; per-user sliding 60s window
.
├── start.sh # Start all Docker services
├── stop.sh # Stop all Docker services
├── docker-compose.yml
├── Dockerfile.render # Render-specific Dockerfile (bundles demo PDFs)
├── render.yaml # One-click Render backend deployment config
├── .env.example
├── CLAUDE.md # Developer reference (architecture, data flow, design decisions)
├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py # FastAPI app entry point
│ ├── config.py # Pydantic settings (reads from .env)
│ ├── database.py # SQLAlchemy engine + session factory
│ ├── auth/ # JWT guards (require_role, require_course_ownership, etc.)
│ ├── middleware/ # Auth, logging, rate limit, security headers
│ ├── models/ # SQLAlchemy ORM models + Pydantic schemas
│ │ └── db_models.py # includes DocumentChunk table for embedding persistence
│ ├── routers/ # auth, courses, modules, invitations, chat
│ ├── services/ # RAG pipeline, LLM, embeddings, chunking, vector store
│ └── tests/ # ~20+ test files covering all layers
└── frontend/
└── src/
├── app/
│ ├── page.tsx # Landing page
│ ├── login/ # Login page (includes one-click demo buttons)
│ ├── register/ # Register page (role selection)
│ ├── professor/
│ │ ├── dashboard/ # Owned courses (card grid UI)
│ │ ├── courses/ # Course detail, modules, students, invitations
│ │ └── settings/ # Profile + password change with strength checklist
│ └── student/
│ ├── dashboard/ # Enrolled courses + pending invitations
│ ├── courses/ # Module workspace (AI chat)
│ └── settings/ # Profile + password change with strength checklist
├── components/
│ ├── AppShell.tsx # App layout shell; user icon navigates to settings
│ └── NavBar.tsx # Responsive sidebar/hamburger with accessibility
├── contexts/
│ └── AuthContext.tsx # JWT auth state + auto-refresh + localStorage hydration
├── hooks/
│ ├── useAuth.ts
│ └── useConversation.ts # Chat state + optimistic message handling
├── lib/
│ └── api.ts # ApiClient (GET/POST/PUT/DELETE/uploadFile)
└── types/
└── index.ts # TypeScript interfaces mirroring all backend models
- Register / login as professor
- Create and manage courses (card-grid dashboard UI)
- Add and reorder modules within courses
- Upload documents (PDF, DOCX, TXT) to modules — processed asynchronously
- Invite students by email (7-day expiry, duplicate prevention)
- View enrolled students with Revoke access per student
- View and manage pending invitations
- Settings page: update profile and change password (with live password-strength checklist)
- Register / login as student
- Accept or decline course invitations from dashboard
- Browse enrolled courses and modules
- Ask AI questions in module workspace
- Get Markdown-rendered, citation-backed answers from course documents
- Inline citation badges
[1][2]with modal viewer showing source chunk text - Relative timestamps: just now / 5m ago / 2h ago / 3d ago
- Conversation history preserved across sessions
- Settings page: update profile and change password (with live password-strength checklist)
- Clicking the user avatar/icon in the app shell navigates directly to the settings page
- Responsive nav: hamburger menu on mobile, sidebar on desktop with focus trap and Escape-key close
Document ingestion:
- Upload returns immediately (status = PENDING); processing runs in background
- Text extracted per-page (PDF with slide title prefix), paragraph (DOCX), or raw (TXT)
- Semantic chunking: sentences embedded → cosine similarity → topic boundaries detected at 25th percentile threshold → 400–2000 char chunks
- Chunks and their embeddings saved to the
DocumentChunktable in the database for fast restore - Embeddings stored in ChromaDB, scoped per module
Question answering:
- Broad vs. specific detection → retrieval strategy:
- Broad: top_k=50, threshold=0.0
- Specific: top_k=5, threshold=0.4
- No relevant context → "insufficient information" response
- Ambiguous question → clarification response
-
10 chunks → K-means cluster by topic, top-3 per cluster
- Claude (
claude-haiku-4-5-20251001) generates answer with[Document: name, Chunk: N]citations - Citations extracted, stored as JSON, rendered as clickable badges in UI
LLM response modes (inferred from question phrasing):
| Mode | Template |
|---|---|
explain |
Key Idea / What This Means / Example / Check Your Understanding |
summary |
Overview / Topics Covered / Check Your Understanding |
step_by_step |
Numbered steps + worked example |
quiz |
3 self-check questions only |
default |
Conversational, no forced template |
- Open
http://localhost:3000 - Create an account from Register — select Professor to create courses, Student to join them
- Sign in from Login using email/password
- The frontend stores a JWT token in local storage (24h expiry, auto-refreshed when <1h remaining)
The primary AI feature is Retrieval-Augmented Generation (RAG).
Create two accounts to test the full workflow:
- Register and log in as Professor
- Create a course
- Add at least one module
- Upload one or more documents (
.pdf,.docx,.txt) - Send an invitation to a student email
- Register and log in as Student
- Accept the pending invitation from the dashboard
- Open the enrolled course → open the module workspace
- Ask a question about the uploaded documents
This exercises: authentication, course creation, module setup, document upload, asynchronous RAG processing, invitation handling, and AI question answering with citations.
When the backend starts for the first time it automatically seeds three demo accounts, two courses, and all course documents. No manual setup required.
| Role | Name | Password | Courses | |
|---|---|---|---|---|
| Professor | Prof Dr Ajay Bansal | prof@demo.coursepilot.com |
Demo@1234 |
SER-502, SER-594 |
| Student | Alex Chen | alex@demo.coursepilot.com |
Demo@1234 |
SER-502, SER-594 |
| Student | Sam Rivera | sam@demo.coursepilot.com |
Demo@1234 |
SER-502 only |
SER-502: Languages and Paradigms (professor-owned)
| Module | Document(s) |
|---|---|
| Module 1: Introduction | M1.1_Introduction.pdf |
| Module 2: Language Design Criteria | M1.2_Language_Design_Criteria.pdf |
| Module 3: Declarative Programming | M1.3_Declarative_Programming.pdf |
| Module 4: Logic Programming | M1.4_Logic_Programming.pdf |
SER-594: AI for Software Engineers (professor-owned)
| Module | Document(s) |
|---|---|
| Module 1: Machine Learning Overview | M1-ML_Overview.pdf |
| Module 2: Classification and Regression | M2-Classification_Regression_V1.pdf · M2-Classification_Regression_V2.pdf |
| Module 3: Features and Dimensionality Reduction | M3_FeaturesAndDimensionalityReduction.pdf |
| Module 4: Neural Networks | M4_NeuralNetworks.pdf |
PDFs are sourced from the SER-502/ and SER-594/ directories in the repo root, copied into the uploads tree, and ingested through the full RAG pipeline on first startup. The seed is resumable — if a restart interrupts it, it continues from where it left off rather than re-processing already-completed documents.
A render.yaml and Dockerfile.render are included for one-click Render deployment.
- Push the repo to GitHub.
- In the Render dashboard, choose New → Blueprint and point it at the repo — Render reads
render.yamlautomatically. - Set the following environment variables in the Render dashboard (not committed to the repo):
ANTHROPIC_API_KEY— your Anthropic keyALLOWED_ORIGINS— your Vercel frontend URL, e.g.https://coursecopilotai.vercel.app
- Deploy.
JWT_SECRETis auto-generated by Render.
Key differences from local Docker:
CHROMA_HOSTis empty → ChromaDB runs in embedded persistent mode (no separate service).DocumentChunktable persists chunk embeddings to the database, so ChromaDB is restored in seconds from the DB on every restart — no re-embedding cost.- The seed pipeline is resumable: interrupted seeding continues from the last completed document on the next restart.
- Import the repo on Vercel.
- Set the root directory to
frontend. - Add the environment variable:
NEXT_PUBLIC_API_BASE_URL=https://ser594-team5-coursecopilotai.onrender.com - Deploy.
Full reference (see .env.example for a ready-to-copy template):
| Variable | Default | Description |
|---|---|---|
APP_ENV |
development |
development or production |
DATABASE_URL |
sqlite:///./course_copilot.db |
SQLite (dev) or PostgreSQL URL (prod) |
JWT_SECRET |
— | Secret for signing JWTs; auto-generated by Render |
JWT_ALGORITHM |
HS256 |
JWT signing algorithm |
ACCESS_TOKEN_EXPIRE_MINUTES |
1440 |
Token lifetime (24 h) |
ANTHROPIC_API_KEY |
— | Required. Anthropic API key |
ANTHROPIC_MODEL |
claude-haiku-4-5-20251001 |
Claude model ID |
CHROMA_HOST |
`` (empty) | Empty → embedded ChromaDB; http://chromadb:8000 when using Docker Compose |
CHROMA_PERSIST_DIR |
./chroma_data |
Path for ChromaDB persistence |
ALLOWED_ORIGINS |
http://localhost:3000,... |
Comma-separated CORS origins; add Vercel URL for production |
UPLOAD_DIR |
./uploads |
Document upload directory |
MAX_FILE_SIZE_MB |
50 |
Maximum upload size |
NEXT_PUBLIC_API_BASE_URL |
http://localhost:8000 |
Backend URL seen by the browser |
# All backend tests
cd backend
pytest
# With coverage report
pytest tests/ --cov=app --cov-report=term-missing
# Specific file
pytest tests/test_chat_router.py -v
# Filter by name
pytest tests/ -k "rag" -v423 tests across 27 files covering every layer: auth, all routers, RAG pipeline (ingestion + MMR reranking), LLM service, chunking, embedding, vector store, text extraction, middleware, data models, and end-to-end workflows.
The Test Suite GitHub Actions workflow runs on every push and pull request:
black --check— enforces consistent formattingpytest --cov=app— runs all 423 tests with coverage report- Coverage XML uploaded as a downloadable artifact on each run
| Where to view | How |
|---|---|
| Live run logs + coverage summary | Actions tab → Test Suite → select run → backend-tests job |
| Coverage XML artifact | Actions tab → select run → scroll to Artifacts → download coverage-report |
The eval/ directory measures RAG pipeline quality using LLM-as-judge metrics across 8 fixed questions, with a zero-shot baseline comparison.
Pre-computed results are committed at eval/eval_results.json — inspect scores directly without running anything.
| Metric | RAG | Baseline | What it measures |
|---|---|---|---|
| Response Relevancy | 0.803 | 0.740 | Does the answer directly address the question? |
| Faithfulness | 0.797 | 0.000 | Are all claims grounded in retrieved course chunks? |
| Context Precision | 0.719 | 0.000 | Are the most relevant chunks ranked first? |
| Context Recall | 0.337 | 0.000 | Do the retrieved chunks cover the reference answer? |
Each question is run twice — RAG pipeline (embed → MMR rerank → generate with context) vs zero-shot baseline (no retrieval) — proving the concrete improvement retrieval provides.
No local setup needed. The workflow:
- Seeds an embedded ChromaDB with all 8 demo module PDFs
- Runs all 8 questions × 2 passes (RAG + baseline) — ~15–25 min
- Posts a formatted results table as the Job Summary
- Commits
eval/eval_results.jsonback to the repo automatically
| Where to view results | How |
|---|---|
| Formatted table (Job Summary) | Actions tab → RAG Evaluation → select run → Summary |
| Downloadable JSON | Actions tab → select run → Artifacts → eval-results |
| Committed JSON (permanent) | eval/eval_results.json in this repo |
# 1. Start all services (seeds ChromaDB with demo course data on first run)
./start.sh
# 2. Run the RAG evaluation (8 questions × RAG + baseline)
python eval/run_eval.py
# 3. Run system evaluation (latency p50/p95 + error rate)
python eval/system_eval.pySee eval/README.md for full methodology, metric definitions, and output format.
"Failed to fetch" on dashboard
docker compose ps # check all containers are Up
curl http://localhost:8000/health # check backend
./stop.sh && ./start.sh # restart if neededDocument stuck in PENDING/PROCESSING
docker compose logs backend --tail=50 # look for extraction or ChromaDB errors
# POST /documents/{id}/reprocess to retryAI responses not using document content
- Confirm document status is COMPLETE (visible in module documents list)
- Check that the question is specific enough — vague questions may return "insufficient information"
Anthropic API errors
- Verify
ANTHROPIC_API_KEYis set correctly in.env - Check the key has not expired or hit its usage limit
Need to rebuild after dependency changes
./stop.sh
./start.sh --buildView logs
docker compose logs backend --tail=50
docker compose logs frontend --tail=50Reset demo data (local)
./stop.sh
rm -f backend/course_copilot.db
rm -rf chroma_data
./start.sh --buildDeveloped as part of SER 594 coursework at Arizona State University.
