chore: rebrand from Kon/Corbie to Magnotia
Replace all instances of the legacy product names "Kon" and "Corbie" with "Magnotia" across user-facing copy, code identifiers, package names, bundle ids, file paths, and documentation. Preserves the unrelated "konsole" (KDE terminal) reference and the parent CORBEL company name. - Renames 10 Rust crates (kon-* → magnotia-*) and the tauri binary - Updates package.json, tauri.conf.json (productName + identifier) - Renames CSS classes (kon-rh-* → magnotia-rh-*) and animations - Renames brand and roadmap docs - Regenerates Cargo.lock and package-lock.json Verified: svelte-check passes; pure-rust crates compile under new names.
This commit is contained in:
@@ -7,9 +7,9 @@ use tokio::sync::{mpsc as tokio_mpsc, Mutex as AsyncMutex};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use crate::commands::security::ensure_main_window;
|
||||
use kon_audio::{DeviceInfo, MicrophoneCapture, WavWriter};
|
||||
use kon_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use kon_core::types::AudioSamples;
|
||||
use magnotia_audio::{DeviceInfo, MicrophoneCapture, WavWriter};
|
||||
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use magnotia_core::types::AudioSamples;
|
||||
|
||||
const MAX_NATIVE_CAPTURE_RETURN_SAMPLES: usize = WHISPER_SAMPLE_RATE as usize * 60 * 10;
|
||||
|
||||
@@ -360,8 +360,8 @@ pub fn resolve_recording_path(
|
||||
/// collisions, which `SystemTime::now()` alone cannot guarantee
|
||||
/// (two calls in the same clock tick can return identical nanos).
|
||||
///
|
||||
/// Format: `kon-<secs>-<nanos_in_sec>-<counter>.wav`, e.g.
|
||||
/// `kon-1776828000-123456789-0000.wav`.
|
||||
/// Format: `magnotia-<secs>-<nanos_in_sec>-<counter>.wav`, e.g.
|
||||
/// `magnotia-1776828000-123456789-0000.wav`.
|
||||
fn recording_filename() -> String {
|
||||
let duration = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -369,11 +369,11 @@ fn recording_filename() -> String {
|
||||
let secs = duration.as_secs();
|
||||
let nanos = duration.subsec_nanos();
|
||||
let counter = RECORDING_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
format!("kon-{secs}-{nanos:09}-{counter:04}.wav")
|
||||
format!("magnotia-{secs}-{nanos:09}-{counter:04}.wav")
|
||||
}
|
||||
|
||||
/// Process-lifetime monotonic counter for `recording_filename`. Starts
|
||||
/// at 0 on each Kon launch; wall-clock secs/nanos still advance across
|
||||
/// at 0 on each Magnotia launch; wall-clock secs/nanos still advance across
|
||||
/// restarts, so cross-launch collisions are already impossible — the
|
||||
/// counter is the last-mile guarantee against within-launch same-tick
|
||||
/// collisions.
|
||||
@@ -408,11 +408,11 @@ mod tests {
|
||||
#[test]
|
||||
fn recording_filename_has_expected_shape() {
|
||||
let name = recording_filename();
|
||||
assert!(name.starts_with("kon-"));
|
||||
assert!(name.starts_with("magnotia-"));
|
||||
assert!(name.ends_with(".wav"));
|
||||
// Shape: kon-<digits>-<9 digits>-<>=4 digits>.wav
|
||||
// Shape: magnotia-<digits>-<9 digits>-<>=4 digits>.wav
|
||||
let rest = name
|
||||
.strip_prefix("kon-")
|
||||
.strip_prefix("magnotia-")
|
||||
.and_then(|s| s.strip_suffix(".wav"))
|
||||
.expect("shape prefix/suffix");
|
||||
let parts: Vec<&str> = rest.split('-').collect();
|
||||
@@ -519,7 +519,7 @@ pub async fn persist_audio_samples(
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let audio = AudioSamples::mono_16khz(samples);
|
||||
kon_audio::write_wav(&path_clone, &audio).map_err(|e| e.to_string())
|
||||
magnotia_audio::write_wav(&path_clone, &audio).map_err(|e| e.to_string())
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())??;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Diagnostics: panic hook, frontend error capture, and the manual
|
||||
//! diagnostic-report bundler used by Settings → About.
|
||||
//!
|
||||
//! Privacy posture (matches Kon's local-first positioning):
|
||||
//! Privacy posture (matches Magnotia's local-first positioning):
|
||||
//! - All capture is to disk only. Nothing is transmitted.
|
||||
//! - The manual report bundler shows the user exactly what would be
|
||||
//! shared and lets them choose to copy/save/email it.
|
||||
@@ -15,7 +15,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use kon_storage::{
|
||||
use magnotia_storage::{
|
||||
app_data_dir, crashes_dir, list_recent_errors, log_error, logs_dir, ErrorLogRow,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::commands::security::ensure_main_window;
|
||||
use crate::AppState;
|
||||
|
||||
const DEFAULT_RECENT_ERRORS: i64 = 50;
|
||||
const KON_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
const MAGNOTIA_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
/// Install the Rust panic hook. Writes each panic to a separate file in
|
||||
/// crashes_dir so the diagnostic-report bundler can attach them. Also
|
||||
@@ -49,7 +49,7 @@ pub fn install_panic_hook() {
|
||||
let path = crashes_dir().join(format!("{ts}-{short:04x}.crash"));
|
||||
|
||||
let payload = format!(
|
||||
"Kon crash dump\n\
|
||||
"Magnotia crash dump\n\
|
||||
==============\n\
|
||||
Version: {ver}\n\
|
||||
Timestamp: {ts} (UTC seconds)\n\
|
||||
@@ -60,7 +60,7 @@ pub fn install_panic_hook() {
|
||||
\n\
|
||||
OS: {os} {arch}\n\
|
||||
RUST_BACKTRACE: {bt}\n",
|
||||
ver = KON_VERSION,
|
||||
ver = MAGNOTIA_VERSION,
|
||||
ts = ts,
|
||||
thread = std::thread::current().name().unwrap_or("<unnamed>"),
|
||||
info = info,
|
||||
@@ -311,8 +311,8 @@ async fn generate_diagnostic_report_inner(
|
||||
let opts = options.unwrap_or_default();
|
||||
let mut out = String::new();
|
||||
|
||||
out.push_str("# Kon diagnostic report\n\n");
|
||||
out.push_str(&format!("- Version: `{}`\n", KON_VERSION));
|
||||
out.push_str("# Magnotia diagnostic report\n\n");
|
||||
out.push_str(&format!("- Version: `{}`\n", MAGNOTIA_VERSION));
|
||||
out.push_str(&format!(
|
||||
"- OS / arch: `{} / {}`\n",
|
||||
std::env::consts::OS,
|
||||
@@ -335,7 +335,7 @@ async fn generate_diagnostic_report_inner(
|
||||
|
||||
if opts.include_settings {
|
||||
out.push_str("## Settings (sanitised)\n\n");
|
||||
match kon_storage::get_setting(&state.db, "kon_preferences").await {
|
||||
match magnotia_storage::get_setting(&state.db, "magnotia_preferences").await {
|
||||
Ok(Some(json)) => {
|
||||
out.push_str("```json\n");
|
||||
out.push_str(&sanitise_preferences_json(&json));
|
||||
@@ -405,7 +405,7 @@ async fn generate_diagnostic_report_inner(
|
||||
|
||||
if opts.include_log_tail {
|
||||
out.push_str("## Log tail\n\n");
|
||||
let log_path = logs_dir().join("kon.log");
|
||||
let log_path = logs_dir().join("magnotia.log");
|
||||
match read_tail(&log_path, 8000) {
|
||||
Ok(tail) if tail.is_empty() => {
|
||||
out.push_str("_(log file empty or not yet written)_\n\n");
|
||||
@@ -421,7 +421,7 @@ async fn generate_diagnostic_report_inner(
|
||||
|
||||
out.push_str("---\n\n");
|
||||
out.push_str(
|
||||
"Generated by Kon. To share, copy the entire markdown above \
|
||||
"Generated by Magnotia. To share, copy the entire markdown above \
|
||||
and paste it into an email or issue. Email: jake@corbel.consulting.\n",
|
||||
);
|
||||
|
||||
@@ -520,14 +520,14 @@ pub async fn save_diagnostic_report(
|
||||
let _ = app; // reserved for future dialog integration
|
||||
let report = generate_diagnostic_report_inner(&state, options).await?;
|
||||
|
||||
let dir = kon_storage::app_data_dir().join("diagnostic-reports");
|
||||
let dir = magnotia_storage::app_data_dir().join("diagnostic-reports");
|
||||
fs::create_dir_all(&dir).map_err(|e| format!("create dir: {e}"))?;
|
||||
|
||||
let ts = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
let path = dir.join(format!("kon-diagnostic-{ts}.md"));
|
||||
let path = dir.join(format!("magnotia-diagnostic-{ts}.md"));
|
||||
|
||||
fs::write(&path, &report).map_err(|e| format!("write file: {e}"))?;
|
||||
Ok(path.to_string_lossy().to_string())
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use kon_storage::{
|
||||
use magnotia_storage::{
|
||||
list_feedback_examples as db_list_feedback_examples, record_feedback as db_record_feedback,
|
||||
FeedbackRow, FeedbackTargetType, RecordFeedbackParams,
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn write_text_file_errors_on_bad_parent() {
|
||||
let result = write_text_file_cmd(
|
||||
"/definitely-not-a-real-path-kon-phase9/out.md".into(),
|
||||
"/definitely-not-a-real-path-magnotia-phase9/out.md".into(),
|
||||
"x".into(),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use kon_core::hardware::{self, Os};
|
||||
use kon_core::recommendation;
|
||||
use magnotia_core::hardware::{self, Os};
|
||||
use magnotia_core::recommendation;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SystemInfo {
|
||||
@@ -53,7 +53,7 @@ pub fn rank_models() -> Result<Vec<ModelRecommendation>, String> {
|
||||
Ok(ranked
|
||||
.into_iter()
|
||||
.map(|scored| {
|
||||
let downloaded = kon_transcription::is_downloaded(&scored.entry.id);
|
||||
let downloaded = magnotia_transcription::is_downloaded(&scored.entry.id);
|
||||
ModelRecommendation {
|
||||
id: scored.entry.id.as_str().to_string(),
|
||||
display_name: scored.entry.display_name,
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use tauri::Emitter;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
|
||||
use kon_hotkey::{EvdevHotkeyListener, HotkeyCombo, HotkeyEvent};
|
||||
use magnotia_hotkey::{EvdevHotkeyListener, HotkeyCombo, HotkeyEvent};
|
||||
|
||||
/// Managed state for the evdev hotkey listener.
|
||||
pub struct HotkeyState {
|
||||
@@ -30,11 +30,11 @@ pub fn is_wayland_session() -> bool {
|
||||
/// Check whether evdev hotkey capture is available (user in `input` group, etc.).
|
||||
#[tauri::command]
|
||||
pub fn check_hotkey_access() -> Result<(), String> {
|
||||
kon_hotkey::check_evdev_access()
|
||||
magnotia_hotkey::check_evdev_access()
|
||||
}
|
||||
|
||||
/// Start the evdev global hotkey listener. Emits "kon:hotkey-pressed" and
|
||||
/// "kon:hotkey-released" events to the frontend.
|
||||
/// Start the evdev global hotkey listener. Emits "magnotia:hotkey-pressed" and
|
||||
/// "magnotia:hotkey-released" events to the frontend.
|
||||
///
|
||||
/// If a listener is already running, it is stopped first.
|
||||
#[tauri::command]
|
||||
@@ -64,10 +64,10 @@ pub async fn start_evdev_hotkey(
|
||||
while let Some(event) = event_rx.recv().await {
|
||||
match event {
|
||||
HotkeyEvent::Pressed => {
|
||||
let _ = app_clone.emit("kon:hotkey-pressed", ());
|
||||
let _ = app_clone.emit("magnotia:hotkey-pressed", ());
|
||||
}
|
||||
HotkeyEvent::Released => {
|
||||
let _ = app_clone.emit("kon:hotkey-released", ());
|
||||
let _ = app_clone.emit("magnotia:hotkey-released", ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use kon_storage::{
|
||||
use magnotia_storage::{
|
||||
delete_implementation_rule as db_delete_rule, get_task_by_id,
|
||||
insert_implementation_rule as db_insert_rule, list_implementation_rules as db_list_rules,
|
||||
mark_implementation_rule_fired as db_mark_rule_fired,
|
||||
|
||||
@@ -19,13 +19,13 @@ use crate::commands::models::{default_model_id_for_engine, ensure_model_loaded};
|
||||
use crate::commands::power::PowerAssertion;
|
||||
use crate::commands::security::ensure_main_window;
|
||||
use crate::AppState;
|
||||
use kon_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
|
||||
use kon_audio::{
|
||||
use magnotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
|
||||
use magnotia_audio::{
|
||||
AudioChunk, CaptureRuntimeError, MicrophoneCapture, StreamingResampler, WavWriter,
|
||||
};
|
||||
use kon_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use kon_core::types::{AudioSamples, Segment, TranscriptionOptions};
|
||||
use kon_transcription::LocalEngine;
|
||||
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use magnotia_core::types::{AudioSamples, Segment, TranscriptionOptions};
|
||||
use magnotia_transcription::LocalEngine;
|
||||
|
||||
const CHUNK_SAMPLES: usize = 32_000; // 2s at 16kHz
|
||||
const OVERLAP_SAMPLES: usize = 4_000; // 0.25s at 16kHz
|
||||
@@ -358,7 +358,7 @@ impl LiveSessionRuntime {
|
||||
let _ = self.status_channel.send(LiveStatusMessage::Overload {
|
||||
session_id: self.session_id,
|
||||
dropped_audio_ms: self.state.dropped_audio_ms,
|
||||
message: "Kon dropped older audio to keep live dictation responsive".into(),
|
||||
message: "Magnotia dropped older audio to keep live dictation responsive".into(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ struct InferenceTask {
|
||||
chunk_start_sample: u64,
|
||||
trim_before_secs: f64,
|
||||
duration_secs: f64,
|
||||
rx: std::sync::mpsc::Receiver<Result<kon_transcription::TimedTranscript, String>>,
|
||||
rx: std::sync::mpsc::Receiver<Result<magnotia_transcription::TimedTranscript, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -503,15 +503,15 @@ pub async fn start_live_transcription_session(
|
||||
let resolved_profile_id = config
|
||||
.profile_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| kon_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
|
||||
let profile = kon_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
let profile = magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
|
||||
|
||||
let profile_terms: Vec<String> =
|
||||
kon_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.into_iter()
|
||||
@@ -657,7 +657,7 @@ fn run_live_session(
|
||||
// is a no-op. Keeping the guard in scope ties the assertion's
|
||||
// lifetime to the session — when the function returns, the Drop
|
||||
// impl lifts it. Item #9 in docs/whisper-ecosystem/brief.md.
|
||||
let _power_guard = PowerAssertion::begin("kon live dictation session");
|
||||
let _power_guard = PowerAssertion::begin("magnotia live dictation session");
|
||||
LiveSessionRuntime::new(
|
||||
session_id,
|
||||
engine,
|
||||
@@ -1554,8 +1554,8 @@ mod tests {
|
||||
let stop_flag = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let (tx1, rx1) = std::sync::mpsc::channel();
|
||||
tx1.send(Ok(kon_transcription::TimedTranscript {
|
||||
transcript: kon_core::types::Transcript::new(
|
||||
tx1.send(Ok(magnotia_transcription::TimedTranscript {
|
||||
transcript: magnotia_core::types::Transcript::new(
|
||||
vec![segment(0.0, 0.8, "first chunk")],
|
||||
"en".into(),
|
||||
0.8,
|
||||
@@ -1596,8 +1596,8 @@ mod tests {
|
||||
);
|
||||
|
||||
let (tx2, rx2) = std::sync::mpsc::channel();
|
||||
tx2.send(Ok(kon_transcription::TimedTranscript {
|
||||
transcript: kon_core::types::Transcript::new(
|
||||
tx2.send(Ok(magnotia_transcription::TimedTranscript {
|
||||
transcript: magnotia_core::types::Transcript::new(
|
||||
vec![segment(0.0, 0.9, "second chunk")],
|
||||
"en".into(),
|
||||
0.9,
|
||||
|
||||
@@ -3,10 +3,10 @@ use tauri::{Emitter, State};
|
||||
use crate::commands::power::PowerAssertion;
|
||||
use crate::commands::security::ensure_main_window;
|
||||
use crate::AppState;
|
||||
use kon_ai_formatting::{llm_cleanup_text, LlmPromptPreset};
|
||||
use kon_core::hardware;
|
||||
use kon_llm::model_manager::{self, model_info};
|
||||
use kon_llm::{ContentTags, LlmModelId};
|
||||
use magnotia_ai_formatting::{llm_cleanup_text, LlmPromptPreset};
|
||||
use magnotia_core::hardware;
|
||||
use magnotia_llm::model_manager::{self, model_info};
|
||||
use magnotia_llm::{ContentTags, LlmModelId};
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -74,7 +74,7 @@ pub async fn download_llm_model(
|
||||
0
|
||||
};
|
||||
let _ = app_clone.emit(
|
||||
"kon:llm-download-progress",
|
||||
"magnotia:llm-download-progress",
|
||||
serde_json::json!({
|
||||
"modelId": id.as_str(),
|
||||
"done": done,
|
||||
@@ -182,7 +182,7 @@ pub struct LlmTestResult {
|
||||
/// The point is that the user sees "Not enough GPU memory — pick a
|
||||
/// smaller tier" rather than a raw C++ exception bubbled up from
|
||||
/// llama.cpp. Mirrors OpenWhispr's "Test connection" UX for cloud
|
||||
/// LLMs, adapted to Kon's local stack.
|
||||
/// LLMs, adapted to Magnotia's local stack.
|
||||
#[tauri::command]
|
||||
pub async fn test_llm_model(
|
||||
window: tauri::WebviewWindow,
|
||||
@@ -293,7 +293,7 @@ fn classify_llm_load_error(raw: &str) -> (&'static str, &'static str) {
|
||||
} else if lower.contains("permission denied") || lower.contains("access is denied") {
|
||||
(
|
||||
"load-failed-permission",
|
||||
"Permission denied reading the model file. Check ownership of ~/.kon/models/llm/.",
|
||||
"Permission denied reading the model file. Check ownership of ~/.magnotia/models/llm/.",
|
||||
)
|
||||
} else {
|
||||
(
|
||||
@@ -369,9 +369,9 @@ pub async fn cleanup_transcript_text_cmd(
|
||||
) -> Result<String, String> {
|
||||
ensure_main_window(&window)?;
|
||||
let resolved_profile_id =
|
||||
profile_id.unwrap_or_else(|| kon_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
let profile_terms: Vec<String> =
|
||||
kon_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.into_iter()
|
||||
@@ -391,7 +391,7 @@ pub async fn cleanup_transcript_text_cmd(
|
||||
// macOS: pin a power assertion for the duration of the LLM
|
||||
// generation so App Nap can't decide to throttle us mid-token.
|
||||
// No-op on every other OS. Item #9.
|
||||
let _power_guard = PowerAssertion::begin("kon LLM cleanup");
|
||||
let _power_guard = PowerAssertion::begin("magnotia LLM cleanup");
|
||||
llm_cleanup_text(&engine, &transcript, &profile_terms, resolved_preset)
|
||||
})
|
||||
.await
|
||||
@@ -414,7 +414,7 @@ pub async fn extract_content_tags_cmd(
|
||||
}
|
||||
let engine = state.llm_engine.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let _power_guard = PowerAssertion::begin("kon LLM content-tag extraction");
|
||||
let _power_guard = PowerAssertion::begin("magnotia LLM content-tag extraction");
|
||||
engine.extract_content_tags(&transcript)
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
||||
use kon_core::process_watch::{self, ProcessLister};
|
||||
use magnotia_core::process_watch::{self, ProcessLister};
|
||||
|
||||
/// Tauri-managed state for the meeting poller. Holds a long-lived
|
||||
/// `ProcessLister` so each poll refreshes the existing `sysinfo::System`
|
||||
|
||||
@@ -5,14 +5,14 @@ use tauri::Emitter;
|
||||
|
||||
use crate::commands::security::ensure_main_window;
|
||||
use crate::AppState;
|
||||
use kon_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use kon_core::hardware::{self, CpuFeatures};
|
||||
use kon_core::model_registry::{self, Engine, LanguageSupport, ModelEntry};
|
||||
use kon_core::types::{AudioSamples, ModelId, TranscriptionOptions};
|
||||
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use magnotia_core::hardware::{self, CpuFeatures};
|
||||
use magnotia_core::model_registry::{self, Engine, LanguageSupport, ModelEntry};
|
||||
use magnotia_core::types::{AudioSamples, ModelId, TranscriptionOptions};
|
||||
#[cfg(feature = "whisper")]
|
||||
use kon_transcription::load_whisper;
|
||||
use kon_transcription::model_manager;
|
||||
use kon_transcription::{load_parakeet, LocalEngine, Transcriber};
|
||||
use magnotia_transcription::load_whisper;
|
||||
use magnotia_transcription::model_manager;
|
||||
use magnotia_transcription::{load_parakeet, LocalEngine, Transcriber};
|
||||
|
||||
/// Map legacy size strings to ModelId.
|
||||
fn whisper_model_id(size: &str) -> ModelId {
|
||||
@@ -94,7 +94,7 @@ pub fn load_model_from_disk(model_id: &ModelId) -> Result<Box<dyn Transcriber +
|
||||
}
|
||||
#[cfg(not(feature = "whisper"))]
|
||||
Engine::Whisper => Err(format!(
|
||||
"Whisper backend not compiled in this build (kon built without the \"whisper\" feature); \
|
||||
"Whisper backend not compiled in this build (magnotia built without the \"whisper\" feature); \
|
||||
cannot load {model_id}"
|
||||
)),
|
||||
Engine::Parakeet => {
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn deliver_nudge(
|
||||
|
||||
app.notification()
|
||||
.builder()
|
||||
.title(if title.is_empty() { "Corbie" } else { title })
|
||||
.title(if title.is_empty() { "Magnotia" } else { title })
|
||||
.body(body)
|
||||
.show()
|
||||
.map_err(|e| format!("notification delivery failed: {e}"))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//! ydotool / osascript / SendKeys), so we probe and fall back.
|
||||
//!
|
||||
//! NOTE: focus must already be on the target window when the keystroke
|
||||
//! fires. The global hotkey flow preserves this naturally; clicking Kon's
|
||||
//! fires. The global hotkey flow preserves this naturally; clicking Magnotia's
|
||||
//! window does not. The frontend surfaces this caveat next to the toggle.
|
||||
|
||||
use std::process::Command;
|
||||
@@ -57,10 +57,10 @@ pub struct PasteOutcome {
|
||||
/// focused window. Returns a structured result so the frontend can surface
|
||||
/// partial success (clipboard set, paste failed).
|
||||
///
|
||||
/// Wayland compositor quirk: if Kon's always-on-top preview overlay is
|
||||
/// Wayland compositor quirk: if Magnotia's always-on-top preview overlay is
|
||||
/// visible when the keystroke fires, KWin / Mutter may resolve the keystroke
|
||||
/// against the overlay (even with `focused: false` set at build time) and
|
||||
/// the paste lands inside Kon instead of the previously-focused app. We hide
|
||||
/// the paste lands inside Magnotia instead of the previously-focused app. We hide
|
||||
/// the preview window and give the compositor a beat to re-focus the real
|
||||
/// target before dispatching. Matches OpenWhispr's PR #246 fix on GNOME.
|
||||
#[tauri::command]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Tauri commands wrapping kon_storage profile + profile_term CRUD.
|
||||
// Pattern mirrors tasks.rs — flat imports from `kon_storage` with a `db_`
|
||||
// Tauri commands wrapping magnotia_storage profile + profile_term CRUD.
|
||||
// Pattern mirrors tasks.rs — flat imports from `magnotia_storage` with a `db_`
|
||||
// alias prefix to avoid name collisions with the command functions, plain
|
||||
// snake_case parameters (Tauri 2.x auto-converts camelCase JS keys),
|
||||
// `.map_err(|e| e.to_string())` for error conversion, and camelCase DTOs
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use kon_ai_formatting::extract_corrections;
|
||||
use kon_storage::{
|
||||
use magnotia_ai_formatting::extract_corrections;
|
||||
use magnotia_storage::{
|
||||
add_profile_term as db_add_profile_term, create_profile as db_create_profile,
|
||||
delete_profile as db_delete_profile, delete_profile_term as db_delete_profile_term,
|
||||
get_profile as db_get_profile, list_profile_terms as db_list_profile_terms,
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
//! filtering rather than adding a second query path.
|
||||
//!
|
||||
//! Stored under the existing SQLite settings table via
|
||||
//! `kon_storage::{get_setting, set_setting}` — same bag as
|
||||
//! `kon_preferences`.
|
||||
//! `magnotia_storage::{get_setting, set_setting}` — same bag as
|
||||
//! `magnotia_preferences`.
|
||||
|
||||
use kon_storage::{get_setting, set_setting};
|
||||
use magnotia_storage::{get_setting, set_setting};
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
const LAST_TRIAGE_KEY: &str = "kon_morning_triage_last_shown";
|
||||
const LAST_TRIAGE_KEY: &str = "magnotia_morning_triage_last_shown";
|
||||
|
||||
/// Returns the YYYY-MM-DD date string stored on the last successful
|
||||
/// morning triage dismissal, or `None` if the user has never been
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Tauri commands wrapping kon_storage task CRUD.
|
||||
// Tauri commands wrapping magnotia_storage task CRUD.
|
||||
// Pattern mirrors transcripts.rs — TaskDto is the camelCase frontend shape,
|
||||
// storage functions are aliased with db_ prefix to avoid name collisions.
|
||||
|
||||
@@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use kon_llm::prompts::FeedbackExample as LlmFeedbackExample;
|
||||
use kon_storage::{
|
||||
use magnotia_llm::prompts::FeedbackExample as LlmFeedbackExample;
|
||||
use magnotia_storage::{
|
||||
complete_subtask_and_check_parent as db_complete_subtask, complete_task as db_complete_task,
|
||||
delete_task as db_delete_task, get_task_by_id as db_get_task,
|
||||
insert_subtask as db_insert_subtask, insert_task as db_insert_task,
|
||||
|
||||
@@ -11,9 +11,9 @@ use crate::commands::build_initial_prompt;
|
||||
use crate::commands::models::{default_model_id_for_engine, ensure_model_loaded};
|
||||
use crate::commands::security::ensure_main_window;
|
||||
use crate::AppState;
|
||||
use kon_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
|
||||
use kon_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use kon_core::types::{AudioSamples, Segment, Transcript, TranscriptionOptions};
|
||||
use magnotia_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions};
|
||||
use magnotia_core::constants::WHISPER_SAMPLE_RATE;
|
||||
use magnotia_core::types::{AudioSamples, Segment, Transcript, TranscriptionOptions};
|
||||
|
||||
const PARAKEET_CHUNK_THRESHOLD_SECS: usize = 18;
|
||||
const PARAKEET_CHUNK_SECS: usize = 15;
|
||||
@@ -31,7 +31,7 @@ struct ChunkingStrategy {
|
||||
fn pick_engine(
|
||||
state: &AppState,
|
||||
engine: &str,
|
||||
) -> Result<Arc<kon_transcription::LocalEngine>, String> {
|
||||
) -> Result<Arc<magnotia_transcription::LocalEngine>, String> {
|
||||
match engine {
|
||||
"whisper" => Ok(state.whisper_engine.clone()),
|
||||
"parakeet" => Ok(state.parakeet_engine.clone()),
|
||||
@@ -72,11 +72,11 @@ fn trim_overlap_segments(segments: &mut Vec<Segment>, trim_before_secs: f64) {
|
||||
}
|
||||
|
||||
fn transcribe_samples_sync(
|
||||
engine: Arc<kon_transcription::LocalEngine>,
|
||||
engine: Arc<magnotia_transcription::LocalEngine>,
|
||||
engine_name: &str,
|
||||
samples: Vec<f32>,
|
||||
options: TranscriptionOptions,
|
||||
) -> Result<kon_transcription::TimedTranscript, String> {
|
||||
) -> Result<magnotia_transcription::TimedTranscript, String> {
|
||||
let Some(strategy) = pick_chunking_strategy(engine_name, samples.len()) else {
|
||||
let audio = AudioSamples::mono_16khz(samples);
|
||||
return engine
|
||||
@@ -127,7 +127,7 @@ fn transcribe_samples_sync(
|
||||
chunk_start = chunk_end.saturating_sub(strategy.overlap_samples);
|
||||
}
|
||||
|
||||
Ok(kon_transcription::TimedTranscript {
|
||||
Ok(magnotia_transcription::TimedTranscript {
|
||||
transcript: Transcript::new(
|
||||
all_segments,
|
||||
options.language.clone().unwrap_or_else(|| "en".to_string()),
|
||||
@@ -155,15 +155,15 @@ pub async fn transcribe_pcm(
|
||||
) -> Result<(), String> {
|
||||
ensure_main_window(&window)?;
|
||||
let resolved_profile_id =
|
||||
profile_id.unwrap_or_else(|| kon_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
|
||||
let profile = kon_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
let profile = magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
|
||||
|
||||
let profile_terms: Vec<String> =
|
||||
kon_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.into_iter()
|
||||
@@ -249,15 +249,15 @@ pub async fn transcribe_file(
|
||||
) -> Result<serde_json::Value, String> {
|
||||
ensure_main_window(&window)?;
|
||||
let resolved_profile_id =
|
||||
profile_id.unwrap_or_else(|| kon_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
|
||||
let profile = kon_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
let profile = magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
|
||||
|
||||
let profile_terms: Vec<String> =
|
||||
kon_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.into_iter()
|
||||
@@ -283,23 +283,23 @@ pub async fn transcribe_file(
|
||||
let engine_name_for_worker = engine_name.clone();
|
||||
let path_for_probe = Path::new(&path);
|
||||
if let Some(duration_secs) =
|
||||
kon_audio::probe_audio_duration_secs(path_for_probe).map_err(|e| e.to_string())?
|
||||
magnotia_audio::probe_audio_duration_secs(path_for_probe).map_err(|e| e.to_string())?
|
||||
{
|
||||
if duration_secs > MAX_FILE_TRANSCRIPTION_SECS {
|
||||
return Err(format!(
|
||||
"File is {:.1} hours long. Kon imports up to 2 hours at a time.",
|
||||
"File is {:.1} hours long. Magnotia imports up to 2 hours at a time.",
|
||||
duration_secs / 3600.0
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let timed = tokio::task::spawn_blocking(move || {
|
||||
let audio = kon_audio::decode_audio_file_limited(
|
||||
let audio = magnotia_audio::decode_audio_file_limited(
|
||||
Path::new(&path),
|
||||
Some(MAX_FILE_TRANSCRIPTION_SECS),
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let resampled = kon_audio::resample_to_16khz(&audio).map_err(|e| e.to_string())?;
|
||||
let resampled = magnotia_audio::resample_to_16khz(&audio).map_err(|e| e.to_string())?;
|
||||
transcribe_samples_sync(
|
||||
engine,
|
||||
&engine_name_for_worker,
|
||||
@@ -353,17 +353,17 @@ pub async fn transcribe_pcm_parakeet(
|
||||
) -> Result<(), String> {
|
||||
ensure_main_window(&window)?;
|
||||
let resolved_profile_id =
|
||||
profile_id.unwrap_or_else(|| kon_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
profile_id.unwrap_or_else(|| magnotia_storage::DEFAULT_PROFILE_ID.to_string());
|
||||
|
||||
// Validate the profile exists so parakeet and whisper behave identically
|
||||
// when a bogus id slips through from the frontend.
|
||||
kon_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::get_profile(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| format!("Profile {resolved_profile_id} not found"))?;
|
||||
|
||||
let profile_terms: Vec<String> =
|
||||
kon_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
magnotia_storage::database::list_profile_terms(&state.db, &resolved_profile_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.into_iter()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Tauri commands wrapping the kon_storage transcript CRUD.
|
||||
// Tauri commands wrapping the magnotia_storage transcript CRUD.
|
||||
// These are the bridge that lets the Svelte frontend treat SQLite as the
|
||||
// canonical store rather than localStorage.
|
||||
//
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use kon_storage::{
|
||||
use magnotia_storage::{
|
||||
count_transcripts, delete_transcript as db_delete_transcript,
|
||||
get_transcript as db_get_transcript, insert_transcript as db_insert_transcript,
|
||||
list_transcripts_paged, search_transcripts as db_search_transcripts,
|
||||
@@ -29,7 +29,7 @@ use crate::AppState;
|
||||
///
|
||||
/// Task 2.5 — `starred`, `manualTags`, `template`, `language`, `segmentsJson`
|
||||
/// were added to back the viewer metadata that previously lived only in the
|
||||
/// removed `kon_history` localStorage cache.
|
||||
/// removed `magnotia_history` localStorage cache.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TranscriptDto {
|
||||
@@ -111,7 +111,7 @@ pub async fn add_transcript(
|
||||
profile_id: transcript
|
||||
.profile_id
|
||||
.as_deref()
|
||||
.unwrap_or(kon_storage::DEFAULT_PROFILE_ID),
|
||||
.unwrap_or(magnotia_storage::DEFAULT_PROFILE_ID),
|
||||
title: transcript.title.as_deref(),
|
||||
audio_path: transcript.audio_path.as_deref(),
|
||||
duration: transcript.duration,
|
||||
|
||||
@@ -60,7 +60,7 @@ pub async fn open_task_window(app: tauri::AppHandle) -> Result<(), String> {
|
||||
|
||||
let mut builder =
|
||||
WebviewWindowBuilder::new(&app, "tasks-float", WebviewUrl::App("/float".into()))
|
||||
.title("Kon Tasks")
|
||||
.title("Magnotia Tasks")
|
||||
.inner_size(480.0, 520.0)
|
||||
.min_inner_size(360.0, 480.0)
|
||||
.always_on_top(true)
|
||||
@@ -113,7 +113,7 @@ pub async fn open_preview_window(app: tauri::AppHandle) -> Result<(), String> {
|
||||
"transcription-preview",
|
||||
WebviewUrl::App("/preview".into()),
|
||||
)
|
||||
.title("Kon — Preview")
|
||||
.title("Magnotia — Preview")
|
||||
.inner_size(420.0, 200.0)
|
||||
.min_inner_size(360.0, 140.0)
|
||||
.max_inner_size(520.0, 360.0)
|
||||
@@ -178,7 +178,7 @@ pub async fn open_viewer_window(app: tauri::AppHandle) -> Result<(), String> {
|
||||
|
||||
let mut builder =
|
||||
WebviewWindowBuilder::new(&app, "transcript-viewer", WebviewUrl::App("/viewer".into()))
|
||||
.title("Kon - Transcription Editor")
|
||||
.title("Magnotia - Transcription Editor")
|
||||
.inner_size(600.0, 700.0)
|
||||
.min_inner_size(560.0, 520.0)
|
||||
.decorations(use_native_decorations)
|
||||
|
||||
@@ -10,9 +10,9 @@ use std::time::Instant;
|
||||
use sqlx::SqlitePool;
|
||||
use tauri::Manager;
|
||||
|
||||
use kon_core::types::EngineName;
|
||||
use kon_llm::LlmEngine;
|
||||
use kon_storage::{
|
||||
use magnotia_core::types::EngineName;
|
||||
use magnotia_llm::LlmEngine;
|
||||
use magnotia_storage::{
|
||||
database_path, get_setting, init as init_db, prune_error_log, set_setting,
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ use kon_storage::{
|
||||
/// 90 days is long enough to triage "this happened a few weeks ago"
|
||||
/// reports and short enough that the table stays kilobyte-scale.
|
||||
const ERROR_LOG_RETENTION_DAYS: i64 = 90;
|
||||
use kon_transcription::LocalEngine;
|
||||
use magnotia_transcription::LocalEngine;
|
||||
|
||||
/// Shared app state holding the transcription engines and database pool.
|
||||
pub struct AppState {
|
||||
@@ -75,7 +75,7 @@ async fn save_preferences(
|
||||
state: tauri::State<'_, AppState>,
|
||||
preferences: String,
|
||||
) -> Result<(), String> {
|
||||
set_setting(&state.db, "kon_preferences", &preferences)
|
||||
set_setting(&state.db, "magnotia_preferences", &preferences)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
@@ -197,7 +197,7 @@ pub fn run() {
|
||||
// Load saved preferences for webview injection
|
||||
let t1 = Instant::now();
|
||||
let prefs_json = tauri::async_runtime::block_on(async {
|
||||
get_setting(&db, "kon_preferences").await.unwrap_or(None)
|
||||
get_setting(&db, "magnotia_preferences").await.unwrap_or(None)
|
||||
});
|
||||
eprintln!("[startup] Preferences load: {:?}", t1.elapsed());
|
||||
let init_script = build_preferences_script(prefs_json);
|
||||
@@ -439,5 +439,5 @@ pub fn run() {
|
||||
commands::update::install_update,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running Kon");
|
||||
.expect("error while running Magnotia");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
kon_lib::run()
|
||||
magnotia_lib::run()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use tauri::tray::TrayIconBuilder;
|
||||
use tauri::{Emitter, Manager};
|
||||
|
||||
pub fn setup(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let show = MenuItemBuilder::with_id("show", "Show Kon").build(app)?;
|
||||
let show = MenuItemBuilder::with_id("show", "Show Magnotia").build(app)?;
|
||||
let status = MenuItemBuilder::with_id("status", "Ready")
|
||||
.enabled(false)
|
||||
.build(app)?;
|
||||
@@ -32,7 +32,7 @@ pub fn setup(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let _tray = TrayIconBuilder::new()
|
||||
.icon(icon)
|
||||
.tooltip("Kon — Ready")
|
||||
.tooltip("Magnotia — Ready")
|
||||
.menu(&menu)
|
||||
.on_menu_event(move |app, event| match event.id().as_ref() {
|
||||
"show" => {
|
||||
@@ -48,7 +48,7 @@ pub fn setup(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
// The frontend layout listens for this event and routes
|
||||
// to the Phase 5 wind-down page.
|
||||
let _ = app.emit("kon:open-wind-down", ());
|
||||
let _ = app.emit("magnotia:open-wind-down", ());
|
||||
}
|
||||
"quit" => {
|
||||
app.exit(0);
|
||||
|
||||
Reference in New Issue
Block a user