diff --git a/crates/audio/src/capture.rs b/crates/audio/src/capture.rs index e8093c2..05c838a 100644 --- a/crates/audio/src/capture.rs +++ b/crates/audio/src/capture.rs @@ -8,7 +8,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use std::sync::OnceLock; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; const AUDIO_CHANNEL_CAPACITY: usize = 32; @@ -106,7 +106,7 @@ impl MicrophoneCapture { let devices = host .input_devices() - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("input_devices: {e}")))?; + .map_err(|e| Error::AudioCaptureFailed(format!("input_devices: {e}")))?; // Load ALSA card descriptions once per enumeration. These are the // "real" product names (e.g. "Blue Microphones") that cpal's @@ -144,7 +144,7 @@ impl MicrophoneCapture { let host = cpal::default_host(); let devices = host .input_devices() - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("input_devices: {e}")))?; + .map_err(|e| Error::AudioCaptureFailed(format!("input_devices: {e}")))?; for device in devices { let name = device_display_name(&device).unwrap_or_default(); @@ -154,7 +154,7 @@ impl MicrophoneCapture { } } - Err(MagnotiaError::AudioCaptureFailed(format!( + Err(Error::AudioCaptureFailed(format!( "Selected device '{device_name}' not found in current host enumeration. \ It may have been disconnected. Open Settings → Audio to pick another." ))) @@ -178,7 +178,7 @@ impl MicrophoneCapture { let mut all_devices: Vec = host .input_devices() - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("input_devices: {e}")))? + .map_err(|e| Error::AudioCaptureFailed(format!("input_devices: {e}")))? .collect(); // Sort: default first, then non-monitor, then monitor-as-last-resort. @@ -237,7 +237,7 @@ impl MicrophoneCapture { } } - Err(MagnotiaError::AudioCaptureFailed( + Err(Error::AudioCaptureFailed( "No working microphone found. Check that an input device is connected, \ that PulseAudio/PipeWire is running, and that the app has microphone permission. \ Then open Settings → Audio to pick a device explicitly." @@ -361,7 +361,7 @@ fn open_and_validate( ) -> Result<(MicrophoneCapture, mpsc::Receiver)> { let config = device .default_input_config() - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("default_input_config: {e}")))?; + .map_err(|e| Error::AudioCaptureFailed(format!("default_input_config: {e}")))?; let sample_rate = config.sample_rate(); let channels = config.channels(); let format = config.sample_format(); @@ -422,16 +422,16 @@ fn open_and_validate( name.to_string(), ), other => { - return Err(MagnotiaError::AudioCaptureFailed(format!( + return Err(Error::AudioCaptureFailed(format!( "unsupported sample format {other:?}" ))) } } - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("build_input_stream: {e}")))?; + .map_err(|e| Error::AudioCaptureFailed(format!("build_input_stream: {e}")))?; stream .play() - .map_err(|e| MagnotiaError::AudioCaptureFailed(format!("stream.play: {e}")))?; + .map_err(|e| Error::AudioCaptureFailed(format!("stream.play: {e}")))?; // Validation window: collect chunks for DEVICE_VALIDATION_MS, compute RMS. let deadline = @@ -460,7 +460,7 @@ fn open_and_validate( } if total_samples == 0 { - return Err(MagnotiaError::AudioCaptureFailed( + return Err(Error::AudioCaptureFailed( "device delivered zero samples in validation window".into(), )); } @@ -475,7 +475,7 @@ fn open_and_validate( ); if require_audio && rms < SILENCE_RMS_FLOOR { - return Err(MagnotiaError::AudioCaptureFailed(format!( + return Err(Error::AudioCaptureFailed(format!( "device produced silence (rms={rms:.6} below floor {SILENCE_RMS_FLOOR:.6})" ))); } @@ -485,7 +485,7 @@ fn open_and_validate( // long stream of f32 zeros from a borked device — that is worse than // failing fast. if rms < DEAD_SILENCE_FLOOR { - return Err(MagnotiaError::AudioCaptureFailed(format!( + return Err(Error::AudioCaptureFailed(format!( "device produced dead silence (rms={rms:.6e} below absolute floor {DEAD_SILENCE_FLOOR:.6e})" ))); } diff --git a/crates/audio/src/concurrency.rs b/crates/audio/src/concurrency.rs index 53b136a..85fb004 100644 --- a/crates/audio/src/concurrency.rs +++ b/crates/audio/src/concurrency.rs @@ -16,6 +16,6 @@ pub async fn decode_and_resample(path: &Path) -> Result { }) .await .map_err(|e| { - lumotia_core::error::MagnotiaError::AudioDecodeFailed(format!("Task join error: {e}")) + lumotia_core::error::Error::AudioDecodeFailed(format!("Task join error: {e}")) })? } diff --git a/crates/audio/src/decode.rs b/crates/audio/src/decode.rs index 6a2583a..e1f62ff 100644 --- a/crates/audio/src/decode.rs +++ b/crates/audio/src/decode.rs @@ -9,13 +9,13 @@ use symphonia::core::io::MediaSourceStream; use symphonia::core::meta::MetadataOptions; use symphonia::core::probe::Hint; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::AudioSamples; /// Decode an audio file to mono f32 PCM samples. /// Supports all formats symphonia handles: mp3, aac, flac, wav, ogg, etc. /// -/// Any read- or decode-side error is propagated as `MagnotiaError::AudioDecodeFailed`. +/// Any read- or decode-side error is propagated as `Error::AudioDecodeFailed`. /// A previous implementation `break`ed out of the packet loop on any read /// error and skipped per-packet decode errors, so a truncated or corrupt /// input silently returned `Ok` with whatever had decoded before the @@ -29,7 +29,7 @@ pub fn decode_audio_file_limited( max_duration_secs: Option, ) -> Result { let file = File::open(path) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Cannot open file: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Cannot open file: {e}")))?; let mss = MediaSourceStream::new(Box::new(file), Default::default()); let mut hint = Hint::new(); @@ -42,7 +42,7 @@ pub fn decode_audio_file_limited( pub fn probe_audio_duration_secs(path: &Path) -> Result> { let file = File::open(path) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Cannot open file: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Cannot open file: {e}")))?; let mss = MediaSourceStream::new(Box::new(file), Default::default()); let mut hint = Hint::new(); if let Some(ext) = path.extension().and_then(|e| e.to_str()) { @@ -56,15 +56,15 @@ pub fn probe_audio_duration_secs(path: &Path) -> Result> { &FormatOptions::default(), &MetadataOptions::default(), ) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Unsupported format: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Unsupported format: {e}")))?; let track = probed .format .default_track() - .ok_or_else(|| MagnotiaError::AudioDecodeFailed("No audio track found".into()))?; + .ok_or_else(|| Error::AudioDecodeFailed("No audio track found".into()))?; let sample_rate = track .codec_params .sample_rate - .ok_or_else(|| MagnotiaError::AudioDecodeFailed("Unknown sample rate".into()))?; + .ok_or_else(|| Error::AudioDecodeFailed("Unknown sample rate".into()))?; Ok(track .codec_params .n_frames @@ -86,20 +86,20 @@ fn decode_media_stream( &FormatOptions::default(), &MetadataOptions::default(), ) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Unsupported format: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Unsupported format: {e}")))?; let mut format = probed.format; let track = format .default_track() - .ok_or_else(|| MagnotiaError::AudioDecodeFailed("No audio track found".into()))?; + .ok_or_else(|| Error::AudioDecodeFailed("No audio track found".into()))?; let sample_rate = track .codec_params .sample_rate - .ok_or_else(|| MagnotiaError::AudioDecodeFailed("Unknown sample rate".into()))?; + .ok_or_else(|| Error::AudioDecodeFailed("Unknown sample rate".into()))?; if sample_rate == 0 { - return Err(MagnotiaError::AudioDecodeFailed( + return Err(Error::AudioDecodeFailed( "Invalid sample rate: 0".into(), )); } @@ -109,7 +109,7 @@ fn decode_media_stream( let mut decoder = symphonia::default::get_codecs() .make(&track.codec_params, &DecoderOptions::default()) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Codec error: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Codec error: {e}")))?; let mut samples: Vec = Vec::new(); @@ -123,12 +123,12 @@ fn decode_media_stream( break; } Err(SymphoniaError::ResetRequired) => { - return Err(MagnotiaError::AudioDecodeFailed( + return Err(Error::AudioDecodeFailed( "decoder reset required mid-stream — input contains a discontinuity".into(), )); } Err(e) => { - return Err(MagnotiaError::AudioDecodeFailed(format!( + return Err(Error::AudioDecodeFailed(format!( "packet read failed: {e}" ))); } @@ -140,7 +140,7 @@ fn decode_media_stream( let decoded = decoder .decode(&packet) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("packet decode failed: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("packet decode failed: {e}")))?; let spec = *decoded.spec(); let channels = spec.channels.count(); @@ -160,7 +160,7 @@ fn decode_media_stream( .map(|limit| samples.len() > limit) .unwrap_or(false) { - return Err(MagnotiaError::AudioDecodeFailed(format!( + return Err(Error::AudioDecodeFailed(format!( "Audio is longer than the {:.0} minute import limit", max_duration_secs.unwrap_or(0.0) / 60.0 ))); @@ -168,7 +168,7 @@ fn decode_media_stream( } if samples.is_empty() { - return Err(MagnotiaError::AudioDecodeFailed( + return Err(Error::AudioDecodeFailed( "No audio data decoded".into(), )); } diff --git a/crates/audio/src/resample.rs b/crates/audio/src/resample.rs index f0e2c24..33b38be 100644 --- a/crates/audio/src/resample.rs +++ b/crates/audio/src/resample.rs @@ -3,7 +3,7 @@ use rubato::{ }; use lumotia_core::constants::WHISPER_SAMPLE_RATE; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::AudioSamples; /// Resample audio to 16kHz mono using sinc interpolation (rubato). @@ -17,7 +17,7 @@ pub fn resample_to_16khz(audio: &AudioSamples) -> Result { } if from_rate == 0 { - return Err(MagnotiaError::AudioDecodeFailed( + return Err(Error::AudioDecodeFailed( "Cannot resample: source rate is 0".into(), )); } @@ -36,7 +36,7 @@ pub fn resample_to_16khz(audio: &AudioSamples) -> Result { let mut resampler = SincFixedIn::::new( ratio, 1.1, params, chunk_size, 1, // mono ) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Resampler init failed: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Resampler init failed: {e}")))?; let samples = audio.samples(); let mut output_samples: Vec = Vec::new(); @@ -53,7 +53,7 @@ pub fn resample_to_16khz(audio: &AudioSamples) -> Result { let input = vec![chunk]; let result = resampler .process(&input, None) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("Resample failed: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("Resample failed: {e}")))?; if !result.is_empty() && !result[0].is_empty() { output_samples.extend_from_slice(&result[0]); diff --git a/crates/audio/src/streaming_resample.rs b/crates/audio/src/streaming_resample.rs index 3f263f3..482dbb4 100644 --- a/crates/audio/src/streaming_resample.rs +++ b/crates/audio/src/streaming_resample.rs @@ -28,7 +28,7 @@ use rubato::{ }; use lumotia_core::constants::WHISPER_SAMPLE_RATE; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; /// Number of input samples the rubato resampler consumes per `process()` /// call. Matches the chunk size used in `resample::resample_to_16khz`. @@ -51,7 +51,7 @@ impl StreamingResampler { /// rubato rejects the requested ratio. pub fn new(from_rate: u32) -> Result { if from_rate == 0 { - return Err(MagnotiaError::AudioDecodeFailed( + return Err(Error::AudioDecodeFailed( "StreamingResampler: input sample rate is 0".into(), )); } @@ -78,7 +78,7 @@ impl StreamingResampler { 1, // mono ) .map_err(|e| { - MagnotiaError::AudioDecodeFailed(format!("StreamingResampler init failed: {e}")) + Error::AudioDecodeFailed(format!("StreamingResampler init failed: {e}")) })?; Ok(Self::Sinc { @@ -110,7 +110,7 @@ impl StreamingResampler { let chunk: Vec = residual.drain(..INPUT_CHUNK).collect(); let input = vec![chunk]; let result = resampler.process(&input, None).map_err(|e| { - MagnotiaError::AudioDecodeFailed(format!( + Error::AudioDecodeFailed(format!( "StreamingResampler process failed: {e}" )) })?; @@ -144,7 +144,7 @@ impl StreamingResampler { let input = vec![chunk]; let result = resampler.process(&input, None).map_err(|e| { - MagnotiaError::AudioDecodeFailed(format!( + Error::AudioDecodeFailed(format!( "StreamingResampler flush failed: {e}" )) })?; diff --git a/crates/audio/src/wav.rs b/crates/audio/src/wav.rs index b702b37..ce300bb 100644 --- a/crates/audio/src/wav.rs +++ b/crates/audio/src/wav.rs @@ -1,7 +1,7 @@ use std::io::BufWriter; use std::path::Path; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::AudioSamples; /// Append-friendly WAV writer for long-running captures. @@ -40,10 +40,10 @@ impl WavWriter { bits_per_sample: 16, sample_format: hound::SampleFormat::Int, }; - let file = std::fs::File::create(path).map_err(MagnotiaError::from)?; + let file = std::fs::File::create(path).map_err(Error::from)?; let buffered = BufWriter::new(file); let inner = hound::WavWriter::new(buffered, spec).map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV create failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV create failed: {e}"))) })?; Ok(Self { inner, @@ -61,7 +61,7 @@ impl WavWriter { let clamped = sample.clamp(-1.0, 1.0); let int_sample = (clamped * i16::MAX as f32) as i16; self.inner.write_sample(int_sample).map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV write failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV write failed: {e}"))) })?; } self.samples_since_flush += samples.len(); @@ -78,7 +78,7 @@ impl WavWriter { /// boundaries (end-of-utterance, UI events) for tighter recovery. pub fn flush(&mut self) -> Result<()> { self.inner.flush().map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV flush failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV flush failed: {e}"))) })?; self.samples_since_flush = 0; Ok(()) @@ -90,7 +90,7 @@ impl WavWriter { /// that care about the unflushed tail should always finalise. pub fn finalize(self) -> Result<()> { self.inner.finalize().map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV finalize failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV finalize failed: {e}"))) })?; Ok(()) } @@ -106,19 +106,19 @@ pub fn write_wav(path: &Path, audio: &AudioSamples) -> Result<()> { }; let mut writer = hound::WavWriter::create(path, spec).map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV create failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV create failed: {e}"))) })?; for &sample in audio.samples() { let clamped = sample.clamp(-1.0, 1.0); let int_sample = (clamped * i16::MAX as f32) as i16; writer.write_sample(int_sample).map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV write failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV write failed: {e}"))) })?; } writer.finalize().map_err(|e| { - MagnotiaError::from(std::io::Error::other(format!("WAV finalize failed: {e}"))) + Error::from(std::io::Error::other(format!("WAV finalize failed: {e}"))) })?; Ok(()) @@ -126,14 +126,14 @@ pub fn write_wav(path: &Path, audio: &AudioSamples) -> Result<()> { /// Read a WAV file to f32 PCM `AudioSamples`. /// -/// Any per-sample decode error is surfaced as `MagnotiaError::AudioDecodeFailed` +/// Any per-sample decode error is surfaced as `Error::AudioDecodeFailed` /// rather than silently dropped. A previous implementation used /// `filter_map(|s| s.ok())`, so a truncated or corrupt payload returned /// a short, silently-partial `AudioSamples` — callers got `Ok` while /// losing audio (flagged by the 2026-04-22 review). pub fn read_wav(path: &Path) -> Result { let reader = hound::WavReader::open(path) - .map_err(|e| MagnotiaError::AudioDecodeFailed(format!("WAV open failed: {e}")))?; + .map_err(|e| Error::AudioDecodeFailed(format!("WAV open failed: {e}")))?; let spec = reader.spec(); let sample_rate = spec.sample_rate; @@ -147,7 +147,7 @@ pub fn read_wav(path: &Path) -> Result { sample .map(|s| s as f32 / (1 << (bits_per_sample - 1)) as f32) .map_err(|e| { - MagnotiaError::AudioDecodeFailed(format!("WAV sample decode failed: {e}")) + Error::AudioDecodeFailed(format!("WAV sample decode failed: {e}")) }) }) .collect::>>()?, @@ -155,7 +155,7 @@ pub fn read_wav(path: &Path) -> Result { .into_samples::() .map(|sample| { sample.map_err(|e| { - MagnotiaError::AudioDecodeFailed(format!("WAV sample decode failed: {e}")) + Error::AudioDecodeFailed(format!("WAV sample decode failed: {e}")) }) }) .collect::>>()?, diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 2f0abbd..e45d09f 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -9,7 +9,7 @@ use crate::types::ModelId; /// Implements `Serialize` so errors can be sent to the frontend as /// structured JSON rather than opaque strings. #[derive(Debug, thiserror::Error, Serialize)] -pub enum MagnotiaError { +pub enum Error { #[error("model not found: {0}")] ModelNotFound(ModelId), @@ -55,7 +55,7 @@ pub enum MagnotiaError { }, } -/// Coarse discriminator for `MagnotiaError::Storage`. The storage crate maps +/// Coarse discriminator for `Error::Storage`. The storage crate maps /// its full typed error onto one of these kinds at the boundary. Backend code /// that wants finer-grained branching pattern-matches on /// `lumotia_storage::Error` directly. @@ -70,7 +70,7 @@ pub enum StorageKind { Filesystem, } -impl From for MagnotiaError { +impl From for Error { fn from(err: std::io::Error) -> Self { Self::Io { kind: format!("{:?}", err.kind()), @@ -80,4 +80,4 @@ impl From for MagnotiaError { } } -pub type Result = std::result::Result; +pub type Result = std::result::Result; diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 4889b32..32bd2e8 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -9,7 +9,7 @@ pub mod recommendation; pub mod tuning; pub mod types; -pub use error::{MagnotiaError, Result}; +pub use error::{Error, Result}; pub use types::{ AudioSamples, DownloadProgress, EngineName, Megabytes, ModelId, Segment, Transcript, TranscriptionOptions, diff --git a/crates/storage/src/error.rs b/crates/storage/src/error.rs index e4117ff..9711bd3 100644 --- a/crates/storage/src/error.rs +++ b/crates/storage/src/error.rs @@ -1,8 +1,8 @@ //! Storage-local typed error. //! //! Backend code that wants to branch on storage failure modes pattern-matches -//! on [`Error`] directly. The crate boundary into [`lumotia_core::error::MagnotiaError`] -//! flattens this into a [`MagnotiaError::Storage`] variant carrying a serde-friendly +//! on [`Error`] directly. The crate boundary into [`lumotia_core::error::Error`] +//! flattens this into a [`Error::Storage`] variant carrying a serde-friendly //! `kind`, an `operation` label, and the Display output as `detail` — so the //! frontend (which still receives stringified errors from Tauri commands today) //! keeps working, and Area E can later expose the typed `kind` to the FE without @@ -14,7 +14,7 @@ use std::borrow::Cow; use std::path::PathBuf; -use lumotia_core::error::{MagnotiaError, StorageKind}; +use lumotia_core::error::{Error as CoreError, StorageKind}; /// Kinds of database-open operation that can fail before the pool is ready. #[derive(Debug, Clone, Copy)] @@ -145,7 +145,7 @@ pub enum Error { } impl Error { - /// Discriminator for the boundary conversion into [`MagnotiaError`]. + /// Discriminator for the boundary conversion into [`Error`]. pub fn kind(&self) -> StorageKind { match self { Error::DatabaseOpen { .. } => StorageKind::DatabaseOpen, @@ -157,7 +157,7 @@ impl Error { } } - /// Operation label that flows into the [`MagnotiaError::Storage`] boundary + /// Operation label that flows into the [`Error::Storage`] boundary /// shape. For per-query failures this is the caller-provided label; /// for the other variants it's the variant's intrinsic label. pub fn operation_label(&self) -> Cow<'static, str> { @@ -175,14 +175,14 @@ impl Error { } /// Boundary conversion — flattens the typed error into the wire-friendly -/// [`MagnotiaError::Storage`] variant. Lives in the storage crate (not in core) +/// [`CoreError::Storage`] variant. Lives in the storage crate (not in core) /// to avoid a `core -> storage` dependency cycle. -impl From for MagnotiaError { +impl From for CoreError { fn from(error: Error) -> Self { let kind = error.kind(); let operation = error.operation_label().into_owned(); let detail = error.to_string(); - MagnotiaError::Storage { + CoreError::Storage { kind, operation, detail, diff --git a/crates/transcription/src/concurrency.rs b/crates/transcription/src/concurrency.rs index c693ba2..2b56673 100644 --- a/crates/transcription/src/concurrency.rs +++ b/crates/transcription/src/concurrency.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::{AudioSamples, TranscriptionOptions}; use crate::local_engine::{LocalEngine, TimedTranscript}; @@ -14,5 +14,5 @@ pub async fn run_inference( ) -> Result { tokio::task::spawn_blocking(move || engine.transcribe_sync(&audio, &options)) .await - .map_err(|e| MagnotiaError::TranscriptionFailed(format!("Task join error: {e}")))? + .map_err(|e| Error::TranscriptionFailed(format!("Task join error: {e}")))? } diff --git a/crates/transcription/src/local_engine.rs b/crates/transcription/src/local_engine.rs index b67e04e..6195bce 100644 --- a/crates/transcription/src/local_engine.rs +++ b/crates/transcription/src/local_engine.rs @@ -4,7 +4,7 @@ use std::time::Instant; use transcribe_rs::{SpeechModel, TranscribeOptions, TranscriptionResult}; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::{ AudioSamples, EngineName, ModelId, Segment, Transcript, TranscriptionOptions, }; @@ -48,7 +48,7 @@ impl Transcriber for SpeechModelAdapter { let result: TranscriptionResult = self .0 .transcribe(samples, &opts) - .map_err(|e| MagnotiaError::TranscriptionFailed(e.to_string()))?; + .map_err(|e| Error::TranscriptionFailed(e.to_string()))?; Ok(result .segments .unwrap_or_default() @@ -140,7 +140,7 @@ impl LocalEngine { options: &TranscriptionOptions, ) -> Result { let mut guard = self.engine.lock().unwrap_or_else(|e| e.into_inner()); - let backend = guard.as_mut().ok_or(MagnotiaError::EngineNotLoaded)?; + let backend = guard.as_mut().ok_or(Error::EngineNotLoaded)?; let start = Instant::now(); let segments = backend.transcribe_sync(audio.samples(), options)?; @@ -197,7 +197,7 @@ impl transcribe_rs::SpeechModel for ParakeetWordGranularity { pub fn load_parakeet(model_dir: &Path) -> Result> { use transcribe_rs::onnx::Quantization; let model = transcribe_rs::onnx::parakeet::ParakeetModel::load(model_dir, &Quantization::Int8) - .map_err(|e| MagnotiaError::TranscriptionFailed(format!("Failed to load Parakeet: {e}")))?; + .map_err(|e| Error::TranscriptionFailed(format!("Failed to load Parakeet: {e}")))?; Ok(Box::new(SpeechModelAdapter(Box::new( ParakeetWordGranularity(model), )))) @@ -207,7 +207,7 @@ pub fn load_parakeet(model_dir: &Path) -> Result> { #[cfg(feature = "whisper")] pub fn load_whisper(model_path: &Path) -> Result> { let backend = WhisperRsBackend::load(model_path) - .map_err(|e| MagnotiaError::TranscriptionFailed(format!("Failed to load Whisper: {e}")))?; + .map_err(|e| Error::TranscriptionFailed(format!("Failed to load Whisper: {e}")))?; Ok(Box::new(backend)) } diff --git a/crates/transcription/src/model_manager.rs b/crates/transcription/src/model_manager.rs index 0ac8be6..c42b5a6 100644 --- a/crates/transcription/src/model_manager.rs +++ b/crates/transcription/src/model_manager.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::path::{Path, PathBuf}; use std::sync::{LazyLock, Mutex}; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::model_registry::{find_model, ModelFile}; use lumotia_core::types::{DownloadProgress, ModelId}; @@ -18,9 +18,9 @@ impl DownloadReservation { let id = id.as_str().to_string(); let mut active = ACTIVE_DOWNLOADS .lock() - .map_err(|_| MagnotiaError::DownloadFailed("download lock poisoned".into()))?; + .map_err(|_| Error::DownloadFailed("download lock poisoned".into()))?; if !active.insert(id.clone()) { - return Err(MagnotiaError::DownloadFailed(format!( + return Err(Error::DownloadFailed(format!( "download already in progress for {id}" ))); } @@ -80,7 +80,7 @@ pub async fn download( progress: impl Fn(DownloadProgress) + Send + 'static, ) -> Result<()> { let _reservation = DownloadReservation::acquire(id)?; - let entry = find_model(id).ok_or_else(|| MagnotiaError::ModelNotFound(id.clone()))?; + let entry = find_model(id).ok_or_else(|| Error::ModelNotFound(id.clone()))?; let dir = model_dir(id); std::fs::create_dir_all(&dir)?; @@ -98,7 +98,7 @@ pub async fn download( let _ = std::fs::remove_file(&dest); } Err(e) => { - return Err(MagnotiaError::DownloadFailed(format!( + return Err(Error::DownloadFailed(format!( "failed to verify existing {}: {e}", file.filename ))); @@ -196,7 +196,7 @@ async fn download_file( let client = reqwest::Client::builder() .connect_timeout(std::time::Duration::from_secs(30)) .build() - .map_err(|e| MagnotiaError::DownloadFailed(e.to_string()))?; + .map_err(|e| Error::DownloadFailed(e.to_string()))?; // Check for existing partial download (resume support) let existing_bytes = if part_path.exists() { @@ -215,7 +215,7 @@ async fn download_file( let response = request .send() .await - .map_err(|e| MagnotiaError::DownloadFailed(e.to_string()))?; + .map_err(|e| Error::DownloadFailed(e.to_string()))?; // If we requested Range but the server returned 200 (full file), the // server does not support resume. Rather than blindly appending a @@ -237,14 +237,14 @@ async fn download_file( false } other => { - return Err(MagnotiaError::DownloadFailed(format!( + return Err(Error::DownloadFailed(format!( "resume request returned unexpected status {other}" ))); } } } else { if !response.status().is_success() { - return Err(MagnotiaError::DownloadFailed(format!( + return Err(Error::DownloadFailed(format!( "download returned HTTP {} for {}", response.status(), file.filename @@ -291,7 +291,7 @@ async fn download_file( } while let Some(chunk) = stream.next().await { - let chunk = chunk.map_err(|e| MagnotiaError::DownloadFailed(e.to_string()))?; + let chunk = chunk.map_err(|e| Error::DownloadFailed(e.to_string()))?; std::io::Write::write_all(&mut out, &chunk)?; hasher.update(&chunk); downloaded += chunk.len() as u64; @@ -319,7 +319,7 @@ async fn download_file( let actual = format!("{:x}", hasher.finalize()); if actual != file.sha256 { let _ = std::fs::remove_file(&part_path); - return Err(MagnotiaError::DownloadFailed(format!( + return Err(Error::DownloadFailed(format!( "SHA256 mismatch for {}: expected {}, got {}", file.filename, file.sha256, actual ))); diff --git a/crates/transcription/src/orchestrator.rs b/crates/transcription/src/orchestrator.rs index 26629ce..dec6027 100644 --- a/crates/transcription/src/orchestrator.rs +++ b/crates/transcription/src/orchestrator.rs @@ -22,7 +22,7 @@ use lumotia_cloud_providers::{ CostClass, EngineProfile, ProviderCapabilities, ProviderId, ProviderKind, ProviderTranscript, TranscriptionProvider, }; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::types::{AudioSamples, TranscriptionOptions}; use crate::local_engine::LocalEngine; @@ -81,7 +81,7 @@ impl TranscriptionProvider for LocalProviderAdapter { if self.engine.is_loaded() { Ok(()) } else { - Err(MagnotiaError::EngineNotLoaded) + Err(Error::EngineNotLoaded) } } @@ -93,7 +93,7 @@ impl TranscriptionProvider for LocalProviderAdapter { let engine = self.engine.clone(); let timed = tokio::task::spawn_blocking(move || engine.transcribe_sync(&audio, &options)) .await - .map_err(|e| MagnotiaError::TranscriptionFailed(format!("Task join error: {e}")))??; + .map_err(|e| Error::TranscriptionFailed(format!("Task join error: {e}")))??; Ok(ProviderTranscript { transcript: timed.transcript, inference_ms: timed.inference_ms, @@ -124,7 +124,7 @@ impl Orchestrator { pub fn resolve(&self, profile: &EngineProfile) -> Result> { self.registry .get(&profile.engine_id) - .ok_or_else(|| MagnotiaError::ProviderNotRegistered(profile.engine_id.to_string())) + .ok_or_else(|| Error::ProviderNotRegistered(profile.engine_id.to_string())) } /// Transcribe audio using the provider named in the profile. The diff --git a/crates/transcription/src/whisper_rs_backend.rs b/crates/transcription/src/whisper_rs_backend.rs index 16557f9..2af5351 100644 --- a/crates/transcription/src/whisper_rs_backend.rs +++ b/crates/transcription/src/whisper_rs_backend.rs @@ -10,7 +10,7 @@ use std::path::Path; use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters}; -use lumotia_core::error::{MagnotiaError, Result}; +use lumotia_core::error::{Error, Result}; use lumotia_core::hardware::vulkan_loader_available; use lumotia_core::tuning::{inference_thread_count, Workload}; use lumotia_core::types::{Segment, TranscriptionOptions}; @@ -65,7 +65,7 @@ impl Transcriber for WhisperRsBackend { ); let mut state = self.ctx.create_state().map_err(|e| { - MagnotiaError::TranscriptionFailed( + Error::TranscriptionFailed( WhisperBackendError::State(e.to_string()).to_string(), ) })?; @@ -88,7 +88,7 @@ impl Transcriber for WhisperRsBackend { params.set_print_realtime(false); state.full(params, samples).map_err(|e| { - MagnotiaError::TranscriptionFailed( + Error::TranscriptionFailed( WhisperBackendError::Transcribe(e.to_string()).to_string(), ) })?; @@ -103,7 +103,7 @@ impl Transcriber for WhisperRsBackend { let text = seg .to_str() .map_err(|e| { - MagnotiaError::TranscriptionFailed( + Error::TranscriptionFailed( WhisperBackendError::Transcribe(e.to_string()).to_string(), ) })?