Commit Graph
211 Commits
Author SHA1 Message Date
Jatin K MalikandGitHub aefdef677b chore: remove accidentally committed temp mock directory (#276)
Remove MagicMock/ directory that was accidentally committed during
previous PR. This was a test artifact that shouldn't be in the repo.

Also add MagicMock/ to .gitignore to prevent future occurrences.
2026-02-28 16:37:01 -08:00
Jatin K MalikandGitHub 0b044cff6b fix(audio): detect and use device-supported channel count (#275)
* fix(audio): detect and use device-supported channel count

This fixes the "Invalid number of channels" (PyAudio error -9998) that
occurs with certain audio devices (e.g., HD-Audio Generic interfaces) that
require stereo (2 channel) input instead of mono (1 channel).

Changes:
- Add _get_supported_channels() helper function to detect supported channel
  configuration by testing mono first, then falling back to stereo
- Update test_audio_input() to detect channels before opening stream
- Update _record_audio() to detect channels and convert stereo to mono
- Update _attempt_audio_reconnection() to use detected channel count
- Add stereo-to-mono conversion in audio processing loop to ensure speech
  recognition engines receive mono audio as expected

Fixes issues introduced by voice commands feature where audio settings test
would fail with "no speech detected" because the audio stream couldn't be
opened due to channel mismatch.

Closes audio device compatibility issues

* fix(settings): delay callback restoration to prevent race condition in test

The recognition test was restoring text callbacks immediately after
stop_recognition(), but the recognition thread has a 1-second timeout.
If whisper.cpp transcription took longer than 1 second, the callbacks
would be restored before transcription completed, causing the text to
be sent to the wrong callback (the main app callback instead of the
test callback).

Changes:
- Add 500ms delay before restoring callbacks to allow transcription to complete
- Add new _restore_callbacks_and_check_result() helper method
- Increase result check delay from 200ms to 300ms for more reliable detection

This fixes the "No speech detected during test" issue where audio was
being recorded and transcribed, but the result wasn't being captured by
the test callback.

* debug: add diagnostic logging to trace recognition test flow

* fix(recognition): prevent race condition between audio enqueue and recognition thread

- Increase audio thread join timeout from 0.1s to 2.0s to ensure audio thread fully exits
- Remove redundant second audio thread join
- Add comprehensive debug logging to trace recognition thread lifecycle
- Add logging for final buffer enqueue to diagnose race conditions

The race condition occurred because:
1. should_record=False was set
2. Recognition thread could check queue.empty() before audio was enqueued
3. Recognition thread would exit before processing the final audio segment

This fix ensures the audio thread completes before we process the final buffer.

* fix(recognition): use poison pill pattern to prevent premature thread exit

The recognition thread was exiting immediately when should_record=False
and the queue was empty, even if audio was about to be enqueued.

Changes:
- Recognition loop now runs until it receives None signal (poison pill)
- When queue times out and should_record=False, waits 0.5s for final items
- When None is received, drains all remaining queue items before exiting
- Increased recognition thread join timeout from 1s to 5s for transcription

This ensures the recognition thread stays alive long enough to process
the final audio buffer that is enqueued after should_record is set to False.
2026-02-28 16:19:08 -08: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 18c099b5bb fix: prevent GTK widget crash on Fedora startup dialog (#268)
The first-run dialog was crashing on Fedora/Wayland when clicking any
button with the error: gtk_widget_get_scale_factor: assertion
'GTK_IS_WIDGET (widget)' failed.

Root cause: Direct destroy() calls from button click handlers caused
race conditions where GTK tried to access widget properties after the
widget was marked for destruction but before event processing completed.

Fix: Use GTK's proper dialog response signal pattern instead of direct
destroy() calls. Buttons are now added with response IDs, and the
response signal handler sets the result. This lets GTK manage the
dialog lifecycle properly and prevents the race condition.

Fixes #267
2026-02-28 00:40:10 -08:00
Jatin K MalikandGitHub cb9b66adf3 fix: resolve text injection issues from issue #34 (#261)
* fix(text_injection): re-check for better tools after xdotool fallback

When wtype fails due to compositor not supporting virtual keyboard protocol,
the code switches to xdotool permanently. This prevents using ydotool
even if its daemon is started later.

This fix adds _try_recover_from_fallback() method that checks for better
tools (ydotool with running daemon, or wtype with compositor support)
on each text injection attempt when in fallback mode.

Fixes issue #34 comment 3 (logs show xdotool but ydotool works)

* feat(main): auto-start IBus daemon on Vocalinux launch

This resolves the IBus autostart issue mentioned in issue #34.

When Vocalinux starts, it now automatically starts the IBus daemon if:
- IBus is installed on the system
- IBus daemon is not already running

This removes the need for users to manually configure IBus autostart
on desktop environments where it doesn't start automatically (e.g.,
some KDE Plasma installations or minimal window managers).

Changes:
- Add start_ibus_daemon() function in ibus_engine.py
- Call start_ibus_daemon() in main() after logging is initialized
- Export start_ibus_daemon in text_injection/__init__.py
2026-02-25 11:56:50 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
98bf30cfa6 chore(deps-dev): bump minimatch (#264)
Bumps the npm_and_yarn group with 1 update in the /web directory: [minimatch](https://github.com/isaacs/minimatch).


Updates `minimatch` from 3.1.2 to 3.1.4
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.4)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-25 11:52:16 -08:00
Jatin K MalikandGitHub a525f3c4a4 fix: prevent state flicker in recognition thread (#259)
- only transition to LISTening if still recording and currently in processing state
- Cleaner state management simplifies thread safety logic
- Fixes #258: high CPU behavior during prolonged sessions
2026-02-25 00:37:36 -08:00
Jatin K MalikandGitHub 60989b3ee1 fix: auto-detect audio sample rate for device compatibility (#262) (#263)
* fix: auto-detect audio sample rate for device compatibility (#262)

- Add _get_supported_sample_rate() helper function
- Tests device default rate first, then common rates (48k, 44.1k, 32k, 22k, 16k, 8k)
- Fixes 'Invalid sample rate' error for devices like Vocaster One (48kHz only)
- Update test_audio_input(), _record_audio(), and _attempt_audio_reconnection()
- Return detected sample_rate in test_audio_input() result dict

* fix: import pyaudio inside _get_supported_sample_rate

* fix: resample audio to 16kHz for Vosk/Whisper compatibility

- Store detected sample rate in self._capture_sample_rate
- Resample audio chunks to 16kHz before appending to buffer (linear interpolation)
- Initialize _capture_sample_rate to 16000 in __init__
- Update both _record_audio() and _attempt_audio_reconnection()

This ensures devices like Vocaster One (48kHz only) can capture audio
and speech recognition engines (Vosk/Whisper) receive 16kHz as expected.

* style: fix black formatting

* feat(ui): show sample rate info in audio test results

- Display detected sample rate in test results (e.g., '48kHz → 16kHz auto')
- Remove redundant numpy import in _record_audio function
- Helps users understand that non-16kHz devices are supported
2026-02-25 00:01:44 -08:00
Jatin K MalikandGitHub f068fbf8d7 fix(web): replace purple gradients with cyan/teal for voice-themed hero (#260) 2026-02-24 00:32:22 -08:00
Jatin K MalikandGitHub bc45108274 feat(web): add 8 new SEO-optimized pages for organic traffic (#257)
* feat(web): add 8 new SEO-optimized pages for organic traffic

## New Pages Added

| Page | Purpose | SEO Value |
|------|---------|-----------|
| `/languages/` | Multilingual support (9+ languages) | International SEO, language-specific keywords |
| `/wayland/` | Wayland support guide | Technical SEO, Linux display server queries |
| `/rsi-prevention/` | Health & accessibility focus | High-intent health keywords |
| `/gpu-acceleration/` | GPU/Vulkan support | Performance-focused technical SEO |
| `/open-source/` | FOSS & privacy positioning | Open source community keywords |
| `/autostart/` | v0.7.0 feature highlight | Linux desktop integration keywords |
| `/for-developers/` | Developer use cases | Developer productivity keywords |
| `/offline/` | Privacy-first positioning | Privacy-conscious user keywords |

## Navigation Improvements

- Redesigned header with hamburger menu for mobile
- Categorized navigation with 5 sections: Get Started, Features, Use Cases, Privacy & Ethics, Support
- Added breadcrumbs for better UX and SEO
- Footer with complete site map organized by category

## Technical Updates

- Updated sitemap.xml with all 21 pages
- All pages include JSON-LD structured data (Article schema)
- Full SEO metadata with targeted keywords per page

## Build Verification

- All 21 pages generated successfully (including dynamic install/[distro] pages)
- Build passes without errors

* feat(web): add dropdown navigation to SEO subpages

- Desktop: 5 dropdown menus (Get Started, Features, Use Cases, Privacy & Ethics, Support)
- Mobile: Hamburger menu with categorized pages
- All pages now accessible from any SEO subpage
- Click outside to close dropdowns
- Breadcrumbs and footer links remain unchanged

* fix(web): make SEO header dropdowns open on hover and focus

* fix(web): remove dead zone between dropdown trigger and menu
2026-02-22 23:24:43 -08:00
Jatin K MalikandGitHub 6e02e928ae chore(release): prepare v0.7.0-beta (#255)
* chore(release): prepare v0.7.0-beta

## Version Bump (v0.6.3-beta → v0.7.0-beta)

This is a major beta release with significant new features including autostart support, tabbed settings, and improved GPU detection.

### Core Version Files
- Updated src/vocalinux/version.py to 0.7.0-beta
- Updated pyproject.toml classifiers (already correct - Beta)

### Documentation
- Updated README.md with new features, bug fixes, and version references
- Updated docs/INSTALL.md with v0.7.0-beta install commands
- Updated docs/UPDATE.md with comprehensive 'What's New' section
- Updated SECURITY.md supported versions table (0.7.x now supported)

### Website
- Updated web/src/app/page.tsx version badge (v0.7.0 Beta)
- Updated web/src/app/page.tsx softwareVersion schema
- Updated web/package.json version to 0.7.0
- Updated web/src/app/changelog/page.tsx with v0.7.0-beta release entry

### Other Updates
- Updated install.sh default tag to v0.7.0-beta
- Updated src/vocalinux/main.py error message install command
- Updated AGENTS.md branch naming example

## Changes Since v0.6.3-beta

### New Features (13 commits)
- Autostart on login support via XDG autostart
- Tabbed settings dialog with 5 organized tabs
- Intel GPU compatibility detection with automatic CPU fallback
- Single instance prevention
- Evdev device management to prevent CPU spin
- Improved GPU detection avoiding false positives
- IBus fallback when daemon not running
- Fedora dnf check-update fix
- Web SEO - 7 new optimized pages

### Contributors
- Jatin K Malik (maintainer)
- Antoine Monnet (contributor)
- jatinkrmalik (contributor)

### Bug Fixes
- #254: Improved GPU detection to avoid false positives
- #251: Skip IBus setup when daemon not running
- #243: Prevent dnf check-update from exiting script on Fedora
- #240: Raise exception on IBus setup failure
- #234: Removed leading space from first speech transcription
- #242/#253: Removed disconnected evdev devices to prevent CPU spin

## Verification
- [x] Lint passed
- [x] Black formatting passed
- [x] isort check passed
- [x] Version imports correctly as 0.7.0-beta

* docs: update version history in RELEASE_PROCESS.md

Add entries for 0.6.0-beta through 0.7.0-beta to the version history table.
2026-02-22 21:30:05 -08:00
Jatin K MalikandGitHub 8d898de5e8 fix(installer): improve GPU detection to avoid false positives (#254)
* fix(installer): improve GPU detection to avoid false positives

- Filter out software renderers (llvmpipe, swiftshader, lavapipe, etc.)
  when checking Vulkan compatibility - these are CPU implementations
  and should not affect hardware GPU detection
- Skip Vulkan compatibility check for NVIDIA GPUs since they use CUDA
  instead of Vulkan for acceleration
- Reorder backend priority: CUDA > Vulkan > CPU
- Only show incompatible GPU warning for actual Vulkan-based GPUs
  (AMD/Intel) that lack VK_KHR_16bit_storage support

Fixes issue where RTX 5080 + llvmpipe combination was incorrectly
flagged as incompatible due to llvmpipe lacking 16-bit storage support.

* fix(installer): recommend GPU even without dev libraries installed

The installer installs dev libraries (libvulkan-dev, glslc) in
install_system_dependencies(), which runs AFTER the backend selection.
So we should recommend GPU if there's a compatible GPU regardless
of whether dev libraries are currently installed.

Changes:
- NVIDIA GPU detected → recommend CUDA (even without nvcc)
- Vulkan-compatible GPU → recommend Vulkan (even without libvulkan-dev)
- Only fall back to CPU if no compatible GPU detected or GPU is
  genuinely incompatible (old Intel Gen7)
2026-02-22 21:03:54 -08:00
Jatin K MalikandGitHub 58b635b8b9 feat: detect incompatible Intel GPUs and fallback to CPU (#239)
* feat: detect incompatible Intel GPUs and fallback to CPU

Implements two-layer protection for users with older Intel GPUs that lack
VK_KHR_16bit_storage support required by whisper.cpp Vulkan backend.

Affected GPUs: Intel Gen7 and older (Ivy Bridge, Haswell, Sandy Bridge)
- Intel HD Graphics 2500/4000 (Ivy Bridge)
- Intel HD Graphics 4400/4600 (Haswell)

Layer 1: Install-Time Detection (Prevention)
- New check_vulkan_gpu_compatibility() function in install.sh
- Parses GPU name from vulkaninfo output
- Checks against known incompatible patterns
- Shows clear warning and recommends CPU backend
- Updates detect_whispercpp_backends() to skip Vulkan for incompatible GPUs

Layer 2: Runtime Fallback (Safety Net)
- Added error handling in recognition_manager.py _init_whispercpp()
- Catches RuntimeError with "16-bit storage" or "Unsupported device"
- Automatically disables Vulkan/CUDA and retries with CPU
- Shows desktop notification explaining the fallback

Fixes #238

* fix(gpu): improve compatibility detection and add tests
2026-02-22 20:29:06 -08:00
7656447995 fix(evdev): remove disconnected devices to prevent CPU spin (#242) (#253)
When an input device is disconnected, select() reports the fd as
readable but read() fails with ENODEV. Previously, the code caught
the error but kept the dead fd in the list, causing an infinite
busy loop that consumed 100% CPU.

Now disconnected devices are removed from both self.devices and
self.device_fds when read() fails, preventing the busy loop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Antoine Monnet <39551484+AntoineMontane@users.noreply.github.com>
Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-22 20:18:12 -08:00
jatinkrmalik e723361c18 fix(evdev): improve device disconnect handling
- Add device.close() before removing from device list
- Add threading.Lock for thread-safe device list modifications
- Log device name when disconnected for troubleshooting

Addresses review comments from PR #242
2026-02-22 20:04:51 -08:00
068240e7be fix(evdev): remove disconnected devices to prevent CPU spin (#242)
When an input device is disconnected, select() reports the fd as
readable but read() fails with ENODEV. Previously, the code caught
the error but kept the dead fd in the list, causing an infinite
busy loop that consumed 100% CPU.

Now disconnected devices are removed from both self.devices and
self.device_fds when read() fails, preventing the busy loop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-22 19:59:49 -08:00
0c5e641060 fix(ibus): skip IBus setup when daemon not running (#251)
On desktop environments like KDE Plasma, the IBus daemon is not started
by default. Previously, Vocalinux would attempt to register its IBus
engine anyway, which would fail and (before #240) not properly fall back
to alternatives.

This change:
- Adds is_ibus_daemon_running() to check if ibus-daemon is running
- Skips IBus setup entirely when daemon isn't running
- Logs an informative message explaining why IBus is skipped
- Falls back to ydotool/xdotool immediately (no wasted time)

Fixes #250

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-22 19:54:32 -08:00
Jatin K MalikandGitHub c8142151eb refactor(ui): convert settings dialog to tabbed layout (#246)
* refactor(ui): convert settings dialog to tabbed layout

Convert the settings dialog from a long scrolling list to a tab-based UI
using Gtk.Notebook. This follows GNOME HIG best practices for settings
panels with 3-5 sections.

Changes:
- Add notebook CSS styling for modern tab appearance
- Create 4 tab content boxes (Recognition, Audio, Shortcuts, General)
- Replace ScrolledWindow with Gtk.Notebook
- Reorganize settings sections into appropriate tabs:
  - Recognition: Engine, Model, Language, VAD, Silence, Test
  - Audio: Device selection, Audio level test
  - Shortcuts: Keyboard shortcuts
  - General: Autostart, Start minimized
- Widen dialog to 700px to accommodate tab content

This eliminates vertical scrolling and provides a cleaner UX with
logical grouping of related settings.

* refactor(settings): split recognition tab into Speech Engine and Recognition tabs

- Reordered tabs by importance: Speech Engine, Recognition, Audio, Shortcuts, General
- Split the Recognition tab into two separate tabs:
  - Speech Engine tab: Engine, Model Size, Language, Model Info
  - Recognition tab: VAD Sensitivity, Silence Timeout, Test Recognition, Recognition Status
- This reduces vertical height of each tab and improves usability

* fix(ui): reduce settings dialog height to 50% of screen

Previously set to 75% which made the dialog unnecessarily tall.

* fix(ui): remove redundant close button from settings dialog

Settings auto-apply, so the bottom close button is unnecessary.
Users can close using the title bar X button.

* test(settings): update test for no-action-buttons pattern

The settings dialog now uses title bar close instead of a bottom
Close button, so update the test accordingly.
2026-02-22 19:52:16 -08:00
Jatin K MalikandGitHub b0565b36ad fix: prevent multiple instances from running simultaneously (#245)
* fix: prevent multiple instances from running simultaneously

Add single-instance enforcement using file locking to prevent duplicate
instances when auto-start is enabled on boot (issue #244).

Changes:
- Add single_instance.py module with fcntl-based file locking
- Check for existing instance early in main() before any initialization
- Register atexit handler to release lock on normal exit
- Lock file located at ~/.local/share/vocalinux/instance.lock

If another instance is already running, the app exits gracefully with
a helpful error message telling the user how to resolve the situation.

* fix: add GTK notification when duplicate instance detected

Show a system notification to the user when another instance is already
running, in addition to the existing stderr/log output.

Changes:
- Import Notify from gi.repository when duplicate instance detected
- Show notification with error icon and message
- Give notification time to display before exiting (0.5s sleep)
- Fallback to silent exit if notification fails (e.g., headless)
2026-02-21 15:35:52 -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
f3bcffad60 fix(install): prevent dnf check-update from exiting script on Fedora (#243)
dnf check-update returns exit code 100 when system updates are
available, which causes the script to exit immediately due to set -e.
Added '|| true' to prevent this non-error condition from stopping
the installer.

Fixes #34 (Fedora installation failure)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-21 11:17:29 -08:00
59455098d3 fix(ibus): raise exception on setup failure to enable fallback (#240)
* fix(ibus): raise exception on setup failure to enable fallback

- Add IBusSetupError exception class for detailed error context
- Modify _setup_engine() to raise exception instead of silent return
- Ensures text_injector.py fallback mechanism works when IBus fails
- Add unit tests for IBusSetupError and setup failure scenarios

Fixes silent IBus text injection failures on Wayland/Fedora reported in #34

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(text-injector): add tests for IBus setup failure fallback

- Test that TextInjector falls back to xdotool when IBus fails
- Test fallback on both X11 and Wayland environments
- Test that text injection still works after IBus failure

Related to #34

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

---------

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-21 00:39:19 -08:00
Jatin K MalikandGitHub be66bdad18 fix(web): improve mobile and tablet responsiveness (#237)
- Remove fixed min-width constraints from comparison tables
  - compare.tsx: remove min-w-[860px]
  - alternatives.tsx: remove min-w-[600px]
  - privacy.tsx: remove min-w-[500px]
- Tables now use native overflow-x-auto for horizontal scroll
- Fix subpage navigation overflow on mobile:
  - Show only icons on mobile (no text labels)
  - Add horizontal scroll support
  - Add proper aria-labels for accessibility
  - Add hover states for better touch feedback

Fixes responsive design issues identified during mobile audit.
2026-02-19 01:22:47 -08:00
Jatin K MalikandGitHub df97164c47 feat(web): add 7 new SEO-optimized pages for organic traffic (#236)
New Pages Added:
- /changelog/ - Release history showing project growth
- /faq/ - SEO-optimized FAQ with JSON-LD schema
- /privacy/ - Privacy policy (trust signal for voice software)
- /shortcuts/ - Keyboard shortcuts and voice commands reference
- /troubleshooting/ - Common issues and solutions
- /use-cases/ - Target audience pages (developers, writers, students, accessibility)
- /alternatives/ - Comparison vs Dragon, Otter.ai, Google Voice Typing

Changes:
- Updated SeoSubpageShell navigation with new pages
- Updated sitemap.xml with all new URLs
- Updated homepage footer with links to new pages
- All pages include proper metadata, JSON-LD schema, and internal linking

SEO Improvements:
- FAQ page with FAQPage schema for rich snippets
- Comparison pages for high-intent keywords
- Use case pages targeting specific audiences
- Privacy page as trust signal for voice software
2026-02-19 00:15:52 -08:00
Jatin K MalikandGitHub d7d91a7db2 chore(release): prepare v0.6.3-beta (#235)
* chore(release): prepare v0.6.3-beta

- Fix #220: Installer default tag now points to correct version
- Update version from 0.6.2-beta to 0.6.3-beta
- Update documentation version references
- Update website schema and badges
- Add v0.6.3-beta changelog entry

The v0.6.2-beta installer was defaulting to v0.6.1-beta which is
missing the psutil dependency, causing fresh installs to fail.

* docs(update): simplify update guide, remove duplicate version history
2026-02-18 23:07:00 -08:00
Jatin K MalikandGitHub ca6ba56318 feat(scripts): add process check and interactive prompts (#230)
install.sh:
- Add check_running_processes() function to detect running Vocalinux
- Prompt user to kill processes before proceeding with installation
- Auto-kill in non-interactive mode

uninstall.sh:
- Add confirmation prompt before killing processes
- Add interactive prompt for keeping data (models, config)
- Simplified --keep-data flag behavior (also keeps config)

This prevents issues during install/upgrade when Vocalinux is
still running, and gives users more control over data preservation.
2026-02-18 22:48:49 -08:00
Jatin K MalikandGitHub 38bacabee0 fix(command-processor): remove leading space from first speech (#234)
The command processor was adding a leading space when processing action
commands with text after them (e.g., 'delete that text' -> ' text').

This was causing the first speech to always have an unwanted leading space.

Changes:
- Modified command_processor.py to only add space when there's text BEFORE
the action command, not at the beginning of the transcription
- Updated test cases to reflect the correct behavior without leading spaces

Fixes leading space issue on first speech.
2026-02-18 22:48:12 -08:00
Jatin K MalikandGitHub f79917c386 docs(readme): add nightly releases section for developers (#232)
- Add new section explaining nightly releases
- Include installation command for nightly channel
- Add warning about stability vs beta releases
- Clarify release channels (Beta vs Nightly)
2026-02-18 00:29:44 -08:00
Jatin K MalikandGitHub 515b715be3 docs(readme): update v0.6.2-beta features and fixes (#231)
- Add IBus text injection engine for Wayland support
- Add X11 IBus support for non-US keyboard layouts
- Add thread-safe model access improvements
- Update bug fix list with all included fixes (#216, #227-229)
- Mark Wayland support via IBus as completed in roadmap
2026-02-18 00:01:01 -08:00
Jatin K MalikandGitHub 9292431452 fix(whisper.cpp): properly suppress [BLANK_AUDIO] tokens (#229)
The previous fix used `suppress_non_speech_tokens` which doesn't exist
in pywhispercpp's C++ bindings (whisper.cpp uses `suppress_nst` but it's
not exposed). This caused initialization error:
"_pywhispercpp.whisper_full_params object has no attribute suppress_non_speech_tokens"

Changes:
- Remove invalid `suppress_non_speech_tokens` parameter
- Add `no_speech_thold=0.6` and `entropy_thold=2.4` for better filtering
- Add `_filter_non_speech()` post-processing function that filters:
  - [BLANK_AUDIO] and other bracketed tokens
  - Music notes (♪♫♬♩♭♮♯)
  - Pure punctuation sequences
  - Low speech-content text (<30% alphanumeric)

Fixes #219
2026-02-17 23:49:00 -08:00
Jatin K MalikandGitHub 68062713cf fix(install): remove premature pkg-config check (#228)
pkg-config is included in the package list to install, so the script
should not exit with an error if it's not already installed. The check
was preventing installation on fresh systems like WSL Ubuntu 24.04.

The script already has proper fallbacks for when pkg-config is not
available (detect_vulkan and detect_typelib_path both check before
calling pkg-config).
2026-02-17 23:06:41 -08:00
Jatin K MalikandGitHub 79c3ca7f88 feat(text-injection): extend IBus support to X11 for non-US keyboard layouts (#227)
IBus sends Unicode directly via commit_text(), bypassing keyboard layout
issues entirely. This provides the same reliable text injection on X11
that we already have on Wayland.

Changes:
- Add X11_IBUS desktop environment enum
- Prefer IBus on both X11 and Wayland (before falling back to xdotool)
- Add tests for X11 IBus preference and fallback behavior

This supersedes the layout-switching approach in PR #206, which only
worked on X11 and had overhead from layout switching.

Closes #199
2026-02-17 22:40:20 -08:00
Jatin K MalikandGitHub 13991e16e6 fix(recognition): add thread safety for model access to prevent crash (#216)
Fixes #215

The crash (segfault at ffffffff in libstdc++.so.6) was caused by a race
condition between the transcription thread and model reconfiguration:

1. When recording finishes, `_transcribe_with_whispercpp()` accesses
   `self.model.transcribe()` which is a C++ object via pywhispercpp
2. If settings change simultaneously, `reconfigure()` sets `self.model = None`
3. The transcription thread then accesses null/freed memory → segfault

This fix adds a `_model_lock` to protect concurrent access to:
- `self.model` (Whisper and whisper.cpp engines)
- `self.recognizer` (VOSK engine)

The lock is now used in:
- `_transcribe_with_whisper()` - protects model.transcribe()
- `_transcribe_with_whispercpp()` - protects model.transcribe()
- `_process_final_buffer()` - protects recognizer for VOSK
- `reconfigure()` - protects model reinitialization

Each transcription method also checks if model/recognizer is None before
proceeding, returning an empty result gracefully if reconfiguration is in
progress.
2026-02-17 22:30:30 -08:00
Jatin K MalikandGitHub 0da4e74005 fix(test): add missing mocks for IBus engine test (#226)
* fix(test): add missing mocks for IBus engine test

The test_init_auto_activate test was missing mocks for:
- install_ibus_component
- start_engine_process

Without these mocks, the test would fail in CI where IBus is not
installed, as _setup_engine() would fail early and never reach
switch_engine().

* style: fix black formatting in test_ibus_engine.py
2026-02-17 22:26:38 -08:00
a1725f7cfc feat(text-injection): add IBus engine for Wayland text injection (#211)
* feat(text-injection): add IBus engine for Wayland text injection

Add a custom IBus input method engine for reliable text injection on
Wayland, solving keyboard layout issues with xdotool/wtype.

Key features:
- IBus proxy engine that passes through normal keyboard input
- Text injection via Unix socket IPC
- User-level component installation (no sudo required)
- Auto-reactivation when user switches keyboard layouts
- Graceful fallback when IBus is unavailable

Changes:
- New ibus_engine.py with VocalinuxEngine and IBusTextInjector
- TextInjector now prefers IBus on Wayland for best compatibility
- Add IBus GObject bindings to system dependencies in install.sh
- Add comprehensive tests for IBus engine

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* security: secure IBus socket with permissions and peer verification

- Set directory to 0o700 (owner-only access)
- Set socket to 0o600 (owner-only read/write)
- Add SO_PEERCRED verification to reject connections from other users

This provides defense-in-depth: even if directory permissions are
bypassed, the socket server verifies the connecting process UID.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address PR review feedback for IBus text injection

- Fix infinite loop in socket server by adding _server_running flag
- Use sys.executable instead of hardcoded python3 for venv compatibility
  - Also inherit environment (env=os.environ.copy()) for venv deps
  - Fix component XML to use sys.executable in <exec> tag
- Replace unsafe pgrep with PID file tracking and /proc verification
- Integrate TextInjector.stop() in TrayIndicator._quit() for cleanup
- Remove unused is_engine_registered import
- Fix redundant hasattr check to use proper None comparison
- Auto-detect and update stale IBus component XML on startup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 22:15:06 -08:00
Jatin K MalikandGitHub c6a8bf2fc7 docs(readme): consolidate What's New section (#225)
- Merge duplicate release sections into single v0.6.2-beta section
- Add highlights table summarizing v0.6.0 → v0.6.2 features
- Simplify bug fixes and improvements sections
- Remove redundant "Previous Release" headers
- Cleaner, more scannable layout
2026-02-17 21:56:49 -08:00
Jatin K MalikandGitHub 2acf6899bd chore(release): prepare v0.6.2-beta (#224)
* chore(release): prepare v0.6.2-beta

- Update version from 0.6.1-beta to 0.6.2-beta
- Update documentation version references
- Update website schema and badges

Changes since v0.6.1-beta:
- Fix #221: Add missing psutil dependency
- Fix #219: Suppress [BLANK_AUDIO] tokens in whisper.cpp output
- Fix #204: Resolve PyAudio paInt16 attribute error
- Fix #205: Ensure whisper module installed with --auto
- Improve Vulkan shader package detection for multiple distros
- CI: Fix nightly build tag cleanup

* docs(agents): update AGENTS.md with current project structure

- Update speech recognition engines list (whisper.cpp is now default)
- Add key dependencies section
- Update project structure with whispercpp_model_info.py and vosk_model_info.py
- Add release process quick summary

* docs(agents): add important rules about PR workflow

- Never push directly to main
- All changes require a PR
- Wait for CI before merging
- Squash merge PRs
2026-02-17 21:48:24 -08:00
Jatin K MalikandGitHub d3e1bd7128 Fix #221: Add missing psutil dependency (#223)
pywhispercpp requires psutil internally but doesn't declare it as a dependency,
causing vocalinux to fail on fresh installs with:
  Failed to import pywhispercpp: No module named 'psutil'

Adding psutil>=5.9.0 to vocalinux's dependencies as a workaround.
2026-02-17 19:02:53 -08:00
Jatin K MalikandGitHub d3f67642c2 Fix #219: Suppress [BLANK_AUDIO] tokens in whisper.cpp output (#222)
- Add suppress_blank=True and suppress_non_speech_tokens=True parameters
  to whisper.cpp Model initialization to prevent blank audio tokens
  from being output when transcribing silent audio
- This implements Option 2 from the investigation: suppress at the
  whisper.cpp level rather than post-processing filtering
- Root cause: whisper.cpp outputs a special [BLANK_AUDIO] token
  when transcribing silent audio, which was being inserted into the
  text field when users paused with the mic on
2026-02-17 17:20:36 -08:00
Jatin K MalikandGitHub b4e59b453d fix(ci): delete local tags before creating nightly release (#218)
The nightly workflow fails when re-running on the same day because
after deleting the remote tag, the local tag still exists in the
runner's checkout. GitHub CLI sees this local tag and expects it
to be pushed to remote.

This fix adds 'git tag -d' to delete local tags in both the
cleanup and create release steps, ensuring clean state before
creating new releases.
2026-02-16 20:52:09 -08:00
Jatin K MalikandGitHub 74f9536ff9 fix(ci): properly delete nightly builds older than 3 days (#217)
The previous cleanup logic sorted releases by column 3 which contained
relative dates like '3 days ago' as text. This doesn't work reliably
for sorting because '3 days ago' and '4 days ago' are compared as
strings, not dates.

This fix:
- Uses gh release list --json to get actual ISO 8601 creation timestamps
- Calculates a proper cutoff date (3 days ago in seconds since epoch)
- Parses and compares actual timestamps
- Only deletes releases that are truly older than 3 days

Fixes the nightly build retention policy.
2026-02-16 20:47:47 -08:00
Jatin K MalikandGitHub f3fc8d6de6 fix(install): correct package detection and package names for multiple distros (#214)
* fix(install): correct package detection for Void and Solus, fix git fetch syntax

- Fix git fetch syntax: remove incorrect quoting around 'tag' argument
- Fix Void Linux: use 'xbps-query' instead of 'xbps-query -S' which checks
  remote repos instead of installed packages
- Fix Solus: use 'eopkg list-installed | grep' instead of 'eopkg info' which
  queries repository info, not installed status

These bugs caused the installer to always attempt reinstalling packages on
Void Linux and Solus, even when they were already installed.

* fix(install): correct package names for Arch, Void, and Gentoo

- Arch Linux: libappindicator-gtk3 -> libappindicator (package was renamed)
- Void Linux: libappindicator -> libappindicator-gtk3 (correct package name)
- Gentoo: dev-libs/libappindicator:3 -> dev-libs/libayatana-appindicator
  (libappindicator is deprecated, use ayatana fork)
2026-02-14 14:38:46 -08:00
Jatin Malik 5fb7c40db7 fix(install): add Vulkan shader packages to all supported distributions
Added glslang and vulkan-tools to distributions that were missing them:
- Gentoo: dev-util/glslang
- Alpine: glslang vulkan-tools
- Void: glslang Vulkan-Tools
- Solus: glslang vulkan-tools

Validated package names against official repositories for each distro.
2026-02-14 20:07:03 +00:00
Jatin Malik bc5ceda546 fix(install): use glslc with glslang-tools fallback for Vulkan shader support
- Try glslc first (available on Ubuntu 24.04+)
- Fall back to glslang-tools if glslc not available (Ubuntu 22.04)
- Update user-facing messages to mention both packages
- Fixes #212 while maintaining compatibility with newer Ubuntu versions
2026-02-14 20:04:08 +00:00
Jatin Malik b9ae10dc8e Revert "docs(readme): replace glslc with glslang-tools for consistency"
This reverts commit 19342aec2a.
2026-02-14 20:02:17 +00:00
Jatin Malik 19342aec2a docs(readme): replace glslc with glslang-tools for consistency
Update README to match the install.sh changes from PR #213.
The glslc package is not available on Ubuntu 22.04.
2026-02-14 19:59:33 +00:00
Jatin K MalikandGitHub bba7829201 feat(web): overhaul SEO structure and intent landing pages (#210)
* feat(web): overhaul SEO structure and landing pages

Add distro-specific install pages and an engine comparison hub to capture high-intent organic queries. Centralize metadata and structured data handling to improve crawl consistency, internal linking, and rich-result eligibility.

* feat(web): add subpage navigation and visual polish

Make SEO landing pages easier to discover and navigate by adding persistent subpage header/footer links to home and key routes. Refresh install and comparison pages with colorful icon-driven sections while expanding homepage footer links for stronger internal linking.

* fix(ci): make web version sync robust to schema location

CI assumed softwareVersion lived in layout.tsx, but SEO refactors moved SoftwareApplication JSON-LD to page.tsx. Update workflow sync steps to patch whichever file currently contains softwareVersion so website build and release jobs keep working.

* chore(web): remove SEO audit artifact

Drop the internal SEO audit markdown from the PR so only production website and workflow changes are included.
2026-02-12 19:27:02 -08:00
Jatin K MalikandGitHub 0d8f914993 fix(web): replace OG social preview image (#209)
Swap the website Open Graph image with the provided design and regenerate both PNG and WebP assets at the standard 1200x630 share size so previews render consistently across platforms.
2026-02-12 18:32:54 -08:00
Jatin K MalikandGitHub 844d2fb104 fix(install): ensure whisper module is properly installed with --auto flag (#205)
When installing with --engine=whisper, the installer would continue even
if the whisper package installation failed, creating a config file with
engine=whisper. This caused the app to crash on startup with
'No module named whisper'.

Changes:
- Add proper verification of whisper installation by importing the module
- Only create whisper config if installation succeeds
- Fall back to whisper.cpp if whisper installation fails
- Provide clear error messages during installation

Fixes #190
2026-02-12 17:50:50 -08:00
Jatin K MalikandGitHub 8b4a1b2f50 fix(audio): resolve PyAudio paInt16 attribute error on reconnection (#204)
The _attempt_audio_reconnection method was incorrectly accessing
paInt16 as an attribute of the PyAudio instance instead of the
pyaudio module. Added local import and fixed the reference.

Fixes #203
2026-02-12 17:46:51 -08:00