A modern web application that generates MCAT-style practice questions using AI. Built with Next.js (TypeScript) frontend and FastAPI backend. Users can specify a concept (e.g., "Acids and Bases") and the number of questions they want, and the system will generate discrete multiple-choice questions with explanations.
- Modern Tech Stack: Next.js 14+ with TypeScript, Tailwind CSS
- Clean Architecture: Reusable components, type-safe API calls, scalable structure
- MCAT-Style Questions: Generate discrete multiple-choice questions on any concept
- Customizable: Select number of questions (1-10)
- Beautiful UI: Modern, responsive design with gradient backgrounds
- Complete Questions: Includes answer choices, correct answers, explanations, and concept tags
- Next.js 14+ (App Router)
- TypeScript for type safety
- Tailwind CSS for styling
- React Hooks for state management
- FastAPI (Python)
- Pydantic for data validation
- OpenRouter API for AI question generation
- Node.js 18+ and npm
- Python 3.8+
- OpenRouter API key (Get one here)
- Clone the repository:
cd generate-questions- Backend Setup:
# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Python dependencies
pip install -r requirements.txt
# Set your OpenRouter API key
export OPENROUTER_API_KEY="your-api-key-here"- Frontend Setup:
cd frontend
# Install dependencies
npm install
# (Optional) Create .env.local file if you need to customize API URL
# NEXT_PUBLIC_API_URL=http://localhost:8000Option 1: Using startup scripts (recommended)
- Start the backend server (in one terminal):
./scripts/start-backend.sh- Start the frontend (in another terminal):
./scripts/start-frontend.shOption 2: Manual startup
- Start the backend server (from project root):
source venv/bin/activate # Activate virtual environment
cd backend
python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reloadThe backend will run on http://localhost:8000
- Start the frontend (in a new terminal):
cd frontend
npm run devThe frontend will run on http://localhost:3000
- Open your browser and navigate to:
http://localhost:3000
- Enter an MCAT concept or topic in the input field (e.g., "Acids and Bases", "Organic Chemistry", "Biochemistry")
- Select the number of questions you want to generate (1-10)
- Click "Generate Questions"
- View the generated questions with answer choices, correct answers, and explanations
generate-questions/
├── backend/
│ ├── main.py # FastAPI backend server
│ └── models/
│ ├── question.py # Question Pydantic model
│ └── user_query.py # UserQuery Pydantic model
├── frontend/
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx # Root layout
│ │ ├── page.tsx # Main page
│ │ └── globals.css # Global styles
│ ├── components/ # Reusable React components
│ │ ├── QuestionCard.tsx
│ │ ├── QuestionForm.tsx
│ │ ├── QuestionsList.tsx
│ │ ├── LoadingSpinner.tsx
│ │ └── ErrorMessage.tsx
│ ├── lib/ # Utility functions
│ │ ├── api.ts # API client
│ │ └── constants.ts # Constants
│ └── types/ # TypeScript types
│ └── index.ts
├── requirements.txt # Python dependencies
└── README.md # This file
The application uses SQLite to store:
- User Queries: Each concept search with number of questions requested
- Generated Questions: All questions with their answers, explanations, and categorization
Database file: backend/mcat_questions.db (created automatically on first run)
Generate MCAT questions based on user input and save to database.
Request Body:
{
"concept": "Acids and Bases",
"num_questions": 5
}Response:
[
{
"question_id": 1,
"created_at": "2024-01-01T12:00:00",
"question_text": "What is the pH of a 0.1 M solution of HCl?",
"answer_choices": ["1.0", "2.0", "7.0", "13.0"],
"correct_answer": "1.0",
"explanation": "HCl is a strong acid...",
"concept_tags": ["Acids", "pH", "Strong Acids"],
"subject": "General Chemistry",
"subject_subtopic": "Acid-Base Chemistry"
}
]Get all past queries (most recent first).
Query Parameters:
limit(optional): Maximum number of queries to return (default: 100)
Response:
[
{
"id": 1,
"concept": "Acids and Bases",
"num_questions": 5,
"created_at": "2024-01-01T12:00:00"
}
]Get all questions for a specific query.
Response: Array of Question objects
cd frontend
npm run dev # Start dev server
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLintsource venv/bin/activate # Activate virtual environment
cd backend
python -m uvicorn main:app --reload # Run with auto-reloadThis project is configured as a Vercel monorepo, deploying both frontend and backend together:
-
Push your code to GitHub
-
Import project to Vercel:
- Go to vercel.com
- Click "New Project"
- Import your repository
- Root Directory: Leave as root (don't set to
frontend) - Vercel will automatically detect the monorepo structure from
vercel.json
-
Configure Environment Variables in Vercel:
OPENROUTER_API_KEY: Your OpenRouter API keyNEXT_PUBLIC_API_URL: Set to/api(already configured in vercel.json)ALLOWED_ORIGINS: (Optional) Comma-separated list of allowed CORS origins- Any Supabase credentials if using Supabase:
SUPABASE_URLSUPABASE_KEY
-
Deploy:
- Vercel will automatically:
- Build the Next.js frontend from
frontend/ - Deploy Python serverless functions from
api/
- Build the Next.js frontend from
- The application will be available at
https://your-project.vercel.app - Frontend routes:
https://your-project.vercel.app/ - API routes:
https://your-project.vercel.app/api/*
- Vercel will automatically:
- Frontend: Next.js app in
frontend/directory - Backend: FastAPI app in
api/directory, wrapped as serverless functions - Configuration: Root
vercel.jsonhandles routing and builds - API Adapter:
api/[...path].pywraps FastAPI with Mangum for Vercel compatibility
The codebase follows best practices:
- DRY (Don't Repeat Yourself): Reusable components and utilities
- Type Safety: Full TypeScript coverage
- Scalable Architecture: Clear separation of concerns
- Clean Code: Well-organized components and functions
- The application uses OpenRouter API with GPT-4o-mini model
- Questions are generated as discrete (standalone) questions, not passage-based
- Make sure to set your
OPENROUTER_API_KEYenvironment variable before running - CORS is configured to allow requests from
localhost:3000(Next.js default port)