def test_cloze_newlines_in_deletion(): fields = [ '{{c1::Washington, D.C.}} is the capital of {{c2::the\nUnited States\nof America}}', '' ] note = Note(model=MY_CLOZE_MODEL, fields=fields) assert sorted(card.ord for card in note.cards) == [0, 1]
def make_note(problem): print(f"📓 Producing note for problem: {problem.title}...") tags = ";".join([t.name for t in problem.tags]) tags_slug = ";".join([t.slug for t in problem.tags]) try: solution = problem.solution.get() except Exception: solution = None codes = [] for item in problem.submissions: source = re.sub(r'(\\u[\s\S]{4})',lambda x:x.group(1).encode("utf-8").decode("unicode-escape"),item.source) output = code_to_html(source, item.language) codes.append(output) submissions = "\n".join(codes) note = Note( model=get_anki_model(), fields=[ str(problem.display_id), problem.title, problem.slug, problem.level, problem.description, tags, tags_slug, markdown_to_html(solution.content) if solution else "", submissions ], guid=str(problem.display_id), sort_field=str(problem.display_id), tags=[t.slug for t in problem.tags] ) return note
def test_cloze(write_to_test_apkg=False): """Test Cloze model""" notes = [] assert MY_CLOZE_MODEL.to_json(0, 0)["type"] == 1 # Question: NOTE ONE: [...] # Answer: NOTE ONE: single deletion fields = ['NOTE ONE: {{c1::single deletion}}', ''] my_cloze_note = Note(model=MY_CLOZE_MODEL, fields=fields) assert {card.ord for card in my_cloze_note.cards} == {0} notes.append(my_cloze_note) # Question: NOTE TWO: [...] 2nd deletion 3rd deletion # Answer: NOTE TWO: **1st deletion** 2nd deletion 3rd deletion # # Question: NOTE TWO: 1st deletion [...] 3rd deletion # Answer: NOTE TWO: 1st deletion **2nd deletion** 3rd deletion # # Question: NOTE TWO: 1st deletion 2nd deletion [...] # Answer: NOTE TWO: 1st deletion 2nd deletion **3rd deletion** fields = [ 'NOTE TWO: {{c1::1st deletion}} {{c2::2nd deletion}} {{c3::3rd deletion}}', '' ] my_cloze_note = Note(model=MY_CLOZE_MODEL, fields=fields) assert sorted(card.ord for card in my_cloze_note.cards) == [0, 1, 2] notes.append(my_cloze_note) # Question: NOTE THREE: C1-CLOZE # Answer: NOTE THREE: 1st deletion fields = ['NOTE THREE: {{c1::1st deletion::C1-CLOZE}}', ''] my_cloze_note = Note(model=MY_CLOZE_MODEL, fields=fields) assert {card.ord for card in my_cloze_note.cards} == {0} notes.append(my_cloze_note) # Question: NOTE FOUR: [...] foo 2nd deletion bar [...] # Answer: NOTE FOUR: 1st deletion foo 2nd deletion bar 3rd deletion fields = [ 'NOTE FOUR: {{c1::1st deletion}} foo {{c2::2nd deletion}} bar {{c1::3rd deletion}}', '' ] my_cloze_note = Note(model=MY_CLOZE_MODEL, fields=fields) assert sorted(card.ord for card in my_cloze_note.cards) == [0, 1] notes.append(my_cloze_note) if write_to_test_apkg: _wr_apkg(notes)
def test_cloze_multi_field(): fields = [ '{{c1::Berlin}} is the capital of {{c2::Germany}}', '{{c3::Paris}} is the capital of {{c4::France}}' ] note = Note(model=MULTI_FIELD_CLOZE_MODEL, fields=fields) assert sorted(card.ord for card in note.cards) == [0, 1, 2, 3]
def create_note(filename, model): hanzi = splitext(filename)[0] translation_result = translate_client.translate( hanzi, target_language='en') english_text = translation_result['translatedText'] audio_text = '[sound:' + hanzi + '.mp3]' pinyin_text = ' '.join([' '.join(phrase) for phrase in pinyin(hanzi)]) return Note( model=model, fields=[hanzi, pinyin_text, english_text, audio_text])
def get_anki_note(item, model, template): fmt = item.meta['format'] if fmt == 'data/dictionary': tags = template['Tags']['template'].render(**item.data).split(' ') _id = template['ID']['template'].render(**item.data) elif fmt == 'data/text': tags = template['Tags']['template'].render(Text=item.data).split(' ') _id = template['ID']['template'].render(Text=item.data) elif fmt == 'data/list': tags = template['Tags']['template'].render(Items=item.data).split(' ') _id = template['ID']['template'].render(Items=item.data) else: raise Exception('Unsupported item format: {fmt}'.format(fmt=fmt)) tags.insert(0, item.meta['file']) fields = [] for f in model.fields: fieldname = f['name'] tpl = template[fieldname]['template'] if fmt == 'data/dictionary': contents = tpl.render(**item.data) elif fmt == 'data/text': contents = tpl.render(text=item.data) elif fmt == 'data/list': contents = tpl.render(items=item.data) if template[fieldname]['markdown']: contents = md.convert(contents) md.reset() fields.append(contents) # print(fields) return Note(guid=guid_for(_id), model=model, fields=fields, tags=tags)
'{{type:Input}}', 'afmt': '{{FrontSide}}' '<hr id="answer">' '{{Back}}', }], css=CSS) notes = [] with open(data_file, 'r', encoding='utf-8') as json_file: data = json.load(json_file) deck_name = data['name'] for card in data['cards']: fields = [card['name'], card['back'], ",".join(card['media'])] model = MY_CLOZE_MODEL # TODO: sanity check the card fields if not "{{c" in card['name'] and not "{{type" in card['name']: model = BASIC_MODEL elif data['card_type'] == 'enable-input': model = INPUT_MODEL fields = [ card['name'].replace('{{type:Input}}', ''), card['back'], card['answer'], ",".join(card['media']) ] my_note = Note(model, fields=fields) notes.append(my_note) _wr_apkg(notes, deck_id, deck_name, data['media'])
def test_cloze_indicies_do_not_start_at_1(): fields = [ '{{c2::Mitochondria}} are the {{c3::powerhouses}} of the cell', '' ] note = Note(model=MY_CLOZE_MODEL, fields=fields) assert sorted(card.ord for card in note.cards) == [1, 2]
try: prac_pts = driver.find_elements_by_class_name( 'prac-pts')[1].text.replace('\n', ' <br/>').replace( 'Practice points:', ' ') field += "<br /><b> Practical points </b> <br /> {{c5::" + prac_pts + "}}" except: print("practical points not found") field += "'" fields = [field, ' '] # # Question: NOTE TWO: [...] 2nd deletion 3rd deletion # # Answer: NOTE TWO: **1st deletion** 2nd deletion 3rd deletion # # # # Question: NOTE TWO: 1st deletion [...] 3rd deletion # # Answer: NOTE TWO: 1st deletion **2nd deletion** 3rd deletion # # # # Question: NOTE TWO: 1st deletion 2nd deletion [...] # # Answer: NOTE TWO: 1st deletion 2nd deletion **3rd deletion** # fields = ['NOTE TWO: {{c1::1st deletion}} {{c2::2nd deletion}} {{c3::3rd deletion}}', ''] my_cloze_note = Note(model=MY_CLOZE_MODEL, fields=fields) notes.append(my_cloze_note) deckname = 'AMH_drugs' deck = Deck(deck_id=0, name=deckname) for note in notes: deck.add_note(note) fout_anki = '{NAME}.apkg'.format(NAME=deckname) Package(deck).write_to_file(fout_anki) print('{N} Notes WROTE: {APKG}'.format(N=len(notes), APKG=fout_anki))
INPUT_STYLE, INPUT_FRONT, INPUT_BACK) fields = [ card["name"].replace("{{type:Input}}", ""), card["back"], card["answer"], ",".join(card["media"]), ] # Cards marked with -1 number means they are breaking compatability, treat them differently by using their respective Notion Id if card["number"] == -1: card["number"] = card["notionId"] if mt.get("useNotionId"): g = guid_for(card["notionId"]) my_note = Note(model, fields=fields, sort_field=card["number"], tags=card['tags'], guid=g) notes.append(my_note) else: my_note = Note(model, fields=fields, sort_field=card["number"], tags=card['tags']) notes.append(my_note) media_files = media_files + card["media"] decks.append({ "notes": notes, "id": deck["id"], "desc": "", "name": deck["name"],
def create_anki_deck(text, deckname=None, filename=None): from genanki import Model, Note, Deck, Package # This is mostly hobbled together from the tests for genanki CSS = """.card { font-family: arial; font-size: 20px; text-align: center; color: black; background-color: white; } .cloze { font-weight: bold; color: blue; } .nightMode .cloze { color: lightblue; } """ MY_CLOZE_MODEL = Model( 998877661, "Nlaco Cloze Model", fields=[{"name": "Text"}, {"name": "Extra"},], templates=[ { "name": "Nlaco Cloze Card", "qfmt": "{{cloze:Text}}", "afmt": "{{cloze:Text}}<br>{{Extra}}", }, ], css=CSS, model_type=Model.CLOZE, ) name_uuid = uuid4() for overlap in range(1, 4): notes = [ Note(model=MY_CLOZE_MODEL, fields=(p, "")) for p in get_card_contents(text, phrases_per_cloze=overlap) ] for n in notes: assert ( n.cards ), f"No cards in note {n}, this will cause your Anki DB to break!" if deckname is None: _deckname = f"nlaco-overlap-{overlap}--" + str(name_uuid) else: raise NotImplementedError("Custom decknames are not supported yet :(") # % 500000 to make sure the int can fit into an SQL database. TODO see # whether this is random enough to make sure there are no collisions. deck = Deck(deck_id=name_uuid.int % 500000, name=_deckname) for note in notes: deck.add_note(note) if filename is None: Package(deck).write_to_file(f"{_deckname}.apkg") else: raise NotImplementedError("Custom filenames are not supported yet :(")