Skip to content

Commit bc63db2

Browse files
ishiko732xiaohajiayou
authored andcommitted
Fix/incorrect state judgment causes stability to remain unchanged
1 parent b89a147 commit bc63db2

File tree

1 file changed

+35
-78
lines changed

1 file changed

+35
-78
lines changed

src/popup/util/fsrs.js

Lines changed: 35 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FSRS, Rating, createEmptyCard, generatorParameters } from 'ts-fsrs';
1+
import { FSRS, Rating, S_MIN, State, TypeConvert, createEmptyCard, dateDiffInDays, generatorParameters } from 'ts-fsrs';
22

33
// 1. 创建自定义参数
44
const params = generatorParameters({
@@ -26,77 +26,42 @@ const qualityToRating = (quality) => {
2626
export const calculateNextReview = (problem, feedback) => {
2727
try {
2828
const now = new Date();
29+
const lastReview = problem.fsrsState && problem.fsrsState.lastReview
30+
? new Date(problem.fsrsState.lastReview)
31+
: new Date(problem.submissionTime || now.getTime());
2932

3033
// 如果没有 fsrsState,创建一个默认的
3134
if (!problem.fsrsState) {
32-
problem.fsrsState = {
33-
difficulty: null,
34-
quality: null,
35-
lastReview: problem.submissionTime || now.getTime(),
36-
nextReview: null,
37-
reviewCount: 0,
38-
stability: 0,
39-
state: 'New',
40-
lapses: 0
41-
};
35+
problem.fsrsState = createEmptyCard(lastReview, (card) => {
36+
return {
37+
nextReview: +card.due,
38+
stability: card.stability,
39+
difficulty: card.difficulty,
40+
state: card.state,
41+
reps: card.reps,
42+
lapses: card.lapses
43+
}
44+
});
4245
}
46+
let card = problem.fsrsState
4347

44-
const lastReview = problem.fsrsState.lastReview
45-
? new Date(problem.fsrsState.lastReview)
46-
: new Date(problem.submissionTime || now.getTime());
47-
48-
let card = createEmptyCard(lastReview);
49-
50-
if (problem.fsrsState.state !== 'New') {
51-
card = {
52-
...card,
53-
state: problem.fsrsState.state,
54-
stability: problem.fsrsState.stability || 0,
55-
difficulty: problem.fsrsState.difficulty || 0,
56-
reps: problem.fsrsState.reviewCount || 0,
57-
lapses: problem.fsrsState.lapses || 0,
58-
// 添加时间相关字段
59-
elapsed_days: problem.fsrsState.lastReview
60-
? (now - new Date(problem.fsrsState.lastReview)) / (24 * 60 * 60 * 1000)
61-
: 0,
62-
scheduled_days: problem.fsrsState.nextReview
63-
? (new Date(problem.fsrsState.nextReview) - new Date(problem.fsrsState.lastReview)) / (24 * 60 * 60 * 1000)
64-
: 0
65-
};
66-
}
67-
6848
const rating = qualityToRating(feedback.quality);
69-
const scheduling_cards = fsrs.repeat(card, now);
70-
const result = scheduling_cards[rating];
49+
const result = fsrs.next({
50+
due: card.nextReview,
51+
stability: card.stability,
52+
difficulty: card.difficulty,
53+
elapsed_days: (now.getTime() - lastReview.getTime()) / (1000 * 60 * 60 * 24),
54+
scheduled_days: Math.floor((card.nextReview - card.lastReview) / (1000 * 60 * 60 * 24)),
55+
reps: card.reviewCount,
56+
lapse_count: card.lapses,
57+
state: card.state,
58+
last_review: card.lastReview || undefined,
59+
}, now, rating);
7160

72-
if (!result || !result.card) {
73-
console.error('FSRS calculation failed:', result);
74-
// 默认间隔
75-
const defaultDays = {
76-
[Rating.Again]: 1,
77-
[Rating.Hard]: 3,
78-
[Rating.Good]: 7,
79-
[Rating.Easy]: 14
80-
}[rating] || 1;
81-
82-
return {
83-
nextReview: now.getTime() + (defaultDays * 24 * 60 * 60 * 1000),
84-
stability: card.stability,
85-
difficulty: card.difficulty,
86-
state: card.state,
87-
reps: card.reps + 1,
88-
lapses: card.lapses
89-
};
90-
}
91-
92-
// 确保间隔至少为1天
93-
const nextReviewTime = Math.max(
94-
result.card.due.getTime(),
95-
now.getTime() + (24 * 60 * 60 * 1000)
96-
);
9761

9862
return {
99-
nextReview: nextReviewTime,
63+
/**长期调度模式,ivl一定大于1d */
64+
nextReview: +result.card.due,
10065
stability: result.card.stability,
10166
difficulty: result.card.difficulty,
10267
state: result.card.state,
@@ -107,25 +72,17 @@ export const calculateNextReview = (problem, feedback) => {
10772
console.error('Error in calculateNextReview:', error);
10873
return {
10974
nextReview: now.getTime() + (24 * 60 * 60 * 1000),
110-
stability: problem.fsrsState.stability || 0,
111-
difficulty: problem.fsrsState.difficulty || 0,
112-
state: problem.fsrsState.state || 'New',
75+
stability: problem.fsrsState.stability || S_MIN,
76+
/** ref: https://github.com/open-spaced-repetition/ts-fsrs/blob/5eabd189d4740027ce1018cc968e67ca46c048a3/src/fsrs/default.ts#L20-L40 */
77+
difficulty: problem.fsrsState.difficulty || params.w[4],
78+
/** 长期调度下状态一定是New或Review */
79+
state: problem.fsrsState.state || State.Review,
11380
reps: (problem.fsrsState.reviewCount || 0) + 1,
11481
lapses: problem.fsrsState.lapses || 0
11582
};
11683
}
11784
};
11885

119-
// 将状态转换为数字
120-
const stateToNumber = (state) => {
121-
switch (state) {
122-
case 'New': return 0;
123-
case 'Learning': return 1;
124-
case 'Review': return 2;
125-
case 'Relearning': return 3;
126-
default: return 0;
127-
}
128-
};
12986

13087
// 5. 更新问题状态
13188
export const updateProblemWithFSRS = (problem, feedback) => {
@@ -137,7 +94,7 @@ export const updateProblemWithFSRS = (problem, feedback) => {
13794
card_id: problem.index, // 使用问题索引作为卡片ID
13895
review_time: now, // 复习时间(毫秒时间戳)
13996
review_rating: qualityToRating(feedback.quality), // 复习评分 (1-4)
140-
review_state: stateToNumber(problem.fsrsState?.state || 'New') // 复习状态 (0-3)
97+
review_state: TypeConvert.state(problem.fsrsState ? problem.fsrsState?.state : 'New') // 复习状态 (0-3)
14198
};
14299

143100
// 将复习日志存储到单独的 localStorage 键中
@@ -149,7 +106,7 @@ export const updateProblemWithFSRS = (problem, feedback) => {
149106
difficulty: fsrsResult.difficulty,
150107
stability: fsrsResult.stability,
151108
state: fsrsResult.state,
152-
lastReview: now,
109+
lastReview: fsrsResult.lastReview,
153110
nextReview: fsrsResult.nextReview,
154111
reviewCount: fsrsResult.reps,
155112
lapses: fsrsResult.lapses,

0 commit comments

Comments
 (0)