leaf

package module
v0.0.0-...-f32db49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 17, 2020 License: MIT Imports: 13 Imported by: 0

README

* Leaf

*Leaf* is a flashcard app that uses [[https://en.wikipedia.org/wiki/Spaced_repetition][spaced repetition]]
 algorithm. *Leaf* focuses on simplifying database management, ease of
 access and support for various spaced repetition curves (including
 custom).

[[https://gitlab.com/ap4y/leaf/raw/master/screenshot.png]]

** Getting started

*Leaf* is a [[https://golang.org/][golang]] application and you are going to need golang
toolchain to compile the app.

To install or update run:

#+BEGIN_SRC shell
go get -u github.com/ap4y/leaf/cmd/leaf
#+END_SRC

or

#+BEGIN_SRC shell
go get -u github.com/ap4y/leaf/cmd/leaf-server
#+END_SRC

Leaf provides 2 different versions:

- ~leaf~ is a command line utility that provides review UI in the terminal
- ~leaf-server~ is a web app that implements review UI along with
  additional features like stats viewer.

Both utilities have following configuration options:

- ~-decks .~ is a path to a folder with deck files.
- ~-db leaf.db~ is a location of a stats DB that contains spaced
  repetition variables for your decks.

For ~leaf-server~ you can also adjust address to start server on via ~-addr :8000~.

Terminal CLI (~leaf~) has following commands:

- ~review~ will initiate review session for a deck
- ~stats~ will return stats snapshots for a deck

Both commands expect deck name after the command name. Full example:

#+BEGIN_SRC shell
./leaf -decks ./fixtures review Hiragana
#+END_SRC

** Database management

*Leaf* uses plain text files structured usin [[https://orgmode.org/manual/Headlines.html#Headlines][org-mode headlines]]. Consider following file:

#+BEGIN_SRC org
* Sample
:PROPERTIES:
:RATER:      auto
:ALGORITHM:  sm2+c
:PER_REVIEW: 20
:SIDES:      answer
:END:
** Question 1
Answer 1
** Question 2
Answer 2
#+END_SRC

Such file will be parsed as a deck named _Sample_ and it will have 2
cards. For a full deck example check [[https://gitlab.com/ap4y/leaf/raw/master/fixtures/hiragana.org][hiragana]] deck.

You can use text formatting, images, links and code blocks in your deck
files. Check [[https://gitlab.com/ap4y/leaf/raw/master/fixtures/org-mode.org][org-mode]] deck for an overview of supported options.

Top header level property drawer is used to adjust review
parameters. Following parameters are supported:

- ~ALGORITHM~ is a spaced repetition algorithm to use. Default is
  ~sm2+c~. All possible values can be found [[https://gitlab.com/ap4y/leaf/blob/master/stats.go#L35-44][here]].
- ~RATER~ defines which rating system will be used for
  reviews. Defaults to ~auto~, supported values: ~auto~ and ~self~.
- ~PER_REVIEW~ is a maximum amount of cards per review session.
- ~SIDES~ is an optional field that defines names of the card sides,
  used in the UI for placeholders.

Spaced repetition variables are stored in a separate file in a binary
database. You can edit deck files at any time and changes will be
automatically reflected in the web app.

** Spaced repetition algorithms

*Leaf* implements multiple spaced repetition algorithms and allows you
to define new ones. Following algorithms are supported as of now:

- [[https://www.supermemo.com/en/archives1990-2015/english/ol/sm2][supermemo2]]
- [[http://www.blueraja.com/blog/477/a-better-spaced-repetition-learning-algorithm-sm2][supermemo2+]]
- Custom curve for supermemo2+. I found it works better for me.
- [[https://fasiha.github.io/ebisu.js/][ebisu]]

You can find calculated intervals in corresponding test files. Check
[[https://gitlab.com/ap4y/leaf/blob/master/stats.go#L9-19][SRSAlgorithm]] interface to define a new algorithm or curve.

Please keep in mind that algorithm variables may not be compatible
with each other and algorithm switching is not supported.

** Review rating

All reviews are rated using ~[0..1]~ scale. Rating higher than ~0.6~
will mark review as successful. You can use 2 different types of
rating systems:

- ~auto~ (default) is based on amount of mistakes made during review. For ~auto~
  rating is assigned using [[https://gitlab.com/ap4y/leaf/blob/master/rating.go#L45-47][HarshRater]] which implements steep curve and
  a single mistake will have score less than ~0.6~. Check [[https://gitlab.com/ap4y/leaf/blob/master/rating.go#L34-36][Rater]]
  interface to get understanding how to define a different rater
  curve.

- ~self~ is a self assessment system. You have to assign score for
  each review and score will be converted to a rating as such: ~hard =
  0.2~, ~good = 0.6~, ~easy = 1.0~, ~again~ will push card back into
  the review queue.

To change rating system for a deck define org-mode property ~RATER~ in
your deck file.

Documentation

Index

Constants

View Source
const (
	// OutputFormatOrg defines pretty printed org output.
	OutputFormatOrg OutputFormat = iota
	// OutputFormatHTML defines html output.
	OutputFormatHTML

	// DeckPropertyRater defines deck's org-mode property for the rater
	DeckPropertyRater = "RATER"
	// DeckPropertyAlgorithm defines deck's org-mode property for the
	// algorithm
	DeckPropertyAlgorithm = "ALGORITHM"
	// DeckPropertyPerReview defines deck's org-mode property for the
	// per review amount
	DeckPropertyPerReview = "PER_REVIEW"
	// DeckPropertySides defines deck's org-mode property for the side
	// names
	DeckPropertySides = "SIDES"
)
View Source
const (
	// SRSSupermemo2 represents Supermemo2 algorithm
	SRSSupermemo2 SRS = "sm2"
	// SRSSupermemo2Plus represents Supermemo2Plus algorithm
	SRSSupermemo2Plus = "sm2+"
	// SRSSupermemo2PlusCustom represents Supermemo2PlusCustom algorithm
	SRSSupermemo2PlusCustom = "sm2+c"
	// SRSEbisu represents Ebisu algorithm
	SRSEbisu = "ebisu"
)

Variables

View Source
var ErrNotFound = errors.New("deck not found")

ErrNotFound represents error returned for requests for non-existing deck.

Functions

This section is empty.

Types

type Card

type Card struct {
	Question    string   `json:"card"`
	RawQuestion string   `json:"raw_card"`
	Sides       []string `json:"-"`
}

Card represents a single card in a Deck. Each card may have multiple sides (answers).

func (Card) Answer

func (c Card) Answer() string

Answer returns combined space separated answer for all sides of the card.

type CardWithStats

type CardWithStats struct {
	Card
	*Stats
}

CardWithStats joins Stats to a Card

type Deck

type Deck struct {
	Name       string
	Cards      []Card
	Algorithm  SRS
	RatingType RatingType
	PerReview  int
	Sides      []string
	// contains filtered or unexported fields
}

Deck represents a named collection of the cards to review.

func OpenDeck

func OpenDeck(filename string, format OutputFormat) (*Deck, error)

OpenDeck loads deck from an org file. File format is: * Deck Name ** Question side 1 side 2

func (*Deck) Reload

func (deck *Deck) Reload() error

Reload compares ModTime on deck file and reloads cards if necessary.

type DeckManager

type DeckManager struct {
	// contains filtered or unexported fields
}

DeckManager manages set of decks.

func NewDeckManager

func NewDeckManager(path string, db StatsStore, outFormat OutputFormat) (*DeckManager, error)

NewDeckManager constructs a new DeckManager by reading all decks from a given folder using provided store.

func (DeckManager) DeckStats

func (dm DeckManager) DeckStats(deckName string) ([]CardWithStats, error)

DeckStats returns card stats for a given deck name.

func (DeckManager) ReviewDecks

func (dm DeckManager) ReviewDecks() ([]DeckStats, error)

ReviewDecks returns stats for available decks.

func (DeckManager) ReviewSession

func (dm DeckManager) ReviewSession(deckName string) (*ReviewSession, error)

ReviewSession initiates a new ReviewSession for a given deck name.

type DeckStats

type DeckStats struct {
	Name         string    `json:"name"`
	CardsReady   int       `json:"cards_ready"`
	NextReviewAt time.Time `json:"next_review_at"`
}

DeckStats stores overview stats for a Deck.

type Ebisu

type Ebisu struct {
	LastReviewedAt time.Time
	Alpha          float64
	Beta           float64
	Interval       float64
	Historical     []IntervalSnapshot
}

Ebisu implements ebisu SSR algorithm.

func NewEbisu

func NewEbisu() *Ebisu

NewEbisu consturcts a new Ebisu instance.

func (*Ebisu) Advance

func (eb *Ebisu) Advance(rating float64) (interval float64)

Advance advances supermemo state for a card.

func (*Ebisu) Less

func (eb *Ebisu) Less(other SRSAlgorithm) bool

Less defines card order for the review.

func (*Ebisu) MarshalJSON

func (eb *Ebisu) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaller for Ebisu

func (*Ebisu) NextReviewAt

func (eb *Ebisu) NextReviewAt() time.Time

NextReviewAt returns next review timestamp for a card.

func (*Ebisu) UnmarshalJSON

func (eb *Ebisu) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaller for Ebisu

type IntervalSnapshot

type IntervalSnapshot struct {
	Timestamp int64   `json:"ts"`
	Interval  float64 `json:"interval"`
	Factor    float64 `json:"factor"`
}

IntervalSnapshot records historical changes of the Interval.

type OutputFormat

type OutputFormat int

OutputFormat defines output type produces during org file parsing.

type Rater

type Rater interface {
	Rate(question string, score ReviewScore) float64
}

Rater rates review attempt based on amount of mistakes. Rating should be within [0, 1] range.

func HarshRater

func HarshRater() Rater

HarshRater returns miss count based Rater. Miss counter will increase for each "again" score. Rating declines really fast and even 1 mistake results in 0.59 rating.

func TableRater

func TableRater() Rater

TableRater returns Rater implementation with following the conversion table: again => 0 hard => 0.2 good => 0.6 easy => 1.0

type RatingType

type RatingType string

RatingType defines types of review rating options.

const (
	// RatingTypeAuto defines auto rated review option.
	RatingTypeAuto RatingType = "auto"
	// RatingTypeSelf defines self rated review option.
	RatingTypeSelf RatingType = "self"
)

type ReviewScore

type ReviewScore int

ReviewScore defines grade for review attempts. Rater uses scores to calculate rating in range from [0, 1].

const (
	// ReviewScoreAgain defines "again" score.
	ReviewScoreAgain ReviewScore = iota
	// ReviewScoreHard defines "hard" score.
	ReviewScoreHard
	// ReviewScoreGood defines "good" score.
	ReviewScoreGood
	// ReviewScoreEasy defines "easy" score.
	ReviewScoreEasy
)

type ReviewSession

type ReviewSession struct {
	// contains filtered or unexported fields
}

ReviewSession contains parameters for a Deck review sessions.

func NewReviewSession

func NewReviewSession(cards []CardWithStats, sides []string, rt RatingType, statsSaver StatsSaveFunc) *ReviewSession

NewReviewSession constructs a new ReviewSession for a given set of cards. Rating calculation will be performed using provided rater. Provided StatsSaveFunc will be used for stats updates post review.

func (*ReviewSession) Again

func (s *ReviewSession) Again() error

Again re-queues current card back for review.

func (*ReviewSession) CorrectAnswer

func (s *ReviewSession) CorrectAnswer() string

CorrectAnswer returns correct answer for a current reviewed card.

func (*ReviewSession) Left

func (s *ReviewSession) Left() int

Left returns amount of cards left to review.

func (*ReviewSession) Next

func (s *ReviewSession) Next() string

Next returns current card to review. Same card will be return until review is attempted via Answer call.

func (*ReviewSession) Rate

func (s *ReviewSession) Rate(rating float64) error

Rate assign rating to a current card and removes it from the queue if rating > 0.

func (*ReviewSession) RatingType

func (s *ReviewSession) RatingType() RatingType

RatingType returns type of rating to be used for the review session.

func (*ReviewSession) Sides

func (s *ReviewSession) Sides() []string

Sides returns side names from the reviewed deck.

func (*ReviewSession) StartedAt

func (s *ReviewSession) StartedAt() time.Time

StartedAt returns start time of the review session.

func (*ReviewSession) Total

func (s *ReviewSession) Total() int

Total returns amount of cards in the session.

type SRS

type SRS string

SRS defines supported spaced-repetiton algorithms.

type SRSAlgorithm

type SRSAlgorithm interface {
	json.Marshaler
	json.Unmarshaler

	// Advance advances supermemo state for a card.
	Advance(rating float64) (interval float64)
	// NextReviewAt returns next review timestamp for a card.
	NextReviewAt() time.Time
	// Less defines card order for the review.
	Less(other SRSAlgorithm) bool
}

SRSAlgorithm calculates review intervals

type Stats

type Stats struct {
	SRSAlgorithm
}

Stats store SM2+ parameters for a Card.

func NewStats

func NewStats(srs SRS) *Stats

NewStats returns a new Stats initialized with provided algorithm with default values. Supported values: sm2, sm2+, sm2+c. If smAlgo is missing or unknown will default to Supermemo2PlusCustom.

func (Stats) IsReady

func (s Stats) IsReady() bool

IsReady signals whether card is read for review.

type StatsSaveFunc

type StatsSaveFunc func(card *CardWithStats) error

StatsSaveFunc persists stats updates.

type StatsStore

type StatsStore interface {
	io.Closer
	// RangeStats iterates over all stats in a Store. DB records will be boxed to provide algoritm.
	RangeStats(deck string, srs SRS, rangeFunc func(card string, stats *Stats) bool) error
	// SaveStats saves stats for a card.
	SaveStats(deck string, card string, stats *Stats) error
}

StatsStore defines storage interface that is used for storing review stats.

func OpenBoltStore

func OpenBoltStore(filename string) (StatsStore, error)

OpenBoltStore returns a new StatsStore implemented on top of BoltDB.

type Supermemo2

type Supermemo2 struct {
	LastReviewedAt time.Time
	Interval       float64
	Easiness       float64
	Correct        int
	Total          int
	Historical     []IntervalSnapshot
}

Supermemo2 calculates review intervals using SM2 algorithm

func NewSupermemo2

func NewSupermemo2() *Supermemo2

NewSupermemo2 returns a new Supermemo2 instance

func (*Supermemo2) Advance

func (sm *Supermemo2) Advance(rating float64) float64

Advance advances supermemo state for a card.

func (*Supermemo2) Less

func (sm *Supermemo2) Less(other SRSAlgorithm) bool

Less defines card order for the review.

func (*Supermemo2) MarshalJSON

func (sm *Supermemo2) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaller for Supermemo2

func (*Supermemo2) NextReviewAt

func (sm *Supermemo2) NextReviewAt() time.Time

NextReviewAt returns next review timestamp for a card.

func (*Supermemo2) UnmarshalJSON

func (sm *Supermemo2) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaller for Supermemo2

type Supermemo2Plus

type Supermemo2Plus struct {
	LastReviewedAt time.Time
	Difficulty     float64
	Interval       float64
	Historical     []IntervalSnapshot
}

Supermemo2Plus calculates review intervals using SM2+ algorithm

func NewSupermemo2Plus

func NewSupermemo2Plus() *Supermemo2Plus

NewSupermemo2Plus returns a new Supermemo2Plus instance

func (*Supermemo2Plus) Advance

func (sm *Supermemo2Plus) Advance(rating float64) float64

Advance advances supermemo state for a card.

func (*Supermemo2Plus) Less

func (sm *Supermemo2Plus) Less(other SRSAlgorithm) bool

Less defines card order for the review.

func (*Supermemo2Plus) MarshalJSON

func (sm *Supermemo2Plus) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaller for Supermemo2Plus

func (*Supermemo2Plus) NextReviewAt

func (sm *Supermemo2Plus) NextReviewAt() time.Time

NextReviewAt returns next review timestamp for a card.

func (*Supermemo2Plus) PercentOverdue

func (sm *Supermemo2Plus) PercentOverdue() float64

PercentOverdue returns corresponding SM2+ value for a Card.

func (*Supermemo2Plus) UnmarshalJSON

func (sm *Supermemo2Plus) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaller for Supermemo2Plus

type Supermemo2PlusCustom

type Supermemo2PlusCustom struct {
	Supermemo2Plus
}

Supermemo2PlusCustom calculates review intervals using altered SM2+ algorithm

func NewSupermemo2PlusCustom

func NewSupermemo2PlusCustom() *Supermemo2PlusCustom

NewSupermemo2PlusCustom returns a new Supermemo2PlusCustom instance

func (*Supermemo2PlusCustom) Advance

func (sm *Supermemo2PlusCustom) Advance(rating float64) float64

Advance advances supermemo state for a card.

func (*Supermemo2PlusCustom) Less

func (sm *Supermemo2PlusCustom) Less(other SRSAlgorithm) bool

Less defines card order for the review.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL