Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a040396
Improve contrast for small text in textgrid viewer (#139)
BeckettFrey May 19, 2026
fa339d8
Refactor: hoist dataset data-path helper to storage.datasets (#140)
BeckettFrey May 19, 2026
58afe37
Optimize workflows for speedup (#138)
BeckettFrey May 19, 2026
1c1dea8
Centralize app version in config/VERSION and update documentation (#141)
BeckettFrey May 19, 2026
cb4af8e
Init shared constants procedure (#142)
BeckettFrey May 21, 2026
fb5553e
Let users set a custom conda path for MFA (Windows) (#149)
BeckettFrey Jun 30, 2026
3c2695f
Out-of-box setup usability fixes (#152)
nrgslp Jul 27, 2026
298a0e8
feat: bake MFA/conda setup into the app via bundled micromamba (#151)
nrgslp Jul 28, 2026
ed75a01
Timeline viewer, Compare Alignments inspector, and Correct Alignments…
nrgslp Jul 28, 2026
f2df243
Brand the first-launch splash screen and clarify setup messaging (#154)
BeckettFrey Jul 29, 2026
615ea4e
Show actionable message when no model is selected for alignment (#156)
BeckettFrey Jul 29, 2026
b435d99
Add clearer tooltips to the Register New Dataset page (#155)
BeckettFrey Jul 29, 2026
c7c6b66
Remove shoutout footer from dataset and model pages (#159)
BeckettFrey Jul 29, 2026
b421c53
Add toolbar Feedback action with prefilled email compose template (#158)
Copilot Jul 29, 2026
e613337
Require confirmation before dataset deletion in DatasetsPage (#157)
Copilot Jul 29, 2026
729367b
Readme planning badges (#160)
BeckettFrey Jul 29, 2026
a86a82b
Prevent overlapping fiels by bumping height
BeckettFrey Jul 30, 2026
78ddb04
Fix alignments table writing Status and Actions into wrong columns
BeckettFrey Jul 30, 2026
a8bd980
Ship the MSVC runtime beside vendored micromamba
BeckettFrey Jul 30, 2026
ba87395
Enable the Postgres backend and stop capturing mfa server output
BeckettFrey Jul 30, 2026
a6fac8d
Retry MFA provisioning on every launch until it succeeds
BeckettFrey Jul 30, 2026
0dd3981
Document MFA runtime state gotchas on Windows in AGENTS.md
BeckettFrey Jul 30, 2026
de224ae
Bump version to 0.5.0
BeckettFrey Jul 30, 2026
45baa05
Merge pull request #161 from BrainBehaviorAnalyticsLab/fix/windows-mf…
BeckettFrey Jul 30, 2026
3f61c69
Link BUILD appendix entry to docs/BUILD.md
BeckettFrey Jul 30, 2026
6267567
MVP polish: W2TG default, tier order, Train Aligners gating, app bran…
nrgslp Aug 11, 2026
89145ec
Merge branch 'develop' into feature/mvp-final-polish
BeckettFrey Aug 19, 2026
2ec15d5
Drop Train Aligners gating from this branch
BeckettFrey Aug 19, 2026
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
Binary file added assets/vk.ico
Binary file not shown.
Binary file added assets/vk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@

log.info("[FROZEN] Environment configured for frozen app")

from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QApplication
from voxkit.config import STARTUP_SCRIPT
from voxkit.config.app_config import get_app_icon_path
from voxkit.gui import VoxKitGUI
from voxkit.gui.workers.startup import execute_mfa_provisioning, execute_startup_script

Expand All @@ -135,6 +137,7 @@ def main():

app = QApplication(sys.argv)
app.setStyle("Fusion")
app.setWindowIcon(QIcon(str(get_app_icon_path())))

# Execute startup script on first launch (before GUI initialization)
log.info("Running startup script")
Expand Down
14 changes: 11 additions & 3 deletions scripts/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ def build(args):
# This is important because PyInstaller resolves paths relative to CWD
project_root = Path(__file__).parent.parent
original_cwd = Path.cwd()

if original_cwd != project_root:
print(f"[INFO] Changing working directory to project root: {project_root}")
os.chdir(project_root)

opts = []

# Basic options
Expand Down Expand Up @@ -184,6 +184,14 @@ def build(args):
print("[INFO] Adding vendor folder to build assets")
opts.append(f'--add-data={vendor_dir}{sep}vendor')

# Add assets folder if it exists (branding images used for the in-app
# window icon and first-launch splash logo, resolved at runtime via
# voxkit.config.app_config.get_assets_root())
assets_dir = project_root / "assets"
if assets_dir.exists() and assets_dir.is_dir():
print("[INFO] Adding assets folder to build assets")
opts.append(f'--add-data={assets_dir}{sep}assets')

for ad in args.add_data:
if sep in ad:
opts.append(f'--add-data={ad}')
Expand Down Expand Up @@ -217,7 +225,7 @@ def build(args):
print(f" Run with: ./dist/{args.name}/{args.name}")
else:
print(f"\n⚠️ Expected build output not found at {app_path}")

# Restore original working directory
if original_cwd != project_root:
os.chdir(original_cwd)
Expand Down
30 changes: 30 additions & 0 deletions src/voxkit/config/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,36 @@ def get_config_root() -> Path:
return Path(__file__).parent.parent.parent.parent / "config"


def get_assets_root() -> Path:
"""Get the path to the assets root directory.

Returns the correct assets path whether running from source or as a
PyInstaller bundle.

Returns:
Path to the assets directory
"""
if getattr(sys, "_MEIPASS", None):
return Path(getattr(sys, "_MEIPASS")) / "assets"
else:
return Path(__file__).parent.parent.parent.parent / "assets"


def get_app_icon_path() -> Path:
"""Get the best available runtime icon file for QIcon/QPixmap use.

Prefers the Windows .ico (multi-resolution, sharper in the taskbar/title
bar) when on Windows, falling back to the PNG everywhere else.

Returns:
Path to the icon file
"""
root = get_assets_root()
if sys.platform == "win32" and (root / "vk.ico").exists():
return root / "vk.ico"
return root / "vk.png"


def get_active_profile() -> str:
"""Get the active configuration profile name.

Expand Down
2 changes: 1 addition & 1 deletion src/voxkit/engines/w2tg_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
name="use_speaker_adaptation",
label="Use Speaker Adaptation",
field_type=FieldType.CHECKBOX,
default_value=False,
default_value=True,
tooltip="Enable speaker adaptation for better alignment results.",
),
FieldConfig(
Expand Down
3 changes: 3 additions & 0 deletions src/voxkit/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,10 @@ def open_feedback(self):
webbrowser.open(mailto_url)

def init_ui(self):
from voxkit.config.app_config import get_app_icon_path

self.setWindowTitle(self.app_config.app_name)
self.setWindowIcon(QIcon(str(get_app_icon_path())))
self.setMinimumSize(1200, 800)

# Set application-wide stylesheet
Expand Down
14 changes: 12 additions & 2 deletions src/voxkit/gui/components/loading_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
QWidget,
)

from voxkit.gui.styles import Colors
from voxkit.gui.styles import Colors, Labels


class _WaveformStrip(QWidget):
Expand Down Expand Up @@ -193,6 +193,16 @@ def init_ui(self, message: str, title: str, subtitle: str | None):
self.subtitle_label.setVisible(bool(subtitle))
layout.addWidget(self.subtitle_label)

# Fine-print institutional credit
credit_label = QLabel(
"VoxKit is brought to you by the University of Wisconsin-Madison "
"and Arizona State University"
)
credit_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
credit_label.setWordWrap(True)
credit_label.setStyleSheet(Labels.CREDIT)
layout.addWidget(credit_label)

# Card background: subtle vertical gradient (light tints of the app's
# primary blue) with a primary-blue rounded border. Painted on the child
# frame (not the translucent window) so it renders reliably.
Expand All @@ -210,7 +220,7 @@ def init_ui(self, message: str, title: str, subtitle: str | None):
"""
)

self.setFixedSize(420, 260)
self.setFixedSize(420, 290)

def center_on_screen(self):
"""Center the dialog on the primary screen."""
Expand Down
8 changes: 6 additions & 2 deletions src/voxkit/gui/pages/pipeline/viewer_stacker.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def __init__(self, parent: QWidget | None = None) -> None:
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
self.setFixedHeight(self.RULER_HEIGHT)

_TIER_ORDER = {"phones": 0, "words": 1}
_TIER_ORDER = {"words": 0, "phones": 1}

def set_data(self, tiers: list[dict], duration: float) -> None:
self._tiers = sorted(
Expand Down Expand Up @@ -1839,7 +1839,11 @@ def _on_position_changed(self, position_ms: int):
def _update_active_segment_label(self, secs: float) -> None:
if self._active_label and self._active_label.isVisible() and self._loaded_tiers:
parts = []
for tier in self._loaded_tiers:
ordered_tiers = sorted(
self._loaded_tiers,
key=lambda t: TextGridTimeline._TIER_ORDER.get(t["name"].lower(), 2),
)
for tier in ordered_tiers:
if tier["class"] == "IntervalTier":
for iv in tier["intervals"]:
if iv["start"] <= secs < iv["end"] and iv["label"] not in _SILENCE_LABELS:
Expand Down
Loading