Merge branch 'ankitects:main' into patch-1

This commit is contained in:
user1823 2025-08-06 14:36:34 +05:30 committed by GitHub
commit 4e1f0d8726
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 55 additions and 22 deletions

View file

@ -236,6 +236,7 @@ Marvin Kopf <marvinkopf@outlook.com>
Kevin Nakamura <grinkers@grinkers.net>
Bradley Szoke <bradleyszoke@gmail.com>
jcznk <https://github.com/jcznk>
Thomas Rixen <thomas.rixen@student.uclouvain.be>
********************

4
Cargo.lock generated
View file

@ -2214,9 +2214,9 @@ dependencies = [
[[package]]
name = "fsrs"
version = "5.0.1"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df5aee516ebf9d4968364363b092371f988cd9fb628f7cae94ea422b6dd52f9c"
checksum = "04954cc67c3c11ee342a2ee1f5222bf76d73f7772df08d37dc9a6cdd73c467eb"
dependencies = [
"burn",
"itertools 0.14.0",

View file

@ -33,10 +33,8 @@ git = "https://github.com/ankitects/linkcheck.git"
rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
[workspace.dependencies.fsrs]
version = "5.0.1"
version = "5.1.0"
# git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
# branch = "Refactor/expected_workload_via_dp"
# rev = "a7f7efc10f0a26b14ee348cc7402155685f2a24f"
# path = "../open-spaced-repetition/fsrs-rs"
[workspace.dependencies]

View file

@ -1450,7 +1450,7 @@
},
{
"name": "fsrs",
"version": "5.0.1",
"version": "5.1.0",
"authors": "Open Spaced Repetition",
"repository": "https://github.com/open-spaced-repetition/fsrs-rs",
"license": "BSD-3-Clause",

View file

@ -3,6 +3,8 @@
use std::collections::HashMap;
use anki_proto::generic;
use rayon::iter::IntoParallelIterator;
use rayon::iter::ParallelIterator;
use crate::collection::Collection;
use crate::deckconfig::DeckConfSchema11;
@ -11,6 +13,7 @@ use crate::deckconfig::DeckConfigId;
use crate::deckconfig::UpdateDeckConfigsRequest;
use crate::error::Result;
use crate::scheduler::fsrs::params::ignore_revlogs_before_date_to_ms;
use crate::scheduler::fsrs::simulator::is_included_card;
impl crate::services::DeckConfigService for Collection {
fn add_or_update_deck_config_legacy(
@ -103,6 +106,7 @@ impl crate::services::DeckConfigService for Collection {
&mut self,
input: anki_proto::deck_config::GetRetentionWorkloadRequest,
) -> Result<anki_proto::deck_config::GetRetentionWorkloadResponse> {
let days_elapsed = self.timing_today().unwrap().days_elapsed as i32;
let guard =
self.search_cards_into_table(&input.search, crate::search::SortMode::NoOrder)?;
@ -112,12 +116,26 @@ impl crate::services::DeckConfigService for Collection {
.get_revlog_entries_for_searched_cards_in_card_order()?;
let config = guard.col.get_optimal_retention_parameters(revlogs)?;
let cards = guard
.col
.storage
.all_searched_cards()?
.into_iter()
.filter(is_included_card)
.filter_map(|c| crate::card::Card::convert(c.clone(), days_elapsed, c.memory_state?))
.collect::<Vec<fsrs::Card>>();
let costs = (70u32..=99u32)
.into_par_iter()
.map(|dr| {
Ok((
dr,
fsrs::expected_workload(&input.w, dr as f32 / 100., &config)?,
fsrs::expected_workload_with_existing_cards(
&input.w,
dr as f32 / 100.,
&config,
&cards,
)?,
))
})
.collect::<Result<HashMap<_, _>>>()?;

View file

@ -121,6 +121,12 @@ fn create_review_priority_fn(
}
}
pub(crate) fn is_included_card(c: &Card) -> bool {
c.queue != CardQueue::Suspended
&& c.queue != CardQueue::PreviewRepeat
&& c.ctype != CardType::New
}
impl Collection {
pub fn simulate_request_to_config(
&mut self,
@ -133,11 +139,6 @@ impl Collection {
.get_revlog_entries_for_searched_cards_in_card_order()?;
let mut cards = guard.col.storage.all_searched_cards()?;
drop(guard);
fn is_included_card(c: &Card) -> bool {
c.queue != CardQueue::Suspended
&& c.queue != CardQueue::PreviewRepeat
&& c.ctype != CardType::New
}
// calculate any missing memory state
for c in &mut cards {
if is_included_card(c) && c.memory_state.is_none() {
@ -306,7 +307,11 @@ impl Collection {
}
impl Card {
fn convert(card: Card, days_elapsed: i32, memory_state: FsrsMemoryState) -> Option<fsrs::Card> {
pub(crate) fn convert(
card: Card,
days_elapsed: i32,
memory_state: FsrsMemoryState,
) -> Option<fsrs::Card> {
match card.queue {
CardQueue::DayLearn | CardQueue::Review => {
let due = card.original_or_current_due();

View file

@ -30,14 +30,24 @@ impl Collection {
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
let timing = self.timing_today()?;
let seconds_elapsed = if let Some(last_review_time) = card.last_review_time {
timing.now.elapsed_secs_since(last_review_time) as u32
let last_review_time = if let Some(last_review_time) = card.last_review_time {
last_review_time
} else {
self.storage
let mut new_card = card.clone();
let last_review_time = self
.storage
.time_of_last_review(card.id)?
.map(|ts| timing.now.elapsed_secs_since(ts))
.unwrap_or_default() as u32
.unwrap_or_default();
new_card.last_review_time = Some(last_review_time);
self.storage.update_card(&new_card)?;
last_review_time
};
let seconds_elapsed = timing.now.elapsed_secs_since(last_review_time) as u32;
let fsrs_retrievability = card
.memory_state
.zip(Some(seconds_elapsed))

View file

@ -646,7 +646,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
.svg-container {
width: 100%;
max-height: calc(100vh - 400px); /* Account for modal header, controls, etc */
/* Account for modal header, controls, etc */
max-height: max(calc(100vh - 400px), 200px);
aspect-ratio: 600 / 250;
display: flex;
align-items: center;

View file

@ -18,8 +18,8 @@ import {
bin,
cumsum,
curveBasis,
interpolateBlues,
interpolateGreens,
interpolateOranges,
interpolatePurples,
interpolateReds,
max,
@ -181,7 +181,7 @@ export function renderReviews(
const reds = scaleSequential((n) => interpolateReds(cappedRange(n)!)).domain(
x.domain() as any,
);
const blues = scaleSequential((n) => interpolateBlues(cappedRange(n)!)).domain(
const oranges = scaleSequential((n) => interpolateOranges(cappedRange(n)!)).domain(
x.domain() as any,
);
const purples = scaleSequential((n) => interpolatePurples(cappedRange(n)!)).domain(
@ -195,7 +195,7 @@ export function renderReviews(
case BinIndex.Young:
return lighterGreens;
case BinIndex.Learn:
return blues;
return oranges;
case BinIndex.Relearn:
return reds;
case BinIndex.Filtered: