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-analyze-button = Analyze
deck-config-desired-retention = Desired retention
deck-config-smaller-is-better = Smaller numbers indicate better memory estimates.
deck-config-steps-too-large-for-fsrs = When FSRS is enabled, interday (re)learning steps are not recommended.
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, learning steps over 1 day are not recommended.
deck-config-get-params = Get Params
deck-config-fsrs-on-all-clients =
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.
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.

View File

@ -96,7 +96,7 @@ statistics-card-ease-title = Card Ease
statistics-card-difficulty-title = Card Difficulty
statistics-card-retrievability-title = Card Retrievability
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.
# eg "3 cards with 150-170% ease"
statistics-card-ease-tooltip =

View File

@ -343,7 +343,7 @@ message ComputeOptimalRetentionRequest {
repeated float weights = 1;
uint32 deck_size = 2;
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;
string search = 6;
}

View File

@ -33,7 +33,7 @@ impl Collection {
&SimulatorConfig {
deck_size: req.deck_size 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,
recall_costs: [p.recall_secs_hard, p.recall_secs_good, p.recall_secs_easy],
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;
const presetName = state.currentPresetName;
const config = state.currentConfig;
const defaults = state.defaults;
let computeWeightsProgress: ComputeWeightsProgress | undefined;
let computeWeightsWarning = "";
let customSearch = "";
let computing = false;
$: customSearch = `preset:"${$presetName}"`;
let computeRetentionProgress:
| ComputeWeightsProgress
@ -41,7 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const optimalRetentionRequest = new ComputeOptimalRetentionRequest({
deckSize: 10000,
daysToSimulate: 365,
maxSecondsOfStudyPerDay: 1800,
maxMinutesOfStudyPerDay: 30,
});
$: if (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 {
await runWithBackendProgress(
async () => {
const search = customSearch
? customSearch
: `preset:"${state.getCurrentName()}"`;
const resp = await computeFsrsWeights({
search,
search: customSearch,
});
if (computeWeightsProgress) {
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.search = `preset:"${state.getCurrentName()}"`;
const resp = await computeOptimalRetention(optimalRetentionRequest);
$config.desiredRetention = resp.optimalRetention;
alert(
tr.deckConfigYourOptimalRetention({
num: resp.optimalRetention,
}),
);
if (computeRetentionProgress) {
computeRetentionProgress.current =
computeRetentionProgress.total;
@ -203,11 +206,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<div class="m-2">
<details>
<summary>{tr.deckConfigComputeOptimalWeights()}</summary>
<input
bind:value={customSearch}
placeholder={tr.deckConfigComputeWeightsSearch()}
class="w-100 mb-1"
/>
<input bind:value={customSearch} class="w-100 mb-1" />
<button
class="btn {computing ? 'btn-warning' : 'btn-primary'}"
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} />
<br />
Max seconds of study per day:
Target minutes of study per day:
<br />
<input
type="number"
bind:value={optimalRetentionRequest.maxSecondsOfStudyPerDay}
bind:value={optimalRetentionRequest.maxMinutesOfStudyPerDay}
/>
<br />

View File

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