Feat/Estimated Total Knowledge By Note & Daily Load (#3507)

* Feat/Estimated Total Knowledge By Note & Daily Load

* Update rslib/src/stats/graphs/retrievability.rs

* Update rslib/src/stats/graphs/future_due.rs
This commit is contained in:
Jarrett Ye 2024-10-21 13:19:42 +08:00 committed by GitHub
parent 6ff309e08f
commit b0eb2a2b97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 54 additions and 12 deletions

View file

@ -48,6 +48,11 @@ statistics-cards =
[one] { $cards } card
*[other] { $cards } cards
}
statistics-notes =
{ $notes ->
[one] { $notes } note
*[other] { $notes } notes
}
# a count of how many cards have been answered, eg "Total: 34 reviews"
statistics-reviews =
{ $reviews ->
@ -220,6 +225,7 @@ statistics-average-answer-time-label = Average answer time
statistics-average = Average
statistics-average-interval = Average interval
statistics-due-tomorrow = Due tomorrow
statistics-daily-load = Daily load
# eg 5 of 15 (33.3%)
statistics-amount-of-total-with-percentage = { $amount } of { $total } ({ $percent }%)
statistics-average-over-period = Average over period

View file

@ -85,11 +85,13 @@ message GraphsResponse {
message Retrievability {
map<uint32, uint32> retrievability = 1;
float average = 2;
float sum = 3;
float sum_by_card = 3;
float sum_by_note = 4;
}
message FutureDue {
map<int32, uint32> future_due = 1;
bool have_backlog = 2;
uint32 daily_load = 3;
}
message Today {
uint32 answer_count = 1;

View file

@ -13,6 +13,7 @@ impl GraphsContext {
pub(super) fn future_due(&self) -> FutureDue {
let mut have_backlog = false;
let mut due_by_day: HashMap<i32, u32> = Default::default();
let mut daily_load = 0.0;
for c in &self.cards {
if matches!(c.queue, CardQueue::New | CardQueue::Suspended) {
continue;
@ -31,10 +32,16 @@ impl GraphsContext {
}
have_backlog |= due_day < 0;
*due_by_day.entry(due_day).or_default() += 1;
if matches!(c.queue, CardQueue::Review | CardQueue::DayLearn) {
daily_load += 1.0 / c.interval.max(1) as f32;
} else {
daily_load += 1.0;
}
}
FutureDue {
future_due: due_by_day,
have_backlog,
daily_load: daily_load as u32,
}
}
}

View file

@ -19,25 +19,37 @@ impl GraphsContext {
next_day_at: Default::default(),
};
let fsrs = FSRS::new(None).unwrap();
// note id -> (sum, count)
let mut note_retrievability: std::collections::HashMap<i64, (f32, u32)> =
std::collections::HashMap::new();
for card in &self.cards {
let entry = note_retrievability
.entry(card.note_id.0)
.or_insert((0.0, 0));
entry.1 += 1;
if let Some(state) = card.memory_state {
let r = fsrs.current_retrievability(
state.into(),
card.days_since_last_review(&timing).unwrap_or_default(),
);
let elapsed_days = card.days_since_last_review(&timing).unwrap_or_default();
let r = fsrs.current_retrievability(state.into(), elapsed_days);
*retrievability
.retrievability
.entry(percent_to_bin(r * 100.0))
.or_insert_with(Default::default) += 1;
retrievability.sum += r;
retrievability.sum_by_card += r;
card_with_retrievability_count += 1;
entry.0 += r;
} else {
entry.0 += 0.0;
}
}
if card_with_retrievability_count != 0 {
retrievability.average =
retrievability.sum * 100.0 / card_with_retrievability_count as f32;
retrievability.sum_by_card * 100.0 / card_with_retrievability_count as f32;
}
retrievability.sum_by_note = note_retrievability
.values()
.map(|(sum, count)| sum / *count as f32)
.sum();
retrievability
}
}

View file

@ -19,11 +19,16 @@ import type { HistogramData } from "./histogram-graph";
export interface GraphData {
dueCounts: Map<number, number>;
haveBacklog: boolean;
dailyLoad: number;
}
export function gatherData(data: GraphsResponse): GraphData {
const msg = data.futureDue!;
return { dueCounts: numericMap(msg.futureDue), haveBacklog: msg.haveBacklog };
return {
dueCounts: numericMap(msg.futureDue),
haveBacklog: msg.haveBacklog,
dailyLoad: msg.dailyLoad,
};
}
export interface FutureDueResponse {
@ -138,6 +143,12 @@ export function buildHistogram(
reviews: sourceData.dueCounts.get(1) ?? 0,
}),
},
{
label: tr.statisticsDailyLoad(),
value: tr.statisticsReviews({
reviews: sourceData.dailyLoad,
}),
},
];
return {

View file

@ -18,14 +18,16 @@ import type { HistogramData } from "./histogram-graph";
export interface GraphData {
retrievability: Map<number, number>;
average: number;
sum: number;
sumByCard: number;
sumByNote: number;
}
export function gatherData(data: GraphsResponse): GraphData {
return {
retrievability: numericMap(data.retrievability!.retrievability),
average: data.retrievability!.average,
sum: data.retrievability!.sum,
sumByCard: data.retrievability!.sumByCard,
sumByNote: data.retrievability!.sumByNote,
};
}
@ -111,7 +113,9 @@ export function prepareData(
},
{
label: tr.statisticsEstimatedTotalKnowledge(),
value: tr.statisticsCards({ cards: +data.sum.toFixed(0) }),
value: `${tr.statisticsCards({ cards: +data.sumByCard.toFixed(0) })} / ${
tr.statisticsNotes({ notes: +data.sumByNote.toFixed(0) })
}`,
},
];