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.9.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.9.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: srsdb-0.9.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.9.0.tar.gz
Algorithm Hash digest
SHA256 2616a1c1d632b73d551d697461c0decb16cb38e0bf7d7ce61af1c098c051580f
MD5 aa39c99b1665706f723ba2c1b52f2af0
BLAKE2b-256 b6be54e8d2e236a87556082e8d2247f6c5f11854e217e1b8bd251e159f8fa740

See more details on using hashes here.

Provenance

The following attestation bundles were made for srsdb-0.9.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.9.0-py3-none-any.whl.

File metadata

  • Download URL: srsdb-0.9.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.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ddca2e4ccd4579973749f057472b727b5f9e0f756bda74722100b9c24f6dbf7
MD5 867bf7995cfad3a7f799104e322ab51e
BLAKE2b-256 8f58d5ea7a77a909a59654d6a3ad7442255a96b1d189cf5993392433b7d62dcf

See more details on using hashes here.

Provenance

The following attestation bundles were made for srsdb-0.9.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