Feat/Use cached workload values

This commit is contained in:
Luc Mcgrady 2025-07-15 14:12:37 +01:00
parent 5a19027185
commit 82a9fa3331
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
3 changed files with 44 additions and 46 deletions

View file

@ -40,12 +40,10 @@ message DeckConfigId {
message GetRetentionWorkloadRequest {
repeated float w = 1;
string search = 2;
float before = 3;
float after = 4;
}
message GetRetentionWorkloadResponse {
float factor = 1;
map<uint32, float> costs = 1;
}
message GetIgnoredBeforeCountRequest {

View file

@ -1,5 +1,8 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use std::collections::HashMap;
use anki_proto::generic;
use crate::collection::Collection;
@ -139,30 +142,25 @@ impl crate::services::DeckConfigService for Collection {
costs.pass_count,
);
let before = fsrs::expected_workload(
let costs = (70u32..=99u32)
.map(|dr| {
Ok((
dr,
fsrs::expected_workload(
&input.w,
input.before,
dr as f32 / 100.,
LEARN_SPAN,
cost_success,
cost_failure,
cost_learn,
initial_pass_rate,
TERMINATION_PROB,
)?;
let after = fsrs::expected_workload(
&input.w,
input.after,
LEARN_SPAN,
cost_success,
cost_failure,
cost_learn,
initial_pass_rate,
TERMINATION_PROB,
)?;
Ok(anki_proto::deck_config::GetRetentionWorkloadResponse {
factor: after / before,
)?,
))
})
.collect::<Result<HashMap<_, _>>>()?;
Ok(anki_proto::deck_config::GetRetentionWorkloadResponse { costs })
}
}

View file

@ -29,6 +29,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import SimulatorModal from "./SimulatorModal.svelte";
import {
GetRetentionWorkloadRequest,
type GetRetentionWorkloadResponse,
UpdateDeckConfigsMode,
} from "@generated/anki/deck_config_pb";
import type Modal from "bootstrap/js/dist/modal";
@ -66,19 +67,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
$: roundedRetention = Number($config.desiredRetention.toFixed(2));
$: desiredRetentionWarning = getRetentionLongShortWarning(roundedRetention);
let timeoutId: ReturnType<typeof setTimeout> | undefined = undefined;
const WORKLOAD_UPDATE_DELAY_MS = 100;
let desiredRetentionChangeInfo = "";
$: {
clearTimeout(timeoutId);
if (showDesiredRetentionTooltip) {
timeoutId = setTimeout(() => {
getRetentionChangeInfo(roundedRetention, fsrsParams($config));
}, WORKLOAD_UPDATE_DELAY_MS);
} else {
desiredRetentionChangeInfo = "";
}
showDesiredRetentionTooltip
? getRetentionChangeInfo(roundedRetention, fsrsParams($config))
: "";
}
$: retentionWarningClass = getRetentionWarningClass(roundedRetention);
@ -111,21 +104,30 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
}
let retentionWorloadInfo: undefined | Promise<GetRetentionWorkloadResponse> =
undefined;
async function getRetentionChangeInfo(retention: number, params: number[]) {
if (!retentionWorloadInfo) {
const request = new GetRetentionWorkloadRequest({
w: params,
search: defaultparamSearch,
});
retentionWorloadInfo = getRetentionWorkload(request);
}
if (+startingDesiredRetention == roundedRetention) {
desiredRetentionChangeInfo = tr.deckConfigWorkloadFactorUnchanged();
return;
}
const request = new GetRetentionWorkloadRequest({
w: params,
search: defaultparamSearch,
before: +startingDesiredRetention,
after: retention,
});
const resp = await getRetentionWorkload(request);
const previous = +startingDesiredRetention * 100;
const after = retention * 100;
const resp = await retentionWorloadInfo;
const factor = resp.costs[after] / resp.costs[previous];
desiredRetentionChangeInfo = tr.deckConfigWorkloadFactorChange({
factor: resp.factor.toFixed(2),
previousDr: (+startingDesiredRetention * 100).toString(),
factor: factor.toFixed(2),
previousDr: previous.toString(),
});
}