Commit Graph
13 Commits
Author SHA1 Message Date
jatinkrmalikandFakhareddine d04947374f fix(recognition): preserve final speech on stop (fixes #401)
Replace hard-coded stop tail trim with configurable stop_sound_guard_ms
(default 200ms) so quick key release no longer clips the final spoken
word in push-to-talk mode.

Co-authored-by: Fakhareddine <fe.sabbari@claranet.com>
2026-05-02 17:33:42 -07:00
Jatin K MalikandGitHub e35bdb2f62 fix(dictation): remove unwanted leading space when starting new transcription (#307)
Reset last_injected_text when recognition transitions to LISTENING state,
ensuring the first dictation segment in each session is not prefixed with
a space. Also simplify the space-prepending logic: always add a separator
space between consecutive segments (not just after punctuation), and strip
incoming text as a safety net against whisper tokenizer artifacts.
2026-03-14 12:40:58 -07:00
Jatin K MalikandGitHub 6fc1401ae0 feat(commands): make voice commands optional with auto-enable for VOSK (#274)
* feat(commands): make voice commands optional with auto-enable for VOSK

This implements a new voice commands feature that:
- Adds 'voice_commands_enabled' config option (None=auto, True, False)
- Auto-enables voice commands for VOSK engine (which needs them for punctuation)
- Auto-disables for Whisper engines (which handle punctuation natively)
- Adds a toggle in Settings > Recognition tab to override the default

The toggle shows the current auto-detected state and allows users to
enable/disable voice commands regardless of engine choice.

This addresses issue #147 discussion about voice commands utility with
modern Whisper models that handle punctuation well.

Closes #270 (by providing an alternative solution - disabling commands)

* fix(tests): add voice_commands_enabled parameter to test expectations

Update test assertions to include the new voice_commands_enabled
parameter that was added to SpeechRecognitionManager.

* style(tests): fix black formatting in test_speech_recognition.py

* fix(commands): keep voice command mode in sync on reconfigure
2026-02-28 13:06:05 -08:00
Jatin K MalikandGitHub 9886e8cb9d feat(ui): add auto-start on boot support (#207)
* feat(ui): add auto-start on boot support

- Add --start-minimized CLI flag for autostart entry
- Create autostart_manager.py to handle XDG autostart desktop entry
- Add autostart config option in config_manager.py
- Add Start on Login toggle in Settings dialog
- Add Start Minimized toggle in Settings dialog
- Add Start on Login checkbox in system tray menu
- Add first-run dialog to ask about autostart preference

Closes #184

* fix(test): add first_run: False to mock config settings

The tests were failing with StopIteration because main() now checks
for first_run and shows a dialog if True. By setting first_run: False
in the mock config, we skip the first-run dialog code path.

* fix(ui): harden autostart behavior across Linux sessions

Use XDG-compliant autostart paths and robust Exec command resolution, keep first-run prompt semantics correct, and fix GTK toggle handling so state changes are applied reliably.

* docs(autostart): document XDG startup model and limits

Clarify that Vocalinux uses desktop-session XDG autostart, not systemd services, and explain compatibility expectations for mainstream DEs versus minimal/custom WM sessions.

* feat(ui): add first-run quick-start guidance text

Expand the welcome dialog with concise first-time usage guidance and clear direction to the tray menu Settings entry while preserving the existing autostart decision flow.

* fix(uninstall): remove XDG autostart desktop entry

Ensure uninstall removes ~/.config autostart registration and reports leftover autostart entries during verification.

* fix(install): ignore defunct processes in running-check

Filter installer process detection to exclude defunct entries and installer/uninstaller shells so stale zombie rows do not block reinstall.

* fix(uninstall): ignore defunct processes in running-check

Use filtered process detection so zombie entries and installer shells do not trigger false running-process warnings during uninstall.
2026-02-21 15:06:20 -08:00
Jatin K MalikandGitHub 0a406b5d73 fix: Update AppIndicator test to match Ayatana fallback behavior (#124)
The test_check_dependencies_missing_appindicator test was failing because
it expected check_dependencies() to return False when AppIndicator3 is
missing. However, the code now supports AyatanaAppIndicator3 as a fallback.

Split the test into two cases:
- test_check_dependencies_missing_appindicator_with_ayatana_fallback:
  Tests that when AppIndicator3 is missing but AyatanaAppIndicator3
  is available, check_dependencies() returns True (fallback works)
- test_check_dependencies_missing_both_appindicators:
  Tests that when both AppIndicator3 and AyatanaAppIndicator3 are
  missing, check_dependencies() returns False
2026-02-04 22:11:43 -08:00
Jatin K MalikandGitHub 9e5b632710 test: Improve test coverage to 80%+ (#122)
* test: Improve test coverage to 80%

Increased test coverage from ~33% to 80.15% statement coverage.

New test files added:
- test_action_handler.py (100% coverage)
- test_version.py (100% coverage)
- test_logging_manager.py (100% coverage)
- test_common_types.py
- test_speech_recognition_init.py (100% coverage)
- test_resource_manager.py (93% coverage)

Significantly expanded existing tests:
- test_tray_indicator.py: 76% -> 98%
- test_main.py: 50% -> 92%
- test_text_injector.py: 60% -> 94%
- test_recognition_manager.py: 30% -> 48%
- test_command_processor.py: 85% -> 98%
- test_keyboard_shortcuts.py: 88% -> 95%
- test_config_manager.py: improved to 98%
- test_audio_feedback.py: improved to 92%

Configuration changes:
- Updated pyproject.toml to exclude untestable GTK dialog files
  (settings_dialog.py, logging_dialog.py) from coverage metrics

Key testing improvements:
- Added comprehensive GTK mocking for UI components
- Added edge case tests for text injection on X11/Wayland
- Added keyboard shortcut injection tests
- Added error handling and callback tests
- Added configuration management tests

* fix: Use runtime CI mode detection to fix Python 3.8/3.10 tests

Change CI_MODE from module-level constant to _is_ci_mode() function
that is evaluated at runtime. This ensures pytest detection works
correctly on all Python versions, since pytest modules may not be
loaded at import time.

* fix: Add PYTEST_RUNNING env var for reliable pytest detection in CI

The previous approach to detect pytest at runtime wasn't working
reliably on Python 3.8/3.10 in CI environments. This adds a
PYTEST_RUNNING=1 environment variable set early in conftest.py
that _is_ci_mode() can check to reliably determine if tests are
running.

* fix: Use patch.object for reliable mocking in audio_feedback tests

The previous approach using patch() with module paths didn't work
reliably because the module reimport caused the patched objects
to not be the same as the ones the functions referenced.

Using patch.object() on the imported module's attributes ensures
the patches are applied to the actual objects the functions use.

* fix: Use patch.object for reliable mocking in test_settings_callback

The test was failing on Python 3.8/3.10 because the module-level patch
for SettingsDialog wasn't being applied reliably across all Python
versions due to import timing differences.

Using patch.object() on the imported module ensures the mock is applied
to the actual reference that _on_settings_clicked() uses, regardless of
Python version or module caching behavior.
2026-02-04 21:01:34 -08:00
Jatin K MalikandGitHub c9810dc7f5 fix: Lazy GTK imports for better pip/pipx compatibility (#49)
* fix: Lazy GTK imports for better pip/pipx compatibility

- Move GTK-dependent imports (tray_indicator) inside main() function
- Import after check_dependencies() so users get helpful error messages
- Update ui/__init__.py to not import tray_indicator at module level
- Update vocalinux/__init__.py to not import GTK-dependent modules
- Improved error messages for pip/pipx users with missing GTK typelibs
- Bump version to 0.2.1-alpha

This fixes the 'Namespace AppIndicator3 not available' error that
pip/pipx users encounter because PyGObject can't find system typelibs.

Closes #47

* test: simplify settings dialog tests

* style: fix lazy import ordering
2026-02-04 19:55:54 -08:00
Jatin K MalikandGitHub 0c2d269a20 Fix: Test failures after language support merge (#73)
* fix: Update tests to include language parameter

- Add language to parse_arguments tests
- Update mock expectations for SpeechRecognitionManager to include language
- Fixes test failures after language support merge

* fix: Update tests for language support and fix None argument handling

- Fix test_parse_arguments_defaults to expect None for model/engine/language
- Add language_combo mock to settings_dialog tests
- Add language attribute to dialog mock setup
- Include language in get_selected_settings mock return values
- Update mock_config_manager to include language in return value
2026-01-26 00:11:38 -08:00
Jatin K MalikandGitHub b5e1d61d17 Fix: Audio detection issues - Add device selection and testing (#55)
* Fix audio detection issues (#34)

This commit addresses the audio detection issues reported in GitHub issue #34
where users on various Linux distributions (Fedora, Ubuntu with Wayland)
were unable to get voice recognition working despite their microphones
functioning in other applications.

Changes:
- Add audio input device enumeration and selection
  - New get_audio_input_devices() function lists all available input devices
  - Users can now select which microphone to use in Settings

- Add audio diagnostics and testing
  - New test_audio_input() function for testing microphone input
  - Test Mic button in Settings to verify audio is being captured
  - Audio level bar shows real-time input levels

- Improve audio debugging/logging
  - Log available audio devices on startup
  - Log which device is being used
  - Periodic audio level logging during recording
  - Warning when no speech detected and max level is very low
  - Log when speech is first detected with threshold info

- Add audio device configuration
  - Audio device selection persisted to config file
  - Device loaded on startup from saved config

- Better error handling
  - Graceful handling of audio stream open failures
  - Clear error messages when audio devices are unavailable

The root cause for many users was that PyAudio's default device selection
may not match the system's default input, especially on systems using
PipeWire or complex audio routing. Users can now explicitly select their
microphone and test it before using voice recognition.

* Fix circular import in speech_recognition module

Move lazy imports for get_audio_input_devices and test_audio_input
to avoid circular dependency when settings_dialog imports from
speech_recognition at module load time.

* Fix audio detection issues with device selection

- Add audio device enumeration and selection in Settings
- Add microphone test button with audio level indicator
- Improve VAD logging with periodic audio level output
- Add warning when no speech detected with low audio levels
- Store audio device preference in config

Fixes #34

* Fix linting issues - remove unused imports, fix module-level imports, format code

* Fix remaining linting issues - add type hints back, fix whitespace, add noqa comments

* Fix final linting issue - break long line in config_manager

* Fix formatting - use black formatting, align flake8 line-length with black (100)

* Fix CI test failures: Update mocks and assertions

* Fix audio feedback mock tests for CI

- Move audio feedback imports to top of recognition_manager.py (remove lazy imports)
- Add shared mock_audio_feedback in conftest.py for consistent mocking across tests
- Update test_recognition_manager.py and test_speech_recognition.py to use shared mock
- Fixes test_start_stop_recognition, test_start_recognition, test_stop_recognition
2026-01-19 23:49:39 -08:00
Jatin K MalikandGitHub 1dc1d44665 feat: Alpha Launch v0.2.0 - Complete UX Overhaul 🚀🎤 (#39)
* feat: prepare for v0.2.0-alpha release

* feat: prepare for v0.2.0-alpha release

* chore: remove CHANGELOG.md, use GitHub Releases instead

* refactor: use existing About dialog instead of Settings section

* style: enhance About dialog UI readability

* style: fix formatting with black and isort

* feat: show VAD and silence timeout settings for Whisper engine

- Renamed 'VOSK Settings' to 'Recognition Settings'
- VAD Sensitivity and Silence Timeout now apply to both engines
- Added tooltips explaining each setting
- VOSK-specific model info only shown when VOSK selected

* fix: resolve overlapping UI elements in settings dialog

* fix: save VAD and silence timeout settings for both engines

Previously these settings were only saved when VOSK was selected.
Now they persist correctly for Whisper as well.

* fix: show download progress when selecting undownloaded model

Previously when auto-applying settings, models would download silently
in the background without showing the progress dialog. Now:
- Download progress dialog appears for undownloaded models
- Model icons update correctly after download completes

* feat: add download progress, speed, ETA and cancel button

- Show real download progress percentage for VOSK models
- Display download speed (MB/s) and estimated time remaining
- Add Cancel button to abort downloads
- Update status during extraction phase
- Whisper downloads still pulse (uses internal downloader)

* fix: defer model download until needed, don't block startup

- App now starts instantly even if models aren't downloaded
- Models are downloaded on-demand when selected in Settings
- If user tries to dictate without a model, plays error sound
- Added model_ready property to check if engine is usable

* fix: improve first-run UX without downloaded models

- Settings dialog now defaults to smallest available model, not saved config
- Only show saved model if it's actually downloaded
- Add desktop notification when trying to dictate without a model
- Prevents auto-downloading large models on first launch

* feat: add download progress tracking for Whisper models

- Implement custom Whisper model download with progress/speed/ETA
- Uses OpenAI's CDN URLs directly instead of whisper.load_model()
- Progress callback works the same as VOSK downloads
- Supports cancellation during download

* fix: enable download progress callback for Whisper models

Progress callback was only being set for VOSK downloads, not Whisper.
Now both engines show real-time progress, speed, and ETA.

* fix: update tests for defer_download and config manager mocking

- test_main: Mock ConfigManager to prevent saved config from overriding test values
- test_settings_dialog: Mock ModelDownloadDialog to prevent GTK init errors
- test_speech_recognition: Use proper MockVoskModule class instead of MagicMock, pass defer_download=False for download test
- test_whisper_support: Pass defer_download=False to trigger model loading in test

* fix: resolve test failures for CI

- test_main: Fix ConfigManager patch path to use source module
- test_settings_dialog: Mock _is_vosk_model_downloaded and _is_whisper_model_downloaded to skip download flow, add missing dialog attributes
- test_speech_recognition: Replace recognizer with properly configured mock that returns valid JSON, fixing test isolation issues when running all tests together

* fix: mock _download_whisper_model in whisper test to avoid requests exception handling issue

* fix: add gir1.2-girepository-2.0 dep for PyGObject on Ubuntu 24.04

- Add missing girepository-2.0 package for newer Ubuntu runners
- Use --no-build-isolation for PyGObject to use system packages

* fix: skip PyGObject pip install, use system python3-gi package

- Use --no-deps for editable install to skip PyGObject
- Install other deps explicitly without PyGObject
- Add python3-gi-cairo for complete GTK support
- Removes problematic girepository-2.0 build requirement

* fix: install PyGObject via pip with proper build deps

- Remove python3-gi/python3-gi-cairo (doesn't work with setup-python)
- Install PyGObject from pip after installing build dependencies
- Simplify venv setup without --system-site-packages hack

* Fix GObject

* fix: set GI_TYPELIB_PATH for pip-installed PyGObject to find AppIndicator3
2025-12-28 15:29:51 -08:00
Jatin K MalikandGitHub f468be627d feat: comprehensive bug fixes and feature improvements (#30)
Major improvements and fixes:

🐛 Bug Fixes:
- Fix VOSK model download URL (v0.42 -> v0.22 for large model)
- Fix resource path resolution across different installation methods
- Fix missing error handling for audio library imports
- Fix text injection return value handling
- Fix test compatibility issues with updated imports

✨ New Features:
- Add centralized ResourceManager for consistent resource access
- Add ActionHandler for voice commands (delete, undo, redo, select, etc.)
- Add keyboard shortcut support for text injection
- Add comprehensive dependency checking with helpful error messages
- Add resource validation with detailed reporting

🔧 Improvements:
- Eliminate code duplication in resource path finding
- Enhance error handling with user-friendly messages
- Improve Wayland/X11 compatibility
- Add proper return type annotations
- Enhance test coverage and fix failing tests

📁 New Files:
- src/vocalinux/utils/resource_manager.py - Centralized resource management
- src/vocalinux/ui/action_handler.py - Voice command action processing
- src/vocalinux/utils/__init__.py - Utils package initialization

🧪 Testing:
- All tests now pass (76 passed, 28 skipped)
- Updated test mocks for new architecture
- Fixed import issues in test files

This makes VocaLinux production-ready with robust error handling,
complete feature implementation, and improved maintainability.
2025-06-23 17:26:03 -05:00
Jatin K MalikandGitHub b5af600714 Custom Icons Implementation and Package Restructuring (#21)
* Implement custom icon for Vocalinux (Closes #10)

* Fix system tray icon display issue

* Temp commit before purging

* refactor: restructure project into proper vocalinux package

* test: fix and improve audio_feedback and tray_indicator tests with proper mocking and isolation

* test: update import paths in test files to use the new package structure

* Remove icon background

* fix: implement robust resource path discovery in audio_feedback module

* fix: improve resource discovery across application for consistent icon and sound loading

* chore: ensure uninstall script is compatible with new resource paths

* Fix black formatting
2025-04-19 20:54:34 -05:00
Jatin K MalikandGitHub 642be732db Fix test suite and improve code stability (#6)
* Improved test coverage for audio_feedback, main, and tray_indicator modules

* Fix test suite and improve code stability

* Black formatter changes

* Fixing import sorting
2025-04-16 23:39:22 -05:00