SQLite database for tracking SRS learning state with FSRS and Ebisu algorithms
Project description
srsdb
A Python library for managing Spaced Repetition System (SRS) learning data using SQLite. Track the state of individual learning items with sophisticated scheduling algorithms.
Features
- 🧠 Multiple SRS Algorithms: FSRS (deterministic) and Ebisu (Bayesian)
- 💾 SQLite Backend: Persistent storage with flexible schema
- 📊 Detailed Tracking: Monitor difficulty, stability, review history, and more
- 🔄 Flexible Correctness: Rate answers on a 0-100 scale
- 🧪 Well Tested: Comprehensive test suite with 35+ unit tests
- 🐍 Python 3.8+: Compatible with modern Python versions
- 🔌 Optional Dependencies: Use FsrsDatabase without any dependencies, add Ebisu when needed
Installation
pip install -e .
Or for development:
pip install -e ".[dev]"
Example Databases
Explore pre-built example databases in the example/ directory:
example/fsrs.db- Spanish vocabulary learning with FSRS (10 cards, 25 reviews)example/ebisu.db- Python programming concepts with Ebisu (10 cards, 44 reviews)
# View statistics
python example/view_stats.py
# Regenerate examples
python example/generate_examples.py
# Explore with SQLite
sqlite3 example/fsrs.db "SELECT * FROM fsrs_cards;"
See example/README.md for more details.
Quick Start
from datetime import datetime
from fsrs_database import FsrsDatabase
# Create a database instance
db = FsrsDatabase("my_learning.db")
# Record answering a question
now = datetime.now()
db.answer(now, "question_id_1", correctness=85) # 85% correct
# Get cards that are due for review
due_cards = db.next(now)
print(f"Cards to review: {due_cards}")
# Check when the next review is scheduled
next_review = db.next_due_date()
print(f"Next review: {next_review}")
Interface: SrsDatabase
The SrsDatabase abstract base class defines the interface for all SRS implementations:
Constructor
SrsDatabase(database_file: str)
Initializes the database with a file path. The file is created if it doesn't exist.
Methods
answer(now: datetime, question_key: str, correct: int) -> None
Records the result of answering a question.
Parameters:
now: The time the question was answered (doesn't have to be real-time, useful for testing)question_key: Unique identifier for the questioncorrect: Correctness value from 0-1000= completely wrong100= completely correct- Values in between = degrees of correctness
The correctness value is internally converted to an appropriate value for the underlying SRS algorithm.
next(now: datetime) -> List[str]
Returns questions that are due for review as of the given time.
Parameters:
now: The current time to check against
Returns:
- List of question keys in chronological order of due date
next_due_date() -> Optional[datetime]
Returns the date/time when the next question becomes due.
Returns:
- The next due date, or
Noneif no questions are scheduled
Implementation: FsrsDatabase
The FsrsDatabase class implements the SrsDatabase interface using the FSRS algorithm, which tracks:
- Difficulty: How hard the card is (0-10 scale)
- Stability: Memory stability in days
- State: Card state (new, learning, review, relearning)
- Review History: Complete history of all reviews
- Lapses: Number of times the card was forgotten
Example Usage
from datetime import datetime, timedelta
from fsrs_database import FsrsDatabase
# Initialize database
db = FsrsDatabase("flashcards.db")
# Day 1: Learn new cards
day1 = datetime(2024, 1, 1, 10, 0, 0)
db.answer(day1, "spanish_hello", 90) # Got it right!
db.answer(day1, "spanish_goodbye", 60) # Mostly correct
db.answer(day1, "spanish_please", 20) # Need more practice
# Day 2: Review due cards
day2 = day1 + timedelta(days=1)
due = db.next(day2)
print(f"Cards due: {due}") # ['spanish_please']
for card in due:
# Review the card and record the result
db.answer(day2, card, 75)
# Day 7: Check what needs review
day7 = day1 + timedelta(days=7)
due = db.next(day7)
print(f"Cards due after a week: {due}")
# Check next scheduled review
next_review = db.next_due_date()
print(f"Next review scheduled: {next_review}")
Advanced Example: Learning Session
from datetime import datetime, timedelta
from fsrs_database import FsrsDatabase
def study_session(db, current_time, responses):
"""Simulate a study session with multiple card reviews."""
# Get cards due for review
due_cards = db.next(current_time)
print(f"\n📚 Study session at {current_time}")
print(f"Cards to review: {len(due_cards)}")
# Review each card
for card_id in due_cards:
correctness = responses.get(card_id, 50)
db.answer(current_time, card_id, correctness)
emoji = "✅" if correctness >= 70 else "⚠️" if correctness >= 40 else "❌"
print(f" {emoji} {card_id}: {correctness}% correct")
# Show next review time
next_due = db.next_due_date()
if next_due:
days_until = (next_due - current_time).days
print(f"📅 Next review in {days_until} day(s)")
# Initialize
db = FsrsDatabase("study.db")
start = datetime(2024, 1, 1, 9, 0, 0)
# Day 1: Initial learning
study_session(db, start, {
"capitals_france": 100,
"capitals_germany": 85,
"capitals_italy": 60,
"capitals_spain": 40,
})
# Day 3: First review
study_session(db, start + timedelta(days=3), {
"capitals_spain": 80,
"capitals_italy": 90,
})
# Day 10: Follow-up review
study_session(db, start + timedelta(days=10), {
"capitals_france": 95,
"capitals_germany": 100,
"capitals_italy": 85,
"capitals_spain": 70,
})
Implementation: EbisuDatabase
The EbisuDatabase class implements the SrsDatabase interface using the Ebisu Bayesian algorithm, which tracks:
- Alpha & Beta: Parameters of the Beta distribution on recall probability
- Half-life (t): Expected time until recall probability reaches 0.5
- Bayesian Updates: Uses quiz results to update beliefs about memory strength
- Review History: Complete history with recall probabilities
Note: Requires the ebisu package: pip install ebisu
Example Usage
from datetime import datetime, timedelta
from ebisu_database import EbisuDatabase
# Initialize database (requires ebisu package)
db = EbisuDatabase("learning.db")
# Day 1: Learn new vocabulary
day1 = datetime(2024, 1, 1, 9, 0, 0)
db.answer(day1, "vocab_apple", 95) # Nearly perfect
db.answer(day1, "vocab_banana", 70) # Pretty good
db.answer(day1, "vocab_cherry", 40) # Struggling
# Day 3: Review cards that are due
day3 = day1 + timedelta(days=3)
due = db.next(day3)
print(f"Cards needing review: {due}")
# Cards are ordered by recall probability (lowest first)
for card in due:
db.answer(day3, card, 80) # Review with 80% correctness
# Check when next review is needed
next_review = db.next_due_date()
print(f"Next review: {next_review}")
Key Differences from FSRS
- Bayesian: Uses probabilistic modeling vs deterministic scheduling
- Adaptive: Continuously updates beliefs about memory strength
- Flexible: Supports soft-binary quiz results (0.0-1.0 success values)
- Half-life Based: Schedules reviews based on predicted forgetting curve
Database Schema
FsrsDatabase Tables
The FsrsDatabase creates two tables:
fsrs_cards
Stores the current state of each card:
question_key(PRIMARY KEY): Unique card identifierdifficulty: Card difficulty (0-10)stability: Memory stability in daysstate: Card state (0=new, 1=learning, 2=review, 3=relearning)due_date: When the card is next duereps: Total number of reviewslapses: Number of times forgotten
fsrs_reviews
Historical record of all reviews:
id(PRIMARY KEY): Auto-incrementing review IDquestion_key: Card being reviewedreview_time: When the review occurredrating: FSRS rating (1-4)state: Card state after review
EbisuDatabase Tables
The EbisuDatabase creates two tables:
ebisu_cards
Stores the current Bayesian model for each card:
question_key(PRIMARY KEY): Unique card identifieralpha: Alpha parameter of Beta distributionbeta: Beta parameter of Beta distributiont: Half-life in hourslast_review: Timestamp of last reviewtotal_reviews: Total number of reviews
ebisu_reviews
Historical record of all reviews:
id(PRIMARY KEY): Auto-incrementing review IDquestion_key: Card being reviewedreview_time: When the review occurredcorrectness: Correctness value (0-100)recall_probability: Predicted recall before this review
Testing
Run the test suite:
# Using unittest
python -m unittest discover -v
# Using pytest (if installed)
pytest -v
Implementation Status
- ✅ SrsDatabase Interface: Complete
- ✅ FsrsDatabase: Fully implemented with comprehensive tests (17+ tests)
- ✅ EbisuDatabase: Fully implemented with comprehensive tests (18+ tests)
Future Enhancements
- Export/import functionality
- Statistics and analytics
- Card tagging and filtering
- Multiple deck support
Contributing
Contributions are welcome! Please ensure:
- All tests pass (
python -m unittest discover) - Code follows Python best practices
- New features include tests
License
MIT License - See LICENSE file for details
See Also
- FSRS Algorithm - Free Spaced Repetition Scheduler
- Ebisu Algorithm - Bayesian spaced repetition algorithm
- Ebisu on PyPI - Python implementation of Ebisu
- SuperMemo - Pioneer of spaced repetition
- Anki - Popular SRS flashcard application
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 srsdb-0.8.0.tar.gz.
File metadata
- Download URL: srsdb-0.8.0.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
342c084f9dccc6554271fb8ab690435d3e331e79f30438dc17b7192ef5c91cb8
|
|
| MD5 |
0d33fc7f69785b6341ca7484d24654db
|
|
| BLAKE2b-256 |
e5302696d95e1c5e6426d31f3347ce3c115c148ac64c2deda237798d0b528358
|
Provenance
The following attestation bundles were made for srsdb-0.8.0.tar.gz:
Publisher:
release.yml on jomof/srsdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
srsdb-0.8.0.tar.gz -
Subject digest:
342c084f9dccc6554271fb8ab690435d3e331e79f30438dc17b7192ef5c91cb8 - Sigstore transparency entry: 748223079
- Sigstore integration time:
-
Permalink:
jomof/srsdb@62b249c0b0f38c72b06382f456144e18519b87a7 -
Branch / Tag:
refs/tags/v0.8.0 - Owner: https://github.com/jomof
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@62b249c0b0f38c72b06382f456144e18519b87a7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file srsdb-0.8.0-py3-none-any.whl.
File metadata
- Download URL: srsdb-0.8.0-py3-none-any.whl
- Upload date:
- Size: 13.3 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 |
8f041f9415cc4915060672cee12c5b37d0c6d52f6eb91831b762aba3786524b4
|
|
| MD5 |
beb664b75ddebdf9202823176e0ed43c
|
|
| BLAKE2b-256 |
06cbbbbcec2a8e1dd5daa722fd45264fc571d84dd5d385d7166818b0b991b5b8
|
Provenance
The following attestation bundles were made for srsdb-0.8.0-py3-none-any.whl:
Publisher:
release.yml on jomof/srsdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
srsdb-0.8.0-py3-none-any.whl -
Subject digest:
8f041f9415cc4915060672cee12c5b37d0c6d52f6eb91831b762aba3786524b4 - Sigstore transparency entry: 748223092
- Sigstore integration time:
-
Permalink:
jomof/srsdb@62b249c0b0f38c72b06382f456144e18519b87a7 -
Branch / Tag:
refs/tags/v0.8.0 - Owner: https://github.com/jomof
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@62b249c0b0f38c72b06382f456144e18519b87a7 -
Trigger Event:
push
-
Statement type: