gabriel becker
2 years ago
commit
aca3d88c19
8 changed files with 143 additions and 0 deletions
@ -0,0 +1,23 @@ |
|||||||
|
# Ankimaker |
||||||
|
|
||||||
|
WIP |
||||||
|
|
||||||
|
A CLI app to generate anki decks. |
||||||
|
|
||||||
|
From csv file, with configurable parameters, filters and media. |
||||||
|
|
||||||
|
From epub, finding difficult* words in the book and getting their translations. |
||||||
|
|
||||||
|
*I still don't know what 'difficult' will mean. Probably difficult words will be less frequent words that are more frequent in the text than in some corpus, cut above a grade threshold. The grades will map percentiles of frequency. |
||||||
|
|
||||||
|
| Language Level | Number of Base Words Needed | |
||||||
|
| ----- | ------ | |
||||||
|
| A1 | 500| |
||||||
|
| A2 | 1000| |
||||||
|
| B1 | 2000| |
||||||
|
| B2 | 4000| |
||||||
|
| C1 | 8000| |
||||||
|
| C2 | 16000| |
||||||
|
|
||||||
|
|
||||||
|
This project is only possible because of the awesome work of genanki team. |
@ -0,0 +1,9 @@ |
|||||||
|
from ankimaker.commands import cli |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
cli(prog_name='ankimaker') |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
main() |
@ -0,0 +1,7 @@ |
|||||||
|
import click |
||||||
|
|
||||||
|
@click.group("cli") |
||||||
|
def cli(): |
||||||
|
pass |
||||||
|
|
||||||
|
from ankimaker.commands.from_csv import generate_anki |
@ -0,0 +1,38 @@ |
|||||||
|
import click |
||||||
|
import re |
||||||
|
from ankimaker.commands import cli |
||||||
|
from ankimaker.tasks import basic_pandas_to_anki |
||||||
|
|
||||||
|
|
||||||
|
@cli.command('csv') |
||||||
|
@click.option('-i', '--input', 'input_file', type=click.Path(exists=True)) |
||||||
|
@click.option('-o', '--output', 'output_file', type=click.Path(exists=False)) |
||||||
|
@click.option('-c', '--conf', 'config_file', default=None, type=click.STRING) |
||||||
|
@click.option('-n', '--name', 'name', default=None, type=click.STRING) |
||||||
|
def generate_anki( |
||||||
|
input_file, |
||||||
|
output_file, |
||||||
|
name, |
||||||
|
config_file, |
||||||
|
): |
||||||
|
output_file = parse_output(output_file) |
||||||
|
if name is None: |
||||||
|
name = get_name_from_output(output_file) |
||||||
|
basic_pandas_to_anki(input_file, output_file, name) |
||||||
|
|
||||||
|
|
||||||
|
def parse_output(filename): |
||||||
|
filetype = filename.split('.')[-1] if len(filename.split('.')) > 0 else None |
||||||
|
if filetype is None: |
||||||
|
return filename + '.apkg' |
||||||
|
elif filetype != 'apkg': |
||||||
|
filename.replace(filetype, 'apkg') |
||||||
|
return filename+filetype |
||||||
|
else: |
||||||
|
return filename |
||||||
|
|
||||||
|
|
||||||
|
def get_name_from_output(filename): |
||||||
|
updated_file = filename.split('/')[-1] if len(filename.split('/')) > 0 else filename |
||||||
|
updated_file = re.sub(r'(.apkg)', '', updated_file) |
||||||
|
return updated_file |
@ -0,0 +1 @@ |
|||||||
|
from .basic_csv_to_anki import basic_pandas_to_anki |
@ -0,0 +1,62 @@ |
|||||||
|
import genanki |
||||||
|
import pandas as pd |
||||||
|
|
||||||
|
|
||||||
|
def create_model(): |
||||||
|
my_model = genanki.Model( |
||||||
|
1607392319, |
||||||
|
'Simple Model', |
||||||
|
fields=[ |
||||||
|
{'name': 'Question'}, |
||||||
|
{'name': 'Answer'}, |
||||||
|
], |
||||||
|
templates=[ |
||||||
|
{ |
||||||
|
'name': 'Card 1', |
||||||
|
'qfmt': '{{Question}}', |
||||||
|
'afmt': '{{FrontSide}}<hr id="answer">{{Answer}}', |
||||||
|
}, |
||||||
|
]) |
||||||
|
return my_model |
||||||
|
|
||||||
|
|
||||||
|
def create_note(model, fields): |
||||||
|
note = genanki.Note( |
||||||
|
model=model, |
||||||
|
fields=fields |
||||||
|
) |
||||||
|
return note |
||||||
|
|
||||||
|
|
||||||
|
def create_deck(name): |
||||||
|
deck = genanki.Deck( |
||||||
|
2059400110, |
||||||
|
name |
||||||
|
) |
||||||
|
return deck |
||||||
|
|
||||||
|
|
||||||
|
def save_deck(deck, destination): |
||||||
|
my_package = genanki.Package(deck) |
||||||
|
# my_package.media_files = ['sound.mp3', 'images/image.jpg'] |
||||||
|
my_package.write_to_file(destination) |
||||||
|
|
||||||
|
|
||||||
|
def load_csv(path): |
||||||
|
df = pd.read_csv(path, header=None) |
||||||
|
return df |
||||||
|
|
||||||
|
|
||||||
|
def add_df_to_deck(df: pd.DataFrame, deck: genanki.Deck): |
||||||
|
model = create_model() |
||||||
|
for x in df.to_dict('records'): |
||||||
|
note = create_note(model, fields=(x[2], x[3])) |
||||||
|
deck.add_note(note) |
||||||
|
return deck |
||||||
|
|
||||||
|
|
||||||
|
def basic_pandas_to_anki(csv_path, output_path, name): |
||||||
|
df = load_csv(csv_path) |
||||||
|
deck = create_deck(name) |
||||||
|
add_df_to_deck(df, deck) |
||||||
|
save_deck(deck, output_path) |
Loading…
Reference in new issue