A Duolingo-style quiz system that generates interactive courses from PDFs
Project description
Quizzer
Quizzer turns PDFs into interactive, Duolingo-style courses you can study from the terminal.
It combines PDF ingestion, question generation, spaced repetition, adaptive difficulty, and lightweight gamification so a static document becomes something you can actually practice.
Built on the five pillars of the Duolingo Method: learn by doing, personalized learning, focus on what matters, stay motivated, feel the delight.
- Generate full courses from textbooks, manuals, lecture notes, or handouts
- Study with seven question types, from easy recognition to free recall
- Revisit the right material at the right time with SM-2 scheduling
- Chat with an in-context tutor after each question
- Keep momentum with XP, streaks, and lesson unlocking
Features
- PDF to course -- Drop in any PDF and generate a full course with 7 question types (true/false, multiple choice, matching, sorting, fill-in-the-blank, ordering, free recall)
- Spaced repetition -- SM-2 algorithm schedules reviews so you see material right before you'd forget it
- Adaptive difficulty -- Tracks your ability and picks questions in your zone of proximal development
- Scaffolded learning -- Questions progress from receptive (true/false) to productive (free recall) within each session
- Gamification -- XP, streaks, levels, and LLM-generated effort-based praise
- Tutor chat -- After any answer, type
/chatto open a multi-turn conversation with the LLM about the question, with the source page images as context - Review mode -- Interleaves due questions across completed lessons, with mistakes weighted 2x
- Any LLM backend -- Works with any OpenAI-compatible API endpoint
Requirements
- Python 3.14+
- An OpenAI-compatible LLM endpoint (local or remote)
Installation
Install from PyPI:
pip install quizzer-ai
Install from source:
git clone https://github.com/suncloudsmoon/quizzer.git
cd quizzer
pip install .
Quick start
quizzer
On first launch, Quizzer prompts you for an OpenAI-compatible endpoint, API key, and model name. After that, these commands drive the flow:
| Command | Description |
|---|---|
/create |
Generate a course from a PDF |
/study |
Study an existing course (in-progress shown first) |
/settings |
View or change LLM settings |
/help |
List available commands |
During a study session, after answering a question:
| Command | Description |
|---|---|
/chat |
Open a multi-turn tutor chat about this question |
/done |
Exit tutor chat and return to the quiz |
How it works
-
Course generation (
/create): Renders each PDF page as an image, sends it to a vision-capable LLM to triage and summarize content, then generates questions with calibrated difficulty. The result is a read-onlycourse.json. -
Study sessions (
/study): Builds a session from due questions, filtered by adaptive difficulty and scaffolded from easy/receptive to hard/productive. After each answer you rate your confidence; the system updates your spaced repetition schedule and ability estimate accordingly. You can then type/chatto discuss the question with an LLM tutor that has the source page images as context. -
Mistake resurfacing: Incorrect answers resurface at the end of the session for a second attempt.
-
Lesson progression: Lessons unlock linearly. Achieving 70%+ accuracy completes a lesson and unlocks the next.
-
Review: Once multiple lessons are complete, review mode interleaves due questions across all of them.
Why it feels different
Most PDF study tools stop at summarization. Quizzer is built around active recall instead:
- It asks you to answer, not just read
- It adapts question difficulty to your current ability
- It brings mistakes back before they disappear from memory
- It keeps each lesson moving from recognition toward recall
- It lets you open a tutor chat exactly when confusion happens
Example setup
This project has been tested with LM Studio using the lmstudio-community/ministral-3-8b-reasoning-2512 model for question generation. Note that course generation can take a long time depending on your hardware -- for a long book (~1000 pages), expect 12 hours or more.
Data storage
Quizzer uses platformdirs to store files in OS-standard locations:
| What | Path |
|---|---|
| Config | <config_dir>/quizzer/config.json |
| Courses | <data_dir>/quizzer/courses/<course-id>/course.json |
| Page images | <data_dir>/quizzer/courses/<course-id>/images/ |
| Learning progress | <data_dir>/quizzer/progress/<course-id>.json |
Typical platform directories:
| Platform | Config dir | Data dir |
|---|---|---|
| macOS | ~/Library/Application Support/quizzer |
~/Library/Application Support/quizzer |
| Linux | ~/.config/quizzer |
~/.local/share/quizzer |
| Windows | C:\Users\<user>\AppData\Local\suncloudsmoon\quizzer |
C:\Users\<user>\AppData\Local\suncloudsmoon\quizzer |
Project structure
src/quizzer/
app.py CLI entry point, config, LLM setup
quiz_creator.py PDF -> course JSON (offline, run once per document)
quiz_handler.py Serves questions at runtime
learner_state.py Per-learner runtime state (single JSON file)
paths.py Platform-specific paths via platformdirs
Dependencies
- Pydantic -- data models
- LlamaIndex -- LLM interface and structured output
- PyMuPDF -- PDF page rendering
- platformdirs -- platform-specific config/data directories
- tqdm -- progress bars during course generation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quizzer_ai-0.1.2.tar.gz.
File metadata
- Download URL: quizzer_ai-0.1.2.tar.gz
- Upload date:
- Size: 29.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e26a83177e877c0849ca88f93da7ed5fba14bdd28996b797a01c89d3e903ebc
|
|
| MD5 |
68fa2da21857bc6cece7322e79293557
|
|
| BLAKE2b-256 |
5609c650fc0d38b371e221109ab2c4efd0dff0605d4d31265cefd22fd38d37e3
|
Provenance
The following attestation bundles were made for quizzer_ai-0.1.2.tar.gz:
Publisher:
release.yml on suncloudsmoon/quizzer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quizzer_ai-0.1.2.tar.gz -
Subject digest:
0e26a83177e877c0849ca88f93da7ed5fba14bdd28996b797a01c89d3e903ebc - Sigstore transparency entry: 1241437386
- Sigstore integration time:
-
Permalink:
suncloudsmoon/quizzer@81714d8191e3c8eebc3ff65965233fcee3bc4749 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/suncloudsmoon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@81714d8191e3c8eebc3ff65965233fcee3bc4749 -
Trigger Event:
push
-
Statement type:
File details
Details for the file quizzer_ai-0.1.2-py3-none-any.whl.
File metadata
- Download URL: quizzer_ai-0.1.2-py3-none-any.whl
- Upload date:
- Size: 27.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0eba7cc843e7a03d12664e8feb1f5e8dab2324bffa67abedda76059c287de23
|
|
| MD5 |
292b12a46ab84a85511bd1a9e92a3263
|
|
| BLAKE2b-256 |
2c7c987a212e0622f16a42ce04125070ae5e50fb1d0600410cc54d58e2521a9f
|
Provenance
The following attestation bundles were made for quizzer_ai-0.1.2-py3-none-any.whl:
Publisher:
release.yml on suncloudsmoon/quizzer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
quizzer_ai-0.1.2-py3-none-any.whl -
Subject digest:
e0eba7cc843e7a03d12664e8feb1f5e8dab2324bffa67abedda76059c287de23 - Sigstore transparency entry: 1241437422
- Sigstore integration time:
-
Permalink:
suncloudsmoon/quizzer@81714d8191e3c8eebc3ff65965233fcee3bc4749 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/suncloudsmoon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@81714d8191e3c8eebc3ff65965233fcee3bc4749 -
Trigger Event:
push
-
Statement type: