/// Audio pipeline constants. pub const WHISPER_SAMPLE_RATE: u32 = 16_000; pub const WHISPER_CHANNELS: u16 = 1; /// Parakeet mel spectrogram constants. pub const PARAKEET_N_FFT: usize = 512; pub const PARAKEET_HOP_LENGTH: usize = 160; pub const PARAKEET_WIN_LENGTH: usize = 400; pub const PARAKEET_N_MELS: usize = 80; pub const PARAKEET_PRE_EMPHASIS: f32 = 0.97; pub const PARAKEET_BLANK_TOKEN: usize = 1024; pub const PARAKEET_LOG_GUARD: f32 = 5.960_464_5e-8; // 2^-24 /// Chunk timing for live transcription. pub const CHUNK_INTERVAL_MS: u64 = 3000; pub const MIN_CHUNK_SAMPLES: usize = 8000; /// Post-processing thresholds. pub const SMART_PARAGRAPH_GAP_SECS: f64 = 2.0; /// Lower bound for inference threads. Single-threaded inference is /// measurably worse than two on every multi-core part; we never go below /// 2. (Whisper Tiny is the exception where the work is so small that /// thread count barely matters — but the floor still costs nothing.) pub const MIN_INFERENCE_THREADS: usize = 2; /// Upper bound for inference threads. Both whisper.cpp and llama.cpp /// scaling flattens around physical core count; SMT siblings contend /// for shared FPU resources during heavy F16/F32 matmul, which means /// going past physical cores often anti-scales. Empirical evidence: /// whisper.cpp issue #200 (sweet spot at 7t on 8c/16t Ryzen 3700X), /// llama.cpp #3167 ("SMT hurts inference"). 8 is a conservative /// ceiling that leaves <5% on the table for big-iron desktops while /// keeping consumer 6c/12t laptops out of contention territory. pub const MAX_INFERENCE_THREADS: usize = 8; /// History limits. pub const HISTORY_MAX_ENTRIES: usize = 100; /// RAM thresholds for model recommendations (in GB). pub const RAM_MINIMUM_FOR_LOCAL_STT: f64 = 2.0; pub const RAM_THRESHOLD_LIGHTWEIGHT: f64 = 4.0; pub const RAM_THRESHOLD_STANDARD: f64 = 8.0; pub const RAM_THRESHOLD_COMFORTABLE: f64 = 16.0; /// VAD configuration defaults. pub const VAD_SPEECH_THRESHOLD: f64 = 0.5; pub const VAD_MIN_SPEECH_DURATION_MS: u32 = 250; pub const VAD_MAX_SPEECH_DURATION_S: u32 = 30; pub const VAD_MIN_SILENCE_DURATION_MS: u32 = 300; pub const VAD_SPEECH_PAD_MS: u32 = 100; /// Model download chunk size for progress reporting. pub const DOWNLOAD_CHUNK_BYTES: usize = 65_536; /// Inference thread count, clamped to physical-core budget. /// /// Returns the system's physical-core count, clamped to /// `[MIN_INFERENCE_THREADS, MAX_INFERENCE_THREADS]`. Uses physical /// rather than logical cores because SMT/hyperthreaded siblings /// contend for shared FPU resources during heavy matmul; counting /// them as additional workers is well-documented to anti-scale on /// both whisper.cpp and llama.cpp. /// /// Falls back to `available_parallelism` only if the physical-core /// probe is unavailable (some non-Linux/non-Windows platforms or /// containerised environments). /// /// Users can override at runtime by setting /// `MAGNOTIA_INFERENCE_THREADS=N` — useful for benchmarking and for /// users on big-iron desktops who want to push past the cap. pub fn inference_thread_count() -> usize { if let Ok(s) = std::env::var("MAGNOTIA_INFERENCE_THREADS") { if let Ok(n) = s.parse::() { if n > 0 { return n; } } } let physical = num_cpus::get_physical(); let chosen = if physical > 0 { physical } else { std::thread::available_parallelism() .map(|p| p.get()) .unwrap_or(MIN_INFERENCE_THREADS) }; chosen.clamp(MIN_INFERENCE_THREADS, MAX_INFERENCE_THREADS) }