fixed anki deck name

This commit is contained in:
stephen 2026-08-21 22:24:50 +10:00
parent 70d9e012f6
commit f8778962b7
28 changed files with 1462 additions and 73 deletions

4
.gitignore vendored
View file

@ -5,6 +5,10 @@ __pycache__/
.venv/ .venv/
.uv/ .uv/
dist/*
build/*
# Local SQLite Databases # Local SQLite Databases
# *.db # *.db
# *.db-journal # *.db-journal

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

View file

@ -2,9 +2,9 @@
import os import os
import tempfile import tempfile
import asyncio import asyncio
import time
import genanki import genanki
import edge_tts import edge_tts
import shutil
import database import database
from tts_utils import parse_text_for_edgetts, get_configured_tts_rate from tts_utils import parse_text_for_edgetts, get_configured_tts_rate
@ -24,9 +24,13 @@ def compile_anki_package(records, output_path, deck_name):
Resolves voice models dynamically by gender selection parameters and applies Resolves voice models dynamically by gender selection parameters and applies
global speed coefficient rates from the active configurations. global speed coefficient rates from the active configurations.
""" """
# Incremented IDs to force a fresh schema mapping without legacy 'Notes' fields # Generate deterministic positive 32-bit integers from deck name and model name
model_id = 1684329060 # to avoid collisions across different decks while keeping imports stable
deck_id = 1684329060 deck_id = abs(hash(deck_name)) % (2**31)
model_id = abs(hash("Spanish Bidirectional Multi-Note HTML Model")) % (2**31)
# Unique timestamp prefix for media files to prevent overwriting prior exports in Anki
run_prefix = int(time.time())
# Global Configuration Pace Resolver Mapping # Global Configuration Pace Resolver Mapping
settings = database.load_all_settings() or {} settings = database.load_all_settings() or {}
@ -95,9 +99,9 @@ def compile_anki_package(records, output_path, deck_name):
# Safely isolate the raw text/HTML data string down to Anki notes field # Safely isolate the raw text/HTML data string down to Anki notes field
anki_notes_html = record['anki_notes'].strip() if record.get('anki_notes') else "" anki_notes_html = record['anki_notes'].strip() if record.get('anki_notes') else ""
# Standard Unique Media Filenames # Unique Media Filenames combining execution timestamp and index
en_audio_filename = f"edge_en_{idx}_{model_id}.mp3" en_audio_filename = f"edge_en_{run_prefix}_{idx}.mp3"
es_audio_filename = f"edge_es_{idx}_{model_id}.mp3" es_audio_filename = f"edge_es_{run_prefix}_{idx}.mp3"
en_audio_path = os.path.join(tmpdir, en_audio_filename) en_audio_path = os.path.join(tmpdir, en_audio_filename)
es_audio_path = os.path.join(tmpdir, es_audio_filename) es_audio_path = os.path.join(tmpdir, es_audio_filename)

BIN
app.icns Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
base_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View file

@ -1,24 +1,79 @@
# database.py # database.py
import sqlite3
import os import os
import sys
import sqlite3
from PyQt6.QtCore import QSettings
APP_NAME = "SpanishVoiceTrainer"
DEFAULT_DB_FILENAME = "spanish_trainer.db"
def get_default_db_path() -> str:
"""Returns standard macOS Application Support path:
~/Library/Application Support/SpanishVoiceTrainer/spanish_trainer.db
"""
app_support_dir = os.path.expanduser(
f"~/Library/Application Support/{APP_NAME}"
)
os.makedirs(app_support_dir, exist_ok=True)
return os.path.join(app_support_dir, DEFAULT_DB_FILENAME)
def get_db_path() -> str:
"""Retrieves database path cleanly based on execution environment.
- In packaged app mode (sys.frozen): strictly isolates data inside
Application Support unless a valid custom production path is chosen.
Heals stale settings pointing to local dev source paths.
- In dev mode: allows fallback to local project directory.
"""
qs = QSettings(APP_NAME, "Settings")
custom_path = qs.value("database_path", type=str)
# 1. Check custom path saved in QSettings
if custom_path and os.path.exists(custom_path):
# Safeguard for packaged production app:
# Ignore custom paths that point back into local development source folders
if getattr(sys, "frozen", False) and "01_Projects" in custom_path:
default_path = get_default_db_path()
qs.setValue("database_path", default_path) # Repair stale setting
return default_path
return custom_path
# 2. Development mode fallback (uncompiled python runtime)
if not getattr(sys, "frozen", False):
local_dev_db = os.path.join(
os.path.dirname(os.path.abspath(__file__)), DEFAULT_DB_FILENAME
)
if os.path.exists(local_dev_db):
return local_dev_db
# 3. Default production fallback
default_path = get_default_db_path()
qs.setValue("database_path", default_path)
return default_path
def set_db_path(new_path: str):
"""Updates active database path in user preferences."""
qs = QSettings(APP_NAME, "Settings")
qs.setValue("database_path", new_path)
DB_NAME = "spanish_trainer.db"
def get_connection(): def get_connection():
"""Returns a connection to the SQLite database with row factory enabled.""" """Establishes connection to the active SQLite database."""
conn = sqlite3.connect(DB_NAME) db_path = get_db_path()
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row conn.row_factory = sqlite3.Row
return conn return conn
def ensure_database_populated(): def ensure_database_populated():
""" """Initializes tables if running against a new or empty database file."""
Creates empty tables using the unified schema if running
in a fresh environment without a database file.
"""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
# 1. Unified translations table with dedicated anki_notes and gender tracks # 1. Unified translations table
cursor.execute(""" cursor.execute("""
CREATE TABLE IF NOT EXISTS translations ( CREATE TABLE IF NOT EXISTS translations (
translation_id INTEGER PRIMARY KEY AUTOINCREMENT, translation_id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -43,10 +98,12 @@ def ensure_database_populated():
finally: finally:
conn.close() conn.close()
# ========================================== # ==========================================
# SETTINGS CRUD FUNCTIONS # SETTINGS CRUD FUNCTIONS
# ========================================== # ==========================================
def load_all_settings(): def load_all_settings():
"""Fetches all system configuration properties into a flat Python dictionary.""" """Fetches all system configuration properties into a flat Python dictionary."""
conn = get_connection() conn = get_connection()
@ -60,28 +117,31 @@ def load_all_settings():
conn.close() conn.close()
return settings_dict return settings_dict
def save_setting_to_db(key, value): def save_setting_to_db(key, value):
"""Inserts or replaces an application configuration entry.""" """Inserts or replaces an application configuration entry."""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(""" cursor.execute(
"""
INSERT OR REPLACE INTO settings (key, value) INSERT OR REPLACE INTO settings (key, value)
VALUES (?, ?); VALUES (?, ?);
""", (key, value)) """,
(key, value),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
# ========================================== # ==========================================
# TRANSLATIONS CRUD FUNCTIONS # TRANSLATIONS CRUD FUNCTIONS
# ========================================== # ==========================================
def get_all_translations_explicit(): def get_all_translations_explicit():
""" """Retrieves all records using explicit, table-qualified column declarations."""
Retrieves all records using completely explicit,
table-qualified column declarations for the engines.
"""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
@ -102,12 +162,14 @@ def get_all_translations_explicit():
finally: finally:
conn.close() conn.close()
def get_translation_by_id(translation_id): def get_translation_by_id(translation_id):
"""Loads a single unified record row for specific inspection or editing.""" """Loads a single unified record row for specific inspection or editing."""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(""" cursor.execute(
"""
SELECT SELECT
translations.translation_id, translations.translation_id,
translations.es_text, translations.es_text,
@ -119,19 +181,31 @@ def get_translation_by_id(translation_id):
translations.gender translations.gender
FROM translations FROM translations
WHERE translations.translation_id = ?; WHERE translations.translation_id = ?;
""", (translation_id,)) """,
(translation_id,),
)
row = cursor.fetchone() row = cursor.fetchone()
return dict(row) if row else None return dict(row) if row else None
finally: finally:
conn.close() conn.close()
def update_translation_record(translation_id, es_text, en_text, source_context, tags, notes, gender, anki_notes):
"""Saves sandbox interface edits directly back down into the table using named arguments.""" def update_translation_record(
translation_id,
es_text,
en_text,
source_context,
tags,
notes,
gender,
anki_notes,
):
"""Saves interface edits directly back into the table using named arguments."""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
# The SQL uses :key syntax instead of ? cursor.execute(
cursor.execute(""" """
UPDATE translations UPDATE translations
SET SET
es_text = :es, es_text = :es,
@ -142,53 +216,62 @@ def update_translation_record(translation_id, es_text, en_text, source_context,
gender = :gender, gender = :gender,
anki_notes = :anki anki_notes = :anki
WHERE translation_id = :id; WHERE translation_id = :id;
""", { """,
# The order inside this dictionary does not matter at all! {
"id": translation_id, "id": translation_id,
"es": es_text, "es": es_text,
"en": en_text, "en": en_text,
"ctx": source_context, "ctx": source_context,
"tags": tags, "tags": tags,
"notes": notes, "notes": notes,
"gender": gender, "gender": gender,
"anki": anki_notes "anki": anki_notes,
}) },
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
def delete_translation_record(translation_id): def delete_translation_record(translation_id):
"""Permanently drops a phrase card row from the data index.""" """Permanently drops a phrase card row from the data index."""
conn = get_connection() conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(""" cursor.execute(
"""
DELETE FROM translations DELETE FROM translations
WHERE translations.translation_id = ?; WHERE translations.translation_id = ?;
""", (translation_id,)) """,
(translation_id,),
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
def insert_translation_record(es_text, en_text, source_context, tags, notes, gender, anki_notes):
"""Inserts a new record using named arguments so positional order doesn't matter.""" def insert_translation_record(
conn = get_connection() # Corrected from get_db_connection es_text, en_text, source_context, tags, notes, gender, anki_notes
):
"""Inserts a new record using named arguments."""
conn = get_connection()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(""" cursor.execute(
"""
INSERT INTO translations (es_text, en_text, source_context, tags, notes, gender, anki_notes) INSERT INTO translations (es_text, en_text, source_context, tags, notes, gender, anki_notes)
VALUES (:es, :en, :ctx, :tags, :notes, :gender, :anki); VALUES (:es, :en, :ctx, :tags, :notes, :gender, :anki);
""", { """,
# SQLite maps these keys directly to the tokens above by name {
"en": en_text, "en": en_text,
"es": es_text, "es": es_text,
"ctx": source_context, "ctx": source_context,
"tags": tags, "tags": tags,
"notes": notes, "notes": notes,
"anki": anki_notes, "anki": anki_notes,
"gender": gender "gender": gender,
}) },
)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()

View file

@ -20,3 +20,48 @@ git switch -c refactor/simplified-schema-modules
# How to start using uv # How to start using uv
(139_spanish-voice-trainer) stephenlohning@Scotty 139_spanish-voice-trainer % uv run main.py (139_spanish-voice-trainer) stephenlohning@Scotty 139_spanish-voice-trainer % uv run main.py
To trim non-relevant files from your directory tree (such as build artifacts, cache files, and non-source assets), you can configure flags for the `tree` command itself or use git-based filtering.
**Tree Command Options**
* **`-I pattern` (Ignore matching patterns):** Exclude build directories, caches, virtual environments, binaries, and temporary files.
* **`-d` (Directories only):** Show only directory structures if file-level detail is unnecessary.
* **`-L level` (Limit depth):** Limit how deep `tree` traverses (e.g., `-L 2` or `-L 3`) to prevent showing deep PyInstaller distribution bundles like `dist/` or `build/`.
* **`--gitignore`:** Automatically respects your `.gitignore` rules (supported in modern `tree` versions).
---
**Recommended Command Patterns**
**1. Ignore standard build & cache artifacts**
```bash
tree -I "__pycache__|*.pyc|build|dist|*.app|*.iconset|*.png|*.pdf|*.jpg|database_legacy"
```
**2. Combine pattern filtering with limited depth**
```bash
tree -L 2 -I "__pycache__|build|dist|database_legacy"
```
**3. Use `.gitignore` directly**
If you already have build outputs, images, and backups ignored in `.gitignore`:
```bash
tree --gitignore
```
---
**Summary of Files/Folders to Exclude**
* **Build & Bundle Outputs:** `build/`, `dist/`, `main.app`
* **Python Caches:** `__pycache__/`, `*.pyc`
* **Static / Temp Media:** `*.png`, `*.jpg`, `*.pdf`, `app_icon.iconset/`
* **Legacy / Backups:** `database_legacy/` (containing database backups like `*.db`)

Binary file not shown.

51
main.spec Normal file
View file

@ -0,0 +1,51 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['app.icns'],
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main',
)
app = BUNDLE(
coll,
name='main.app',
icon='app.icns',
bundle_identifier=None,
)

View file

@ -12,6 +12,7 @@ dependencies = [
"librosa>=0.11.0", "librosa>=0.11.0",
"numpy>=2.4.6", "numpy>=2.4.6",
"pillow>=12.2.0", "pillow>=12.2.0",
"pyinstaller>=6.21.0",
"pyqt6>=6.11.0", "pyqt6>=6.11.0",
"scipy>=1.17.1", "scipy>=1.17.1",
"sounddevice>=0.5.5", "sounddevice>=0.5.5",

BIN
spanish_trainer-26-08-21.db Normal file

Binary file not shown.

BIN
spanish_trainer-backup.db Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1,10 +1,12 @@
# tabs/review_tab.py # tabs/review_tab.py
import random import random
import os import os
import re
import subprocess import subprocess
import tempfile import tempfile
import threading import threading
import asyncio import asyncio
from datetime import datetime
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QPushButton, QTableWidget, QTableWidgetItem, QLineEdit, QPushButton, QTableWidget, QTableWidgetItem,
@ -338,14 +340,14 @@ class ReviewTab(QWidget):
@pyqtSlot() @pyqtSlot()
def generate_deck_action(self): def generate_deck_action(self):
"""Generates a specialized lightweight .apkg Anki deck matching active filter parameters, """Generates a specialized .apkg Anki deck matching active filter parameters,
respecting exact user database configuration keys for target folders and naming chains.""" prepending yyyy-mm-dd-hhmm timestamp and matching Sub-Deck-Namespace-Hierarchy without brackets/parentheses."""
if not self.filtered_review_pool: if not self.filtered_review_pool:
QMessageBox.warning(self, "Export Aborted", "The current matching review deck queue is empty. Cannot compile an empty deck.") QMessageBox.warning(self, "Export Aborted", "The current matching review deck queue is empty. Cannot compile an empty deck.")
return return
try: try:
# Load active settings dictionary directly from your database configurations # Load active settings dictionary directly from database configurations
settings = database.load_all_settings() or {} settings = database.load_all_settings() or {}
# Extract configurations targeting exact database schema names found in settings # Extract configurations targeting exact database schema names found in settings
@ -364,17 +366,27 @@ class ReviewTab(QWidget):
if root_deck_name and str(root_deck_name).strip(): if root_deck_name and str(root_deck_name).strip():
deck_tree_parts.append(str(root_deck_name).strip()) deck_tree_parts.append(str(root_deck_name).strip())
else:
deck_tree_parts.append("DefaultDeck") # Baseline structural root name fallback
if sub_deck_hierarchy and str(sub_deck_hierarchy).strip(): if sub_deck_hierarchy and str(sub_deck_hierarchy).strip():
deck_tree_parts.append(str(sub_deck_hierarchy).strip()) deck_tree_parts.append(str(sub_deck_hierarchy).strip())
else:
if not deck_tree_parts:
deck_tree_parts.append("DefaultDeck")
# Join parts using Anki double-colon syntax (::) # Join parts using Anki double-colon syntax (::) for internal Anki hierarchy
full_deck_namespace = "::".join(deck_tree_parts) full_deck_namespace = "::".join(deck_tree_parts)
# Establish absolute output filename file path anchor # --- Format Timestamp and Clean Filename ---
filename = "Spanish_Filtered_Review.apkg" # Format: YYYY-MM-DD-HHMM
timestamp = datetime.now().strftime("%Y-%m-%d-%H%M")
# Explicitly strip out parentheses/brackets before regex normalization
clean_namespace = full_deck_namespace.replace('(', '').replace(')', '').replace('[', '').replace(']', '')
clean_namespace = re.sub(r'[^a-zA-Z0-9]', '-', clean_namespace)
clean_namespace = re.sub(r'-+', '-', clean_namespace).strip('-')
# Complete output filename pattern: yyyy-mm-dd-hhmm-Sub-Deck-Namespace-Hierarchy.apkg
filename = f"{timestamp}-{clean_namespace}.apkg"
file_path = os.path.join(target_dir, filename) file_path = os.path.join(target_dir, filename)
# Execute actual compilation algorithm pipeline mapping filtered records cleanly # Execute actual compilation algorithm pipeline mapping filtered records cleanly
@ -383,9 +395,10 @@ class ReviewTab(QWidget):
QMessageBox.information( QMessageBox.information(
self, self,
"Export Complete", "Export Complete",
f"Successfully exported Anki package to your configured target directory!\n\n" f"Successfully exported Anki package!\n\n"
f"<b>Full Namespace Tree:</b> {full_deck_namespace}\n" f"<b>Deck Hierarchy:</b> {full_deck_namespace}\n"
f"<b>Destination Path:</b> {file_path}" f"<b>File Name:</b> {filename}\n"
f"<b>Path:</b> {file_path}"
) )
except Exception as e: except Exception as e:
QMessageBox.critical(self, "Compiler Fault Safeguard", f"An exception occurred building your deck container package:\n{str(e)}") QMessageBox.critical(self, "Compiler Fault Safeguard", f"An exception occurred building your deck container package:\n{str(e)}")

View file

@ -20,6 +20,29 @@ class SettingsTab(QWidget):
main_layout = QVBoxLayout(self) main_layout = QVBoxLayout(self)
main_layout.setSpacing(15) main_layout.setSpacing(15)
# --- SECTION 0: DATABASE FILE CONFIGURATION ---
db_group = QGroupBox("Database Storage Configuration")
db_form = QFormLayout(db_group)
db_form.setSpacing(10)
db_picker_layout = QHBoxLayout()
self.txt_db_path = QLineEdit()
self.txt_db_path.setReadOnly(True)
self.txt_db_path.setStyleSheet("background-color: #F8F9F9; color: #34495E;")
btn_browse_db = QPushButton("Browse...")
btn_browse_db.clicked.connect(self.browse_database_file)
btn_reset_db = QPushButton("Reset Default")
btn_reset_db.clicked.connect(self.reset_default_database)
db_picker_layout.addWidget(self.txt_db_path)
db_picker_layout.addWidget(btn_browse_db)
db_picker_layout.addWidget(btn_reset_db)
db_form.addRow("Active Database File:", db_picker_layout)
main_layout.addWidget(db_group)
# --- SECTION 1: GLOBAL ANKI PACKAGING CONFIGURATIONS --- # --- SECTION 1: GLOBAL ANKI PACKAGING CONFIGURATIONS ---
anki_group = QGroupBox("Anki Compilation Settings") anki_group = QGroupBox("Anki Compilation Settings")
anki_form = QFormLayout(anki_group) anki_form = QFormLayout(anki_group)
@ -59,7 +82,7 @@ class SettingsTab(QWidget):
self.txt_tts_voice.textChanged.connect(lambda text: self.update_setting("tts_preferred_voice", text.strip())) self.txt_tts_voice.textChanged.connect(lambda text: self.update_setting("tts_preferred_voice", text.strip()))
self.txt_tts_speed = QLineEdit() self.txt_tts_speed = QLineEdit()
self.txt_tts_speed.setPlaceholderText("1.15") self.txt_tts_speed.setPlaceholderText("0.75")
self.txt_tts_speed.textChanged.connect(lambda text: self.update_setting("tts_playback_speed", text.strip())) self.txt_tts_speed.textChanged.connect(lambda text: self.update_setting("tts_playback_speed", text.strip()))
engine_form.addRow("Fallback System Voice Name:", self.txt_tts_voice) engine_form.addRow("Fallback System Voice Name:", self.txt_tts_voice)
@ -106,13 +129,16 @@ class SettingsTab(QWidget):
# Block signals briefly so loading state doesn't trigger write-back loops # Block signals briefly so loading state doesn't trigger write-back loops
self.blockSignals(True) self.blockSignals(True)
# Populate active database path
self.txt_db_path.setText(database.get_db_path())
stored_settings = database.load_all_settings() stored_settings = database.load_all_settings()
self.txt_root_deck.setText(stored_settings.get("anki_root_deck_name", "Spanish")) self.txt_root_deck.setText(stored_settings.get("anki_root_deck_name", "Spanish"))
self.txt_sub_deck.setText(stored_settings.get("anki_sub_deck_name", "")) self.txt_sub_deck.setText(stored_settings.get("anki_sub_deck_name", ""))
self.txt_export_dir.setText(stored_settings.get("anki_export_directory", os.path.expanduser("~"))) self.txt_export_dir.setText(stored_settings.get("anki_export_directory", os.path.expanduser("~")))
self.txt_tts_voice.setText(stored_settings.get("tts_preferred_voice", "Apple_Monica")) self.txt_tts_voice.setText(stored_settings.get("tts_preferred_voice", "Apple_Monica"))
self.txt_tts_speed.setText(stored_settings.get("tts_playback_speed", "1.15")) self.txt_tts_speed.setText(stored_settings.get("tts_playback_speed", "0.75"))
self.blockSignals(False) self.blockSignals(False)
@ -120,6 +146,37 @@ class SettingsTab(QWidget):
"""Internal helper to communicate state mutations instantly upward.""" """Internal helper to communicate state mutations instantly upward."""
self.settings_changed.emit(key, value) self.settings_changed.emit(key, value)
def browse_database_file(self):
"""Allows user to choose an existing SQLite database file or create a new one."""
current_db = self.txt_db_path.text()
file_path, _ = QFileDialog.getOpenFileName(
self,
"Select SQLite Database File",
current_db,
"SQLite Database (*.db *.sqlite *.sqlite3);;All Files (*)",
)
if file_path:
database.set_db_path(file_path)
database.ensure_database_populated()
self.populate_fields_from_db_state()
QMessageBox.information(
self,
"Database Switched",
f"Active database switched to:\n{file_path}",
)
def reset_default_database(self):
"""Resets the database path back to macOS Application Support default directory."""
default_path = database.get_default_db_path()
database.set_db_path(default_path)
database.ensure_database_populated()
self.populate_fields_from_db_state()
QMessageBox.information(
self,
"Database Reset",
f"Reset database path to default location:\n{default_path}",
)
def browse_export_directory(self): def browse_export_directory(self):
"""Invokes a native macOS directory finder path browser window.""" """Invokes a native macOS directory finder path browser window."""
current_dir = self.txt_export_dir.text() or os.path.expanduser("~") current_dir = self.txt_export_dir.text() or os.path.expanduser("~")

981
tree.txt Normal file
View file

@ -0,0 +1,981 @@
.
├── LICENSE
├── README.md
├── README.pdf
├── Santiago_cathedral_2021_Sunset.jpg
├── __pycache__
│   ├── anki_exporter.cpython-313.pyc
│   ├── database.cpython-313.pyc
│   ├── tts_utils.cpython-313.pyc
│   └── video_generator.cpython-313.pyc
├── anki_exporter.py
├── app.icns
├── app_icon.iconset
│   ├── icon_128x128.png
│   ├── icon_128x128@2x.png
│   ├── icon_16x16.png
│   ├── icon_16x16@2x.png
│   ├── icon_256x256.png
│   ├── icon_256x256@2x.png
│   ├── icon_32x32.png
│   ├── icon_32x32@2x.png
│   ├── icon_512x512.png
│   └── icon_512x512@2x.png
├── aula_int_plus_1_glos_en_alfa.pdf
├── base_icon.png
├── build
│   └── main
│   ├── Analysis-00.toc
│   ├── BUNDLE-00.toc
│   ├── COLLECT-00.toc
│   ├── EXE-00.toc
│   ├── PKG-00.toc
│   ├── PYZ-00.pyz
│   ├── PYZ-00.toc
│   ├── base_library.zip
│   ├── localpycs
│   │   ├── pyimod01_archive.pyc
│   │   ├── pyimod02_importers.pyc
│   │   ├── pyimod03_ctypes.pyc
│   │   └── struct.pyc
│   ├── main
│   ├── main.pkg
│   ├── warn-main.txt
│   └── xref-main.html
├── core
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── asset_generator.cpython-313.pyc
│   │   ├── bulk_importer.cpython-313.pyc
│   │   ├── clean_glossary.cpython-313.pyc
│   │   └── phrase_manager.cpython-313.pyc
│   ├── asset_generator.py
│   ├── audio_engine.py
│   ├── bulk_importer.py
│   ├── clean_glossary.py
│   └── phrase_manager.py
├── database.py
├── database_legacy
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   └── connection.cpython-313.pyc
│   ├── connection.py
│   ├── trainer_backup_20260618_220043.db
│   └── trainer_backup_20260618_224811.db
├── dist
│   ├── main
│   │   ├── _internal
│   │   │   ├── 81d243bd2c585b0f4821__mypyc.cpython-313-darwin.so
│   │   │   ├── PIL
│   │   │   │   ├── _avif.cpython-313-darwin.so
│   │   │   │   ├── _imaging.cpython-313-darwin.so
│   │   │   │   ├── _imagingcms.cpython-313-darwin.so
│   │   │   │   ├── _imagingft.cpython-313-darwin.so
│   │   │   │   ├── _imagingmath.cpython-313-darwin.so
│   │   │   │   ├── _imagingtk.cpython-313-darwin.so
│   │   │   │   └── _webp.cpython-313-darwin.so
│   │   │   ├── PyQt6
│   │   │   │   ├── Qt6
│   │   │   │   │   ├── lib
│   │   │   │   │   │   ├── QtCore.framework
│   │   │   │   │   │   │   ├── QtCore -> Versions/Current/QtCore
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtCore
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   ├── QtDBus.framework
│   │   │   │   │   │   │   ├── QtDBus -> Versions/Current/QtDBus
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtDBus
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   ├── QtGui.framework
│   │   │   │   │   │   │   ├── QtGui -> Versions/Current/QtGui
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtGui
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   ├── QtNetwork.framework
│   │   │   │   │   │   │   ├── QtNetwork -> Versions/Current/QtNetwork
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtNetwork
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   ├── QtPdf.framework
│   │   │   │   │   │   │   ├── QtPdf -> Versions/Current/QtPdf
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtPdf
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   ├── QtSvg.framework
│   │   │   │   │   │   │   ├── QtSvg -> Versions/Current/QtSvg
│   │   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   │   └── Versions
│   │   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   │   ├── QtSvg
│   │   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── Current -> A
│   │   │   │   │   │   └── QtWidgets.framework
│   │   │   │   │   │   ├── QtWidgets -> Versions/Current/QtWidgets
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtWidgets
│   │   │   │   │   │   │   └── Resources
│   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── plugins
│   │   │   │   │   │   ├── generic
│   │   │   │   │   │   │   └── libqtuiotouchplugin.dylib
│   │   │   │   │   │   ├── iconengines
│   │   │   │   │   │   │   └── libqsvgicon.dylib
│   │   │   │   │   │   ├── imageformats
│   │   │   │   │   │   │   ├── libqgif.dylib
│   │   │   │   │   │   │   ├── libqicns.dylib
│   │   │   │   │   │   │   ├── libqico.dylib
│   │   │   │   │   │   │   ├── libqjpeg.dylib
│   │   │   │   │   │   │   ├── libqmacheif.dylib
│   │   │   │   │   │   │   ├── libqmacjp2.dylib
│   │   │   │   │   │   │   ├── libqpdf.dylib
│   │   │   │   │   │   │   ├── libqsvg.dylib
│   │   │   │   │   │   │   ├── libqtga.dylib
│   │   │   │   │   │   │   ├── libqtiff.dylib
│   │   │   │   │   │   │   ├── libqwbmp.dylib
│   │   │   │   │   │   │   └── libqwebp.dylib
│   │   │   │   │   │   ├── platforms
│   │   │   │   │   │   │   ├── libqcocoa.dylib
│   │   │   │   │   │   │   ├── libqminimal.dylib
│   │   │   │   │   │   │   └── libqoffscreen.dylib
│   │   │   │   │   │   └── styles
│   │   │   │   │   │   └── libqmacstyle.dylib
│   │   │   │   │   └── translations
│   │   │   │   │   ├── qt_ar.qm
│   │   │   │   │   ├── qt_bg.qm
│   │   │   │   │   ├── qt_ca.qm
│   │   │   │   │   ├── qt_cs.qm
│   │   │   │   │   ├── qt_da.qm
│   │   │   │   │   ├── qt_de.qm
│   │   │   │   │   ├── qt_en.qm
│   │   │   │   │   ├── qt_es.qm
│   │   │   │   │   ├── qt_fa.qm
│   │   │   │   │   ├── qt_fi.qm
│   │   │   │   │   ├── qt_fr.qm
│   │   │   │   │   ├── qt_gd.qm
│   │   │   │   │   ├── qt_gl.qm
│   │   │   │   │   ├── qt_he.qm
│   │   │   │   │   ├── qt_help_ar.qm
│   │   │   │   │   ├── qt_help_bg.qm
│   │   │   │   │   ├── qt_help_ca.qm
│   │   │   │   │   ├── qt_help_cs.qm
│   │   │   │   │   ├── qt_help_da.qm
│   │   │   │   │   ├── qt_help_de.qm
│   │   │   │   │   ├── qt_help_en.qm
│   │   │   │   │   ├── qt_help_es.qm
│   │   │   │   │   ├── qt_help_fr.qm
│   │   │   │   │   ├── qt_help_gl.qm
│   │   │   │   │   ├── qt_help_hr.qm
│   │   │   │   │   ├── qt_help_hu.qm
│   │   │   │   │   ├── qt_help_it.qm
│   │   │   │   │   ├── qt_help_ja.qm
│   │   │   │   │   ├── qt_help_ka.qm
│   │   │   │   │   ├── qt_help_ko.qm
│   │   │   │   │   ├── qt_help_nl.qm
│   │   │   │   │   ├── qt_help_nn.qm
│   │   │   │   │   ├── qt_help_pl.qm
│   │   │   │   │   ├── qt_help_pt_BR.qm
│   │   │   │   │   ├── qt_help_ru.qm
│   │   │   │   │   ├── qt_help_sk.qm
│   │   │   │   │   ├── qt_help_sl.qm
│   │   │   │   │   ├── qt_help_sv.qm
│   │   │   │   │   ├── qt_help_tr.qm
│   │   │   │   │   ├── qt_help_uk.qm
│   │   │   │   │   ├── qt_help_zh_CN.qm
│   │   │   │   │   ├── qt_help_zh_TW.qm
│   │   │   │   │   ├── qt_hr.qm
│   │   │   │   │   ├── qt_hu.qm
│   │   │   │   │   ├── qt_it.qm
│   │   │   │   │   ├── qt_ja.qm
│   │   │   │   │   ├── qt_ka.qm
│   │   │   │   │   ├── qt_ko.qm
│   │   │   │   │   ├── qt_lg.qm
│   │   │   │   │   ├── qt_lt.qm
│   │   │   │   │   ├── qt_lv.qm
│   │   │   │   │   ├── qt_nl.qm
│   │   │   │   │   ├── qt_nn.qm
│   │   │   │   │   ├── qt_pl.qm
│   │   │   │   │   ├── qt_pt_BR.qm
│   │   │   │   │   ├── qt_pt_PT.qm
│   │   │   │   │   ├── qt_ru.qm
│   │   │   │   │   ├── qt_sk.qm
│   │   │   │   │   ├── qt_sl.qm
│   │   │   │   │   ├── qt_sv.qm
│   │   │   │   │   ├── qt_tr.qm
│   │   │   │   │   ├── qt_uk.qm
│   │   │   │   │   ├── qt_zh_CN.qm
│   │   │   │   │   ├── qt_zh_TW.qm
│   │   │   │   │   ├── qtbase_ar.qm
│   │   │   │   │   ├── qtbase_bg.qm
│   │   │   │   │   ├── qtbase_ca.qm
│   │   │   │   │   ├── qtbase_cs.qm
│   │   │   │   │   ├── qtbase_da.qm
│   │   │   │   │   ├── qtbase_de.qm
│   │   │   │   │   ├── qtbase_en.qm
│   │   │   │   │   ├── qtbase_es.qm
│   │   │   │   │   ├── qtbase_fa.qm
│   │   │   │   │   ├── qtbase_fi.qm
│   │   │   │   │   ├── qtbase_fr.qm
│   │   │   │   │   ├── qtbase_gd.qm
│   │   │   │   │   ├── qtbase_he.qm
│   │   │   │   │   ├── qtbase_hr.qm
│   │   │   │   │   ├── qtbase_hu.qm
│   │   │   │   │   ├── qtbase_it.qm
│   │   │   │   │   ├── qtbase_ja.qm
│   │   │   │   │   ├── qtbase_ka.qm
│   │   │   │   │   ├── qtbase_ko.qm
│   │   │   │   │   ├── qtbase_lg.qm
│   │   │   │   │   ├── qtbase_lv.qm
│   │   │   │   │   ├── qtbase_nl.qm
│   │   │   │   │   ├── qtbase_nn.qm
│   │   │   │   │   ├── qtbase_pl.qm
│   │   │   │   │   ├── qtbase_pt_BR.qm
│   │   │   │   │   ├── qtbase_ru.qm
│   │   │   │   │   ├── qtbase_sk.qm
│   │   │   │   │   ├── qtbase_sv.qm
│   │   │   │   │   ├── qtbase_tr.qm
│   │   │   │   │   ├── qtbase_uk.qm
│   │   │   │   │   ├── qtbase_zh_CN.qm
│   │   │   │   │   └── qtbase_zh_TW.qm
│   │   │   │   ├── QtCore.abi3.so
│   │   │   │   ├── QtDBus.abi3.so
│   │   │   │   ├── QtGui.abi3.so
│   │   │   │   ├── QtWidgets.abi3.so
│   │   │   │   └── sip.cpython-313-darwin.so
│   │   │   ├── QtCore -> PyQt6/Qt6/lib/QtCore.framework/Versions/A/QtCore
│   │   │   ├── QtDBus -> PyQt6/Qt6/lib/QtDBus.framework/Versions/A/QtDBus
│   │   │   ├── QtGui -> PyQt6/Qt6/lib/QtGui.framework/Versions/A/QtGui
│   │   │   ├── QtNetwork -> PyQt6/Qt6/lib/QtNetwork.framework/Versions/A/QtNetwork
│   │   │   ├── QtPdf -> PyQt6/Qt6/lib/QtPdf.framework/Versions/A/QtPdf
│   │   │   ├── QtSvg -> PyQt6/Qt6/lib/QtSvg.framework/Versions/A/QtSvg
│   │   │   ├── QtWidgets -> PyQt6/Qt6/lib/QtWidgets.framework/Versions/A/QtWidgets
│   │   │   ├── aiohttp
│   │   │   │   ├── _http_parser.cpython-313-darwin.so
│   │   │   │   ├── _http_writer.cpython-313-darwin.so
│   │   │   │   └── _websocket
│   │   │   │   ├── mask.cpython-313-darwin.so
│   │   │   │   └── reader_c.cpython-313-darwin.so
│   │   │   ├── attrs-26.1.0.dist-info
│   │   │   │   ├── INSTALLER
│   │   │   │   ├── METADATA
│   │   │   │   ├── RECORD
│   │   │   │   ├── REQUESTED
│   │   │   │   ├── WHEEL
│   │   │   │   └── licenses
│   │   │   │   └── LICENSE
│   │   │   ├── base_library.zip
│   │   │   ├── certifi
│   │   │   │   ├── cacert.pem
│   │   │   │   └── py.typed
│   │   │   ├── charset_normalizer
│   │   │   │   ├── cd.cpython-313-darwin.so
│   │   │   │   └── md.cpython-313-darwin.so
│   │   │   ├── frozenlist
│   │   │   │   └── _frozenlist.cpython-313-darwin.so
│   │   │   ├── libXau.6.dylib -> PIL/.dylibs/libXau.6.dylib
│   │   │   ├── libavif.16.4.1.dylib -> PIL/.dylibs/libavif.16.4.1.dylib
│   │   │   ├── libbrotlicommon.1.2.0.dylib -> PIL/.dylibs/libbrotlicommon.1.2.0.dylib
│   │   │   ├── libbrotlidec.1.2.0.dylib -> PIL/.dylibs/libbrotlidec.1.2.0.dylib
│   │   │   ├── libfreetype.6.dylib -> PIL/.dylibs/libfreetype.6.dylib
│   │   │   ├── libharfbuzz.0.dylib -> PIL/.dylibs/libharfbuzz.0.dylib
│   │   │   ├── libjpeg.62.4.0.dylib -> PIL/.dylibs/libjpeg.62.4.0.dylib
│   │   │   ├── liblcms2.2.dylib -> PIL/.dylibs/liblcms2.2.dylib
│   │   │   ├── liblzma.5.dylib -> PIL/.dylibs/liblzma.5.dylib
│   │   │   ├── libopenjp2.2.5.4.dylib -> PIL/.dylibs/libopenjp2.2.5.4.dylib
│   │   │   ├── libpng16.16.dylib -> PIL/.dylibs/libpng16.16.dylib
│   │   │   ├── libpython3.13.dylib
│   │   │   ├── libsharpyuv.0.dylib -> PIL/.dylibs/libsharpyuv.0.dylib
│   │   │   ├── libtiff.6.dylib -> PIL/.dylibs/libtiff.6.dylib
│   │   │   ├── libwebp.7.dylib -> PIL/.dylibs/libwebp.7.dylib
│   │   │   ├── libwebpdemux.2.dylib -> PIL/.dylibs/libwebpdemux.2.dylib
│   │   │   ├── libwebpmux.3.dylib -> PIL/.dylibs/libwebpmux.3.dylib
│   │   │   ├── libxcb.1.1.0.dylib -> PIL/.dylibs/libxcb.1.1.0.dylib
│   │   │   ├── libz.1.3.1.zlib-ng.dylib -> PIL/.dylibs/libz.1.3.1.zlib-ng.dylib
│   │   │   ├── lxml
│   │   │   │   ├── _elementpath.cpython-313-darwin.so
│   │   │   │   ├── builder.cpython-313-darwin.so
│   │   │   │   ├── etree.cpython-313-darwin.so
│   │   │   │   ├── html
│   │   │   │   │   ├── _difflib.cpython-313-darwin.so
│   │   │   │   │   └── diff.cpython-313-darwin.so
│   │   │   │   ├── isoschematron
│   │   │   │   │   └── resources
│   │   │   │   │   ├── rng
│   │   │   │   │   │   └── iso-schematron.rng
│   │   │   │   │   └── xsl
│   │   │   │   │   ├── RNG2Schtrn.xsl
│   │   │   │   │   ├── XSD2Schtrn.xsl
│   │   │   │   │   └── iso-schematron-xslt1
│   │   │   │   │   ├── iso_abstract_expand.xsl
│   │   │   │   │   ├── iso_dsdl_include.xsl
│   │   │   │   │   ├── iso_schematron_message.xsl
│   │   │   │   │   ├── iso_schematron_skeleton_for_xslt1.xsl
│   │   │   │   │   ├── iso_svrl_for_xslt1.xsl
│   │   │   │   │   └── readme.txt
│   │   │   │   ├── objectify.cpython-313-darwin.so
│   │   │   │   └── sax.cpython-313-darwin.so
│   │   │   ├── multidict
│   │   │   │   └── _multidict.cpython-313-darwin.so
│   │   │   ├── numpy
│   │   │   │   ├── _core
│   │   │   │   │   ├── _multiarray_tests.cpython-313-darwin.so
│   │   │   │   │   └── _multiarray_umath.cpython-313-darwin.so
│   │   │   │   ├── fft
│   │   │   │   │   └── _pocketfft_umath.cpython-313-darwin.so
│   │   │   │   ├── linalg
│   │   │   │   │   └── _umath_linalg.cpython-313-darwin.so
│   │   │   │   └── random
│   │   │   │   ├── _bounded_integers.cpython-313-darwin.so
│   │   │   │   ├── _common.cpython-313-darwin.so
│   │   │   │   ├── _generator.cpython-313-darwin.so
│   │   │   │   ├── _mt19937.cpython-313-darwin.so
│   │   │   │   ├── _pcg64.cpython-313-darwin.so
│   │   │   │   ├── _philox.cpython-313-darwin.so
│   │   │   │   ├── _sfc64.cpython-313-darwin.so
│   │   │   │   ├── bit_generator.cpython-313-darwin.so
│   │   │   │   └── mtrand.cpython-313-darwin.so
│   │   │   ├── numpy-2.4.6.dist-info
│   │   │   │   ├── INSTALLER
│   │   │   │   ├── METADATA
│   │   │   │   ├── RECORD
│   │   │   │   ├── REQUESTED
│   │   │   │   ├── WHEEL
│   │   │   │   ├── entry_points.txt
│   │   │   │   └── licenses
│   │   │   │   ├── LICENSE.txt
│   │   │   │   └── numpy
│   │   │   │   ├── _core
│   │   │   │   │   ├── include
│   │   │   │   │   │   └── numpy
│   │   │   │   │   │   └── libdivide
│   │   │   │   │   │   └── LICENSE.txt
│   │   │   │   │   └── src
│   │   │   │   │   ├── common
│   │   │   │   │   │   └── pythoncapi-compat
│   │   │   │   │   │   └── COPYING
│   │   │   │   │   ├── highway
│   │   │   │   │   │   └── LICENSE
│   │   │   │   │   ├── multiarray
│   │   │   │   │   │   └── dragon4_LICENSE.txt
│   │   │   │   │   ├── npysort
│   │   │   │   │   │   └── x86-simd-sort
│   │   │   │   │   │   └── LICENSE.md
│   │   │   │   │   └── umath
│   │   │   │   │   └── svml
│   │   │   │   │   └── LICENSE
│   │   │   │   ├── fft
│   │   │   │   │   └── pocketfft
│   │   │   │   │   └── LICENSE.md
│   │   │   │   ├── linalg
│   │   │   │   │   └── lapack_lite
│   │   │   │   │   └── LICENSE.txt
│   │   │   │   ├── ma
│   │   │   │   │   └── LICENSE
│   │   │   │   └── random
│   │   │   │   ├── LICENSE.md
│   │   │   │   └── src
│   │   │   │   ├── distributions
│   │   │   │   │   └── LICENSE.md
│   │   │   │   ├── mt19937
│   │   │   │   │   └── LICENSE.md
│   │   │   │   ├── pcg64
│   │   │   │   │   └── LICENSE.md
│   │   │   │   ├── philox
│   │   │   │   │   └── LICENSE.md
│   │   │   │   ├── sfc64
│   │   │   │   │   └── LICENSE.md
│   │   │   │   └── splitmix64
│   │   │   │   └── LICENSE.md
│   │   │   ├── propcache
│   │   │   │   └── _helpers_c.cpython-313-darwin.so
│   │   │   ├── psutil
│   │   │   │   └── _psutil_osx.abi3.so
│   │   │   ├── pydantic-2.13.4.dist-info
│   │   │   │   ├── INSTALLER
│   │   │   │   ├── METADATA
│   │   │   │   ├── RECORD
│   │   │   │   ├── REQUESTED
│   │   │   │   ├── WHEEL
│   │   │   │   └── licenses
│   │   │   │   └── LICENSE
│   │   │   ├── pydantic_core
│   │   │   │   └── _pydantic_core.cpython-313-darwin.so
│   │   │   ├── setuptools
│   │   │   │   └── _vendor
│   │   │   │   ├── importlib_metadata-8.7.1.dist-info
│   │   │   │   │   ├── INSTALLER
│   │   │   │   │   ├── METADATA
│   │   │   │   │   ├── RECORD
│   │   │   │   │   ├── REQUESTED
│   │   │   │   │   ├── WHEEL
│   │   │   │   │   ├── licenses
│   │   │   │   │   │   └── LICENSE
│   │   │   │   │   └── top_level.txt
│   │   │   │   └── jaraco
│   │   │   │   └── text
│   │   │   │   └── Lorem ipsum.txt
│   │   │   ├── yaml
│   │   │   │   └── _yaml.cpython-313-darwin.so
│   │   │   └── yarl
│   │   │   └── _quoting_c.cpython-313-darwin.so
│   │   └── main
│   └── main.app
│   └── Contents
│   ├── Frameworks
│   │   ├── 81d243bd2c585b0f4821__mypyc.cpython-313-darwin.so
│   │   ├── PIL
│   │   │   ├── __dot__dylibs
│   │   │   │   ├── libXau.6.dylib
│   │   │   │   ├── libavif.16.4.1.dylib
│   │   │   │   ├── libbrotlicommon.1.2.0.dylib
│   │   │   │   ├── libbrotlidec.1.2.0.dylib
│   │   │   │   ├── libfreetype.6.dylib
│   │   │   │   ├── libharfbuzz.0.dylib
│   │   │   │   ├── libjpeg.62.4.0.dylib
│   │   │   │   ├── liblcms2.2.dylib
│   │   │   │   ├── liblzma.5.dylib
│   │   │   │   ├── libopenjp2.2.5.4.dylib
│   │   │   │   ├── libpng16.16.dylib
│   │   │   │   ├── libsharpyuv.0.dylib
│   │   │   │   ├── libtiff.6.dylib
│   │   │   │   ├── libwebp.7.dylib
│   │   │   │   ├── libwebpdemux.2.dylib
│   │   │   │   ├── libwebpmux.3.dylib
│   │   │   │   ├── libxcb.1.1.0.dylib
│   │   │   │   └── libz.1.3.1.zlib-ng.dylib
│   │   │   ├── _avif.cpython-313-darwin.so
│   │   │   ├── _imaging.cpython-313-darwin.so
│   │   │   ├── _imagingcms.cpython-313-darwin.so
│   │   │   ├── _imagingft.cpython-313-darwin.so
│   │   │   ├── _imagingmath.cpython-313-darwin.so
│   │   │   ├── _imagingtk.cpython-313-darwin.so
│   │   │   └── _webp.cpython-313-darwin.so
│   │   ├── PyQt6
│   │   │   ├── Qt6
│   │   │   │   ├── lib
│   │   │   │   │   ├── QtCore.framework
│   │   │   │   │   │   ├── QtCore -> Versions/Current/QtCore
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtCore
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── QtDBus.framework
│   │   │   │   │   │   ├── QtDBus -> Versions/Current/QtDBus
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtDBus
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── QtGui.framework
│   │   │   │   │   │   ├── QtGui -> Versions/Current/QtGui
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtGui
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── QtNetwork.framework
│   │   │   │   │   │   ├── QtNetwork -> Versions/Current/QtNetwork
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtNetwork
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── QtPdf.framework
│   │   │   │   │   │   ├── QtPdf -> Versions/Current/QtPdf
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtPdf
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   ├── QtSvg.framework
│   │   │   │   │   │   ├── QtSvg -> Versions/Current/QtSvg
│   │   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   │   └── Versions
│   │   │   │   │   │   ├── A
│   │   │   │   │   │   │   ├── QtSvg
│   │   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   │   └── CodeResources
│   │   │   │   │   │   └── Current -> A
│   │   │   │   │   └── QtWidgets.framework
│   │   │   │   │   ├── QtWidgets -> Versions/Current/QtWidgets
│   │   │   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   │   │   └── Versions
│   │   │   │   │   ├── A
│   │   │   │   │   │   ├── QtWidgets
│   │   │   │   │   │   ├── Resources
│   │   │   │   │   │   │   └── Info.plist
│   │   │   │   │   │   └── _CodeSignature
│   │   │   │   │   │   └── CodeResources
│   │   │   │   │   └── Current -> A
│   │   │   │   ├── plugins
│   │   │   │   │   ├── generic
│   │   │   │   │   │   └── libqtuiotouchplugin.dylib
│   │   │   │   │   ├── iconengines
│   │   │   │   │   │   └── libqsvgicon.dylib
│   │   │   │   │   ├── imageformats
│   │   │   │   │   │   ├── libqgif.dylib
│   │   │   │   │   │   ├── libqicns.dylib
│   │   │   │   │   │   ├── libqico.dylib
│   │   │   │   │   │   ├── libqjpeg.dylib
│   │   │   │   │   │   ├── libqmacheif.dylib
│   │   │   │   │   │   ├── libqmacjp2.dylib
│   │   │   │   │   │   ├── libqpdf.dylib
│   │   │   │   │   │   ├── libqsvg.dylib
│   │   │   │   │   │   ├── libqtga.dylib
│   │   │   │   │   │   ├── libqtiff.dylib
│   │   │   │   │   │   ├── libqwbmp.dylib
│   │   │   │   │   │   └── libqwebp.dylib
│   │   │   │   │   ├── platforms
│   │   │   │   │   │   ├── libqcocoa.dylib
│   │   │   │   │   │   ├── libqminimal.dylib
│   │   │   │   │   │   └── libqoffscreen.dylib
│   │   │   │   │   └── styles
│   │   │   │   │   └── libqmacstyle.dylib
│   │   │   │   └── translations -> ../../../Resources/PyQt6/Qt6/translations
│   │   │   ├── QtCore.abi3.so
│   │   │   ├── QtDBus.abi3.so
│   │   │   ├── QtGui.abi3.so
│   │   │   ├── QtWidgets.abi3.so
│   │   │   └── sip.cpython-313-darwin.so
│   │   ├── QtCore -> PyQt6/Qt6/lib/QtCore.framework/Versions/A/QtCore
│   │   ├── QtDBus -> PyQt6/Qt6/lib/QtDBus.framework/Versions/A/QtDBus
│   │   ├── QtGui -> PyQt6/Qt6/lib/QtGui.framework/Versions/A/QtGui
│   │   ├── QtNetwork -> PyQt6/Qt6/lib/QtNetwork.framework/Versions/A/QtNetwork
│   │   ├── QtPdf -> PyQt6/Qt6/lib/QtPdf.framework/Versions/A/QtPdf
│   │   ├── QtSvg -> PyQt6/Qt6/lib/QtSvg.framework/Versions/A/QtSvg
│   │   ├── QtWidgets -> PyQt6/Qt6/lib/QtWidgets.framework/Versions/A/QtWidgets
│   │   ├── aiohttp
│   │   │   ├── _http_parser.cpython-313-darwin.so
│   │   │   ├── _http_writer.cpython-313-darwin.so
│   │   │   └── _websocket
│   │   │   ├── mask.cpython-313-darwin.so
│   │   │   └── reader_c.cpython-313-darwin.so
│   │   ├── attrs-26.1.0.dist-info -> ../Resources/attrs-26.1.0.dist-info
│   │   ├── base_library.zip -> ../Resources/base_library.zip
│   │   ├── certifi -> ../Resources/certifi
│   │   ├── charset_normalizer
│   │   │   ├── cd.cpython-313-darwin.so
│   │   │   └── md.cpython-313-darwin.so
│   │   ├── frozenlist
│   │   │   └── _frozenlist.cpython-313-darwin.so
│   │   ├── libXau.6.dylib -> PIL/.dylibs/libXau.6.dylib
│   │   ├── libavif.16.4.1.dylib -> PIL/.dylibs/libavif.16.4.1.dylib
│   │   ├── libbrotlicommon.1.2.0.dylib -> PIL/.dylibs/libbrotlicommon.1.2.0.dylib
│   │   ├── libbrotlidec.1.2.0.dylib -> PIL/.dylibs/libbrotlidec.1.2.0.dylib
│   │   ├── libfreetype.6.dylib -> PIL/.dylibs/libfreetype.6.dylib
│   │   ├── libharfbuzz.0.dylib -> PIL/.dylibs/libharfbuzz.0.dylib
│   │   ├── libjpeg.62.4.0.dylib -> PIL/.dylibs/libjpeg.62.4.0.dylib
│   │   ├── liblcms2.2.dylib -> PIL/.dylibs/liblcms2.2.dylib
│   │   ├── liblzma.5.dylib -> PIL/.dylibs/liblzma.5.dylib
│   │   ├── libopenjp2.2.5.4.dylib -> PIL/.dylibs/libopenjp2.2.5.4.dylib
│   │   ├── libpng16.16.dylib -> PIL/.dylibs/libpng16.16.dylib
│   │   ├── libpython3.13.dylib
│   │   ├── libsharpyuv.0.dylib -> PIL/.dylibs/libsharpyuv.0.dylib
│   │   ├── libtiff.6.dylib -> PIL/.dylibs/libtiff.6.dylib
│   │   ├── libwebp.7.dylib -> PIL/.dylibs/libwebp.7.dylib
│   │   ├── libwebpdemux.2.dylib -> PIL/.dylibs/libwebpdemux.2.dylib
│   │   ├── libwebpmux.3.dylib -> PIL/.dylibs/libwebpmux.3.dylib
│   │   ├── libxcb.1.1.0.dylib -> PIL/.dylibs/libxcb.1.1.0.dylib
│   │   ├── libz.1.3.1.zlib-ng.dylib -> PIL/.dylibs/libz.1.3.1.zlib-ng.dylib
│   │   ├── lxml
│   │   │   ├── _elementpath.cpython-313-darwin.so
│   │   │   ├── builder.cpython-313-darwin.so
│   │   │   ├── etree.cpython-313-darwin.so
│   │   │   ├── html
│   │   │   │   ├── _difflib.cpython-313-darwin.so
│   │   │   │   └── diff.cpython-313-darwin.so
│   │   │   ├── isoschematron -> ../../Resources/lxml/isoschematron
│   │   │   ├── objectify.cpython-313-darwin.so
│   │   │   └── sax.cpython-313-darwin.so
│   │   ├── multidict
│   │   │   └── _multidict.cpython-313-darwin.so
│   │   ├── numpy
│   │   │   ├── _core
│   │   │   │   ├── _multiarray_tests.cpython-313-darwin.so
│   │   │   │   └── _multiarray_umath.cpython-313-darwin.so
│   │   │   ├── fft
│   │   │   │   └── _pocketfft_umath.cpython-313-darwin.so
│   │   │   ├── linalg
│   │   │   │   └── _umath_linalg.cpython-313-darwin.so
│   │   │   └── random
│   │   │   ├── _bounded_integers.cpython-313-darwin.so
│   │   │   ├── _common.cpython-313-darwin.so
│   │   │   ├── _generator.cpython-313-darwin.so
│   │   │   ├── _mt19937.cpython-313-darwin.so
│   │   │   ├── _pcg64.cpython-313-darwin.so
│   │   │   ├── _philox.cpython-313-darwin.so
│   │   │   ├── _sfc64.cpython-313-darwin.so
│   │   │   ├── bit_generator.cpython-313-darwin.so
│   │   │   └── mtrand.cpython-313-darwin.so
│   │   ├── numpy-2.4.6.dist-info -> ../Resources/numpy-2.4.6.dist-info
│   │   ├── propcache
│   │   │   └── _helpers_c.cpython-313-darwin.so
│   │   ├── psutil
│   │   │   └── _psutil_osx.abi3.so
│   │   ├── pydantic-2.13.4.dist-info -> ../Resources/pydantic-2.13.4.dist-info
│   │   ├── pydantic_core
│   │   │   └── _pydantic_core.cpython-313-darwin.so
│   │   ├── setuptools -> ../Resources/setuptools
│   │   ├── yaml
│   │   │   └── _yaml.cpython-313-darwin.so
│   │   └── yarl
│   │   └── _quoting_c.cpython-313-darwin.so
│   ├── Info.plist
│   ├── MacOS
│   │   └── main
│   ├── Resources
│   │   ├── 81d243bd2c585b0f4821__mypyc.cpython-313-darwin.so -> ../Frameworks/81d243bd2c585b0f4821__mypyc.cpython-313-darwin.so
│   │   ├── PIL -> ../Frameworks/PIL
│   │   ├── PyQt6
│   │   │   ├── Qt6
│   │   │   │   ├── lib -> ../../../Frameworks/PyQt6/Qt6/lib
│   │   │   │   ├── plugins -> ../../../Frameworks/PyQt6/Qt6/plugins
│   │   │   │   └── translations
│   │   │   │   ├── qt_ar.qm
│   │   │   │   ├── qt_bg.qm
│   │   │   │   ├── qt_ca.qm
│   │   │   │   ├── qt_cs.qm
│   │   │   │   ├── qt_da.qm
│   │   │   │   ├── qt_de.qm
│   │   │   │   ├── qt_en.qm
│   │   │   │   ├── qt_es.qm
│   │   │   │   ├── qt_fa.qm
│   │   │   │   ├── qt_fi.qm
│   │   │   │   ├── qt_fr.qm
│   │   │   │   ├── qt_gd.qm
│   │   │   │   ├── qt_gl.qm
│   │   │   │   ├── qt_he.qm
│   │   │   │   ├── qt_help_ar.qm
│   │   │   │   ├── qt_help_bg.qm
│   │   │   │   ├── qt_help_ca.qm
│   │   │   │   ├── qt_help_cs.qm
│   │   │   │   ├── qt_help_da.qm
│   │   │   │   ├── qt_help_de.qm
│   │   │   │   ├── qt_help_en.qm
│   │   │   │   ├── qt_help_es.qm
│   │   │   │   ├── qt_help_fr.qm
│   │   │   │   ├── qt_help_gl.qm
│   │   │   │   ├── qt_help_hr.qm
│   │   │   │   ├── qt_help_hu.qm
│   │   │   │   ├── qt_help_it.qm
│   │   │   │   ├── qt_help_ja.qm
│   │   │   │   ├── qt_help_ka.qm
│   │   │   │   ├── qt_help_ko.qm
│   │   │   │   ├── qt_help_nl.qm
│   │   │   │   ├── qt_help_nn.qm
│   │   │   │   ├── qt_help_pl.qm
│   │   │   │   ├── qt_help_pt_BR.qm
│   │   │   │   ├── qt_help_ru.qm
│   │   │   │   ├── qt_help_sk.qm
│   │   │   │   ├── qt_help_sl.qm
│   │   │   │   ├── qt_help_sv.qm
│   │   │   │   ├── qt_help_tr.qm
│   │   │   │   ├── qt_help_uk.qm
│   │   │   │   ├── qt_help_zh_CN.qm
│   │   │   │   ├── qt_help_zh_TW.qm
│   │   │   │   ├── qt_hr.qm
│   │   │   │   ├── qt_hu.qm
│   │   │   │   ├── qt_it.qm
│   │   │   │   ├── qt_ja.qm
│   │   │   │   ├── qt_ka.qm
│   │   │   │   ├── qt_ko.qm
│   │   │   │   ├── qt_lg.qm
│   │   │   │   ├── qt_lt.qm
│   │   │   │   ├── qt_lv.qm
│   │   │   │   ├── qt_nl.qm
│   │   │   │   ├── qt_nn.qm
│   │   │   │   ├── qt_pl.qm
│   │   │   │   ├── qt_pt_BR.qm
│   │   │   │   ├── qt_pt_PT.qm
│   │   │   │   ├── qt_ru.qm
│   │   │   │   ├── qt_sk.qm
│   │   │   │   ├── qt_sl.qm
│   │   │   │   ├── qt_sv.qm
│   │   │   │   ├── qt_tr.qm
│   │   │   │   ├── qt_uk.qm
│   │   │   │   ├── qt_zh_CN.qm
│   │   │   │   ├── qt_zh_TW.qm
│   │   │   │   ├── qtbase_ar.qm
│   │   │   │   ├── qtbase_bg.qm
│   │   │   │   ├── qtbase_ca.qm
│   │   │   │   ├── qtbase_cs.qm
│   │   │   │   ├── qtbase_da.qm
│   │   │   │   ├── qtbase_de.qm
│   │   │   │   ├── qtbase_en.qm
│   │   │   │   ├── qtbase_es.qm
│   │   │   │   ├── qtbase_fa.qm
│   │   │   │   ├── qtbase_fi.qm
│   │   │   │   ├── qtbase_fr.qm
│   │   │   │   ├── qtbase_gd.qm
│   │   │   │   ├── qtbase_he.qm
│   │   │   │   ├── qtbase_hr.qm
│   │   │   │   ├── qtbase_hu.qm
│   │   │   │   ├── qtbase_it.qm
│   │   │   │   ├── qtbase_ja.qm
│   │   │   │   ├── qtbase_ka.qm
│   │   │   │   ├── qtbase_ko.qm
│   │   │   │   ├── qtbase_lg.qm
│   │   │   │   ├── qtbase_lv.qm
│   │   │   │   ├── qtbase_nl.qm
│   │   │   │   ├── qtbase_nn.qm
│   │   │   │   ├── qtbase_pl.qm
│   │   │   │   ├── qtbase_pt_BR.qm
│   │   │   │   ├── qtbase_ru.qm
│   │   │   │   ├── qtbase_sk.qm
│   │   │   │   ├── qtbase_sv.qm
│   │   │   │   ├── qtbase_tr.qm
│   │   │   │   ├── qtbase_uk.qm
│   │   │   │   ├── qtbase_zh_CN.qm
│   │   │   │   └── qtbase_zh_TW.qm
│   │   │   ├── QtCore.abi3.so -> ../../Frameworks/PyQt6/QtCore.abi3.so
│   │   │   ├── QtDBus.abi3.so -> ../../Frameworks/PyQt6/QtDBus.abi3.so
│   │   │   ├── QtGui.abi3.so -> ../../Frameworks/PyQt6/QtGui.abi3.so
│   │   │   ├── QtWidgets.abi3.so -> ../../Frameworks/PyQt6/QtWidgets.abi3.so
│   │   │   └── sip.cpython-313-darwin.so -> ../../Frameworks/PyQt6/sip.cpython-313-darwin.so
│   │   ├── QtCore -> PyQt6/Qt6/lib/QtCore.framework/Versions/A/QtCore
│   │   ├── QtDBus -> PyQt6/Qt6/lib/QtDBus.framework/Versions/A/QtDBus
│   │   ├── QtGui -> PyQt6/Qt6/lib/QtGui.framework/Versions/A/QtGui
│   │   ├── QtNetwork -> PyQt6/Qt6/lib/QtNetwork.framework/Versions/A/QtNetwork
│   │   ├── QtPdf -> PyQt6/Qt6/lib/QtPdf.framework/Versions/A/QtPdf
│   │   ├── QtSvg -> PyQt6/Qt6/lib/QtSvg.framework/Versions/A/QtSvg
│   │   ├── QtWidgets -> PyQt6/Qt6/lib/QtWidgets.framework/Versions/A/QtWidgets
│   │   ├── aiohttp -> ../Frameworks/aiohttp
│   │   ├── app.icns
│   │   ├── attrs-26.1.0.dist-info
│   │   │   ├── INSTALLER
│   │   │   ├── METADATA
│   │   │   ├── RECORD
│   │   │   ├── REQUESTED
│   │   │   ├── WHEEL
│   │   │   └── licenses
│   │   │   └── LICENSE
│   │   ├── base_library.zip
│   │   ├── certifi
│   │   │   ├── cacert.pem
│   │   │   └── py.typed
│   │   ├── charset_normalizer -> ../Frameworks/charset_normalizer
│   │   ├── frozenlist -> ../Frameworks/frozenlist
│   │   ├── libXau.6.dylib -> PIL/.dylibs/libXau.6.dylib
│   │   ├── libavif.16.4.1.dylib -> PIL/.dylibs/libavif.16.4.1.dylib
│   │   ├── libbrotlicommon.1.2.0.dylib -> PIL/.dylibs/libbrotlicommon.1.2.0.dylib
│   │   ├── libbrotlidec.1.2.0.dylib -> PIL/.dylibs/libbrotlidec.1.2.0.dylib
│   │   ├── libfreetype.6.dylib -> PIL/.dylibs/libfreetype.6.dylib
│   │   ├── libharfbuzz.0.dylib -> PIL/.dylibs/libharfbuzz.0.dylib
│   │   ├── libjpeg.62.4.0.dylib -> PIL/.dylibs/libjpeg.62.4.0.dylib
│   │   ├── liblcms2.2.dylib -> PIL/.dylibs/liblcms2.2.dylib
│   │   ├── liblzma.5.dylib -> PIL/.dylibs/liblzma.5.dylib
│   │   ├── libopenjp2.2.5.4.dylib -> PIL/.dylibs/libopenjp2.2.5.4.dylib
│   │   ├── libpng16.16.dylib -> PIL/.dylibs/libpng16.16.dylib
│   │   ├── libpython3.13.dylib -> ../Frameworks/libpython3.13.dylib
│   │   ├── libsharpyuv.0.dylib -> PIL/.dylibs/libsharpyuv.0.dylib
│   │   ├── libtiff.6.dylib -> PIL/.dylibs/libtiff.6.dylib
│   │   ├── libwebp.7.dylib -> PIL/.dylibs/libwebp.7.dylib
│   │   ├── libwebpdemux.2.dylib -> PIL/.dylibs/libwebpdemux.2.dylib
│   │   ├── libwebpmux.3.dylib -> PIL/.dylibs/libwebpmux.3.dylib
│   │   ├── libxcb.1.1.0.dylib -> PIL/.dylibs/libxcb.1.1.0.dylib
│   │   ├── libz.1.3.1.zlib-ng.dylib -> PIL/.dylibs/libz.1.3.1.zlib-ng.dylib
│   │   ├── lxml
│   │   │   ├── _elementpath.cpython-313-darwin.so -> ../../Frameworks/lxml/_elementpath.cpython-313-darwin.so
│   │   │   ├── builder.cpython-313-darwin.so -> ../../Frameworks/lxml/builder.cpython-313-darwin.so
│   │   │   ├── etree.cpython-313-darwin.so -> ../../Frameworks/lxml/etree.cpython-313-darwin.so
│   │   │   ├── html -> ../../Frameworks/lxml/html
│   │   │   ├── isoschematron
│   │   │   │   └── resources
│   │   │   │   ├── rng
│   │   │   │   │   └── iso-schematron.rng
│   │   │   │   └── xsl
│   │   │   │   ├── RNG2Schtrn.xsl
│   │   │   │   ├── XSD2Schtrn.xsl
│   │   │   │   └── iso-schematron-xslt1
│   │   │   │   ├── iso_abstract_expand.xsl
│   │   │   │   ├── iso_dsdl_include.xsl
│   │   │   │   ├── iso_schematron_message.xsl
│   │   │   │   ├── iso_schematron_skeleton_for_xslt1.xsl
│   │   │   │   ├── iso_svrl_for_xslt1.xsl
│   │   │   │   └── readme.txt
│   │   │   ├── objectify.cpython-313-darwin.so -> ../../Frameworks/lxml/objectify.cpython-313-darwin.so
│   │   │   └── sax.cpython-313-darwin.so -> ../../Frameworks/lxml/sax.cpython-313-darwin.so
│   │   ├── multidict -> ../Frameworks/multidict
│   │   ├── numpy -> ../Frameworks/numpy
│   │   ├── numpy-2.4.6.dist-info
│   │   │   ├── INSTALLER
│   │   │   ├── METADATA
│   │   │   ├── RECORD
│   │   │   ├── REQUESTED
│   │   │   ├── WHEEL
│   │   │   ├── entry_points.txt
│   │   │   └── licenses
│   │   │   ├── LICENSE.txt
│   │   │   └── numpy
│   │   │   ├── _core
│   │   │   │   ├── include
│   │   │   │   │   └── numpy
│   │   │   │   │   └── libdivide
│   │   │   │   │   └── LICENSE.txt
│   │   │   │   └── src
│   │   │   │   ├── common
│   │   │   │   │   └── pythoncapi-compat
│   │   │   │   │   └── COPYING
│   │   │   │   ├── highway
│   │   │   │   │   └── LICENSE
│   │   │   │   ├── multiarray
│   │   │   │   │   └── dragon4_LICENSE.txt
│   │   │   │   ├── npysort
│   │   │   │   │   └── x86-simd-sort
│   │   │   │   │   └── LICENSE.md
│   │   │   │   └── umath
│   │   │   │   └── svml
│   │   │   │   └── LICENSE
│   │   │   ├── fft
│   │   │   │   └── pocketfft
│   │   │   │   └── LICENSE.md
│   │   │   ├── linalg
│   │   │   │   └── lapack_lite
│   │   │   │   └── LICENSE.txt
│   │   │   ├── ma
│   │   │   │   └── LICENSE
│   │   │   └── random
│   │   │   ├── LICENSE.md
│   │   │   └── src
│   │   │   ├── distributions
│   │   │   │   └── LICENSE.md
│   │   │   ├── mt19937
│   │   │   │   └── LICENSE.md
│   │   │   ├── pcg64
│   │   │   │   └── LICENSE.md
│   │   │   ├── philox
│   │   │   │   └── LICENSE.md
│   │   │   ├── sfc64
│   │   │   │   └── LICENSE.md
│   │   │   └── splitmix64
│   │   │   └── LICENSE.md
│   │   ├── propcache -> ../Frameworks/propcache
│   │   ├── psutil -> ../Frameworks/psutil
│   │   ├── pydantic-2.13.4.dist-info
│   │   │   ├── INSTALLER
│   │   │   ├── METADATA
│   │   │   ├── RECORD
│   │   │   ├── REQUESTED
│   │   │   ├── WHEEL
│   │   │   └── licenses
│   │   │   └── LICENSE
│   │   ├── pydantic_core -> ../Frameworks/pydantic_core
│   │   ├── setuptools
│   │   │   └── _vendor
│   │   │   ├── importlib_metadata-8.7.1.dist-info
│   │   │   │   ├── INSTALLER
│   │   │   │   ├── METADATA
│   │   │   │   ├── RECORD
│   │   │   │   ├── REQUESTED
│   │   │   │   ├── WHEEL
│   │   │   │   ├── licenses
│   │   │   │   │   └── LICENSE
│   │   │   │   └── top_level.txt
│   │   │   └── jaraco
│   │   │   └── text
│   │   │   └── Lorem ipsum.txt
│   │   ├── yaml -> ../Frameworks/yaml
│   │   └── yarl -> ../Frameworks/yarl
│   └── _CodeSignature
│   └── CodeResources
├── doc
│   ├── Notes.md
│   ├── Notes.pdf
│   └── images
│   ├── image-01.png
│   ├── image-02.png
│   └── image-03.png
├── docling_output.md
├── exported_phases.csv
├── main.py
├── main.spec
├── media
├── migrate_database.py
├── pyproject.toml
├── requirements.txt
├── spanish_alphabetical.txt
├── spanish_glossary_sorted.txt
├── spanish_glossary_sorted.xlsx
├── spanish_glossary_sorted_B.pdf
├── spanish_glossary_sorted_B.txt
├── spanish_glossary_sorted_B.xlsx
├── spanish_trainer-26-08-21.db
├── spanish_trainer-backup.db
├── spanish_trainer.db
├── spanish_trainer_backup.sql
├── spanish_trainer_legacy.db
├── tabs
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-313.pyc
│   │   ├── review_tab.cpython-313.pyc
│   │   ├── sandbox_tab.cpython-313.pyc
│   │   └── settings_tab.cpython-313.pyc
│   ├── review_tab.py
│   ├── sandbox_tab.py
│   └── settings_tab.py
├── test_dual.py
├── test_tts.py
├── tree.txt
├── tts_utils.py
├── ui
│   ├── __init__.py
│   ├── cli
│   │   └── interface.py
│   └── gui
│   ├── create_mode.py
│   ├── interface.py
│   └── trainer_mode.py
├── uv.lock
└── video_generator.py
289 directories, 690 files

69
tree2.txt Normal file
View file

@ -0,0 +1,69 @@
.
├── LICENSE
├── README.md
├── README.pdf
├── Santiago_cathedral_2021_Sunset.jpg
├── anki_exporter.py
├── app.icns
├── app_icon.iconset
│   ├── icon_128x128.png
│   ├── icon_128x128@2x.png
│   ├── icon_16x16.png
│   ├── icon_16x16@2x.png
│   ├── icon_256x256.png
│   ├── icon_256x256@2x.png
│   ├── icon_32x32.png
│   ├── icon_32x32@2x.png
│   ├── icon_512x512.png
│   └── icon_512x512@2x.png
├── aula_int_plus_1_glos_en_alfa.pdf
├── base_icon.png
├── core
│   ├── __init__.py
│   ├── asset_generator.py
│   ├── audio_engine.py
│   ├── bulk_importer.py
│   ├── clean_glossary.py
│   └── phrase_manager.py
├── database.py
├── doc
│   ├── Notes.md
│   ├── Notes.pdf
│   └── images
├── docling_output.md
├── exported_phases.csv
├── main.py
├── main.spec
├── media
├── migrate_database.py
├── pyproject.toml
├── requirements.txt
├── spanish_alphabetical.txt
├── spanish_glossary_sorted.txt
├── spanish_glossary_sorted.xlsx
├── spanish_glossary_sorted_B.pdf
├── spanish_glossary_sorted_B.txt
├── spanish_glossary_sorted_B.xlsx
├── spanish_trainer-26-08-21.db
├── spanish_trainer-backup.db
├── spanish_trainer.db
├── spanish_trainer_backup.sql
├── spanish_trainer_legacy.db
├── tabs
│   ├── __init__.py
│   ├── review_tab.py
│   ├── sandbox_tab.py
│   └── settings_tab.py
├── test_dual.py
├── test_tts.py
├── tree.txt
├── tree2.txt
├── tts_utils.py
├── ui
│   ├── __init__.py
│   ├── cli
│   └── gui
├── uv.lock
└── video_generator.py
10 directories, 57 files

81
uv.lock
View file

@ -24,6 +24,7 @@ dependencies = [
{ name = "librosa" }, { name = "librosa" },
{ name = "numpy" }, { name = "numpy" },
{ name = "pillow" }, { name = "pillow" },
{ name = "pyinstaller" },
{ name = "pyqt6" }, { name = "pyqt6" },
{ name = "scipy" }, { name = "scipy" },
{ name = "sounddevice" }, { name = "sounddevice" },
@ -38,6 +39,7 @@ requires-dist = [
{ name = "librosa", specifier = ">=0.11.0" }, { name = "librosa", specifier = ">=0.11.0" },
{ name = "numpy", specifier = ">=2.4.6" }, { name = "numpy", specifier = ">=2.4.6" },
{ name = "pillow", specifier = ">=12.2.0" }, { name = "pillow", specifier = ">=12.2.0" },
{ name = "pyinstaller", specifier = ">=6.21.0" },
{ name = "pyqt6", specifier = ">=6.11.0" }, { name = "pyqt6", specifier = ">=6.11.0" },
{ name = "scipy", specifier = ">=1.17.1" }, { name = "scipy", specifier = ">=1.17.1" },
{ name = "sounddevice", specifier = ">=0.5.5" }, { name = "sounddevice", specifier = ">=0.5.5" },
@ -163,6 +165,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
] ]
[[package]]
name = "altgraph"
version = "0.17.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7e/f8/97fdf103f38fed6792a1601dbc16cc8aac56e7459a9fff08c812d8ae177a/altgraph-0.17.5.tar.gz", hash = "sha256:c87b395dd12fabde9c99573a9749d67da8d29ef9de0125c7f536699b4a9bc9e7", size = 48428, upload-time = "2025-11-21T20:35:50.583Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl", hash = "sha256:f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597", size = 21228, upload-time = "2025-11-21T20:35:49.444Z" },
]
[[package]] [[package]]
name = "annotated-doc" name = "annotated-doc"
version = "0.0.4" version = "0.0.4"
@ -1152,6 +1163,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/2c/0f1e93c636720e8a3eb59af2bfda99d98b55891e1c53bc30c2e0e865f01b/lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c", size = 3817223, upload-time = "2026-05-19T19:22:56.823Z" }, { url = "https://files.pythonhosted.org/packages/7f/2c/0f1e93c636720e8a3eb59af2bfda99d98b55891e1c53bc30c2e0e865f01b/lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c", size = 3817223, upload-time = "2026-05-19T19:22:56.823Z" },
] ]
[[package]]
name = "macholib"
version = "1.16.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "altgraph", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362", size = 59427, upload-time = "2025-11-22T08:28:38.373Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl", hash = "sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea", size = 38117, upload-time = "2025-11-22T08:28:36.939Z" },
]
[[package]] [[package]]
name = "mail-parser" name = "mail-parser"
version = "4.4.0" version = "4.4.0"
@ -1744,6 +1767,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0f/54/68a0978d1ef8502b8492099beaa6e7a0c1b32e3b5d4f677f5810cb08711c/pandas-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b2c95f8bfc1ee412bf482605d7bfd30c12d1d26bd59fdd91efeef1d4718decb1", size = 9466464, upload-time = "2026-05-11T18:54:22.754Z" }, { url = "https://files.pythonhosted.org/packages/0f/54/68a0978d1ef8502b8492099beaa6e7a0c1b32e3b5d4f677f5810cb08711c/pandas-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b2c95f8bfc1ee412bf482605d7bfd30c12d1d26bd59fdd91efeef1d4718decb1", size = 9466464, upload-time = "2026-05-11T18:54:22.754Z" },
] ]
[[package]]
name = "pefile"
version = "2024.8.26"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/03/4f/2750f7f6f025a1507cd3b7218691671eecfd0bbebebe8b39aa0fe1d360b8/pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632", size = 76008, upload-time = "2024-08-26T20:58:38.155Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766, upload-time = "2024-08-26T21:01:02.632Z" },
]
[[package]] [[package]]
name = "pillow" name = "pillow"
version = "12.2.0" version = "12.2.0"
@ -2079,6 +2111,46 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
] ]
[[package]]
name = "pyinstaller"
version = "6.21.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "altgraph" },
{ name = "macholib", marker = "sys_platform == 'darwin'" },
{ name = "packaging" },
{ name = "pefile", marker = "sys_platform == 'win32'" },
{ name = "pyinstaller-hooks-contrib" },
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
{ name = "setuptools" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d5/4d/ec706c3fcf39e26888c35b39615ff4d5865d184069666c47492cff1fbe50/pyinstaller-6.21.0.tar.gz", hash = "sha256:bb9fab705983e393a2d1cac77d6972513057ad800215fd861dc15ff5272e98fd", size = 4061519, upload-time = "2026-06-13T14:15:06.25Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/4a/53cf98bf66daed012dc9cd78c8203f19a675d696f2fc12afcf8c5049a0e0/pyinstaller-6.21.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:327d132389f37912609e01be62810cf96b5aa95b613903e4b8692e0d12fb0eda", size = 1052350, upload-time = "2026-06-13T14:13:55.88Z" },
{ url = "https://files.pythonhosted.org/packages/30/83/b591295c352ef464c50b4c6ffff1c4f771d875c9e833f578d1b9f564f6b3/pyinstaller-6.21.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7071d4b094d5b40deeef5fa3d3b98a1b846087f7562b49209663d5f9281fe251", size = 748477, upload-time = "2026-06-13T14:14:00.327Z" },
{ url = "https://files.pythonhosted.org/packages/3d/8f/88fff4e403873b1e22286911350e75ff00db014aa08e57045da9d4328993/pyinstaller-6.21.0-py3-none-manylinux2014_i686.whl", hash = "sha256:6b6374d652107dd4a2eeece903ff82bb4045bb5e1006c5a158a6dcdbefe84bf2", size = 760877, upload-time = "2026-06-13T14:14:04.836Z" },
{ url = "https://files.pythonhosted.org/packages/8a/13/f0e48fbdfd1d05d948157121cea8b1b823dcb89efe6934b71fdd8bdb3f0f/pyinstaller-6.21.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:4e3108b3f02384560da70e39b8bf22b0ad597d02bd68a40d76ea91c1cfa00cad", size = 759194, upload-time = "2026-06-13T14:14:10.61Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d5/ea7878cf9924ed30d946d8288777424e6d069d94f5bde56b4d0890069664/pyinstaller-6.21.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:697532279f535ad572bda613db4f821540e235c7854ca6da4d3bf0373f4415ee", size = 754979, upload-time = "2026-06-13T14:14:15.226Z" },
{ url = "https://files.pythonhosted.org/packages/9f/09/51b8905714b733bac66dbc041a7821372d70d888d273ae474c4037d4202d/pyinstaller-6.21.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:605169523a6b5ace39f13dfbff21add9f2bc43df99c7daf9394fefb2c45e8b6f", size = 754812, upload-time = "2026-06-13T14:14:20.264Z" },
{ url = "https://files.pythonhosted.org/packages/4b/43/d77779439d8c6c2e27a77bcfbd1d5cc0f568ebb611bb472b11af81b5f177/pyinstaller-6.21.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5fa56746c1e76f93634d018502301378a2d0c382553d37d8c3c34ff436c12dd1", size = 753887, upload-time = "2026-06-13T14:14:25.268Z" },
{ url = "https://files.pythonhosted.org/packages/51/8f/c22df1f6837784ac349057ba693f08e7b1ca7a0e06f9c33c63bc6280007b/pyinstaller-6.21.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:42395ec76df8e8120c36b13339d9db8cab83e316a12839ee303cc00fc941bb74", size = 753779, upload-time = "2026-06-13T14:14:29.445Z" },
{ url = "https://files.pythonhosted.org/packages/c9/76/1ce8a27ce62ba8cf3a87c9ce6d575610f4e55d7cb0123e7512fc3f4b921a/pyinstaller-6.21.0-py3-none-win32.whl", hash = "sha256:c6b28d30d8fd99ce162ff3aab5013ed44dbfb747566b1f01b9bed7964d7c14e9", size = 1336462, upload-time = "2026-06-13T14:14:35.785Z" },
{ url = "https://files.pythonhosted.org/packages/c1/fa/ca1d7e5257dd8566a9dfc0dfb02f8a8075eeb53d4b2d3c579f1276759042/pyinstaller-6.21.0-py3-none-win_amd64.whl", hash = "sha256:7fae06c494ce0ebfe6bd3055c0e409def884f63af2e3705d06bd431ad9237fc7", size = 1397487, upload-time = "2026-06-13T14:14:42.328Z" },
{ url = "https://files.pythonhosted.org/packages/dc/75/21b51523ce8d96629b71311775a0a65f5f5a872124ab0de33e5c848f8bff/pyinstaller-6.21.0-py3-none-win_arm64.whl", hash = "sha256:f13c95c9c03fb567217135919f93815c305813126780b0ed6e0123cb8acaf025", size = 1346094, upload-time = "2026-06-13T14:14:48.914Z" },
]
[[package]]
name = "pyinstaller-hooks-contrib"
version = "2026.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/94/5b/c9fe0db5e83ee1c39b2258fa21d23b15e1a60786b6c5990ee5074ead8bb6/pyinstaller_hooks_contrib-2026.6.tar.gz", hash = "sha256:bef5002c32f4f50bd55b005da12cff64eca8783e7eaf86a06a62410164bab725", size = 173354, upload-time = "2026-06-08T22:37:16.152Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/31/f2d7343d8ed5f7c4678377886f6ce533e6eaaa131b252ce950114c2a7efa/pyinstaller_hooks_contrib-2026.6-py3-none-any.whl", hash = "sha256:fd13b8ac126b35361175edacd41a0d97080b75dd5f4b594ecefefff969509dd3", size = 457159, upload-time = "2026-06-08T22:37:14.722Z" },
]
[[package]] [[package]]
name = "pylatexenc" name = "pylatexenc"
version = "2.10" version = "2.10"
@ -2227,6 +2299,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/23/ed/4532e9388e65fa16b46776ef47ad631a64eda1631884488af707666350ed/pywin32-312-cp315-cp315-win_arm64.whl", hash = "sha256:a8597d28f267b39074aef51fa593530082b39cbe5a074226096857b1fed2dfb9", size = 6840337, upload-time = "2026-06-04T07:49:57.531Z" }, { url = "https://files.pythonhosted.org/packages/23/ed/4532e9388e65fa16b46776ef47ad631a64eda1631884488af707666350ed/pywin32-312-cp315-cp315-win_arm64.whl", hash = "sha256:a8597d28f267b39074aef51fa593530082b39cbe5a074226096857b1fed2dfb9", size = 6840337, upload-time = "2026-06-04T07:49:57.531Z" },
] ]
[[package]]
name = "pywin32-ctypes"
version = "0.2.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.3" version = "6.0.3"