From 2becfb5a980013c3b85135e155562d80fc61bfeb Mon Sep 17 00:00:00 2001 From: Jatin K Malik Date: Thu, 5 Feb 2026 13:45:26 -0800 Subject: [PATCH] fix(install): fix model download and VOSK-only option in interactive mode (#132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(install): fix model download and VOSK-only option in interactive mode - Add missing option 3 handling in interactive prompt to create VOSK config when user selects VOSK-only mode (mirrors --no-whisper flag) - Set WITH_WHISPER and WHISPER_CPU flags correctly for options 1 and 2 - Fix Whisper model download logic to check actual installation status using venv python instead of relying on unreliable flag combinations - Always download Whisper tiny model when Whisper is installed since it's the default engine in config_manager.py - Add informative messages about model download status Fixes issues where: 1. Selecting option 2 or 3 didn't properly configure the system 2. Whisper tiny model wasn't downloaded even when Whisper was selected 3. App defaulted to Whisper engine but model wasn't available * fix(install): use explicit venv python path and simplify condition - Use $VENV_DIR/bin/python instead of bare 'python' in run_tests() and verify_installation() for consistency and reliability - Simplify Whisper install condition since WITH_WHISPER is already set by auto-detection in non-interactive mode (lines 412-424) - Update comments to better explain the logic flow * style(install): restore ASCII art logo and improve formatting - Restore beautiful VOCALINUX ASCII art banner in interactive installer - Restore ASCII art banner in installation complete message - Use Unicode box-drawing characters (━) for section separators - Use bullet points (•) instead of dashes for lists - Add colored terminal output for commands - Add star emoji for GitHub link * style(install): show ASCII art banner in all installation modes The ASCII art logo is now displayed at the start of installation regardless of mode (interactive, curl|bash, or with flags). * fix(install): remove duplicate ASCII art in interactive mode The ASCII art banner is now shown once at script start for all modes. Remove the duplicate from run_interactive_install() to avoid showing it twice when running with -i/--interactive flag. * docs(install): rename options to 'Full install' and 'Minimal install' Clarify that VOSK is always installed as a fallback engine: - 'Full install' = Whisper + VOSK (recommended, highest accuracy) - 'Minimal install' = VOSK only (lightweight, ~40MB) Updates both the -i interactive installer and the fallback prompt. Also improves the installation summary display. * fix(install): update desktop database so app appears in menu immediately Previously only the icon cache was updated after installation, but not the desktop database. This caused the app to not appear in application menus until the user logged out and back in (or manually ran update-desktop-database). Now the installer runs update-desktop-database after installing the .desktop file, so Vocalinux appears in the app launcher immediately. --- install.sh | 200 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 137 insertions(+), 63 deletions(-) diff --git a/install.sh b/install.sh index 5e6da32..3046af8 100755 --- a/install.sh +++ b/install.sh @@ -116,6 +116,18 @@ if [[ "$DEV_MODE" == "yes" ]]; then RUN_TESTS="yes" fi +# Display ASCII art banner +cat << "EOF" + + ▗▖ ▗▖ ▗▄▖ ▗▄▄▖ ▗▄▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▖ ▗▖▗▖ ▗▖ + ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ ▐▌▐▌ █ ▐▛▚▖▐▌▐▌ ▐▌ ▝▚▞▘ + ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▛▀▜▌▐▌ █ ▐▌ ▝▜▌▐▌ ▐▌ ▐▌ + ▝▚▞▘ ▝▚▄▞▘▝▚▄▄▖▐▌ ▐▌▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▝▚▄▞▘▗▞▘▝▚▖ + + Voice Dictation for Linux + +EOF + print_info "Vocalinux Installer" print_info "==============================" echo "" @@ -253,8 +265,8 @@ run_interactive_install() { clear_screen cat << "EOF" -Vocalinux - Interactive Installation Guide -========================================== + Interactive Installation Guide + =============================== EOF @@ -281,31 +293,31 @@ EOF fi echo "" - # Step 2: Choose speech engine - print_header "Step 2: Speech Recognition Engine" - echo "Vocalinux supports two speech recognition engines:" + # Step 2: Choose installation type + print_header "Step 2: Installation Type" + echo "Choose what to install:" echo "" - echo " 1. Whisper AI (recommended)" - echo " - Highest accuracy available" - echo " - 99+ languages supported" - echo " - Created by OpenAI" + echo " 1. Full install (recommended)" + echo " • Whisper AI - highest accuracy, 99+ languages" + echo " • VOSK - fast fallback engine" + echo " • Can switch between engines in Settings" echo "" - echo " 2. VOSK" - echo " - Lightweight and fast" - echo " - Works on older/low-RAM systems" - echo " - 20+ languages supported" + echo " 2. Minimal install" + echo " • VOSK only - lightweight and fast" + echo " • Works on older/low-RAM systems" + echo " • ~40MB vs ~2GB+ for full install" echo "" - read -p "Choose your speech engine [1-2] (default: 1): " ENGINE_CHOICE + read -p "Choose installation type [1-2] (default: 1): " ENGINE_CHOICE ENGINE_CHOICE=${ENGINE_CHOICE:-1} if [[ "$ENGINE_CHOICE" == "2" ]]; then WITH_WHISPER="no" NO_WHISPER_EXPLICIT="yes" - SELECTED_ENGINE="VOSK" + SELECTED_ENGINE="Minimal (VOSK only)" else WITH_WHISPER="yes" - SELECTED_ENGINE="Whisper AI" + SELECTED_ENGINE="Full (Whisper + VOSK)" # Step 3: Whisper variant (if Whisper selected) print_header "Step 3: Whisper Installation Type" @@ -352,7 +364,10 @@ EOF # Summary print_header "Installation Summary" - echo "Speech engine: $SELECTED_ENGINE${SELECTED_VARIANT:+ ($SELECTED_VARIANT)}" + echo "Install type: $SELECTED_ENGINE" + if [[ "$WITH_WHISPER" == "yes" ]]; then + echo "Whisper variant: ${SELECTED_VARIANT:-GPU}" + fi echo "Models: $([[ "$SKIP_MODELS" == "yes" ]] && echo "Download on first use" || echo "Download now")" echo "" read -p "Press Enter to continue, or Ctrl+C to cancel..." @@ -971,8 +986,8 @@ VOSK_CONFIG print_warning "Failed to install Whisper." print_warning "Voice recognition will fall back to VOSK." } - elif [ "$WITH_WHISPER" = "yes" ] || [ "$NON_INTERACTIVE" = "yes" ]; then - # Default: Install Whisper with GPU support (either explicitly requested or non-interactive default) + elif [ "$WITH_WHISPER" = "yes" ]; then + # Install Whisper with GPU support (set by --with-whisper flag or auto-detected in non-interactive mode) print_info "Installing Whisper AI support with GPU/CUDA (~2.3GB download, ~5-10 min)..." print_info "This enables high-accuracy speech recognition with GPU acceleration." print_info "Tip: Use --whisper-cpu for a smaller download if you don't have an NVIDIA GPU." @@ -983,21 +998,23 @@ VOSK_CONFIG else # Interactive mode: Prompt user echo "" - print_info "Whisper AI provides better accuracy but requires more disk space." - print_info "Options:" - print_info " 1) Full install with GPU support (~2.3GB) - best if you have NVIDIA GPU" - print_info " 2) CPU-only install (~200MB) - works on any system, slightly slower" - print_info " 3) Skip Whisper - use VOSK only" + print_info "Choose installation type:" + print_info " 1) Full install - GPU (~2.3GB) - Whisper + VOSK, best accuracy" + print_info " 2) Full install - CPU (~200MB) - Whisper + VOSK, no GPU needed" + print_info " 3) Minimal install (~40MB) - VOSK only, lightweight" read -p "Choose option [1/2/3]: " -n 1 -r echo if [[ $REPLY == "1" ]]; then - print_info "Installing Whisper with GPU support (this might take a while)..." + WITH_WHISPER="yes" + print_info "Installing full (Whisper + VOSK) with GPU support..." pip install ".[whisper]" --log "$PIP_LOG_FILE" || { print_warning "Failed to install Whisper support." print_warning "Voice recognition will fall back to VOSK." } elif [[ $REPLY == "2" ]]; then - print_info "Installing Whisper with CPU-only PyTorch..." + WITH_WHISPER="yes" + WHISPER_CPU="yes" + print_info "Installing full (Whisper + VOSK) with CPU-only PyTorch..." pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu --log "$PIP_LOG_FILE" || { print_warning "Failed to install CPU-only PyTorch." } @@ -1005,6 +1022,43 @@ VOSK_CONFIG print_warning "Failed to install Whisper." print_warning "Voice recognition will fall back to VOSK." } + elif [[ $REPLY == "3" ]]; then + # User selected minimal install (VOSK only) + NO_WHISPER_EXPLICIT="yes" + print_info "Installing minimal (VOSK only)..." + + # Create config file with VOSK as default engine + local CONFIG_FILE_PATH="$CONFIG_DIR/config.json" + if [ ! -f "$CONFIG_FILE_PATH" ]; then + print_info "Creating config with VOSK as default engine..." + cat > "$CONFIG_FILE_PATH" << 'VOSK_INTERACTIVE_CONFIG' +{ + "speech_recognition": { + "engine": "vosk", + "model_size": "small", + "vosk_model_size": "small", + "whisper_model_size": "tiny", + "vad_sensitivity": 3, + "silence_timeout": 2.0 + }, + "audio": { + "device_index": null, + "device_name": null + }, + "shortcuts": { + "toggle_recognition": "ctrl+ctrl" + }, + "ui": { + "start_minimized": false, + "show_notifications": true + }, + "advanced": { + "debug_logging": false, + "wayland_mode": false + } +} +VOSK_INTERACTIVE_CONFIG + fi fi fi fi @@ -1342,7 +1396,7 @@ install_icons() { fi } -# Function to update icon cache +# Function to update icon cache and desktop database update_icon_cache() { print_info "Updating icon cache..." @@ -1354,6 +1408,16 @@ update_icon_cache() { else print_warning "gtk-update-icon-cache command not found, skipping icon cache update" fi + + # Update desktop database so the app appears in application menus immediately + print_info "Updating desktop database..." + if command_exists update-desktop-database; then + update-desktop-database "${XDG_DATA_HOME:-$HOME/.local/share}/applications" 2>/dev/null || { + print_warning "Failed to update desktop database" + } + else + print_warning "update-desktop-database command not found - app may not appear in menu until next login" + fi } # Install desktop entry @@ -1362,21 +1426,27 @@ install_desktop_entry || print_warning "Desktop entry installation failed" # Install icons install_icons || print_warning "Icon installation failed" -# Install Whisper tiny model (if Whisper was installed) -if [ "$WITH_WHISPER" = "yes" ] || [ "$NON_INTERACTIVE" = "yes" ]; then - # Check if Whisper is actually installed before downloading model - if python -c "import whisper" 2>/dev/null; then - if [ "$SKIP_MODELS" = "no" ]; then - install_whisper_model || print_warning "Whisper model download failed - model will be downloaded on first run" - else - print_info "Skipping Whisper model download (--skip-models specified)" - fi +# Install Whisper tiny model if Whisper is available +# This is important because Whisper is the default engine in config_manager.py +# We check if Whisper was actually installed (importable) rather than relying on flags +if [ "$SKIP_MODELS" = "no" ]; then + if "$VENV_DIR/bin/python" -c "import whisper" 2>/dev/null; then + print_info "Whisper is installed - downloading tiny model (default engine)..." + install_whisper_model || print_warning "Whisper model download failed - model will be downloaded on first run" + elif [ "$NO_WHISPER_EXPLICIT" != "yes" ]; then + # Whisper is not installed but wasn't explicitly disabled + # This shouldn't happen in normal flow, but warn the user + print_warning "Whisper not available but is the default engine." + print_warning "The app will try to download the model on first run." else - print_info "Whisper not available, skipping model download" + print_info "Whisper not installed (VOSK-only mode), skipping Whisper model download" fi +else + print_info "Skipping Whisper model download (--skip-models specified)" + print_info "Model will be downloaded automatically on first application run" fi -# Install VOSK models (as fallback) +# Install VOSK models (always useful as fallback, and required for VOSK-only mode) if [ "$SKIP_MODELS" = "no" ]; then install_vosk_models || print_warning "VOSK model installation failed - models will be downloaded on first run" else @@ -1391,8 +1461,8 @@ update_icon_cache run_tests() { print_info "Running tests..." - # Check if pytest is installed - if ! python -c "import pytest" &>/dev/null; then + # Check if pytest is installed in the virtual environment + if ! "$VENV_DIR/bin/python" -c "import pytest" &>/dev/null; then print_info "Installing pytest and related packages..." pip install pytest pytest-mock pytest-cov || { print_error "Failed to install pytest. Cannot run tests." @@ -1471,8 +1541,8 @@ verify_installation() { ((ISSUES++)) fi - # Check if Python package is importable - if ! python -c "import vocalinux" &>/dev/null; then + # Check if Python package is importable using venv python + if ! "$VENV_DIR/bin/python" -c "import vocalinux" &>/dev/null; then print_error "Vocalinux Python package cannot be imported." ((ISSUES++)) fi @@ -1487,10 +1557,15 @@ print_welcome_message() { clear_screen + # ASCII art header cat << "EOF" -Vocalinux - Installation Complete -================================ + ▗▖ ▗▖ ▗▄▖ ▗▄▄▖ ▗▄▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▖ ▗▖▗▖ ▗▖ + ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ ▐▌▐▌ █ ▐▛▚▖▐▌▐▌ ▐▌ ▝▚▞▘ + ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▛▀▜▌▐▌ █ ▐▌ ▝▜▌▐▌ ▐▌ ▐▌ + ▝▚▞▘ ▝▚▄▞▘▝▚▄▄▖▐▌ ▐▌▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▝▚▄▞▘▗▞▘▝▚▖ + + ✓ Installation Complete! EOF @@ -1503,45 +1578,44 @@ EOF fi echo "" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Getting Started" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "1. Launch Vocalinux from your app menu" echo " Look for 'Vocalinux' in your application launcher." echo "" - echo " Or from terminal:" - echo " vocalinux" + echo -e " Or from terminal: \e[36mvocalinux\e[0m" echo "" echo "2. Find Vocalinux in your system tray (top bar)" - echo " - Click the icon to access settings" - echo " - Right-click for options (Quit, Settings, etc.)" + echo " • Click the icon to access settings" + echo " • Right-click for options (Quit, Settings, etc.)" echo "" echo "3. Start dictating!" - echo " Double-tap Ctrl anywhere to start/stop dictation" + echo -e " \e[1mDouble-tap Ctrl\e[0m anywhere to start/stop dictation" echo "" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " First Run Tips" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" - echo "- Speak clearly and at a natural pace" - echo "- Use voice commands: 'period', 'comma', 'new line', 'delete that'" - echo "- Both engines are 100% offline - your privacy is protected" + echo "• Speak clearly and at a natural pace" + echo "• Use voice commands: 'period', 'comma', 'new line', 'delete that'" + echo "• Both engines are 100% offline - your privacy is protected" echo "" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Need Help?" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" - echo "- Report issues: https://github.com/jatinkrmalik/vocalinux/issues" - echo "- Documentation: https://github.com/jatinkrmalik/vocalinux" - echo "- Star us on GitHub: https://github.com/jatinkrmalik/vocalinux" + echo "• Report issues: https://github.com/jatinkrmalik/vocalinux/issues" + echo "• Documentation: https://github.com/jatinkrmalik/vocalinux" + echo "• Star us on GitHub: ⭐ https://github.com/jatinkrmalik/vocalinux" echo "" # Installation details (optional, for debugging) if [[ "$VERBOSE" == "yes" ]]; then - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Installation Details" - echo "============================================================" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Virtual environment: $VENV_DIR" echo "Desktop entry: $DESKTOP_DIR/vocalinux.desktop"