mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 09:16:38 -04:00
Merge branch 'ankitects:main' into patch-1
This commit is contained in:
commit
4e1f0d8726
9 changed files with 55 additions and 22 deletions
|
@ -236,6 +236,7 @@ Marvin Kopf <marvinkopf@outlook.com>
|
||||||
Kevin Nakamura <grinkers@grinkers.net>
|
Kevin Nakamura <grinkers@grinkers.net>
|
||||||
Bradley Szoke <bradleyszoke@gmail.com>
|
Bradley Szoke <bradleyszoke@gmail.com>
|
||||||
jcznk <https://github.com/jcznk>
|
jcznk <https://github.com/jcznk>
|
||||||
|
Thomas Rixen <thomas.rixen@student.uclouvain.be>
|
||||||
|
|
||||||
********************
|
********************
|
||||||
|
|
||||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2214,9 +2214,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsrs"
|
name = "fsrs"
|
||||||
version = "5.0.1"
|
version = "5.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df5aee516ebf9d4968364363b092371f988cd9fb628f7cae94ea422b6dd52f9c"
|
checksum = "04954cc67c3c11ee342a2ee1f5222bf76d73f7772df08d37dc9a6cdd73c467eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"burn",
|
"burn",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
|
|
|
@ -33,10 +33,8 @@ git = "https://github.com/ankitects/linkcheck.git"
|
||||||
rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
|
rev = "184b2ca50ed39ca43da13f0b830a463861adb9ca"
|
||||||
|
|
||||||
[workspace.dependencies.fsrs]
|
[workspace.dependencies.fsrs]
|
||||||
version = "5.0.1"
|
version = "5.1.0"
|
||||||
# git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
|
# git = "https://github.com/open-spaced-repetition/fsrs-rs.git"
|
||||||
# branch = "Refactor/expected_workload_via_dp"
|
|
||||||
# rev = "a7f7efc10f0a26b14ee348cc7402155685f2a24f"
|
|
||||||
# path = "../open-spaced-repetition/fsrs-rs"
|
# path = "../open-spaced-repetition/fsrs-rs"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
@ -1450,7 +1450,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fsrs",
|
"name": "fsrs",
|
||||||
"version": "5.0.1",
|
"version": "5.1.0",
|
||||||
"authors": "Open Spaced Repetition",
|
"authors": "Open Spaced Repetition",
|
||||||
"repository": "https://github.com/open-spaced-repetition/fsrs-rs",
|
"repository": "https://github.com/open-spaced-repetition/fsrs-rs",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anki_proto::generic;
|
use anki_proto::generic;
|
||||||
|
use rayon::iter::IntoParallelIterator;
|
||||||
|
use rayon::iter::ParallelIterator;
|
||||||
|
|
||||||
use crate::collection::Collection;
|
use crate::collection::Collection;
|
||||||
use crate::deckconfig::DeckConfSchema11;
|
use crate::deckconfig::DeckConfSchema11;
|
||||||
|
@ -11,6 +13,7 @@ use crate::deckconfig::DeckConfigId;
|
||||||
use crate::deckconfig::UpdateDeckConfigsRequest;
|
use crate::deckconfig::UpdateDeckConfigsRequest;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::scheduler::fsrs::params::ignore_revlogs_before_date_to_ms;
|
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 {
|
impl crate::services::DeckConfigService for Collection {
|
||||||
fn add_or_update_deck_config_legacy(
|
fn add_or_update_deck_config_legacy(
|
||||||
|
@ -103,6 +106,7 @@ impl crate::services::DeckConfigService for Collection {
|
||||||
&mut self,
|
&mut self,
|
||||||
input: anki_proto::deck_config::GetRetentionWorkloadRequest,
|
input: anki_proto::deck_config::GetRetentionWorkloadRequest,
|
||||||
) -> Result<anki_proto::deck_config::GetRetentionWorkloadResponse> {
|
) -> Result<anki_proto::deck_config::GetRetentionWorkloadResponse> {
|
||||||
|
let days_elapsed = self.timing_today().unwrap().days_elapsed as i32;
|
||||||
let guard =
|
let guard =
|
||||||
self.search_cards_into_table(&input.search, crate::search::SortMode::NoOrder)?;
|
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()?;
|
.get_revlog_entries_for_searched_cards_in_card_order()?;
|
||||||
|
|
||||||
let config = guard.col.get_optimal_retention_parameters(revlogs)?;
|
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)
|
let costs = (70u32..=99u32)
|
||||||
|
.into_par_iter()
|
||||||
.map(|dr| {
|
.map(|dr| {
|
||||||
Ok((
|
Ok((
|
||||||
dr,
|
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<_, _>>>()?;
|
.collect::<Result<HashMap<_, _>>>()?;
|
||||||
|
|
|
@ -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 {
|
impl Collection {
|
||||||
pub fn simulate_request_to_config(
|
pub fn simulate_request_to_config(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -133,11 +139,6 @@ impl Collection {
|
||||||
.get_revlog_entries_for_searched_cards_in_card_order()?;
|
.get_revlog_entries_for_searched_cards_in_card_order()?;
|
||||||
let mut cards = guard.col.storage.all_searched_cards()?;
|
let mut cards = guard.col.storage.all_searched_cards()?;
|
||||||
drop(guard);
|
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
|
// calculate any missing memory state
|
||||||
for c in &mut cards {
|
for c in &mut cards {
|
||||||
if is_included_card(c) && c.memory_state.is_none() {
|
if is_included_card(c) && c.memory_state.is_none() {
|
||||||
|
@ -306,7 +307,11 @@ impl Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Card {
|
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 {
|
match card.queue {
|
||||||
CardQueue::DayLearn | CardQueue::Review => {
|
CardQueue::DayLearn | CardQueue::Review => {
|
||||||
let due = card.original_or_current_due();
|
let due = card.original_or_current_due();
|
||||||
|
|
|
@ -30,14 +30,24 @@ impl Collection {
|
||||||
|
|
||||||
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
|
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
|
||||||
let timing = self.timing_today()?;
|
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 {
|
} else {
|
||||||
self.storage
|
let mut new_card = card.clone();
|
||||||
|
let last_review_time = self
|
||||||
|
.storage
|
||||||
.time_of_last_review(card.id)?
|
.time_of_last_review(card.id)?
|
||||||
.map(|ts| timing.now.elapsed_secs_since(ts))
|
.unwrap_or_default();
|
||||||
.unwrap_or_default() as u32
|
|
||||||
|
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
|
let fsrs_retrievability = card
|
||||||
.memory_state
|
.memory_state
|
||||||
.zip(Some(seconds_elapsed))
|
.zip(Some(seconds_elapsed))
|
||||||
|
|
|
@ -646,7 +646,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
.svg-container {
|
.svg-container {
|
||||||
width: 100%;
|
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;
|
aspect-ratio: 600 / 250;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -18,8 +18,8 @@ import {
|
||||||
bin,
|
bin,
|
||||||
cumsum,
|
cumsum,
|
||||||
curveBasis,
|
curveBasis,
|
||||||
interpolateBlues,
|
|
||||||
interpolateGreens,
|
interpolateGreens,
|
||||||
|
interpolateOranges,
|
||||||
interpolatePurples,
|
interpolatePurples,
|
||||||
interpolateReds,
|
interpolateReds,
|
||||||
max,
|
max,
|
||||||
|
@ -181,7 +181,7 @@ export function renderReviews(
|
||||||
const reds = scaleSequential((n) => interpolateReds(cappedRange(n)!)).domain(
|
const reds = scaleSequential((n) => interpolateReds(cappedRange(n)!)).domain(
|
||||||
x.domain() as any,
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
const blues = scaleSequential((n) => interpolateBlues(cappedRange(n)!)).domain(
|
const oranges = scaleSequential((n) => interpolateOranges(cappedRange(n)!)).domain(
|
||||||
x.domain() as any,
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
const purples = scaleSequential((n) => interpolatePurples(cappedRange(n)!)).domain(
|
const purples = scaleSequential((n) => interpolatePurples(cappedRange(n)!)).domain(
|
||||||
|
@ -195,7 +195,7 @@ export function renderReviews(
|
||||||
case BinIndex.Young:
|
case BinIndex.Young:
|
||||||
return lighterGreens;
|
return lighterGreens;
|
||||||
case BinIndex.Learn:
|
case BinIndex.Learn:
|
||||||
return blues;
|
return oranges;
|
||||||
case BinIndex.Relearn:
|
case BinIndex.Relearn:
|
||||||
return reds;
|
return reds;
|
||||||
case BinIndex.Filtered:
|
case BinIndex.Filtered:
|
||||||
|
|
Loading…
Reference in a new issue