Damien Elmes 2023-09-25 15:54:18 +10:00
parent bb0acd9d92
commit baae685dbb
6 changed files with 22 additions and 19 deletions

View file

@ -328,12 +328,13 @@ deck-config-compute-optimal-retention = Compute optimal retention
deck-config-compute-button = Compute deck-config-compute-button = Compute
deck-config-analyze-button = Analyze deck-config-analyze-button = Analyze
deck-config-desired-retention = Desired retention deck-config-desired-retention = Desired retention
deck-config-smaller-is-better = Smaller numbers indicate better memory estimates. deck-config-smaller-is-better = Smaller numbers indicate a better fit to your review history.
deck-config-steps-too-large-for-fsrs = When FSRS is enabled, interday (re)learning steps are not recommended. deck-config-steps-too-large-for-fsrs = When FSRS is enabled, learning steps over 1 day are not recommended.
deck-config-get-params = Get Params deck-config-get-params = Get Params
deck-config-fsrs-on-all-clients = deck-config-fsrs-on-all-clients =
Please ensure all of your Anki clients are Anki(Mobile) 23.10+ or AnkiDroid 2.17+. FSRS will Please ensure all of your Anki clients are Anki(Mobile) 23.10+ or AnkiDroid 2.17+. FSRS will
not work correctly if one of your clients is older. not work correctly if one of your clients is older.
deck-config-your-optimal-retention = Your optimal retention is { $num }.
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. ## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.

View file

@ -96,7 +96,7 @@ statistics-card-ease-title = Card Ease
statistics-card-difficulty-title = Card Difficulty statistics-card-difficulty-title = Card Difficulty
statistics-card-retrievability-title = Card Retrievability statistics-card-retrievability-title = Card Retrievability
statistics-card-ease-subtitle = The lower the ease, the more frequently a card will appear. statistics-card-ease-subtitle = The lower the ease, the more frequently a card will appear.
statistics-card-difficulty-subtitle = The higher the difficulty, the more frequently a card will appear. statistics-card-difficulty-subtitle = The higher the difficulty, the harder it is to remember.
statistics-retrievability-subtitle = How likely you are to remember. statistics-retrievability-subtitle = How likely you are to remember.
# eg "3 cards with 150-170% ease" # eg "3 cards with 150-170% ease"
statistics-card-ease-tooltip = statistics-card-ease-tooltip =

View file

@ -343,7 +343,7 @@ message ComputeOptimalRetentionRequest {
repeated float weights = 1; repeated float weights = 1;
uint32 deck_size = 2; uint32 deck_size = 2;
uint32 days_to_simulate = 3; uint32 days_to_simulate = 3;
uint32 max_seconds_of_study_per_day = 4; uint32 max_minutes_of_study_per_day = 4;
uint32 max_interval = 5; uint32 max_interval = 5;
string search = 6; string search = 6;
} }

View file

