mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
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:
parent
6ff309e08f
commit
b0eb2a2b97
6 changed files with 54 additions and 12 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) })
|
||||
}`,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
Loading…
Reference in a new issue