Bridging the 1:58 Teacher-Student Gap Through AI Β· Built for the AI for Education Hackathon 2026
- The Problem
- The Solution
- Architecture
- Features
- Tech Stack
- Local Development
- Deployment
- File Structure
- API Documentation
- Contributing
- License
Kenya faces a critical STEM education challenge:
- 1:58 Teacher-to-Student Ratio β Average public secondary school has ~1,800 students with only ~30 teachers
- Language Barrier β All STEM materials are in formal English, but many students learn best in Swahili/Sheng
- Limited Resources β Rural schools lack qualified STEM teachers and learning materials
- Inconsistent Quality β Student outcomes depend heavily on which school/teacher they're assigned to
- No Personalized Learning β Teachers can't provide individual attention due to overcrowding
Impact: Students struggle with abstract concepts, fall behind, and lose interest in STEM careers.
Elimu AI ("Elimu" = "Education" in Swahili) is an AI-powered STEM tutor designed specifically for the Kenyan secondary school context. It bridges the gap between students and qualified teachers through:
-
π£οΈ Natural Code-Switching
- Seamlessly switches between Formal English, Kiswahili, and Sheng (Nairobi youth slang)
- Students learn in the language they think in
- Maintains scientific accuracy while being culturally authentic
-
π°πͺ Localized Analogies
- Explains abstract concepts using everyday Kenyan contexts
- Example: Newton's First Law β matatu behavior on Thika Road
- Example: Chemical reactions β cooking ugali (mixing ingredients, applying heat)
- Example: Probability β KCSE exam pass rates in your school
-
π Subject Coverage
- Mathematics (Form 1-4)
- Physics (Form 1-4)
- Chemistry (Form 1-4)
- Biology (Form 1-4)
- Computer Science (Form 3-4)
-
π Instant Quizzes
- AI generates 5-question multiple-choice quizzes aligned with KCSE standards
- Covers any topic discussed
- Instant grading with detailed explanations for wrong answers
- Helps reinforce learning through practice
-
π¬ Real-Time Streaming
- Responses stream token-by-token via Server-Sent Events (SSE)
- No waiting for full responses β students see thinking in real-time
- Feels like natural conversation with a tutor
-
π Persistent Chat History
- All conversations saved to MongoDB
- Students can continue learning across sessions
- No need to re-explain context
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend Layer (Vercel) β
β React 18 + Vite + Tailwind CSS β
β ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββββ
β βWelcomeScreen β ChatWindow β QuizPanel ββ
β β(subject/lang)β(SSE Stream) β(KCSE quiz) ββ
β ββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββββ
βββββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β HTTP + SSE
β
βββββββββββββββββββββββΌβββββββββββββββββββββββββββ
β Backend Layer (Render) β
β Node.js + Express.js (ES Modules) β
β βββββββββββββββββββββββββββββββββββββββββββββββ
β β REST API Routes ββ
β β β’ POST /api/chat/stream (SSE stream) ββ
β β β’ GET /api/sessions (fetch chats) ββ
β β β’ POST /api/quiz (generate) ββ
β β β’ DELETE /api/sessions/:id (clear) ββ
β βββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββββ
β β
ββββββββββΌβββββββββ ββββββββΌβββββββββββ
β Gemini 2.5 β β MongoDB Atlas β
β Flash API β β β
β (via Google β β Collections: β
β AI Studio) β β β’ sessions β
β β β β’ messages β
β Responsibilities: β β
β β’ AI explanations β β
β β’ Quiz generation β β
β β’ Code-switching β β
β β’ Analogies β β
βββββββββββββββββββ βββββββββββββββββββ
- Student asks question β Client sends to server
- Server validates β Checks session exists, adds to history
- Gemini processes β AI generates response with system prompt
- Streaming response β SSE sends chunks to client as they arrive
- Client displays β Real-time text appearing in chat
- Database saves β Full response persisted to MongoDB
- Student can continue β Query stored session for future interactions
The system uses a sophisticated prompt engineering approach:
System Instruction Includes:
"You are Elimu AI, a brilliant tutor for Kenyan secondary students.
For English mode:
- Use formal, academic language
- Align with Form 1-4 curriculum
For Kiswahili mode:
- Use clear Swahili (not English with Swahili words)
- Use scientific terms where Swahili equivalents don't exist
For Sheng mode:
- Mix English, Swahili, and authentic Nairobi Sheng
- Examples: 'Sawa fam', 'unaelewa?', 'poa sana'
- Keep scientific accuracy
Example Response:
"Sawa boss, let me explain velocity. Basically, ni distance divided by time, right?
Think of a matatu on Thika Road:
- Ikiwa inahama 100 km in 2 hours
- Velocity = 100/2 = 50 km/h
But poa β velocity has DIRECTION. So si ka speed tu.
Ikiwa driver anajazamuka East at 50 km/h, hiyo ni velocity.
Unaelewa the difference? Speed = scalar, velocity = vector. Sawa?
For each subject, the system includes context:
const SUBJECT_CONTEXTS = {
physics: "Use matatus, bodabodas, football, water flow",
chemistry: "Use cooking ugali, M-Pesa transactions, farm reactions",
biology: "Use shamba ecosystems, human body like a farm",
mathematics: "Use market pricing, M-Pesa, KCSE statistics",
};When explaining concepts, Gemini pulls from this context to create relatable examples.
Server Implementation:
export async function streamChat(messages, subject, languageMode) {
const stream = await chat.sendMessageStream(lastMessage);
// Streams chunks as they arrive from Gemini API
for await (const chunk of stream) {
res.write(`data: ${JSON.stringify({ text: chunk.text() })}\n\n`);
}
}Client Implementation:
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Append each chunk to display in real-time
fullMessage += decoder.decode(value);
}Benefits:
- β‘ No waiting for full response
- π― Engages students faster
- π± Better for slow internet (shows progress)
Flow:
- User clicks "π Generate Quiz" on any topic
- Server sends topic + subject to Gemini
- AI generates 5 KCSE-aligned multiple-choice questions
- Returns as JSON with explanations
- Client displays with instant grading
Gemini Prompt:
"Generate a 5-question KCSE-aligned quiz on [TOPIC] for Form [LEVEL] students.
Return JSON with:
- question (in chosen language)
- options (A, B, C, D)
- correctAnswer
- explanation (using local Kenyan context)"
- React 18 β UI framework with hooks
- Vite β Lightning-fast build tool & dev server
- Tailwind CSS v4 β Utility-first styling
- Zustand β Lightweight state management
- Lucide Icons β Beautiful, consistent icons
- Vite API URL β Environment-aware API configuration
- Node.js 20+ β Runtime
- Express.js β Minimal, unopinionated web framework
- ES Modules (ESM) β Modern JavaScript modules
- dotenv β Environment variable management
- Google Gemini 2.5 Flash β Latest, fastest Gemini model
- @google/generative-ai SDK β Official Google client library
- Server-Sent Events (SSE) β For real-time streaming
- MongoDB Atlas β Cloud MongoDB
- Mongoose β Object modeling for Node.js
- Automatic indexing β On sessionId, createdAt
- Docker β Containerization for consistent deployments
- Render β Backend deployment (Node.js service)
- Vercel β Frontend deployment (React app)
- pnpm β Fast, disk-space-efficient package manager
- ESLint β Code linting
- Vite Config β For both dev and production builds
- Morgan β HTTP logging
Before starting, ensure you have:
# Check Node.js version (need 20+)
node --version # v20.x.x or higher
# Install pnpm globally
npm install -g pnpm
# Verify pnpm
pnpm --version # 9.x.x or highergit clone https://github.com/your-username/elimu-ai.git
cd elimu-ai-
Gemini API Key (Free)
- Visit Google AI Studio
- Click "Create API Key"
- Copy the key
- Add to
.env
-
MongoDB Connection String (Free tier available)
- Go to MongoDB Atlas
- Create free cluster
- Get connection string
- Add to
.env
cd server
# Install dependencies
pnpm install
# Create .env file
cat > .env << EOF
GEMINI_API_KEY=your_api_key_here
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/elimu-ai
PORT=8080
NODE_ENV=development
CLIENT_URL=http://localhost:5173
EOF
# Start development server (with auto-reload)
pnpm devThe server will run at http://localhost:8080
Expected Output:
β
MongoDB connected
π Elimu AI Server running on port 8080
π€ Gemini model: gemini-2.5-flash
cd ../client
# Install dependencies
pnpm install
# Create .env file
cat > .env << EOF
VITE_API_URL=http://localhost:8080
EOF
# Start development server
pnpm devThe client will run at http://localhost:5173
Visit: Open browser to http://localhost:5173 and test! π
This is the recommended approach for this hackathon.
- Push to GitHub
git add .
git commit -m "Ready for deployment"
git push origin main-
Create Render Account
- Go to render.com
- Sign up with GitHub
- Authorize repository access
-
Deploy Server
- Click New + β Web Service
- Select your GitHub repository
- Fill in:
- Name:
elimu-ai-server - Environment:
Node - Build Command:
cd server && pnpm install - Start Command:
cd server && node src/server.js - Plan: Free tier is fine
- Name:
-
Add Environment Variables (in Render dashboard)
GEMINI_API_KEY = your_api_key MONGODB_URI = your_mongo_connection_string NODE_ENV = production -
Deploy β Click "Create Web Service"
- Wait 3-5 minutes for build/deploy
- Copy the service URL (e.g.,
https://elimu-ai-server.onrender.com)
-
Create Vercel Account
- Go to vercel.com
- Sign up with GitHub
- Authorize repository access
-
Import Project
- Click New Project
- Select your GitHub repository
- Configure:
- Framework: Vite
- Root Directory:
./client - Build Command:
pnpm build - Output Directory:
dist
-
Add Environment Variables
VITE_API_URL = https://elimu-ai-server.onrender.com(Use the Render server URL from previous step)
-
Deploy β Click "Deploy"
- Wait 2-3 minutes
- Get your Vercel URL (e.g.,
https://elimu-ai.vercel.app)
-
Update Server's CLIENT_URL
- Go back to Render dashboard
- Select
elimu-ai-server - Update environment variable:
CLIENT_URL = https://elimu-ai.vercel.app - Render auto-redeploys
- Open your Vercel URL
- Select subject and language
- Send a test message
- Verify chat works end-to-end β
elimu-ai/
βββ client/ # React frontend
β βββ src/
β β βββ components/
β β β βββ Chat/
β β β β βββ ChatWindow.jsx # Main chat interface
β β β β βββ InputBar.jsx # Message input
β β β β βββ MessageBubble.jsx # Chat bubble component
β β β β βββ TypingIndicator.jsx
β β β β βββ WelcomeScreen.jsx # Initial screen
β β β βββ Quiz/
β β β β βββ QuizPanel.jsx # Quiz interface
β β β βββ Sidebar/
β β β β βββ Sidebar.jsx # Subject selector
β β β βββ UI/
β β β βββ Navbar.jsx # Top navbar
β β βββ hooks/
β β β βββ useChat.js # Chat logic hook
β β βββ pages/
β β β βββ LandingPage.jsx # Marketing page
β β β βββ TutorPage.jsx # Main tutor interface
β β βββ store/
β β β βββ useTutorStore.js # Zustand state
β β βββ utils/
β β β βββ api.js # API client
β β βββ App.jsx # Router
β β βββ App.css # Global styles
β β βββ index.css # Tailwind import
β β βββ main.jsx # Entry point
β βββ index.html
β βββ Dockerfile # Container build
β βββ nginx.conf # Web server config
β βββ package.json
β βββ pnpm-lock.yaml
β βββ vite.config.js
β
βββ server/ # Express backend
β βββ src/
β β βββ controllers/
β β β βββ chat.controller.js # Chat endpoint handler
β β β βββ quiz.controller.js # Quiz generation
β β β βββ session.controller.js # Session management
β β βββ models/
β β β βββ Session.model.js # MongoDB schema
β β βββ routes/
β β β βββ chat.routes.js
β β β βββ quiz.routes.js
β β β βββ session.routes.js
β β βββ services/
β β β βββ gemini.service.js # AI logic
β β βββ server.js # Express app
β βββ Dockerfile # Container build
β βββ package.json
β βββ pnpm-lock.yaml
β βββ .env # Config (gitignored)
β
βββ docker-compose.yml # Local dev orchestration
βββ render.yaml # Render deployment config
βββ DEPLOYMENT.md # GCP deployment guide
βββ DEPLOY_VERCEL_RENDER.md # Vercel+Render guide
βββ README.md # This file
βββ .gitignore
βββ package.json # Root workspace
- Local:
http://localhost:8080 - Production:
https://elimu-ai-server.onrender.com
Streams AI responses via Server-Sent Events
Request Body:
{
"sessionId": "optional-session-id",
"message": "Explain momentum",
"subject": "physics",
"languageMode": "sheng"
}Subject Options: mathematics, physics, chemistry, biology, computer_science
Language Options: english, swahili, sheng
Response: Server-Sent Events stream
data: {"text":"Sawa "}
data: {"text":"boss"}
data: {"text":", let"}
...
data: {"done":true,"sessionId":"62a...","fullText":"Sawa boss, let me explain momentum..."}
Example cURL:
curl -X POST http://localhost:8080/api/chat/stream \
-H "Content-Type: application/json" \
-d '{
"message": "What is photosynthesis?",
"subject": "biology",
"languageMode": "sheng"
}'Fetch all sessions for a user
Query Parameters:
limit(optional, default: 10) β Number of sessions to returnskip(optional, default: 0) β Pagination offset
Response:
[
{
"_id": "62a...",
"subject": "biology",
"languageMode": "sheng",
"createdAt": "2026-04-25T10:30:00Z",
"messages": [
{
"role": "user",
"content": "What is photosynthesis?"
},
{
"role": "model",
"content": "Sawa boss, photosynthesis ni process..."
}
]
}
]Generate a quiz on a topic
Request Body:
{
"topic": "Newton's Laws of Motion",
"subject": "physics",
"languageMode": "english"
}Response:
{
"topic": "Newton's Laws of Motion",
"questions": [
{
"id": 1,
"question": "What does Newton's First Law state?",
"options": [
"A. F = ma",
"B. An object at rest stays at rest...",
"C. For every action...",
"D. Energy cannot be created..."
],
"correctAnswer": "B",
"explanation": "Newton's First Law is about inertia... (using Kenyan analogy)"
}
]
}Delete a chat session
Response:
{
"message": "Session deleted successfully",
"deletedId": "62a..."
}Found a bug? Please create an issue with:
- Steps to reproduce
- Expected behavior
- Actual behavior
- Screenshots if applicable
Have an idea? Open an issue with label enhancement and describe:
- Problem it solves
- How it works
- Why it's needed
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Write/update tests
- Commit (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use ESLint for code style
- Write meaningful commit messages
- Test locally before pushing
- Add comments for complex logic
This project is licensed under the MIT License β See LICENSE file for details.
- Google Gemini 2.5 Flash β Powering the AI tutor
- MongoDB Atlas β Database hosting
- Vercel & Render β Cloud hosting
- Kenyan Secondary School Curriculum β KCSE guidelines
- AI for Education Hackathon 2026 β For hosting this challenge
- Email: support@elimu-ai.app
- GitHub Issues: Report bugs here
- Documentation: This README +
/DEPLOYMENT.md
Made with β€οΈ for Kenyan Students π°πͺ export PROJECT_ID=your-gcp-project-id export REGION=us-central1
gcloud auth configure-docker ${REGION}-docker.pkg.dev
gcloud artifacts repositories create elimu-ai
--repository-format=docker
--location=$REGION
docker build -t ${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/server ./server docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/server
docker build
--build-arg VITE_API_URL=https://elimu-server-XXXX-uc.a.run.app
-t ${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/client ./client
docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/client
### Step 2 β Deploy Server
```bash
gcloud run deploy elimu-server \
--image=${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/server \
--region=$REGION \
--platform=managed \
--allow-unauthenticated \
--port=8080 \
--set-env-vars="GEMINI_API_KEY=your_key,MONGODB_URI=your_uri,NODE_ENV=production,CLIENT_URL=https://elimu-client-XXXX-uc.a.run.app"
gcloud run deploy elimu-client \
--image=${REGION}-docker.pkg.dev/${PROJECT_ID}/elimu-ai/client \
--region=$REGION \
--platform=managed \
--allow-unauthenticated \
--port=8080Buildathon/
βββ client/ # React + Vite + Tailwind CSS
β βββ src/
β β βββ components/ # Chat, Quiz, Sidebar, UI
β β βββ hooks/ # useChat
β β βββ pages/ # TutorPage
β β βββ store/ # Zustand global state
β β βββ utils/ # API calls (SSE + REST)
β βββ Dockerfile
β βββ nginx.conf
βββ server/ # Express.js API
βββ src/
β βββ controllers/ # chat, quiz, session
β βββ models/ # Session (MongoDB)
β βββ routes/ # /api/chat, /api/quiz, /api/sessions
β βββ services/ # gemini.service.js β core AI logic
βββ Dockerfile
| Metric | Our Approach |
|---|---|
| Originality | Code-switching + localized Kenyan analogies is unique in African EdTech |
| Execution | Full MERN stack, SSE streaming, MongoDB persistence, Dockerized Cloud Run |
| Real-world Impact | Directly addresses 1:58 teacher-student ratio with 24/7 AI availability |
| Google Cloud / AI | Gemini 2.0 Flash (AI Studio), Cloud Run, Artifact Registry |
Built with β€οΈ for Kenya at the AI for Education Hackathon 2026
"Elimu ni ufunguo wa maisha" β Education is the key to life π°πͺ