kela-quiz
A self-hosted multiple-choice quiz webapp for university exam practice.
Structure
kela-quiz/
├── knoledgebase/ # Source documents (PDF, DOCX, ODT) per professor
├── extraction/ # Python pipeline: documents → structured JSON
│ └── prompts/ # LLM prompt files (Markdown, one per prompt)
├── data/ # Extracted question JSON files (one per exam)
├── app/ # Svelte + Vite frontend
├── Dockerfile # Multi-stage build (Svelte → nginx)
└── docker-compose.yaml # Self-hosted deployment
Quickstart
1. Extract questions from source documents
cd extraction
pip install -r requirements.txtCopy the .env file and add your GitHub token:
cp .env .env # already exists — just edit itEdit extraction/.env:
GITHUB_TOKEN=your_token_here
Get your token at github.com/settings/tokens — it needs Copilot access.
Then run the extraction:
python extract.py --professor all --output-dir ../dataOptional flags:
--professor malusa— process a single professor instead of all--model claude-sonnet-4.6— choose which GitHub Copilot model to use (default:gpt-4o)
2. Run locally (dev)
cd app
npm install
npm run dev3. Deploy with Docker
docker compose up -dThe app is available at http://localhost:8080
Customising prompts
The LLM prompts used during extraction live in extraction/prompts/ as Markdown files. You can edit them without touching any Python code:
| File | Used for |
|---|---|
text_system.md |
System prompt for text document extraction (PDF, DOCX, ODT) |
text_user.md |
User message template for text extraction ({professor}, {source_file}, {text} placeholders) |
image_system.md |
System prompt for image/screenshot extraction |
image_user.md |
User message sent alongside each image |
After editing a prompt, just re-run the extraction pipeline — no rebuild required.
Adding new material
- Place new PDF/DOCX/ODT files in
knoledgebase/<professor>/ - Re-run the extraction pipeline
- Rebuild the Docker image:
docker compose up -d --build
On this page
Languages
Svelte43.8%Python41.0%Shell5.6%JavaScript4.7%CSS2.5%Dockerfile1.5%HTML0.9%
Contributors
Created March 11, 2026
Updated March 18, 2026