feat: Package VOSK model with installation for faster first-run experience (#32)

* feat: Package VOSK model with installation for faster first-run experience

🚀 Installation Improvements:
- Add VOSK small model download during installation process
- Eliminate first-run model download delay for better user experience
- Add --skip-models option for offline installations
- Include wget, curl, unzip in system dependencies for model download

🔍 Model Management Enhancements:
- Add multi-location model search (user, system-wide, pre-installed)
- Prioritize pre-installed models over downloads
- Add informative logging for model source detection
- Create marker files to identify installer-provided models

📦 Installation Script Features:
- Robust model download with progress indicators
- Internet connectivity checking before download attempts
- Graceful fallback when download fails (runtime download)
- Comprehensive error handling and cleanup
- Installation summary includes model status

🔧 Recognition Manager Updates:
- Check multiple model locations in priority order:
  1. User's local models directory
  2. System-wide installation directories
  3. Download to user directory if not found
- Enhanced logging for model source identification
- Backward compatibility with existing installations

💡 Benefits:
- Faster application startup (no initial model download)
- Better offline installation support
- Reduced first-run friction for users
- Maintains fallback to runtime download if needed
- Clear feedback about model installation status

This addresses the issue where users had to wait for model downloads
on first application launch, making VocaLinux ready to use immediately
after installation.

* fix: Move install_vosk_models function definition before its call

The function was being called before it was defined, causing a
'command not found' error during installation. Fixed by moving
the function definition to before the installation steps where
it's called.

This resolves the installation error:
./install.sh: line 701: install_vosk_models: command not found
This commit is contained in:
Jatin K Malik
2025-06-23 18:05:29 -05:00
committed by GitHub
parent d265607d40
commit 98cba5f549
2 changed files with 162 additions and 5 deletions
@@ -8,6 +8,7 @@ currently supporting VOSK and Whisper.
import json
import logging
import os
import sys
import threading
import time
from pathlib import Path
@@ -21,6 +22,11 @@ logger = logging.getLogger(__name__)
# Define constants
MODELS_DIR = os.path.expanduser("~/.local/share/vocalinux/models")
# Alternative locations for pre-installed models
SYSTEM_MODELS_DIRS = [
"/usr/local/share/vocalinux/models",
"/usr/share/vocalinux/models",
]
class SpeechRecognitionManager:
@@ -86,6 +92,16 @@ class SpeechRecognitionManager:
f"VOSK model not found at {self.vosk_model_path}. Downloading..."
)
self._download_vosk_model()
# Update path after download
self.vosk_model_path = self._get_vosk_model_path()
else:
# Check if this is a pre-installed model
if any(self.vosk_model_path.startswith(sys_dir) for sys_dir in SYSTEM_MODELS_DIRS):
logger.info(f"Using pre-installed VOSK model from {self.vosk_model_path}")
elif os.path.exists(os.path.join(self.vosk_model_path, ".vocalinux_preinstalled")):
logger.info(f"Using installer-provided VOSK model from {self.vosk_model_path}")
else:
logger.info(f"Using existing VOSK model from {self.vosk_model_path}")
logger.info(f"Loading VOSK model from {self.vosk_model_path}")
# Ensure previous model/recognizer are released if re-initializing
@@ -129,7 +145,23 @@ class SpeechRecognitionManager:
}
model_name = model_map.get(self.model_size, model_map["small"])
return os.path.join(MODELS_DIR, model_name)
# First, check user's local models directory
user_model_path = os.path.join(MODELS_DIR, model_name)
if os.path.exists(user_model_path):
logger.debug(f"Found user model at: {user_model_path}")
return user_model_path
# Then check system-wide installation directories
for system_dir in SYSTEM_MODELS_DIRS:
system_model_path = os.path.join(system_dir, model_name)
if os.path.exists(system_model_path):
logger.info(f"Found pre-installed model at: {system_model_path}")
return system_model_path
# If not found anywhere, return the user path (will be created if needed)
logger.debug(f"No existing model found, will use: {user_model_path}")
return user_model_path
def _download_vosk_model(self):
"""Download the VOSK model if it doesn't exist."""
@@ -149,8 +181,15 @@ class SpeechRecognitionManager:
raise ValueError(f"Unknown model size: {self.model_size}")
model_name = os.path.basename(url).replace(".zip", "")
# Always download to user's local directory
model_path = os.path.join(MODELS_DIR, model_name)
zip_path = os.path.join(MODELS_DIR, os.path.basename(url))
# Create models directory if it doesn't exist
os.makedirs(MODELS_DIR, exist_ok=True)
logger.info(f"Downloading VOSK {self.model_size} model to user directory: {model_path}")
# Download the model
logger.info(f"Downloading VOSK model from {url}")