hoàn thành v 1.0.2 bản áp dụng thuật toán FSRS
This commit is contained in:
@@ -1104,7 +1104,8 @@ export class PageService {
|
||||
nextDifficulty = w[4] - w[5] * (quality - 3);
|
||||
nextState = quality === 1 ? 1 : 2; // If Again, move to Learning, else Review
|
||||
} else {
|
||||
const retrievability = Math.pow(0.9, elapsedDays / stability);
|
||||
// Avoid division by zero if stability is 0
|
||||
const retrievability = stability > 0 ? Math.pow(0.9, elapsedDays / stability) : 0;
|
||||
|
||||
if (quality === 1) {
|
||||
// Failed
|
||||
@@ -1123,8 +1124,9 @@ export class PageService {
|
||||
}
|
||||
}
|
||||
|
||||
// Constraints
|
||||
nextStability = Math.min(Math.max(nextStability, 0.1), 36500);
|
||||
// Constraints & NaN guard
|
||||
nextStability = Math.min(Math.max(nextStability || 0.1, 0.1), 36500);
|
||||
nextDifficulty = Math.min(Math.max(nextDifficulty || 5, 1), 10);
|
||||
|
||||
// FSRS interval formula: I = S * ln(target_recall) / ln(0.9)
|
||||
// For default target_recall = 0.9, I = S
|
||||
@@ -1147,54 +1149,63 @@ export class PageService {
|
||||
pageId,
|
||||
);
|
||||
|
||||
return this.pageRepo.findById(pageId);
|
||||
}
|
||||
|
||||
async getPagesToReview(userId: string, pagination: PaginationOptions, spaceId?: string, onlyDue = true) {
|
||||
let query = this.db
|
||||
.selectFrom('pages')
|
||||
.innerJoin('spaces', 'spaces.id', 'pages.spaceId')
|
||||
.select([
|
||||
'pages.id',
|
||||
'pages.slugId',
|
||||
'pages.title',
|
||||
'pages.icon',
|
||||
'pages.spaceId',
|
||||
'pages.nextReviewDate',
|
||||
'pages.easeFactor',
|
||||
'pages.repetitionCount',
|
||||
'pages.reviewInterval',
|
||||
'pages.createdAt',
|
||||
'pages.updatedAt',
|
||||
])
|
||||
.select(
|
||||
sql<{ name: string; slug: string }>`json_build_object('name', spaces.name, 'slug', spaces.slug)`.as('space'),
|
||||
)
|
||||
.where('pages.nextReviewDate', 'is not', null)
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.orderBy('pages.nextReviewDate', 'asc');
|
||||
|
||||
if (onlyDue) {
|
||||
query = query.where('pages.nextReviewDate', '<=', new Date());
|
||||
}
|
||||
|
||||
if (spaceId) {
|
||||
query = query.where('pages.spaceId', '=', spaceId);
|
||||
} else {
|
||||
query = query.where('pages.spaceId', 'in', this.spaceMemberRepo.getUserSpaceIdsQuery(userId));
|
||||
}
|
||||
|
||||
return executeWithCursorPagination(query, {
|
||||
perPage: pagination.limit,
|
||||
cursor: pagination.cursor,
|
||||
fields: [
|
||||
{ expression: 'pages.nextReviewDate', direction: 'asc' },
|
||||
{ expression: 'pages.id', direction: 'asc' },
|
||||
],
|
||||
parseCursor: (cursor: any) => ({
|
||||
nextReviewDate: new Date(cursor.nextReviewDate),
|
||||
id: cursor.id,
|
||||
}),
|
||||
console.log('FSRS CALCULATION:', {
|
||||
pageId,
|
||||
quality,
|
||||
nextStability,
|
||||
nextDifficulty,
|
||||
nextReviewDate: nextReviewDate.toISOString(),
|
||||
reviewInterval: Math.round(exactReviewInterval)
|
||||
});
|
||||
|
||||
return this.pageRepo.findById(pageId);
|
||||
}
|
||||
|
||||
async getPagesToReview(userId: string, pagination: PaginationOptions, spaceId ?: string, onlyDue = true) {
|
||||
let query = this.db
|
||||
.selectFrom('pages')
|
||||
.innerJoin('spaces', 'spaces.id', 'pages.spaceId')
|
||||
.select([
|
||||
'pages.id',
|
||||
'pages.slugId',
|
||||
'pages.title',
|
||||
'pages.icon',
|
||||
'pages.spaceId',
|
||||
'pages.nextReviewDate',
|
||||
'pages.easeFactor',
|
||||
'pages.repetitionCount',
|
||||
'pages.reviewInterval',
|
||||
'pages.createdAt',
|
||||
'pages.updatedAt',
|
||||
])
|
||||
.select(
|
||||
sql<{ name: string; slug: string }>`json_build_object('name', spaces.name, 'slug', spaces.slug)`.as('space'),
|
||||
)
|
||||
.where('pages.nextReviewDate', 'is not', null)
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.orderBy('pages.nextReviewDate', 'asc');
|
||||
|
||||
if (onlyDue) {
|
||||
query = query.where('pages.nextReviewDate', '<=', new Date());
|
||||
}
|
||||
|
||||
if (spaceId) {
|
||||
query = query.where('pages.spaceId', '=', spaceId);
|
||||
} else {
|
||||
query = query.where('pages.spaceId', 'in', this.spaceMemberRepo.getUserSpaceIdsQuery(userId));
|
||||
}
|
||||
|
||||
return executeWithCursorPagination(query, {
|
||||
perPage: pagination.limit,
|
||||
cursor: pagination.cursor,
|
||||
fields: [
|
||||
{ expression: 'pages.nextReviewDate', direction: 'asc' },
|
||||
{ expression: 'pages.id', direction: 'asc' },
|
||||
],
|
||||
parseCursor: (cursor: any) => ({
|
||||
nextReviewDate: new Date(cursor.nextReviewDate),
|
||||
id: cursor.id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user