Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions _frozen_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
if getattr(sys, "frozen", False):
# We're running in a PyInstaller bundle
print("[PATCH] Applying frozen app patches...")

# Patch 1: Disable typeguard runtime checking
try:
import typeguard

# Replace typechecked decorator with a no-op
def _noop_decorator(func=None, **kwargs):
"""No-op decorator that just returns the function unchanged"""
Expand All @@ -20,12 +20,12 @@ def _noop_decorator(func=None, **kwargs):
return lambda f: f
# Called without arguments: @typechecked
return func
typeguard.typechecked = _noop_decorator

typeguard.typechecked = _noop_decorator # type: ignore[assignment]
print("[PATCH] Disabled typeguard runtime checking")
except ImportError:
pass

# Patch 2: Fix inspect.getsource to not fail in frozen apps
import inspect

Expand Down Expand Up @@ -70,7 +70,7 @@ def _patched_getsourcefile(object):
try:
result = _original_getsourcefile(object)
# Check if the file actually exists
if result and not __import__('os').path.exists(result):
if result and not __import__("os").path.exists(result):
return None
return result
except (OSError, TypeError):
Expand Down
4 changes: 2 additions & 2 deletions hooks/hook-nltk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

# Don't collect any NLTK data files - they will be downloaded at runtime
datas = []
datas: list[tuple[str, str, str]] = []

