# anki_exporter.py import os import tempfile import subprocess import shutil import genanki def compile_anki_package(records, output_path, deck_name): """ Compiles database records into an .apkg package using native macOS TTS. Uses 'Monica' for Spanish targets and the default premium system voice for English. """ # Create a unique random Model ID and Deck ID for genanki model_id = 1684329011 deck_id = 1684329012 # Define the Anki Card Layout structure with audio fields anki_model = genanki.Model( model_id, 'Spanish Voice Trainer Model', fields=[ {'name': 'EnglishText'}, {'name': 'SpanishText'}, {'name': 'Notes'}, {'name': 'EnglishAudio'}, {'name': 'SpanishAudio'} ], templates=[ { 'name': 'Card 1', 'qfmt': '
' 'Translate to Spanish:

{{EnglishText}}
{{EnglishAudio}}
', 'afmt': '{{FrontSide}}
' '
' '{{SpanishText}}

' '
' '{{Notes}}

' '
{{SpanishAudio}}
', }, ] ) deck = genanki.Deck(deck_id, deck_name) media_files = [] # Process all records inside a secure temporary directory workspace with tempfile.TemporaryDirectory() as tmpdir: for idx, record in enumerate(records): en_text = record["en_text"] es_text = record["es_text"] notes = f"Context: {record['source_context'] or ''} | {record['notes'] or ''}".strip(" | ") # Generate unique filenames for the media assets en_audio_filename = f"en_audio_{idx}.mp3" es_audio_filename = f"es_audio_{idx}.mp3" en_audio_path = os.path.join(tmpdir, en_audio_filename) es_audio_path = os.path.join(tmpdir, es_audio_filename) try: # 1. Render English Audio using native macOS text-to-speech engine subprocess.run( ["say", "-o", en_audio_path, "--data-format=Iface", en_text], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) media_files.append(en_audio_path) en_audio_field = f"[sound:{en_audio_filename}]" except Exception: en_audio_field = "" try: # 2. Render Spanish Audio explicitly targeting the Monica voice profile subprocess.run( ["say", "-v", "Monica", "-o", es_audio_path, "--data-format=Iface", es_text], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) media_files.append(es_audio_path) es_audio_field = f"[sound:{es_audio_filename}]" except Exception: es_audio_field = "" # Build the card note stack note = genanki.Note( model=anki_model, fields=[en_text, es_text, notes, en_audio_field, es_audio_field] ) deck.add_note(note) # Build package collection mapping archive pipelines package = genanki.Package(deck) package.media_files = media_files package.write_to_file(output_path)