272 lines
7.4 KiB
Python
272 lines
7.4 KiB
Python
"""anki_generation.py
|
|
|
|
Produces anki output
|
|
"""
|
|
|
|
# Standard Library
|
|
import random
|
|
from pathlib import Path
|
|
|
|
# Pip
|
|
from genanki import Deck, Model, Note, Package
|
|
from pinyin_tone_converter.pinyin_tone_converter import PinyinToneConverter
|
|
|
|
# Local
|
|
from .utility import DictionaryResult, ProcessFile, ProcessFolder, TranslationResult
|
|
|
|
# Constants
|
|
|
|
CSS = """
|
|
.card {
|
|
font-family: arial;
|
|
font-size: 20px;
|
|
text-align: center;
|
|
color: black;
|
|
background-color: white;
|
|
}
|
|
.simple {
|
|
font-family: Arial;
|
|
font-size: 100px;
|
|
}
|
|
.trad {
|
|
font-family: Arial;
|
|
font-size: 75px;
|
|
}
|
|
"""
|
|
|
|
# Models
|
|
|
|
PHRASE_MODEL = Model(
|
|
2076166425,
|
|
"Phrase Model",
|
|
fields=[
|
|
{"name": "Translated"},
|
|
{"name": "Phrase"},
|
|
{"name": "Audio"},
|
|
],
|
|
templates=[
|
|
{
|
|
"name": "Card 1",
|
|
"qfmt": "{{Translated}}<br>{{Audio}}<br>{{type:Phrase}}",
|
|
"afmt": '{{FrontSide}}<hr id="answer">{{Phrase}}',
|
|
},
|
|
{
|
|
"name": "Card 2",
|
|
"qfmt": "{{Phrase}}<br>{{Audio}}<br>{{type:Translated}}",
|
|
"afmt": '{{FrontSide}}<hr id="answer">{{Translated}}',
|
|
},
|
|
{
|
|
"name": "Card 3",
|
|
"qfmt": "{{Audio}}<br>{{type:Phrase}}",
|
|
"afmt": '{{FrontSide}}<hr id="answer">{{Phrase}}',
|
|
},
|
|
],
|
|
css=CSS,
|
|
)
|
|
|
|
DICTATION_MODEL = Model(
|
|
3187277536,
|
|
"Phrase Model",
|
|
fields=[
|
|
{"name": "Translated"},
|
|
{"name": "Phrase"},
|
|
{"name": "Audio"},
|
|
],
|
|
templates=[
|
|
{
|
|
"name": "Card 1",
|
|
"qfmt": "{{Audio}}<br>{{type:Phrase}}",
|
|
"afmt": '{{FrontSide}}<hr id="answer">{{Phrase}}<br>{{Translated}}',
|
|
},
|
|
],
|
|
css=CSS,
|
|
)
|
|
|
|
HSK_MODEL = Model(
|
|
1708536519,
|
|
"HSK Model",
|
|
fields=[
|
|
{"name": "Translated"},
|
|
{"name": "Pinyin"},
|
|
{"name": "Simplified"},
|
|
{"name": "Traditional"},
|
|
{"name": "Audio"},
|
|
],
|
|
templates=[
|
|
{
|
|
"name": "Card 1",
|
|
"qfmt": (
|
|
"<strong>{{Pinyin}}</strong>"
|
|
"<br>{{Translated}}"
|
|
"<br>{{Audio}}"
|
|
"<br>Simplified: {{type:Simplified}}"
|
|
),
|
|
"afmt": (
|
|
"{{FrontSide}}<hr id='answer''><div class='simple'>{{Simplified}}</div>"
|
|
"<br><div class='trad'>{{Traditional}}</div>"
|
|
),
|
|
},
|
|
{
|
|
"name": "Card 2",
|
|
"qfmt": (
|
|
"<div class='simple'>{{Simplified}}</div>"
|
|
"<br><div class='trad'>{{Traditional}}</div>"
|
|
"<br>Pinyin: {{type:Pinyin}}"
|
|
# "<br>Translated: {{type:Translated}}"
|
|
),
|
|
"afmt": (
|
|
"{{FrontSide}}<hr id='answer'><strong>{{Pinyin}}</strong>"
|
|
"<br>{{Translated}}<br>{{Audio}}"
|
|
),
|
|
},
|
|
{
|
|
"name": "Card 3",
|
|
"qfmt": (
|
|
"{{Audio}}"
|
|
# "<br>Pinyin: {{type:Pinyin}}"
|
|
"<br>Simplified: {{type:Simplified}}"
|
|
),
|
|
"afmt": (
|
|
"{{FrontSide}}<hr id='answer'><strong>{{Pinyin}}</strong>"
|
|
"<br><div class='simple'>{{Simplified}}</div>"
|
|
"<br><div class='trad'>{{Traditional}}</div>"
|
|
),
|
|
},
|
|
],
|
|
css=CSS,
|
|
)
|
|
|
|
# Proccess
|
|
|
|
|
|
def output_anki_dictation(
|
|
process_file: ProcessFile, results: list[DictionaryResult]
|
|
) -> Path:
|
|
"""Creates an anki file for dictation result"""
|
|
final_file = process_file.output_name.with_suffix(".apkg")
|
|
deck_name = "::".join(
|
|
process_file.input_file.parts[:-1] + (process_file.output_name.stem,)
|
|
)
|
|
deck = Deck(
|
|
random.randrange(1 << 30, 1 << 31),
|
|
deck_name,
|
|
f"Deck for {final_file.name}, "
|
|
"created in https://www.wolfang.info.ve/hskankicreator/",
|
|
)
|
|
audios = []
|
|
for result in results:
|
|
note = Note(
|
|
model=DICTATION_MODEL,
|
|
fields=[
|
|
result.translated,
|
|
result.line,
|
|
f"[sound:{result.audio_path.name}]",
|
|
],
|
|
)
|
|
deck.add_note(note)
|
|
audios.append(result.audio_path)
|
|
package = Package(deck)
|
|
package.media_files = audios
|
|
package.write_to_file(final_file)
|
|
return final_file
|
|
|
|
|
|
def output_anki_dictionary(
|
|
process_file: ProcessFile, results: list[DictionaryResult]
|
|
) -> Path:
|
|
"""Creates an anki file from a dictionary results"""
|
|
final_file = process_file.output_name.with_suffix(".apkg")
|
|
deck_name = "::".join(
|
|
process_file.input_file.parts[:-1] + (process_file.output_name.stem,)
|
|
)
|
|
deck = Deck(
|
|
random.randrange(1 << 30, 1 << 31),
|
|
deck_name,
|
|
f"Deck for {final_file.name}, "
|
|
"created in https://www.wolfang.info.ve/hskankicreator/",
|
|
)
|
|
package = Package(deck)
|
|
audios = []
|
|
for result in results:
|
|
note = Note(
|
|
model=HSK_MODEL,
|
|
fields=[
|
|
# "\n ".join(f"{n+1}. {m}" for n, m in enumerate(result.meanings)),
|
|
result.meaning,
|
|
PinyinToneConverter().convert_text(result.pinyin),
|
|
result.simplified,
|
|
result.traditional,
|
|
f"[sound:{result.audio_path.name}]",
|
|
],
|
|
)
|
|
audios.append(result.audio_path)
|
|
deck.add_note(note)
|
|
package.media_files = audios
|
|
package.write_to_file(final_file)
|
|
return final_file
|
|
|
|
|
|
def output_anki_phrase(
|
|
process_file: ProcessFile, results: list[TranslationResult]
|
|
) -> Path:
|
|
"""Creates an anki file from a phrases results"""
|
|
final_file = process_file.output_name.with_suffix(".apkg")
|
|
deck_name = "::".join(
|
|
process_file.input_file.parts[:-1] + (process_file.output_name.stem,)
|
|
)
|
|
deck = Deck(
|
|
random.randrange(1 << 30, 1 << 31),
|
|
deck_name,
|
|
f"Deck for {final_file.name}, "
|
|
"created in https://www.wolfang.info.ve/hskankicreator/",
|
|
)
|
|
package = Package(deck)
|
|
audios = []
|
|
for result in results:
|
|
note = Note(
|
|
model=PHRASE_MODEL,
|
|
fields=[
|
|
result.translated,
|
|
result.line,
|
|
f"[sound:{result.audio_path.name}]",
|
|
],
|
|
)
|
|
deck.add_note(note)
|
|
audios.append(result.audio_path)
|
|
package.media_files = audios
|
|
package.write_to_file(final_file)
|
|
return final_file
|
|
|
|
|
|
def output_anki_package(
|
|
process_folder: ProcessFolder, results: dict[ProcessFile, list[TranslationResult]]
|
|
):
|
|
final_file = process_file.output_name.with_suffix(".apkg")
|
|
decks = []
|
|
audios = []
|
|
for process_file, results in results.items():
|
|
deck_name = "::".join(
|
|
ProcessFolder.input_folder.parts[:-1] + (ProcessFolder.output_name.stem,)
|
|
)
|
|
deck = Deck(
|
|
random.randrange(1 << 30, 1 << 31),
|
|
deck_name,
|
|
f"Deck for {final_file.name}, "
|
|
"created in https://www.wolfang.info.ve/hskankicreator/",
|
|
)
|
|
for result in results:
|
|
note = Note(
|
|
model=DICTATION_MODEL,
|
|
fields=[
|
|
result.translated,
|
|
result.line,
|
|
f"[sound:{result.audio_path}]",
|
|
],
|
|
)
|
|
deck.add_note(note)
|
|
audios.append(result.audio_path)
|
|
decks.append(deck)
|
|
package = Package(decks)
|
|
package.media_files = audios
|
|
package.write_to_file(final_file)
|