File size: 5,346 Bytes
651b002
 
a1adbb2
3725eab
651b002
b74f760
e057d05
a1adbb2
 
3e784b7
 
 
 
f7d3514
651b002
4246b36
 
 
 
 
48f4086
0fdc9b3
a7657f2
 
 
 
4246b36
 
a7657f2
0bcc04d
 
3725eab
 
 
 
651b002
4246b36
a1adbb2
651b002
a1adbb2
 
 
 
 
 
a7657f2
a1adbb2
a7657f2
206f64a
96793a0
a1adbb2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651b002
 
 
 
 
 
 
 
 
 
0bcc04d
9290363
a1adbb2
3725eab
a1adbb2
651b002
4246b36
3e784b7
 
7405c46
1f530a5
7405c46
 
 
651b002
 
 
 
7405c46
651b002
 
4246b36
 
7405c46
 
 
 
 
a7657f2
7405c46
272015d
7405c46
d011873
651b002
 
 
 
 
 
b74f760
651b002
 
 
a79f7cd
 
 
b74f760
 
651b002
 
a7657f2
a1adbb2
651b002
a1adbb2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import gradio as gr
import pytz
import os
import matplotlib.pyplot as plt
from datetime import datetime
from markdown import instructions_markdown, faq_markdown
from fsrs_optimizer import Optimizer
from pathlib import Path
from utilities import cleanup
import re

with open("./requirements.txt", "r") as f:
    txt = f.read().strip()
    version = re.search(r"FSRS-Optimizer==(.*)", txt).group(1)

def get_w_markdown(w):
    return f"""
    # Updated Parameters
    Copy and paste these as shown in step 5 of the instructions:

    `{w}`
    
    Check out the Analysis tab for more detailed information.
    
    **Note**: These values should be used with FSRS scheduler v4.0.0 or above.
    """


def anki_optimizer(file: gr.File, timezone, next_day_starts_at, revlog_start_date, filter_out_suspended_cards, requestRetention,
                   progress=gr.Progress(track_tqdm=True)):
    os.chdir('/home/user/app')                
    if file is None or (not file.name.endswith(".apkg") and not file.name.endswith(".colpkg")):
        raise ValueError("Please upload a deck/collection file.")
    if timezone == "":
        raise ValueError("Please select a timezone.")
    now = datetime.now()
    files = ['prediction.tsv', 'revlog.csv', 'revlog_history.tsv', 'stability_for_analysis.tsv',
             'expected_time.csv', 'evaluation.tsv']
    prefix = now.strftime(f'%Y_%m_%d_%H_%M_%S')
    suffix = file.name.split('/')[-1].replace(".", "_").replace("@", "_")
    proj_dir = Path(f'projects/{prefix}/{suffix}')
    proj_dir.mkdir(parents=True, exist_ok=True)
    os.chdir(proj_dir)
    optimizer = Optimizer()
    optimizer.anki_extract(file.name)
    analysis_markdown = optimizer.create_time_series(timezone, revlog_start_date, next_day_starts_at, filter_out_suspended_cards).replace("\n", "\n\n")
    optimizer.define_model()
    optimizer.pretrain(verbose=False)
    optimizer.train(verbose=False)
    print(optimizer.w)
    w_markdown = get_w_markdown(optimizer.w)
    optimizer.predict_memory_states()
    difficulty_distribution = optimizer.difficulty_distribution.to_string().replace("\n", "\n\n")
    plot_output = optimizer.find_optimal_retention()[0]
    suggested_retention_markdown = f"""# Suggested Retention: `{optimizer.optimal_retention:.2f}`"""
    rating_markdown = optimizer.preview(requestRetention).replace("\n", "\n\n")
    loss_before, loss_after = optimizer.evaluate()
    loss_markdown = f"""
**Loss before training**: {loss_before}

**Loss after training**: {loss_after}
    """
    # optimizer.calibration_graph()
    # optimizer.compare_with_sm2()
    markdown_out = f"""{suggested_retention_markdown}

# Loss Information
{loss_markdown}

# Difficulty Distribution
{difficulty_distribution}

# Ratings
{rating_markdown}
"""
    os.chdir('/home/user/app')
    files_out = [proj_dir / file for file in files if (proj_dir / file).exists()]
    cleanup(proj_dir, files)
    plt.close('all')
    return w_markdown, markdown_out, plot_output, files_out


description = f"""
# FSRS4Anki Optimizer App - v{version}
Based on the [tutorial](https://medium.com/@JarrettYe/how-to-use-the-next-generation-spaced-repetition-algorithm-fsrs-on-anki-5a591ca562e2) 
of [Jarrett Ye](https://github.com/L-M-Sherlock). This application can give you personalized anki parameters without having to code.

Read the `Instructions` if its your first time using the app.
"""

with gr.Blocks() as demo:
    with gr.Tab("FSRS4Anki Optimizer"):
        with gr.Box():
            gr.Markdown(description)
        with gr.Box():
            with gr.Row():
                with gr.Column():
                    file = gr.File(label='Review Logs (Step 1)')
                with gr.Column():
                    next_day_starts_at = gr.Number(value=4,
                                                   label="Next Day Starts at (Step 2)",
                                                   precision=0)
                    timezone = gr.Dropdown(label="Timezone (Step 3.1)", choices=pytz.all_timezones)
                    filter_out_suspended_cards = gr.Checkbox(value=False, label="Filter out suspended cards")
                    with gr.Accordion(label="Advanced Settings (Step 3.2)", open=False):
                        requestRetention = gr.Number(value=.9, label="Desired Retention: Recommended to set between 0.8  0.9")
                        revlog_start_date = gr.Textbox(value="2006-10-05",
                                                       label="Revlog Start Date: Optimize review logs after this date.")
        with gr.Row():
            btn_plot = gr.Button('Optimize your Anki!')
        with gr.Row():
            w_output = gr.Markdown()
    with gr.Tab("Instructions"):
        with gr.Box():
            gr.Markdown(instructions_markdown)
    with gr.Tab("Analysis"):
        with gr.Row():
            markdown_output = gr.Markdown()
            with gr.Column():
                plot_output = gr.Plot()
                files_output = gr.Files(label="Analysis Files")
    with gr.Tab("FAQ"):
        gr.Markdown(faq_markdown)

    btn_plot.click(anki_optimizer,
                   inputs=[file, timezone, next_day_starts_at, revlog_start_date, filter_out_suspended_cards, requestRetention],
                   outputs=[w_output, markdown_output, plot_output, files_output])

demo.queue().launch(show_error=True)