@ -33,7 +33,7 @@ impl Collection {
&SimulatorConfig { &SimulatorConfig {
deck_size: req.deck_size as usize, deck_size: req.deck_size as usize,
learn_span: req.days_to_simulate as usize, learn_span: req.days_to_simulate as usize,
max_cost_perday: req.max_seconds_of_study_per_day as f64, max_cost_perday: req.max_minutes_of_study_per_day as f64 * 60.0,
max_ivl: req.max_interval as f64, max_ivl: req.max_interval as f64,
recall_costs: [p.recall_secs_hard, p.recall_secs_good, p.recall_secs_easy], recall_costs: [p.recall_secs_hard, p.recall_secs_good, p.recall_secs_easy],
forget_cost: p.forget_secs, forget_cost: p.forget_secs,

View file

@ -25,13 +25,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let state: DeckOptionsState; export let state: DeckOptionsState;
const presetName = state.currentPresetName;
const config = state.currentConfig; const config = state.currentConfig;
const defaults = state.defaults; const defaults = state.defaults;
let computeWeightsProgress: ComputeWeightsProgress | undefined; let computeWeightsProgress: ComputeWeightsProgress | undefined;
let computeWeightsWarning = ""; let computeWeightsWarning = "";
let customSearch = "";
let computing = false; let computing = false;
$: customSearch = `preset:"${$presetName}"`;
let computeRetentionProgress: let computeRetentionProgress:
| ComputeWeightsProgress | ComputeWeightsProgress
@ -41,7 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const optimalRetentionRequest = new ComputeOptimalRetentionRequest({ const optimalRetentionRequest = new ComputeOptimalRetentionRequest({
deckSize: 10000, deckSize: 10000,
daysToSimulate: 365, daysToSimulate: 365,
maxSecondsOfStudyPerDay: 1800, maxMinutesOfStudyPerDay: 30,
}); });
$: if (optimalRetentionRequest.daysToSimulate > 3650) { $: if (optimalRetentionRequest.daysToSimulate > 3650) {
optimalRetentionRequest.daysToSimulate = 3650; optimalRetentionRequest.daysToSimulate = 3650;
@ -55,11 +57,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
try { try {
await runWithBackendProgress( await runWithBackendProgress(
async () => { async () => {
const search = customSearch
? customSearch
: `preset:"${state.getCurrentName()}"`;
const resp = await computeFsrsWeights({ const resp = await computeFsrsWeights({
search, search: customSearch,
}); });
if (computeWeightsProgress) { if (computeWeightsProgress) {
computeWeightsProgress.current = computeWeightsProgress.total; computeWeightsProgress.current = computeWeightsProgress.total;
@ -137,7 +136,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
optimalRetentionRequest.weights = $config.fsrsWeights; optimalRetentionRequest.weights = $config.fsrsWeights;
optimalRetentionRequest.search = `preset:"${state.getCurrentName()}"`; optimalRetentionRequest.search = `preset:"${state.getCurrentName()}"`;
const resp = await computeOptimalRetention(optimalRetentionRequest); const resp = await computeOptimalRetention(optimalRetentionRequest);
$config.desiredRetention = resp.optimalRetention; alert(
tr.deckConfigYourOptimalRetention({
num: resp.optimalRetention,
}),
);
if (computeRetentionProgress) { if (computeRetentionProgress) {
computeRetentionProgress.current = computeRetentionProgress.current =
computeRetentionProgress.total; computeRetentionProgress.total;
@ -203,11 +206,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<div class="m-2"> <div class="m-2">
<details> <details>
<summary>{tr.deckConfigComputeOptimalWeights()}</summary> <summary>{tr.deckConfigComputeOptimalWeights()}</summary>
<input <input bind:value={customSearch} class="w-100 mb-1" />
bind:value={customSearch}
placeholder={tr.deckConfigComputeWeightsSearch()}
class="w-100 mb-1"
/>
<button <button
class="btn {computing ? 'btn-warning' : 'btn-primary'}" class="btn {computing ? 'btn-warning' : 'btn-primary'}"
on:click={() => computeWeights()} on:click={() => computeWeights()}
@ -247,11 +246,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<input type="number" bind:value={optimalRetentionRequest.daysToSimulate} /> <input type="number" bind:value={optimalRetentionRequest.daysToSimulate} />
<br /> <br />
Max seconds of study per day: Target minutes of study per day:
<br /> <br />
<input <input
type="number" type="number"
bind:value={optimalRetentionRequest.maxSecondsOfStudyPerDay} bind:value={optimalRetentionRequest.maxMinutesOfStudyPerDay}
/> />
<br /> <br />

View file

@ -49,6 +49,7 @@ export class DeckOptionsState {
readonly v3Scheduler: boolean; readonly v3Scheduler: boolean;
readonly newCardsIgnoreReviewLimit: Writable<boolean>; readonly newCardsIgnoreReviewLimit: Writable<boolean>;
readonly fsrs: Writable<boolean>; readonly fsrs: Writable<boolean>;
readonly currentPresetName: Writable<string>;
private targetDeckId: DeckOptionsId; private targetDeckId: DeckOptionsId;
private configs: ConfigWithCount[]; private configs: ConfigWithCount[];
@ -87,6 +88,7 @@ export class DeckOptionsState {
this.configs[this.selectedIdx].useCount -= 1; this.configs[this.selectedIdx].useCount -= 1;
this.currentConfig = writable(this.getCurrentConfig()); this.currentConfig = writable(this.getCurrentConfig());
this.currentAuxData = writable(this.getCurrentAuxData()); this.currentAuxData = writable(this.getCurrentAuxData());
this.currentPresetName = writable(this.configs[this.selectedIdx].config.name);
this.configList = readable(this.getConfigList(), (set) => { this.configList = readable(this.getConfigList(), (set) => {
this.configListSetter = set; this.configListSetter = set;
return; return;
@ -256,6 +258,7 @@ export class DeckOptionsState {
private updateConfigList(): void { private updateConfigList(): void {
this.configListSetter?.(this.getConfigList()); this.configListSetter?.(this.getConfigList());
this.currentPresetName.set(this.configs[this.selectedIdx].config.name);
} }
/** Returns a copy of the currently selected config. */ /** Returns a copy of the currently selected config. */