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
51 changes: 33 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Onboarding guide for coding agents working in this repository.

## Project

VoxKit is a PyQt6 desktop application for speech pathology researcha GUI front-end over multiple speech toolkits (alignment, training, transcription). Package lives at `src/voxkit/`. Python 3.11+, managed with `uv`.
VoxKit is a PyQt6 desktop application for speech pathology research; a GUI front-end over multiple speech toolkits (alignment, training, transcription) with a shared storage for interacting with and processing speech datasets. Package lives at `src/voxkit/`. Python 3.11+, managed with `uv`.

## Repository Layout

Expand All @@ -15,11 +15,18 @@ src/voxkit/
├── analyzers/ # Dataset metadata extractors (CSV summaries)
├── storage/ # Persistence/CRUD for datasets, models, alignments
├── services/ # External subprocess integrations
└── config/ # App configuration and startup
└── config/ # App configuration loaders (profile-aware)
config/
├── VERSION # Single source of truth for app version
├── profile.txt # Active profile name
├── app_info.yaml # Legacy fallback metadata
├── pipeline_definitions.yaml # Legacy fallback metadata
└── profiles/<name>/ # Per-profile yaml configurations
tests/ # Pytest suite (unit + GUI via pytest-qt)
docs/ # ARCHITECTURE.md, CONTRIBUTING.md, RESEARCH.md
hooks/ # Pre-commit hooks
scripts/ # Dev scripts
hooks/ # Build-time hooks to fix dependency problems in the build
scripts/ # Dev scripts (incl. build.py for PyInstaller)
installer/ # Platform installer scripts (Inno Setup for Windows)
main.py # Entry point
```

Expand All @@ -33,45 +40,53 @@ Hybrid "unstructured state + signals" PyQt pattern. See `docs/ARCHITECTURE.md` f
- **Async work runs in QThread workers** that emit `pyqtSignal` back to views.
- **Cross-page state** refreshes via parent window calling `reload()` on tab switch.
- **Engines** and **analyzers** each have an abstract base class and a singleton manager for discovery.
- **Config profiles**: `config/profile.txt` selects an active profile under `config/profiles/<name>/`. The loader is in (`src/voxkit/config/app_config.py`).

## Setup & Common Commands

Use `invoke` (pyinvoke, tasks defined in `tasks.py`) — do not invoke tools directly unless you need a flag the task doesn't expose.
> **IMPORTANT (read before touching anything):**
> 1. **Run `invoke setup` first, every fresh checkout.** It installs dependencies (`uv sync`), wires up pre-commit hooks, and prepares the local environment.
> 2. **Use `invoke` tasks for everything during development.** Do **not** reach for `pytest`, `ruff`, `mypy`, `pyinstaller`, or `uv run …` directly. The tasks in `tasks.py` set the right flags, paths, and env vars; bypassing them produces results that won't match CI or other contributors. Only call a tool directly if you genuinely need a flag the task doesn't expose, and prefer adding the flag to the task over a one-off workaround.

Tasks are defined in `tasks.py` (pyinvoke).

| Command | Purpose |
|---|---|
| `invoke setup` | Install deps + pre-commit hooks (run first) |
| `invoke dev` | Launch the app in dev mode |
| `invoke watch` | Dev mode with auto-reload on source changes |
| `invoke run-tests` | Unit + GUI tests |
| `invoke test-coverage` | Coverage for core modules |
| `invoke generate-coverage-badge` | Refresh `coverage.svg` |
| `invoke generate-documentation` | Build pdoc HTML into `docs/` |
| `invoke lint` / `invoke lint-check` | Ruff lint (fix / check) |
| `invoke format` / `invoke format-check` | Ruff format |
| `invoke mypy-check` | Type check |
| `invoke build` | Standalone executable (PyInstaller) |
| `invoke macos-build` / `linux-build` / `windows-build` | Standalone executable (PyInstaller) |
| `invoke clean` | Remove build artifacts |
| `invoke fresh-slate` | Remove virtual environment and lock file (Dependency troubleshooting) |
| `invoke --list` | Full list |

## Code Standards
## Versioning

`config/VERSION` is the single source of truth. All consumers read it:

- `pyproject.toml` via `[tool.setuptools.dynamic] version = {file = ["config/VERSION"]}`
- `src/voxkit/__init__.py` (`__version__` read at import, handles PyInstaller `_MEIPASS`)
- `AppConfig.from_yaml` overrides any YAML `version:` with this file (legacy behavior)
- `installer/windows/VoxKit.iss` reads it via ISPP at compile time

- **Ruff**: line length 100, double quotes, isort-managed imports. Lints: `E`, `F`, `I`, `S` (bandit). Per-file ignores in `pyproject.toml`.
- **Mypy**: Python 3.11, `warn_return_any=true`. `tests/` and `main.py` excluded.
- **Coverage targets**: 70–80% on new business logic in `storage/`, `config/`, `analyzers/`. GUI, engines, and services are deliberately omitted from coverage.
- Pre-commit runs on every commit — don't bypass with `--no-verify`.
To bump the version, edit `config/VERSION` and nothing else. Do not reintroduce hardcoded version strings in `__init__.py`, `app_info.yaml`, or the installer.

## Testing

- Framework: `pytest`, with `pytest-qt` for GUI and `pytest-asyncio` for async.
- Write tests for new business logic in `storage/`, `config/`, `analyzers/`. GUI components are excluded from coverage metrics but still testable with `pytest-qt` when useful.
- Run `invoke run-tests` before reporting a task complete. For UI changes, also launch `invoke dev` and exercise the feature — type checks don't verify user-facing behavior.

## Commit & PR Conventions

Format: `<type>: <subject>` where type ∈ `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`. Keep commits small and logical. See `docs/CONTRIBUTING.md` for the review process.

## Gotchas for Agents

- Two test directories exist at repo root: `tests/` (the real suite, in `pyproject.toml` config) and `test/` (untracked scratch). Put new tests in `tests/`.
- The `pyproject.toml` `name` is still `pypllr-gui` (legacy) but the package is `voxkit`. Don't "fix" this without asking.
- `main.py`, `build.py`, `_frozen_patch.py` are excluded from lint/mypy/coverage — they're build/entry shims.
- `src/voxkit/__init__.py` eagerly imports all subpackages (including PyQt6 via `gui`) so pdoc can discover them. `import voxkit` is therefore expensive — fine for the app, painful for scripts that just want `__version__`. Don't "optimize" by removing the imports without checking pdoc output.
- Engines and services wrap external binaries; changes there are hard to unit-test and are omitted from coverage by design.
- Dependencies pin `torch==2.8.0` and pull several packages from Git SHAs — don't loosen these casually.
- PyInstaller bundles `config/` via `scripts/build.py` (`--add-data`); anything new in `config/` that the runtime needs will ship automatically, but custom paths outside `config/` will not.
1 change: 1 addition & 0 deletions config/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.4.1
20 changes: 10 additions & 10 deletions config/app_info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file contains metadata about the application version and purpose

app_name: "VoxKit"
version: "0.1.0"
# version is sourced from config/VERSION (single source of truth)
description: "AI/ML Research -> Clinical Applications (Speech Pathology)"
help_url: "https://voxkit-web.vercel.app/help"

Expand All @@ -12,17 +12,17 @@ log_backup_count: 3 # number of rotated files to retain

# Introduction text displayed to users
introduction: |
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
expertise in machine learning or command-line interfaces.

Core Workflow:
1. Register and analyze your speech datasets
2. Train custom acoustic models or use pretrained engines (MFA, W2TG)
3. Generate phoneme-level forced alignments with timing precision
4. Extract Goodness of Pronunciation (PLLR) scores for clinical assessment
5. Export results with full provenance tracking for reproducible research

Key Capabilities:
- Multiple alignment engines (MFA, Wav2TextGrid, WhisperX in development)
- Extensible analyzer system for custom metadata extraction
Expand All @@ -38,7 +38,7 @@ release_notes: |
- Enhanced dataset analyzers with custom metadata extraction
- Model management interface with version tracking
- Startup routines for automated asset downloads

Configuration Changes:
- Researchers can now modify workflows by editing config/pipeline_definitions.yaml
- No code changes required for common workflow adaptations
Expand All @@ -49,10 +49,10 @@ contact_info:
github_issues: "https://github.com/BrainBehaviorAnalyticsLab/voxkit-desktop/issues"
email_support: "bfrey6@wisc.edu"
documentation: "https://voxkit-web.vercel.app/help"

# Research context
research_context: |
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
rather than generic audio processing workflows.
20 changes: 10 additions & 10 deletions config/profiles/default/app_info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file contains metadata about the application version and purpose

app_name: "VoxKit"
version: "0.1.0"
# version is sourced from config/VERSION (single source of truth)
description: "AI/ML Research -> Clinical Applications (Speech Pathology)"
help_url: "https://voxkit-web.vercel.app/help"

Expand All @@ -12,17 +12,17 @@ log_backup_count: 3 # number of rotated files to retain

# Introduction text displayed to users
introduction: |
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
expertise in machine learning or command-line interfaces.

Core Workflow:
1. Register and analyze your speech datasets
2. Train custom acoustic models or use pretrained engines (MFA, W2TG)
3. Generate phoneme-level forced alignments with timing precision
4. Extract Goodness of Pronunciation (GOP) scores for clinical assessment
5. Export results with full provenance tracking for reproducible research

Key Capabilities:
- Multiple alignment engines (MFA, Wav2TextGrid, WhisperX in development)
- Extensible analyzer system for custom metadata extraction
Expand All @@ -38,7 +38,7 @@ release_notes: |
- Enhanced dataset analyzers with custom metadata extraction
- Model management interface with version tracking
- Startup routines for automated asset downloads

Configuration Changes:
- Researchers can now modify workflows by editing config/pipeline_definitions.yaml
- No code changes required for common workflow adaptations
Expand All @@ -49,10 +49,10 @@ contact_info:
github_issues: "https://github.com/BrainBehaviorAnalyticsLab/voxkit-desktop/issues"
email_support: "bfrey6@wisc.edu"
documentation: "https://voxkit-web.vercel.app/help"

# Research context
research_context: |
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
rather than generic audio processing workflows.
20 changes: 10 additions & 10 deletions config/profiles/explanatory/app_info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file contains metadata about the application version and purpose

app_name: "VoxKit"
version: "0.1.0"
# version is sourced from config/VERSION (single source of truth)
description: "AI/ML Research -> Clinical Applications (Speech Pathology)"
help_url: "https://voxkit-web.vercel.app/help"

Expand All @@ -12,17 +12,17 @@ log_backup_count: 3 # number of rotated files to retain

# Introduction text displayed to users
introduction: |
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
VoxKit bridges advanced ML alignment tools and clinical speech pathology research.
This toolkit enables rigorous phonetic analysis without requiring deep technical
expertise in machine learning or command-line interfaces.

Core Workflow:
1. Register and analyze your speech datasets
2. Train custom acoustic models or use pretrained engines (MFA, W2TG)
3. Generate phoneme-level forced alignments with timing precision
4. Extract Goodness of Pronunciation (PLLR) scores for clinical assessment
5. Export results with full provenance tracking for reproducible research

Key Capabilities:
- Multiple alignment engines (MFA, Wav2TextGrid, WhisperX in development)
- Extensible analyzer system for custom metadata extraction
Expand All @@ -38,7 +38,7 @@ release_notes: |
- Enhanced dataset analyzers with custom metadata extraction
- Model management interface with version tracking
- Startup routines for automated asset downloads

Configuration Changes:
- Researchers can now modify workflows by editing config/pipeline_definitions.yaml
- No code changes required for common workflow adaptations
Expand All @@ -49,10 +49,10 @@ contact_info:
github_issues: "https://github.com/BrainBehaviorAnalyticsLab/voxkit-desktop/issues"
email_support: "bfrey6@wisc.edu"
documentation: "https://voxkit-web.vercel.app/help"

# Research context
research_context: |
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
VoxKit was developed through collaboration between WISCLab and the Brain Behavior
Analytics Lab to democratize access to state-of-the-art forced alignment tools.
The platform is designed around established speech pathology research methodologies
rather than generic audio processing workflows.
11 changes: 10 additions & 1 deletion installer/windows/VoxKit.iss
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
#define AppName "VoxKit"
#define AppVersion "0.4.1"

; AppVersion is read from config/VERSION (single source of truth).
#define VersionFile "..\..\config\VERSION"
#define VersionHandle FileOpen(VersionFile)
#if VersionHandle
#define AppVersion Trim(FileRead(VersionHandle))
#expr FileClose(VersionHandle)
#else
#error "Could not open config/VERSION"
#endif
#define AppPublisher "Brain Behavior Analytics Lab"
#define AppURL "https://github.com/BrainBehaviorAnalyticsLab/voxkit-desktop"
#define AppExeName "VoxKit.exe"
Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "pypllr-gui"
version = "0.1.0"
description = "AI/ML Research -> Clinical Applications (Speech Pathology)"
dynamic = ["version"]
description = "PyQt6 workbench bridging audio ML engines and speech-pathology clinical workflows."
readme = "README.md"
requires-python = ">=3.11"
license = {text = "MIT"}
Expand Down Expand Up @@ -212,6 +212,9 @@ show_missing = true
[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.dynamic]
version = {file = ["config/VERSION"]}

[tool.shredguard]

[[tool.shredguard.patterns]]
Expand Down
16 changes: 14 additions & 2 deletions src/voxkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,24 @@
- **config**: Application and pipeline configuration
"""

__version__ = "0.4.0"
__author__ = "Beckett Frey - code@beckettfrey.com"
import sys
from pathlib import Path

# Import subpackages for pdoc discoverability (not re-exported in __all__)
from . import analyzers, config, engines, gui, storage


def _read_version() -> str:
if getattr(sys, "_MEIPASS", None):
root = Path(getattr(sys, "_MEIPASS")) / "config"
else:
root = Path(__file__).resolve().parents[2] / "config"
return (root / "VERSION").read_text(encoding="utf-8").strip()


__version__ = _read_version()
__author__ = "Beckett Frey - code@beckettfrey.com"

__all__ = [
"__version__",
"__author__",
Expand Down
7 changes: 6 additions & 1 deletion src/voxkit/config/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,14 @@ def from_yaml(cls, config_path: Path) -> "AppConfig":
with open(config_path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f)

# Version is sourced from config/VERSION (single source of truth),
# not from per-profile YAML.
version_file = get_config_root() / "VERSION"
version = version_file.read_text(encoding="utf-8").strip()

return cls(
app_name=data.get("app_name", "VoxKit"),
version=data.get("version", "0.0.0"),
version=version,
description=data.get("description", ""),
introduction=data.get("introduction", ""),
help_url=data.get("help_url", "https://voxkit-web.vercel.app/help"),
Expand Down
Loading
Loading