# Exclude data collection
excludedimports = []
excludedimports: list[str] = []
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dev = [
"pre-commit>=4.3.0",
"ruff>=0.14.0",
"mypy>=1.18.2",
"types-PyYAML>=6.0.0",
"genbadge[coverage]>=1.1.3",
]
docs = [
Expand Down Expand Up @@ -109,11 +110,15 @@ indent-style = "space"
[tool.mypy]
python_version = "3.11"
ignore_missing_imports = true
check_untyped_defs = false
warn_return_any = true
warn_unused_configs = true
exclude = [
"main.py",
"build.py",
"example_startup_script.py",
"test_imports.py"
"test_imports.py",
"tests/"
]


Expand Down
3 changes: 3 additions & 0 deletions src/voxkit/analyzers/default_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ def paintEvent(self, event):

color = QColor("#3498db")
h, s, lightness, a = color.getHsl()
assert (
h is not None and s is not None and lightness is not None and a is not None
)
ratio = count / max_count
new_l = int(lightness + (220 - lightness) * (1 - ratio))
color.setHsl(h, s, min(new_l, 240), a)
Expand Down
5 changes: 2 additions & 3 deletions src/voxkit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from voxkit.services.mfa import download_acoustic_model
from voxkit.storage import models
from voxkit.storage.config import MODELS_ROOT
from voxkit.storage.models import download_and_copy_huggingface_model
from voxkit.storage.utils import get_storage_root

AppName = "VoxKit"
Expand Down Expand Up @@ -94,10 +93,10 @@ def startup_routine():
# else:
# print("[STARTUP] Failed to download W2TG model.")


try:
import nltk
nltk.download('averaged_perceptron_tagger_eng')

nltk.download("averaged_perceptron_tagger_eng")

except Exception as e:
print(f"[STARTUP] Failed to download NLTK resources. Error: {e}")
Expand Down
6 changes: 4 additions & 2 deletions src/voxkit/config/startup_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def startup_routine():
if not success:
print(f"[STARTUP] Failed to create model metadata for {model}. {metadata}")
continue
assert not isinstance(metadata, str)
model_dest = metadata.get("model_path")
if not model_dest:
print(f"[STARTUP] Model path not found in metadata for {model}.")
Expand Down Expand Up @@ -81,6 +82,7 @@ def startup_routine():
if not success:
print(f"[STARTUP] Failed to create model metadata. {metadata}")
return
assert not isinstance(metadata, str)
model_dest = metadata.get("model_path")
if not model_dest:
print("[STARTUP] Model path not found in metadata.")
Expand All @@ -94,10 +96,10 @@ def startup_routine():
else:
print("[STARTUP] Failed to download W2TG model.")


try:
import nltk
nltk.download('averaged_perceptron_tagger_eng')

nltk.download("averaged_perceptron_tagger_eng")

except Exception as e:
print(f"[STARTUP] Failed to download NLTK resources. Error: {e}")
Expand Down
2 changes: 1 addition & 1 deletion src/voxkit/engines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def get_tool_providers(self, tool: ToolType) -> dict[str, AlignmentEngine]:
w2tg = W2TGEngine(id="W2TGENGINE")
mfa = MFAEngine(id="MFAENGINE")
faster_whisper = FasterWhisperEngine(id="FASTERWHISPERENGINE")
engines = EngineManager({ mfa.id: mfa, faster_whisper.id: faster_whisper, w2tg.id: w2tg })
engines = EngineManager({mfa.id: mfa, faster_whisper.id: faster_whisper, w2tg.id: w2tg})

__all__ = [
"engines",
Expand Down
3 changes: 2 additions & 1 deletion src/voxkit/engines/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ def _load_json(self, path: Path | str) -> dict:
return {}

with open(path, "r", encoding="utf-8") as f:
return json.load(f)
result: dict = json.load(f)
return result

def _get_default_settings(self, cfg: Any) -> dict:
"""
Expand Down
28 changes: 18 additions & 10 deletions src/voxkit/engines/mfa_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,16 @@ def __init__(self, id: str | None = None):
id=id,
)


def align(self, dataset_id: str, model_id: str) -> None:
print(f"Aligning with MFA using model: {model_id}")

model_metadata = models.get_model_metadata(self.id, model_id)

dataset_metadata = datasets.get_dataset_metadata(dataset_id)
if dataset_metadata is None:
raise ValueError(f"Dataset '{dataset_id}' not found.")

corpus_path = None
corpus_path: Path | None = None

if bool(dataset_metadata["cached"]):
corpus_path = datasets._get_dataset_root(dataset_id)
Expand All @@ -130,6 +131,10 @@ def align(self, dataset_id: str, model_id: str) -> None:
dataset_id=dataset_id,
)

if not result:
raise ValueError(f"Alignment creation failed: {msg}")

assert not isinstance(msg, str)
alignment_output_path = msg["tg_path"]

print(
Expand Down Expand Up @@ -172,6 +177,11 @@ def train_aligner(
model_name=new_model_id,
)

if not success:
raise ValueError(f"Failed to create model entry: {msg}")

assert not isinstance(msg, str)

# ========= TEMP FIX FOR MFA MODEL EXTENSION ========
# MFA models use .model extension, so we need to adjust the model path accordingly
# This should ideally be handled in the storage/models.py create_model function
Expand All @@ -182,21 +192,22 @@ def train_aligner(
new_metadata = msg
new_model_path = new_metadata["model_path"]
if str(new_model_path).endswith(".model"):
new_model_path = str(new_model_path).split(".model")[0] + ".zip"
new_model_path = Path(str(new_model_path).split(".model")[0] + ".zip")
new_metadata["model_path"] = new_model_path
# ==================================================

# Save updated metadata with correct model path
model_metadata_path = Path(new_metadata["model_path"]).parent / "voxkit_model.json"

# Make metadata dict serializable
for key in new_metadata:
if isinstance(new_metadata[key], Path):
new_metadata[key] = str(new_metadata[key])
serializable: dict[str, object] = dict(new_metadata)
for key in serializable:
if isinstance(serializable[key], Path):
serializable[key] = str(serializable[key])
with open(model_metadata_path, "w") as f:
import json

json.dump(new_metadata, f, indent=4)
json.dump(serializable, f, indent=4)

# ==================================================

Expand All @@ -209,9 +220,6 @@ def train_aligner(

# ==================================================

if not success:
raise ValueError(f"Failed to create model entry: {msg}")

new_model_path = new_metadata["model_path"]

print(
Expand Down
9 changes: 6 additions & 3 deletions src/voxkit/engines/w2tg_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,11 @@ def align(self, dataset_id: str, model_id: str) -> None:
)
print(f"Alignment creation result: {result}, message: {msg}")

if result is False:
if not result:
print(f"Alignment creation failed: {msg}")
return

assert not isinstance(msg, str)
alignment_meta = msg
dataset_meta = datasets.get_dataset_metadata(dataset_id)
model_meta = models.get_model_metadata(self.id, model_id)
Expand Down Expand Up @@ -191,6 +192,7 @@ def train_aligner(
if not success:
raise ValueError(f"Failed to create model entry: {message}")

assert not isinstance(message, str)
model_meta = message
model_path = Path(model_meta["model_path"])
data_path = Path(model_meta["data_path"])
Expand Down Expand Up @@ -235,8 +237,9 @@ def train_aligner(
)
except Exception as e:
print(f"Training failed: {e}")
# CLean up model entry on failure
models.delete_model(engine_id=self.id, model_id=new_model_actual_id)
# Clean up model entry on failure
if new_model_actual_id is not None:
models.delete_model(engine_id=self.id, model_id=new_model_actual_id)
raise e

def _validate_align_settings(self, settings: dict) -> bool:
Expand Down
1 change: 1 addition & 0 deletions src/voxkit/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
}
"""


class AlignmentGUI(QMainWindow):
def __init__(
self,
Expand Down
19 changes: 14 additions & 5 deletions src/voxkit/gui/components/column_dropdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ def __init__(self, parent=None):
table_view = QTableView()
table_view.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows)
table_view.setSelectionMode(QTableView.SelectionMode.SingleSelection)
table_view.verticalHeader().hide()
table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
vertical_header = table_view.verticalHeader()
if vertical_header is not None:
vertical_header.hide()
horizontal_header = table_view.horizontalHeader()
if horizontal_header is not None:
horizontal_header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
table_view.setShowGrid(False)

self.setView(table_view)

# Optional: make the popup wider
self.view().setMinimumWidth(400)
view = self.view()
if view is not None:
view.setMinimumWidth(400)

def set_data(self, rows, headers=None, placeholder=None):
"""
Expand Down Expand Up @@ -71,12 +77,15 @@ def set_data(self, rows, headers=None, placeholder=None):

def current_id(self):
"""Get the ID of the currently selected row."""
index = self.model().index(self.currentIndex(), 0)
model = self.model()
if model is None:
return None
index = model.index(self.currentIndex(), 0)

if not index.isValid():
return None

return self.model().data(index, Qt.ItemDataRole.UserRole)
return model.data(index, Qt.ItemDataRole.UserRole)


if __name__ == "__main__":
Expand Down
23 changes: 13 additions & 10 deletions src/voxkit/gui/components/csv_viewer_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, csv_path: str, parent=None, visualization=None):
self.blur_effect.setBlurRadius(10)
parent.setGraphicsEffect(self.blur_effect)

self.parent = parent
self._parent_widget = parent
self._init_ui()
if not self.visualization:
self._load_csv()
Expand Down Expand Up @@ -119,12 +119,15 @@ def _load_csv(self):

# Auto-resize columns
header = self.table.horizontalHeader()
for i in range(len(headers)):
header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents)
if header is not None:
for i in range(len(headers)):
header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents)

# Make last column stretch
if len(headers) > 0:
header.setSectionResizeMode(len(headers) - 1, QHeaderView.ResizeMode.Stretch)
# Make last column stretch
if len(headers) > 0:
header.setSectionResizeMode(
len(headers) - 1, QHeaderView.ResizeMode.Stretch
)

# Update stats
self.stats_label.setText(f"✅ {len(data)} rows × {len(headers)} columns")
Expand All @@ -135,14 +138,14 @@ def _load_csv(self):
def closeEvent(self, event):
"""Handle dialog close event to remove blur effect."""
print("Dialog closed, removing blur effect from parent")
if self.parent:
if self._parent_widget:
print("Removing blur effect from parent")
self.parent.setGraphicsEffect(None)
self._parent_widget.setGraphicsEffect(None)
event.accept()

def reject(self):
"""Handle dialog rejection to remove blur effect."""
if self.parent:
if self._parent_widget:
print("Removing blur effect from parent")
self.parent.setGraphicsEffect(None)
self._parent_widget.setGraphicsEffect(None)
super().reject()
4 changes: 1 addition & 3 deletions src/voxkit/gui/components/grip_splitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ def paintEvent(self, event):
else:
x = center_x
y = center_y + (i * dot_spacing)
painter.drawEllipse(
x - dot_radius, y - dot_radius, dot_radius * 2, dot_radius * 2
)
painter.drawEllipse(x - dot_radius, y - dot_radius, dot_radius * 2, dot_radius * 2)

painter.end()

Expand Down
4 changes: 2 additions & 2 deletions src/voxkit/gui/components/huggingface_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QWidget
from voxkit.gui.styles import Labels, Buttons

from voxkit.gui.styles import Buttons, Labels


class HuggingFaceButton(QPushButton):
Expand Down Expand Up @@ -43,7 +44,6 @@ def _setup_ui(self, title):
self.setCursor(Qt.CursorShape.PointingHandCursor)



# Example usage
if __name__ == "__main__":
import sys
Expand Down
Loading
Loading