Skip to main content

SQLite database for tracking SRS learning state with FSRS and Ebisu algorithms

Project description

srsdb

Canary Build and Test Python 3.8+

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 question
  • correct: Correctness value from 0-100
    • 0 = completely wrong
    • 100 = 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 None if 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 identifier
  • difficulty: Card difficulty (0-10)
  • stability: Memory stability in days
  • state: Card state (0=new, 1=learning, 2=review, 3=relearning)
  • due_date: When the card is next due
  • reps: Total number of reviews
  • lapses: Number of times forgotten

fsrs_reviews

Historical record of all reviews:

  • id (PRIMARY KEY): Auto-incrementing review ID
  • question_key: Card being reviewed
  • review_time: When the review occurred
  • rating: 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 identifier
  • alpha: Alpha parameter of Beta distribution
  • beta: Beta parameter of Beta distribution
  • t: Half-life in hours
  • last_review: Timestamp of last review
  • total_reviews: Total number of reviews

ebisu_reviews

Historical record of all reviews:

  • id (PRIMARY KEY): Auto-incrementing review ID
  • question_key: Card being reviewed
  • review_time: When the review occurred
  • correctness: 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

srsdb-0.10.0.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

srsdb-0.10.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file srsdb-0.10.0.tar.gz.

File metadata

  • Download URL: srsdb-0.10.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

Hashes for srsdb-0.10.0.tar.gz
Algorithm Hash digest
SHA256 b345fd4ab9d117d84c04cdd50b54678b55b636d5e5453c66bb940cdd7a2b9b31
MD5 f4a1abc16a95e1385923399d3ceca071
BLAKE2b-256 9a81f1fe5a1d184c619b99480ea1b2d7946f8ff78f479d03eff1c726b951db75

See more details on using hashes here.

Provenance

The following attestation bundles were made for srsdb-0.10.0.tar.gz:

Publisher: release.yml on jomof/srsdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file srsdb-0.10.0-py3-none-any.whl.

File metadata

  • Download URL: srsdb-0.10.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

Hashes for srsdb-0.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4060a6887745fd9cfe469762c2effcaed0745452d42c2b67386e1f44b2d161aa
MD5 fa41a934382b30c8709dc20a1cf9cb7b
BLAKE2b-256 279425918bc97a611dcfaad3ccd01fb3a8f154a131f7eb0cfaa9234989e7cf46

See more details on using hashes here.

Provenance

The following attestation bundles were made for srsdb-0.10.0-py3-none-any.whl:

Publisher: release.yml on jomof/srsdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page