ts-fsrs 5.3.1 → 5.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/LICENSE +1 -1
- package/README.md +253 -0
- package/README_CN.md +243 -0
- package/README_JA.md +251 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# ts-fsrs
|
|
2
2
|
|
|
3
|
+
## 5.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#329](https://github.com/open-spaced-repetition/ts-fsrs/pull/329) [`5cd8949`](https://github.com/open-spaced-repetition/ts-fsrs/commit/5cd8949544788224eada1b2e6f8597756ca594cb) Thanks [@ishiko732](https://github.com/ishiko732)! - fix: include README, localized package docs, and license files in the published `ts-fsrs` tarball
|
|
8
|
+
|
|
3
9
|
## 5.3.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/LICENSE
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# ts-fsrs
|
|
2
|
+
|
|
3
|
+
[](https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-6)
|
|
4
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
5
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
6
|
+
|
|
7
|
+
[Introduction](./README.md) | [简体中文](./README_CN.md) | [はじめに](./README_JA.md)
|
|
8
|
+
|
|
9
|
+
**ts-fsrs is a TypeScript package that helps developers build their own spaced repetition system using the Free Spaced Repetition Scheduler algorithm.**
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [ts-fsrs](#ts-fsrs)
|
|
14
|
+
- [Table of Contents](#table-of-contents)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Quickstart](#quickstart)
|
|
17
|
+
- [Usage](#usage)
|
|
18
|
+
- [Custom parameters](#custom-parameters)
|
|
19
|
+
- [`generatorParameters`](#generatorparameters)
|
|
20
|
+
- [`repeat` vs `next`](#repeat-vs-next)
|
|
21
|
+
- [Retrievability](#retrievability)
|
|
22
|
+
- [`next_state` and `next_interval`](#next_state-and-next_interval)
|
|
23
|
+
- [History helpers](#history-helpers)
|
|
24
|
+
- [Reference](#reference)
|
|
25
|
+
- [API Documentation](#api-documentation)
|
|
26
|
+
- [Examples](#examples)
|
|
27
|
+
- [Contributing](#contributing)
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
`ts-fsrs` requires Node.js `>=20.0.0`.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install ts-fsrs
|
|
35
|
+
yarn add ts-fsrs
|
|
36
|
+
pnpm install ts-fsrs
|
|
37
|
+
bun add ts-fsrs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quickstart
|
|
41
|
+
|
|
42
|
+
Import and initialize the scheduler:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { createEmptyCard, fsrs, Rating } from 'ts-fsrs'
|
|
46
|
+
|
|
47
|
+
const scheduler = fsrs()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Create a new card:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const card = createEmptyCard()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Preview all possible scheduling outcomes:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const preview = scheduler.repeat(card, new Date())
|
|
60
|
+
|
|
61
|
+
console.log(preview[Rating.Again].card)
|
|
62
|
+
console.log(preview[Rating.Hard].card)
|
|
63
|
+
console.log(preview[Rating.Good].card)
|
|
64
|
+
console.log(preview[Rating.Easy].card)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Apply a specific rating:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
71
|
+
|
|
72
|
+
console.log(result.card)
|
|
73
|
+
console.log(result.log)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
### Custom parameters
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { fsrs } from 'ts-fsrs'
|
|
82
|
+
|
|
83
|
+
const scheduler = fsrs({
|
|
84
|
+
request_retention: 0.9,
|
|
85
|
+
maximum_interval: 36500,
|
|
86
|
+
enable_fuzz: true,
|
|
87
|
+
enable_short_term: true,
|
|
88
|
+
learning_steps: ['1m', '10m'],
|
|
89
|
+
relearning_steps: ['10m'],
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`request_retention` Is the percentage (`0.0-1.0`) that the scheduler will try and have you get correct. Higher values increase review load, lower values reduce it.
|
|
94
|
+
|
|
95
|
+
`maximum_interval` caps how far into the future a card can be scheduled.
|
|
96
|
+
|
|
97
|
+
`enable_fuzz` adds a small amount of randomness to long intervals.
|
|
98
|
+
|
|
99
|
+
`enable_short_term`, `learning_steps`, and `relearning_steps` control short-term and relearning step behavior.
|
|
100
|
+
|
|
101
|
+
### `generatorParameters`
|
|
102
|
+
|
|
103
|
+
`fsrs()` already applies `generatorParameters()` internally, so in normal scheduler setup you can pass a partial parameter object directly to `fsrs()`.
|
|
104
|
+
|
|
105
|
+
Use `generatorParameters()` when you need a complete `FSRSParameters` object for serialization, persistence, or reuse:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { fsrs, generatorParameters } from 'ts-fsrs'
|
|
109
|
+
|
|
110
|
+
const params = generatorParameters({
|
|
111
|
+
request_retention: 0.9,
|
|
112
|
+
maximum_interval: 36500,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
console.log(JSON.stringify(params))
|
|
116
|
+
|
|
117
|
+
const scheduler = fsrs(params)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
If you persist those parameters and load them later, pass the parsed object back into `fsrs()`:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { fsrs, type FSRSParameters } from 'ts-fsrs'
|
|
124
|
+
|
|
125
|
+
const serializedParams = '{"request_retention":0.9,"maximum_interval":36500}'
|
|
126
|
+
const params = JSON.parse(serializedParams) as FSRSParameters
|
|
127
|
+
const scheduler = fsrs(params)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If the parameters come from external storage, user input, or the network, validate them at your application boundary before passing them to `fsrs()`. A runtime schema library such as `zod` is a good fit for that.
|
|
131
|
+
|
|
132
|
+
### `repeat` vs `next`
|
|
133
|
+
|
|
134
|
+
Use `repeat` when you want to preview all four outcomes before the user answers.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const preview = scheduler.repeat(card, new Date())
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Use `next` when you already know the selected rating.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
If you want to map the result into your own storage type, pass an `afterHandler`.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const saved = scheduler.next(card, new Date(), Rating.Good, ({ card, log }) => ({
|
|
150
|
+
card: {
|
|
151
|
+
...card,
|
|
152
|
+
due: card.due.getTime(),
|
|
153
|
+
last_review: card.last_review?.getTime() ?? null,
|
|
154
|
+
},
|
|
155
|
+
log: {
|
|
156
|
+
...log,
|
|
157
|
+
due: log.due.getTime(),
|
|
158
|
+
review: log.review.getTime(),
|
|
159
|
+
},
|
|
160
|
+
}))
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Retrievability
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
const retrievability = scheduler.get_retrievability(result.card, new Date(), false)
|
|
167
|
+
console.log(retrievability)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
You can also calculate retrievability directly with `forgetting_curve()` if you already have `elapsed_days`, `stability`, and a valid decay value:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { forgetting_curve } from 'ts-fsrs'
|
|
174
|
+
|
|
175
|
+
const retrievability = forgetting_curve(0.5, 12, result.card.stability)
|
|
176
|
+
console.log(retrievability)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
When you pass a decay value directly, it must be positive and within the range `0.1` to `0.8`.
|
|
180
|
+
|
|
181
|
+
### `next_state` and `next_interval`
|
|
182
|
+
|
|
183
|
+
If you are working directly with memory states, you can combine `next_state()` and `next_interval()`:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { fsrs, Rating, type FSRSState } from 'ts-fsrs'
|
|
187
|
+
|
|
188
|
+
const scheduler = fsrs({ enable_fuzz: false })
|
|
189
|
+
|
|
190
|
+
const memoryState: FSRSState = {
|
|
191
|
+
stability: 3.2,
|
|
192
|
+
difficulty: 5.6,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const elapsedDays = 12
|
|
196
|
+
const nextState = scheduler.next_state(memoryState, elapsedDays, Rating.Good)
|
|
197
|
+
const nextInterval = scheduler.next_interval(nextState.stability, elapsedDays)
|
|
198
|
+
|
|
199
|
+
console.log(nextState)
|
|
200
|
+
console.log(nextInterval)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
This is useful for simulations, analytics, or custom scheduling pipelines. For standard review flows, prefer `repeat()` or `next()`.
|
|
204
|
+
|
|
205
|
+
### History helpers
|
|
206
|
+
|
|
207
|
+
The scheduler also provides:
|
|
208
|
+
|
|
209
|
+
- `rollback(card, log)`
|
|
210
|
+
- `forget(card, now, reset_count?)`
|
|
211
|
+
- `reschedule(card, reviews, options?)`
|
|
212
|
+
|
|
213
|
+
These are useful when replaying imported review logs or rebuilding state from persistence.
|
|
214
|
+
|
|
215
|
+
## Reference
|
|
216
|
+
|
|
217
|
+
Card states:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
State.New
|
|
221
|
+
State.Learning
|
|
222
|
+
State.Review
|
|
223
|
+
State.Relearning
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Review ratings:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
Rating.Again
|
|
230
|
+
Rating.Hard
|
|
231
|
+
Rating.Good
|
|
232
|
+
Rating.Easy
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## API Documentation
|
|
236
|
+
|
|
237
|
+
- Repository overview: [github.com/open-spaced-repetition/ts-fsrs](https://github.com/open-spaced-repetition/ts-fsrs#readme)
|
|
238
|
+
- TypeDoc API docs: [open-spaced-repetition.github.io/ts-fsrs](https://open-spaced-repetition.github.io/ts-fsrs/)
|
|
239
|
+
- Optimizer package: [`@open-spaced-repetition/binding`](https://www.npmjs.com/package/@open-spaced-repetition/binding)
|
|
240
|
+
- Simplified Chinese README: [README_CN.md](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/packages/fsrs/README_CN.md)
|
|
241
|
+
- Japanese README: [README_JA.md](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/packages/fsrs/README_JA.md)
|
|
242
|
+
|
|
243
|
+
## Examples
|
|
244
|
+
|
|
245
|
+
- Browser example: [example/example.html](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/example/example.html)
|
|
246
|
+
- Full-stack demo: [ts-fsrs-demo](https://github.com/ishiko732/ts-fsrs-demo)
|
|
247
|
+
- Other:
|
|
248
|
+
- [spaced](https://github.com/zsh-eng/spaced)
|
|
249
|
+
- [Anki Search Stats Extended](https://github.com/Luc-Mcgrady/Anki-Search-Stats-Extended)
|
|
250
|
+
|
|
251
|
+
## Contributing
|
|
252
|
+
|
|
253
|
+
Contribution guidelines are available in [`CONTRIBUTING.md`](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/CONTRIBUTING.md).
|
package/README_CN.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# ts-fsrs
|
|
2
|
+
|
|
3
|
+
[Introduction](./README.md) | [简体中文](./README_CN.md) | [はじめに](./README_JA.md)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-6)
|
|
6
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
7
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
8
|
+
|
|
9
|
+
**ts-fsrs 是一个 TypeScript 包,帮助开发者基于自由间隔重复调度器(FSRS)算法构建自己的间隔重复系统。**
|
|
10
|
+
|
|
11
|
+
## 目录
|
|
12
|
+
|
|
13
|
+
- [安装](#安装)
|
|
14
|
+
- [快速开始](#快速开始)
|
|
15
|
+
- [使用说明](#使用说明)
|
|
16
|
+
- [参考](#参考)
|
|
17
|
+
- [API 文档](#api-文档)
|
|
18
|
+
- [示例](#示例)
|
|
19
|
+
- [贡献](#贡献)
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
`ts-fsrs` 需要 Node.js `>=20.0.0`。
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install ts-fsrs
|
|
27
|
+
yarn add ts-fsrs
|
|
28
|
+
pnpm install ts-fsrs
|
|
29
|
+
bun add ts-fsrs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 快速开始
|
|
33
|
+
|
|
34
|
+
导入并初始化调度器:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { createEmptyCard, fsrs, Rating } from 'ts-fsrs'
|
|
38
|
+
|
|
39
|
+
const scheduler = fsrs()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
创建一张新卡片:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const card = createEmptyCard()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
预览四种评分下的全部调度结果:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const preview = scheduler.repeat(card, new Date())
|
|
52
|
+
|
|
53
|
+
console.log(preview[Rating.Again].card)
|
|
54
|
+
console.log(preview[Rating.Hard].card)
|
|
55
|
+
console.log(preview[Rating.Good].card)
|
|
56
|
+
console.log(preview[Rating.Easy].card)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
如果用户已经作答,可以直接应用一个确定评分:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
63
|
+
|
|
64
|
+
console.log(result.card)
|
|
65
|
+
console.log(result.log)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 使用说明
|
|
69
|
+
|
|
70
|
+
### 自定义参数
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { fsrs } from 'ts-fsrs'
|
|
74
|
+
|
|
75
|
+
const scheduler = fsrs({
|
|
76
|
+
request_retention: 0.9,
|
|
77
|
+
maximum_interval: 36500,
|
|
78
|
+
enable_fuzz: true,
|
|
79
|
+
enable_short_term: true,
|
|
80
|
+
learning_steps: ['1m', '10m'],
|
|
81
|
+
relearning_steps: ['10m'],
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`request_retention` 调度器希望维持的最低记忆保持率(0%到100%)。值越高,复习越频繁;值越低,复习越少。
|
|
86
|
+
|
|
87
|
+
`maximum_interval` 用于限制卡片最多可以被安排到未来多少天。
|
|
88
|
+
|
|
89
|
+
`enable_fuzz` 会给较长的间隔增加少量随机扰动,避免大量卡片在同一天到期。
|
|
90
|
+
|
|
91
|
+
`enable_short_term`、`learning_steps` 和 `relearning_steps` 用于控制短期学习和重新学习步骤。
|
|
92
|
+
|
|
93
|
+
### `generatorParameters`
|
|
94
|
+
|
|
95
|
+
`fsrs()` 内部已经会调用 `generatorParameters()` 来补齐和规范化参数,所以普通初始化调度器时,直接把部分参数对象传给 `fsrs()` 即可。
|
|
96
|
+
|
|
97
|
+
当你需要一个完整的 `FSRSParameters` 对象用于序列化、持久化或复用时,再使用 `generatorParameters()`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { fsrs, generatorParameters } from 'ts-fsrs'
|
|
101
|
+
|
|
102
|
+
const params = generatorParameters({
|
|
103
|
+
request_retention: 0.9,
|
|
104
|
+
maximum_interval: 36500,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
console.log(JSON.stringify(params))
|
|
108
|
+
|
|
109
|
+
const scheduler = fsrs(params)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
如果你把参数持久化之后再加载回来,也可以把解析后的对象直接传回 `fsrs()`:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { fsrs, type FSRSParameters } from 'ts-fsrs'
|
|
116
|
+
|
|
117
|
+
const serializedParams = '{"request_retention":0.9,"maximum_interval":36500}'
|
|
118
|
+
const params = JSON.parse(serializedParams) as FSRSParameters
|
|
119
|
+
const scheduler = fsrs(params)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
如果这些参数来自外部存储、用户输入或网络,建议在应用边界先做运行时校验,再传给 `fsrs()`。像 `zod` 这样的运行时 schema 校验库就很适合这个场景。
|
|
123
|
+
|
|
124
|
+
### `repeat` 与 `next`
|
|
125
|
+
|
|
126
|
+
如果你需要在用户作答前预览四种评分结果,使用 `repeat`:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const preview = scheduler.repeat(card, new Date())
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
如果你已经拿到了用户的评分,直接使用 `next`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
如果你想把结果直接映射成自己的存储结构,可以传入 `afterHandler`:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const saved = scheduler.next(card, new Date(), Rating.Good, ({ card, log }) => ({
|
|
142
|
+
card: {
|
|
143
|
+
...card,
|
|
144
|
+
due: card.due.getTime(),
|
|
145
|
+
last_review: card.last_review?.getTime() ?? null,
|
|
146
|
+
},
|
|
147
|
+
log: {
|
|
148
|
+
...log,
|
|
149
|
+
due: log.due.getTime(),
|
|
150
|
+
review: log.review.getTime(),
|
|
151
|
+
},
|
|
152
|
+
}))
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 可提取率
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const retrievability = scheduler.get_retrievability(result.card, new Date(), false)
|
|
159
|
+
console.log(retrievability)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
如果你已经有 `elapsed_days`、`stability` 和合法的 decay 值,也可以直接用 `forgetting_curve()` 来计算可提取率:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { forgetting_curve } from 'ts-fsrs'
|
|
166
|
+
|
|
167
|
+
const retrievability = forgetting_curve(0.5, 12, result.card.stability)
|
|
168
|
+
console.log(retrievability)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
如果你直接传入 decay,它必须是正数,并且范围在 `0.1` 到 `0.8` 之间。
|
|
172
|
+
|
|
173
|
+
### `next_state` 与 `next_interval`
|
|
174
|
+
|
|
175
|
+
如果你直接基于记忆状态做推导,可以把 `next_state()` 和 `next_interval()` 组合使用:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { fsrs, Rating, type FSRSState } from 'ts-fsrs'
|
|
179
|
+
|
|
180
|
+
const scheduler = fsrs({ enable_fuzz: false })
|
|
181
|
+
|
|
182
|
+
const memoryState: FSRSState = {
|
|
183
|
+
stability: 3.2,
|
|
184
|
+
difficulty: 5.6,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const elapsedDays = 12
|
|
188
|
+
const nextState = scheduler.next_state(memoryState, elapsedDays, Rating.Good)
|
|
189
|
+
const nextInterval = scheduler.next_interval(nextState.stability, elapsedDays)
|
|
190
|
+
|
|
191
|
+
console.log(nextState)
|
|
192
|
+
console.log(nextInterval)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
这种写法适合做模拟、分析,或者你自己维护 `{ stability, difficulty }` 的自定义调度流程。对于普通复习流程,优先使用 `repeat()` 或 `next()`。
|
|
196
|
+
|
|
197
|
+
### 历史辅助能力
|
|
198
|
+
|
|
199
|
+
调度器还提供这些辅助方法:
|
|
200
|
+
|
|
201
|
+
- `rollback(card, log)`
|
|
202
|
+
- `forget(card, now, reset_count?)`
|
|
203
|
+
- `reschedule(card, reviews, options?)`
|
|
204
|
+
|
|
205
|
+
它们适合导入旧数据、回放历史复习记录,或从持久化日志重建卡片状态。
|
|
206
|
+
|
|
207
|
+
## 参考
|
|
208
|
+
|
|
209
|
+
卡片状态:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
State.New
|
|
213
|
+
State.Learning
|
|
214
|
+
State.Review
|
|
215
|
+
State.Relearning
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
评分枚举:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
Rating.Again
|
|
222
|
+
Rating.Hard
|
|
223
|
+
Rating.Good
|
|
224
|
+
Rating.Easy
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## API 文档
|
|
228
|
+
|
|
229
|
+
- 仓库主页:[github.com/open-spaced-repetition/ts-fsrs](https://github.com/open-spaced-repetition/ts-fsrs#readme)
|
|
230
|
+
- TypeDoc API 文档:[open-spaced-repetition.github.io/ts-fsrs](https://open-spaced-repetition.github.io/ts-fsrs/)
|
|
231
|
+
- 优化器包:[`@open-spaced-repetition/binding`](https://www.npmjs.com/package/@open-spaced-repetition/binding)
|
|
232
|
+
|
|
233
|
+
## 示例
|
|
234
|
+
|
|
235
|
+
- 浏览器示例:[example/example.html](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/example/example.html)
|
|
236
|
+
- 完整示例项目:[ts-fsrs-demo](https://github.com/ishiko732/ts-fsrs-demo)
|
|
237
|
+
- 其他:
|
|
238
|
+
- [spaced](https://github.com/zsh-eng/spaced)
|
|
239
|
+
- [Anki Search Stats Extended](https://github.com/Luc-Mcgrady/Anki-Search-Stats-Extended)
|
|
240
|
+
|
|
241
|
+
## 贡献
|
|
242
|
+
|
|
243
|
+
贡献说明见 [`CONTRIBUTING.md`](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/CONTRIBUTING.md)。
|
package/README_JA.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# ts-fsrs
|
|
2
|
+
|
|
3
|
+
[Introduction](./README.md) | [简体中文](./README_CN.md) | [はじめに](./README_JA.md)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-6)
|
|
6
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
7
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
8
|
+
|
|
9
|
+
**ts-fsrs は、Free Spaced Repetition Scheduler (FSRS) アルゴリズムを使って独自の間隔反復システムを構築するための TypeScript パッケージです。**
|
|
10
|
+
|
|
11
|
+
## 目次
|
|
12
|
+
|
|
13
|
+
- [ts-fsrs](#ts-fsrs)
|
|
14
|
+
- [目次](#目次)
|
|
15
|
+
- [インストール](#インストール)
|
|
16
|
+
- [クイックスタート](#クイックスタート)
|
|
17
|
+
- [使い方](#使い方)
|
|
18
|
+
- [カスタムパラメータ](#カスタムパラメータ)
|
|
19
|
+
- [`generatorParameters`](#generatorparameters)
|
|
20
|
+
- [`repeat` と `next`](#repeat-と-next)
|
|
21
|
+
- [想起確率](#想起確率)
|
|
22
|
+
- [`next_state` と `next_interval`](#next_state-と-next_interval)
|
|
23
|
+
- [履歴関連のヘルパー](#履歴関連のヘルパー)
|
|
24
|
+
- [リファレンス](#リファレンス)
|
|
25
|
+
- [API ドキュメント](#api-ドキュメント)
|
|
26
|
+
- [例](#例)
|
|
27
|
+
- [コントリビュート](#コントリビュート)
|
|
28
|
+
|
|
29
|
+
## インストール
|
|
30
|
+
|
|
31
|
+
`ts-fsrs` は Node.js `>=20.0.0` を必要とします。
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install ts-fsrs
|
|
35
|
+
yarn add ts-fsrs
|
|
36
|
+
pnpm install ts-fsrs
|
|
37
|
+
bun add ts-fsrs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## クイックスタート
|
|
41
|
+
|
|
42
|
+
スケジューラーを初期化します。
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { createEmptyCard, fsrs, Rating } from 'ts-fsrs'
|
|
46
|
+
|
|
47
|
+
const scheduler = fsrs()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
新しいカードを作成します。
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const card = createEmptyCard()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
4 つの評価に対する結果をまとめてプレビューします。
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const preview = scheduler.repeat(card, new Date())
|
|
60
|
+
|
|
61
|
+
console.log(preview[Rating.Again].card)
|
|
62
|
+
console.log(preview[Rating.Hard].card)
|
|
63
|
+
console.log(preview[Rating.Good].card)
|
|
64
|
+
console.log(preview[Rating.Easy].card)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
ユーザーの評価がすでに確定している場合は、その評価を直接適用します。
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
71
|
+
|
|
72
|
+
console.log(result.card)
|
|
73
|
+
console.log(result.log)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 使い方
|
|
77
|
+
|
|
78
|
+
### カスタムパラメータ
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { fsrs } from 'ts-fsrs'
|
|
82
|
+
|
|
83
|
+
const scheduler = fsrs({
|
|
84
|
+
request_retention: 0.9,
|
|
85
|
+
maximum_interval: 36500,
|
|
86
|
+
enable_fuzz: true,
|
|
87
|
+
enable_short_term: true,
|
|
88
|
+
learning_steps: ['1m', '10m'],
|
|
89
|
+
relearning_steps: ['10m'],
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`request_retention` は、スケジューラーが維持したい最低保持率(0%から100%)を表します。値を高くすると復習回数は増え、低くすると減ります。
|
|
94
|
+
|
|
95
|
+
`maximum_interval` は、カードをどれだけ先までスケジュールできるかの上限です。
|
|
96
|
+
|
|
97
|
+
`enable_fuzz` は、長い間隔に少量のランダムな揺らぎを加えます。
|
|
98
|
+
|
|
99
|
+
`enable_short_term`、`learning_steps`、`relearning_steps` は短期学習と再学習のステップ挙動を制御します。
|
|
100
|
+
|
|
101
|
+
### `generatorParameters`
|
|
102
|
+
|
|
103
|
+
`fsrs()` は内部で `generatorParameters()` を使って入力を正規化するため、通常の初期化では部分的な設定オブジェクトをそのまま `fsrs()` に渡せます。
|
|
104
|
+
|
|
105
|
+
`generatorParameters()` は、シリアライズ、保存、または完全な `FSRSParameters` オブジェクトの再利用が必要な場合に使ってください。
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { fsrs, generatorParameters } from 'ts-fsrs'
|
|
109
|
+
|
|
110
|
+
const params = generatorParameters({
|
|
111
|
+
request_retention: 0.9,
|
|
112
|
+
maximum_interval: 36500,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
console.log(JSON.stringify(params))
|
|
116
|
+
|
|
117
|
+
const scheduler = fsrs(params)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
保存したパラメータをあとで読み込む場合も、パースしたオブジェクトをそのまま `fsrs()` に渡せます。
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { fsrs, type FSRSParameters } from 'ts-fsrs'
|
|
124
|
+
|
|
125
|
+
const serializedParams = '{"request_retention":0.9,"maximum_interval":36500}'
|
|
126
|
+
const params = JSON.parse(serializedParams) as FSRSParameters
|
|
127
|
+
const scheduler = fsrs(params)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
これらのパラメータが外部ストレージ、ユーザー入力、またはネットワークから来る場合は、`fsrs()` に渡す前にアプリケーション境界でランタイム検証を行うことを推奨します。`zod` のようなランタイム schema ライブラリはこの用途に適しています。
|
|
131
|
+
|
|
132
|
+
### `repeat` と `next`
|
|
133
|
+
|
|
134
|
+
ユーザーが回答する前に 4 通りの結果を見たい場合は `repeat` を使います。
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const preview = scheduler.repeat(card, new Date())
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
ユーザーの評価がすでに分かっている場合は `next` を使います。
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const result = scheduler.next(card, new Date(), Rating.Good)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
結果をそのまま自分の保存形式に変換したい場合は `afterHandler` を使えます。
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const saved = scheduler.next(card, new Date(), Rating.Good, ({ card, log }) => ({
|
|
150
|
+
card: {
|
|
151
|
+
...card,
|
|
152
|
+
due: card.due.getTime(),
|
|
153
|
+
last_review: card.last_review?.getTime() ?? null,
|
|
154
|
+
},
|
|
155
|
+
log: {
|
|
156
|
+
...log,
|
|
157
|
+
due: log.due.getTime(),
|
|
158
|
+
review: log.review.getTime(),
|
|
159
|
+
},
|
|
160
|
+
}))
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 想起確率
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
const retrievability = scheduler.get_retrievability(result.card, new Date(), false)
|
|
167
|
+
console.log(retrievability)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`elapsed_days`、`stability`、そして有効な decay 値がすでにある場合は、`forgetting_curve()` を直接使って想起確率を計算することもできます。
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { forgetting_curve } from 'ts-fsrs'
|
|
174
|
+
|
|
175
|
+
const retrievability = forgetting_curve(0.5, 12, result.card.stability)
|
|
176
|
+
console.log(retrievability)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
decay 値を直接渡す場合は、正の数であり、`0.1` から `0.8` の範囲内である必要があります。
|
|
180
|
+
|
|
181
|
+
### `next_state` と `next_interval`
|
|
182
|
+
|
|
183
|
+
記憶状態を直接扱う場合は、`next_state()` と `next_interval()` を組み合わせて使えます。
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { fsrs, Rating, type FSRSState } from 'ts-fsrs'
|
|
187
|
+
|
|
188
|
+
const scheduler = fsrs({ enable_fuzz: false })
|
|
189
|
+
|
|
190
|
+
const memoryState: FSRSState = {
|
|
191
|
+
stability: 3.2,
|
|
192
|
+
difficulty: 5.6,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const elapsedDays = 12
|
|
196
|
+
const nextState = scheduler.next_state(memoryState, elapsedDays, Rating.Good)
|
|
197
|
+
const nextInterval = scheduler.next_interval(nextState.stability, elapsedDays)
|
|
198
|
+
|
|
199
|
+
console.log(nextState)
|
|
200
|
+
console.log(nextInterval)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
これはシミュレーション、分析、または `{ stability, difficulty }` を自前で扱うカスタムスケジューリングに便利です。通常の復習フローでは `repeat()` または `next()` を使うほうが自然です。
|
|
204
|
+
|
|
205
|
+
### 履歴関連のヘルパー
|
|
206
|
+
|
|
207
|
+
スケジューラーは次の補助メソッドも提供します。
|
|
208
|
+
|
|
209
|
+
- `rollback(card, log)`
|
|
210
|
+
- `forget(card, now, reset_count?)`
|
|
211
|
+
- `reschedule(card, reviews, options?)`
|
|
212
|
+
|
|
213
|
+
これらは、既存データのインポート、履歴の再生、保存済みログからの状態再構築に便利です。
|
|
214
|
+
|
|
215
|
+
## リファレンス
|
|
216
|
+
|
|
217
|
+
カードの状態:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
State.New
|
|
221
|
+
State.Learning
|
|
222
|
+
State.Review
|
|
223
|
+
State.Relearning
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
レビュー評価:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
Rating.Again
|
|
230
|
+
Rating.Hard
|
|
231
|
+
Rating.Good
|
|
232
|
+
Rating.Easy
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## API ドキュメント
|
|
236
|
+
|
|
237
|
+
- リポジトリ概要:[github.com/open-spaced-repetition/ts-fsrs](https://github.com/open-spaced-repetition/ts-fsrs#readme)
|
|
238
|
+
- TypeDoc API ドキュメント:[open-spaced-repetition.github.io/ts-fsrs](https://open-spaced-repetition.github.io/ts-fsrs/)
|
|
239
|
+
- オプティマイザーパッケージ:[`@open-spaced-repetition/binding`](https://www.npmjs.com/package/@open-spaced-repetition/binding)
|
|
240
|
+
|
|
241
|
+
## 例
|
|
242
|
+
|
|
243
|
+
- ブラウザ例:[example/example.html](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/example/example.html)
|
|
244
|
+
- フルスタックデモ:[ts-fsrs-demo](https://github.com/ishiko732/ts-fsrs-demo)
|
|
245
|
+
- その他の例:
|
|
246
|
+
- [spaced](https://github.com/zsh-eng/spaced)
|
|
247
|
+
- [Anki Search Stats Extended](https://github.com/Luc-Mcgrady/Anki-Search-Stats-Extended)
|
|
248
|
+
|
|
249
|
+
## コントリビュート
|
|
250
|
+
|
|
251
|
+
貢献ガイドは [`CONTRIBUTING.md`](https://github.com/open-spaced-repetition/ts-fsrs/blob/main/CONTRIBUTING.md) を参照してください。
|
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -410,7 +410,7 @@ declare const clipParameters: (parameters: number[], numRelearningSteps: number,
|
|
|
410
410
|
* alert(e);
|
|
411
411
|
* }
|
|
412
412
|
*/
|
|
413
|
-
declare const checkParameters: (parameters: number[] | readonly number[]) =>
|
|
413
|
+
declare const checkParameters: (parameters: number[] | readonly number[]) => number[] | readonly number[];
|
|
414
414
|
declare const migrateParameters: (parameters?: number[] | readonly number[], numRelearningSteps?: number, enableShortTerm?: boolean) => number[];
|
|
415
415
|
declare const generatorParameters: (props?: Partial<FSRSParameters>) => FSRSParameters;
|
|
416
416
|
/**
|
package/dist/index.mjs
CHANGED
package/dist/index.umd.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-fsrs",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "5.3.
|
|
4
|
+
"version": "5.3.2",
|
|
5
5
|
"description": "ts-fsrs is a versatile package written in TypeScript that supports ES modules, CommonJS, and UMD. It implements the Free Spaced Repetition Scheduler (FSRS) algorithm, enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@rollup/plugin-commonjs": "^29.0.
|
|
20
|
+
"@rollup/plugin-commonjs": "^29.0.2",
|
|
21
21
|
"@rollup/plugin-json": "^6.1.0",
|
|
22
22
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
23
23
|
"decimal.js": "^10.5.0",
|
|
24
24
|
"rollup": "^4.54.0",
|
|
25
|
-
"rollup-plugin-dts": "^6.
|
|
25
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
26
26
|
"rollup-plugin-esbuild": "^6.2.1",
|
|
27
27
|
"tslib": "^2.8.1",
|
|
28
|
-
"typedoc": "0.28.
|
|
29
|
-
"typedoc-plugin-extras": "4.0.
|
|
28
|
+
"typedoc": "0.28.18",
|
|
29
|
+
"typedoc-plugin-extras": "4.0.1"
|
|
30
30
|
},
|
|
31
31
|
"author": "ishiko",
|
|
32
32
|
"license": "MIT",
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
"dist",
|
|
40
40
|
"CHANGELOG.md",
|
|
41
41
|
"README.md",
|
|
42
|
+
"README_CN.md",
|
|
43
|
+
"README_JA.md",
|
|
42
44
|
"LICENSE"
|
|
43
45
|
],
|
|
44
46
|
"repository": {
|