From f8e5de562198da003743221b5a300e0f46aa33d7 Mon Sep 17 00:00:00 2001 From: Jatin K Malik Date: Sun, 28 Dec 2025 20:31:29 -0800 Subject: [PATCH] feat: Make Whisper tiny the default engine and download during install (#45) * feat: Make Whisper tiny the default engine and download during install - Changed default engine from 'vosk' to 'whisper' in config_manager.py - Changed default model_size from 'small' to 'tiny' in config_manager.py - Added install_whisper_model() function to install.sh that downloads the Whisper tiny model (~75MB) during installation - Whisper model is downloaded when Whisper package is installed (in non-interactive mode or with --with-whisper flag) - Updated installation summary to show Whisper model status - Updated documentation (README.md, INSTALL.md, SECURITY.md, USER_GUIDE.md) to reflect Whisper tiny as the default engine This provides a better out-of-box experience: users can install and immediately use Vocalinux without any additional downloads or prompts. * test: Update test to reflect whisper as default engine --- README.md | 2 +- SECURITY.md | 6 +- docs/INSTALL.md | 7 +- docs/USER_GUIDE.md | 4 +- install.sh | 102 ++++++++++++++++++++++++++++- src/vocalinux/ui/config_manager.py | 4 +- tests/test_config_manager.py | 6 +- 7 files changed, 115 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4d32239..dc86741 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ This will: - Set up a virtual environment in `~/.local/share/vocalinux/venv` - Install **both VOSK and Whisper AI** speech engines - Create a symlink at `~/.local/bin/vocalinux` -- Download the default VOSK speech model +- Download the default **Whisper tiny** speech model (~75MB) > ⏱️ **Note**: Installation takes ~5-10 minutes due to Whisper AI dependencies (PyTorch). diff --git a/SECURITY.md b/SECURITY.md index ebe1530..429b874 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -42,14 +42,14 @@ We take security seriously. If you discover a security vulnerability within Voca Vocalinux is designed with privacy in mind: -- **Offline by default**: The VOSK engine works completely offline +- **Offline by default**: Both Whisper (default) and VOSK engines work completely offline - **Local processing**: All speech recognition happens on your device - **No data collection**: We don't collect or transmit your voice data - **No telemetry**: We don't track usage or behavior -### Whisper AI +### Whisper AI (Default Engine) -When using Whisper, be aware: +Whisper is the default speech recognition engine: - Whisper processes locally on your machine - Models are downloaded once and cached locally - No audio data is sent to external servers diff --git a/docs/INSTALL.md b/docs/INSTALL.md index e91b069..988f8ce 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -83,7 +83,7 @@ Options: 1. **Detects your Linux distribution** and installs appropriate system packages 2. **Creates a Python virtual environment** with system site-packages access 3. **Installs the Vocalinux package** and all dependencies -4. **Downloads speech recognition models** (VOSK small model by default) +4. **Downloads speech recognition models** (Whisper tiny model by default, VOSK as fallback) 5. **Installs desktop integration** (icons, .desktop file) 6. **Creates activation script** for easy environment activation @@ -108,8 +108,9 @@ vocalinux ```bash vocalinux --help # Show all options vocalinux --debug # Enable debug logging -vocalinux --engine whisper # Use Whisper AI engine -vocalinux --engine vosk # Use VOSK engine (default) +vocalinux --engine whisper # Use Whisper AI engine (default) +vocalinux --engine vosk # Use VOSK engine +vocalinux --model tiny # Use tiny model (default, fastest) vocalinux --model small # Use small model vocalinux --model medium # Use medium model vocalinux --model large # Use large model diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 68c25b0..553f3c4 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -63,8 +63,8 @@ You can change the speech recognition model for better accuracy or faster perfor 1. Open settings from the tray icon menu 2. Go to the "Recognition" tab -3. Select your preferred model size -4. Choose between VOSK (offline, faster) and Whisper (offline, more accurate) +3. Select your preferred model size (tiny is the default, use larger models for better accuracy) +4. Choose between Whisper (default, more accurate) and VOSK (lighter weight, faster) ## Troubleshooting diff --git a/install.sh b/install.sh index 729713e..01ae2bc 100755 --- a/install.sh +++ b/install.sh @@ -699,6 +699,83 @@ if ! install_python_package; then exit 1 fi +# Function to download and install Whisper tiny model +install_whisper_model() { + print_info "Installing Whisper tiny model (~75MB)..." + + # Create whisper models directory + local WHISPER_DIR="$DATA_DIR/models/whisper" + mkdir -p "$WHISPER_DIR" + + # Whisper tiny model URL and path + local TINY_MODEL_URL="https://openaipublic.azureedge.net/main/whisper/models/65147644a518d12f04e32d6f3b26facc3f8dd46e5390956a9424a650c0ce22b9/tiny.pt" + local TINY_MODEL_PATH="$WHISPER_DIR/tiny.pt" + + # Check if model already exists + if [ -f "$TINY_MODEL_PATH" ]; then + print_info "Whisper tiny model already exists at $TINY_MODEL_PATH" + return 0 + fi + + # Check internet connectivity + if ! command -v wget >/dev/null 2>&1 && ! command -v curl >/dev/null 2>&1; then + print_warning "Neither wget nor curl found. Cannot download Whisper model." + print_warning "Model will be downloaded on first application run." + return 1 + fi + + # Test internet connectivity + if ! ping -c 1 google.com >/dev/null 2>&1; then + print_warning "No internet connection detected." + print_warning "Whisper model will be downloaded on first application run." + return 1 + fi + + print_info "Downloading Whisper tiny model..." + print_info "This may take a few minutes depending on your internet connection." + + local TEMP_FILE="$TINY_MODEL_PATH.tmp" + + # Download the model + if command -v wget >/dev/null 2>&1; then + if ! wget --progress=bar:force:noscroll -O "$TEMP_FILE" "$TINY_MODEL_URL" 2>&1; then + print_error "Failed to download Whisper model with wget" + rm -f "$TEMP_FILE" + return 1 + fi + elif command -v curl >/dev/null 2>&1; then + if ! curl -L --progress-bar -o "$TEMP_FILE" "$TINY_MODEL_URL"; then + print_error "Failed to download Whisper model with curl" + rm -f "$TEMP_FILE" + return 1 + fi + fi + + # Verify download + if [ ! -f "$TEMP_FILE" ] || [ ! -s "$TEMP_FILE" ]; then + print_error "Downloaded model file is empty or missing" + rm -f "$TEMP_FILE" + return 1 + fi + + # Move to final location + mv "$TEMP_FILE" "$TINY_MODEL_PATH" + + # Verify the model file + if [ -f "$TINY_MODEL_PATH" ]; then + local MODEL_SIZE=$(du -h "$TINY_MODEL_PATH" | cut -f1) + print_success "Whisper tiny model installed successfully ($MODEL_SIZE)" + + # Create a marker file to indicate this model was pre-installed + echo "$(date)" > "$WHISPER_DIR/.vocalinux_preinstalled" + + return 0 + else + print_error "Whisper model installation failed" + return 1 + fi +} + # Function to download and install VOSK models install_vosk_models() { print_info "Installing VOSK speech recognition models..." @@ -906,7 +983,21 @@ install_desktop_entry || print_warning "Desktop entry installation failed" # Install icons install_icons || print_warning "Icon installation failed" -# Install VOSK models +# 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 + else + print_info "Whisper not available, skipping model download" + fi +fi + +# Install VOSK models (as fallback) if [ "$SKIP_MODELS" = "no" ]; then install_vosk_models || print_warning "VOSK model installation failed - models will be downloaded on first run" else @@ -1036,9 +1127,16 @@ print_installation_summary() { print_info "- Configuration: $CONFIG_DIR" print_info "- Data directory: $DATA_DIR" + # Check if Whisper model was installed + if [ -f "$DATA_DIR/models/whisper/tiny.pt" ]; then + print_info "- Whisper tiny model: $DATA_DIR/models/whisper/tiny.pt (default engine)" + elif python -c "import whisper" 2>/dev/null; then + print_info "- Whisper tiny model: Will be downloaded on first run" + fi + # Check if VOSK model was installed if [ "$SKIP_MODELS" = "no" ] && [ -d "$DATA_DIR/models/vosk-model-small-en-us-0.15" ]; then - print_info "- VOSK small model: $DATA_DIR/models/vosk-model-small-en-us-0.15" + print_info "- VOSK small model: $DATA_DIR/models/vosk-model-small-en-us-0.15 (fallback)" elif [ "$SKIP_MODELS" = "yes" ]; then print_info "- VOSK models: Will be downloaded on first run (--skip-models used)" else diff --git a/src/vocalinux/ui/config_manager.py b/src/vocalinux/ui/config_manager.py index dcb3987..507eb29 100644 --- a/src/vocalinux/ui/config_manager.py +++ b/src/vocalinux/ui/config_manager.py @@ -19,8 +19,8 @@ CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json") # Default configuration DEFAULT_CONFIG = { "speech_recognition": { # Changed section name - "engine": "vosk", # "vosk" or "whisper" - "model_size": "small", # "small", "medium", or "large" + "engine": "whisper", # "vosk" or "whisper" + "model_size": "tiny", # "tiny", "small", "medium", or "large" "vad_sensitivity": 3, # Voice Activity Detection sensitivity (1-5) - Moved here "silence_timeout": 2.0, # Seconds of silence before stopping recognition - Moved here }, diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index 98aaa1b..05ffc98 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -142,7 +142,7 @@ class TestConfigManager(unittest.TestCase): """Test getting an existing configuration value.""" config_manager = ConfigManager() value = config_manager.get("speech_recognition", "engine") - self.assertEqual(value, "vosk") + self.assertEqual(value, "whisper") # Default is now whisper def test_get_nonexistent_value(self): """Test getting a nonexistent configuration value.""" @@ -153,9 +153,9 @@ class TestConfigManager(unittest.TestCase): def test_set_existing_section(self): """Test setting a value in an existing section.""" config_manager = ConfigManager() - result = config_manager.set("speech_recognition", "engine", "whisper") + result = config_manager.set("speech_recognition", "engine", "vosk") self.assertTrue(result) - self.assertEqual(config_manager.config["speech_recognition"]["engine"], "whisper") + self.assertEqual(config_manager.config["speech_recognition"]["engine"], "vosk") def test_set_new_section(self): """Test setting a value in a new section."""