Model commands handle the lifecycle of local and cloud speech recognition models (Whisper, Parakeet, Soniox).
Model Discovery
get_model_status
Get status of all available speech recognition models.
#[tauri::command]
pub async fn get_model_status(
whisper_state: State<'_, RwLock<WhisperManager>>,
parakeet_manager: State<'_, ParakeetManager>,
app: AppHandle,
) -> Result<ModelStatusResponse, String>
Returns:
interface ModelStatusResponse {
models: ModelInfo[];
}
interface ModelInfo {
name: string; // e.g., "base.en", "parakeet-1.0", "soniox"
display_name: string; // e.g., "Whisper Base English"
size: number; // Bytes (0 for cloud models)
url: string; // Download URL (empty for cloud)
sha256: string; // Checksum (empty for cloud)
downloaded: boolean; // true if available locally
speed_score: number; // 1-10 (higher = faster)
accuracy_score: number; // 1-10 (higher = more accurate)
recommended: boolean; // Official recommendation
engine: 'whisper' | 'parakeet' | 'soniox';
kind: 'local' | 'cloud';
requires_setup: boolean; // true if API key needed
}
Usage:
const response = await invoke<ModelStatusResponse>('get_model_status');
// Filter downloaded models
const downloaded = response.models.filter(m => m.downloaded);
// Find recommended models
const recommended = response.models.filter(m => m.recommended);
// Separate by engine
const whisperModels = response.models.filter(m => m.engine === 'whisper');
const parakeetModels = response.models.filter(m => m.engine === 'parakeet');
const cloudModels = response.models.filter(m => m.kind === 'cloud');
Platform Behavior:
- macOS: Returns Whisper + Parakeet + Soniox models
- Windows/Linux: Returns Whisper + Soniox only (Parakeet requires Apple Neural Engine)
list_available_models
Alias for get_model_status - deprecated, use get_model_status instead.
get_model_info
Get detailed information about a specific model.
#[tauri::command]
pub async fn get_model_info(
model_name: String,
state: State<'_, RwLock<WhisperManager>>,
) -> Result<ModelInfo, String>
Model identifier (e.g., "base.en", "large-v3")
Usage:
const info = await invoke<ModelInfo>('get_model_info', {
modelName: 'base.en'
});
console.log(`${info.display_name}: ${(info.size / 1024 / 1024).toFixed(1)} MB`);
Model Downloads
download_model
Download a speech recognition model.
#[tauri::command]
pub async fn download_model(
app: AppHandle,
model_name: String,
whisper_state: State<'_, RwLock<WhisperManager>>,
parakeet_manager: State<'_, ParakeetManager>,
active_downloads: State<'_, Arc<Mutex<HashMap<String, Arc<AtomicBool>>>>>,
) -> Result<(), String>
Model to download (e.g., "base.en", "parakeet-1.0")
Usage:
// Start download (non-blocking)
await invoke('download_model', { modelName: 'base.en' });
// Listen for progress
const unlisten = await listen('download-progress', (event) => {
const { model, progress, downloaded, total } = event.payload;
console.log(`${model}: ${progress.toFixed(1)}% (${downloaded}/${total} bytes)`);
});
Events Emitted:
-
download-progress - Progress updates (every ~100ms)
{
model: string;
engine: string;
downloaded: number; // Bytes downloaded
total: number; // Total bytes
progress: number; // Percentage (0-100)
}
-
model-verifying - Download complete, verifying file
{
model: string;
engine: string;
}
-
model-downloaded - Download and verification complete
{
model: string;
engine: string;
}
-
download-error - Download failed
{
model: string;
engine: string;
error: string;
}
Behavior:
- Determines model engine (Whisper vs Parakeet)
- Downloads model file with progress tracking
- Verifies SHA256 checksum
- Refreshes model status
- Updates tray menu
Errors:
"Model already downloading" - Download in progress
"Network error" - Connection failed
"Invalid checksum" - File corruption
"Insufficient disk space" - Not enough storage
Example with Progress UI:
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { useState } from 'react';
function ModelDownloader({ modelName }: { modelName: string }) {
const [progress, setProgress] = useState(0);
const [isDownloading, setIsDownloading] = useState(false);
const startDownload = async () => {
setIsDownloading(true);
const unlisten = await listen('download-progress', (event: any) => {
if (event.payload.model === modelName) {
setProgress(event.payload.progress);
}
});
try {
await invoke('download_model', { modelName });
} catch (error) {
console.error('Download failed:', error);
} finally {
unlisten();
setIsDownloading(false);
}
};
return (
<div>
<button onClick={startDownload} disabled={isDownloading}>
Download
</button>
{isDownloading && <progress value={progress} max={100} />}
</div>
);
}
cancel_download
Cancel an in-progress model download.
#[tauri::command]
pub async fn cancel_download(
model_name: String,
active_downloads: State<'_, Arc<Mutex<HashMap<String, Arc<AtomicBool>>>>>,
) -> Result<(), String>
Model to cancel (e.g., "large-v3")
Usage:
await invoke('cancel_download', { modelName: 'large-v3' });
Events Emitted:
download-cancelled: { model: string, engine: string }
Model Management
delete_model
Delete a downloaded model from disk.
#[tauri::command]
pub async fn delete_model(
app: AppHandle,
model_name: String,
whisper_state: State<'_, RwLock<WhisperManager>>,
parakeet_manager: State<'_, ParakeetManager>,
) -> Result<(), String>
Usage:
try {
await invoke('delete_model', { modelName: 'base.en' });
console.log('Model deleted successfully');
} catch (error) {
console.error('Failed to delete model:', error);
}
Events Emitted:
model-deleted: { model: string, engine: string }
Behavior:
- Deletes model file from disk
- Updates model registry
- Refreshes tray menu
- If deleted model was selected, user must choose another
Errors:
"Model not found" - Model doesn’t exist
"Model in use" - Currently selected or downloading
"Permission denied" - Filesystem error
verify_model
Verify a downloaded model’s integrity.
#[tauri::command]
pub async fn verify_model(
app: AppHandle,
model_name: String,
state: State<'_, RwLock<WhisperManager>>,
) -> Result<(), String>
Usage:
try {
await invoke('verify_model', { modelName: 'base.en' });
console.log('Model verified successfully');
} catch (error) {
console.error('Verification failed:', error);
// Model file is corrupted, re-download required
}
Behavior:
- Checks if model file exists
- Validates file size (must be within 5% of expected)
- If corrupted, deletes file and marks as not downloaded
Errors:
"Model file not found" - File missing from disk
"Model is corrupted and has been deleted" - File size mismatch
preload_model
Preload a model into memory for faster transcription.
#[tauri::command]
pub async fn preload_model(
app: AppHandle,
model_name: String,
state: State<'_, RwLock<WhisperManager>>,
) -> Result<(), String>
Model to preload (Whisper only)
Usage:
// Preload model on app startup for instant transcription
await invoke('preload_model', { modelName: 'base.en' });
console.log('Model ready for instant transcription');
Behavior:
- Loads model into TranscriberCache
- Subsequent transcriptions use cached model (no load time)
- Only applies to Whisper models
- Parakeet and Soniox models are always “instant”
Errors:
"Model not found" - Model not downloaded
"License required to preload models" - Invalid license
List Commands
list_downloaded_models
Get list of downloaded model filenames.
#[tauri::command]
pub async fn list_downloaded_models(
state: State<'_, RwLock<WhisperManager>>,
) -> Result<Vec<String>, String>
Returns: Array of model names
Usage:
const models = await invoke<string[]>('list_downloaded_models');
console.log('Downloaded:', models.join(', '));
Model Selection
Models are selected via Settings Commands:
import { invoke } from '@tauri-apps/api/core';
// Get current settings
const settings = await invoke<AppSettings>('get_settings');
console.log('Current model:', settings.current_model);
// Update selected model
await invoke('save_settings', {
settings: {
...settings,
current_model: 'base.en',
current_model_engine: 'whisper'
}
});
See Also