51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
import { fsrs as createFSRS, createEmptyCard, Rating, type Card, type Grade } from "ts-fsrs"
|
|
|
|
const scheduler = createFSRS({ maximum_interval: 365, request_retention: 0.9 })
|
|
|
|
export type FsrsGrade = "again" | "hard" | "good" | "easy"
|
|
|
|
const gradeMap: Record<FsrsGrade, Grade> = {
|
|
again: Rating.Again,
|
|
hard: Rating.Hard,
|
|
good: Rating.Good,
|
|
easy: Rating.Easy,
|
|
}
|
|
|
|
export function buildFsrsCard(params: {
|
|
stability?: number
|
|
difficulty?: number
|
|
reps?: number
|
|
lapses?: number
|
|
due?: Date
|
|
}): Card {
|
|
const card = createEmptyCard(params.due ?? new Date())
|
|
return {
|
|
...card,
|
|
stability: params.stability ?? card.stability,
|
|
difficulty: params.difficulty ?? card.difficulty,
|
|
reps: params.reps ?? 0,
|
|
lapses: params.lapses ?? 0,
|
|
due: params.due ?? card.due,
|
|
}
|
|
}
|
|
|
|
export function gradeCard(card: Card, grade: FsrsGrade, now: Date = new Date()) {
|
|
const result = scheduler.next(card, now, gradeMap[grade])
|
|
return {
|
|
card: result.card,
|
|
log: result.log,
|
|
}
|
|
}
|
|
|
|
export function getRetrievability(card: Card, now: Date = new Date()): number {
|
|
const r = scheduler.get_retrievability(card, now, false)
|
|
return typeof r === "number" ? r : parseFloat(r)
|
|
}
|
|
|
|
export function skillCodeFromGrade(correct: boolean, responseMs: number): FsrsGrade {
|
|
if (!correct) return "again"
|
|
if (responseMs > 8000) return "hard"
|
|
if (responseMs > 4000) return "good"
|
|
return "easy"
|
|
}
|