2026-03-25 01:22:30 -06:00
|
|
|
// --- Commands ---
|
|
|
|
|
|
2026-03-26 00:58:57 -06:00
|
|
|
mod transcription;
|
|
|
|
|
|
2026-03-25 01:22:30 -06:00
|
|
|
/// Returns the backend URL. Stubbed for now; will be replaced once the
|
|
|
|
|
/// Python/Rust backend is fully wired up.
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
fn get_backend_url() -> String {
|
|
|
|
|
// During development the Python backend still runs on 8642.
|
|
|
|
|
// In production this will be replaced with a local Rust server or IPC.
|
|
|
|
|
"http://localhost:8642".to_string()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Minimal encrypt: base64-encodes the string as a placeholder until a proper
|
|
|
|
|
/// OS keychain implementation is added (e.g. tauri-plugin-stronghold).
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
fn encrypt_string(data: String) -> String {
|
2026-03-25 01:41:40 -06:00
|
|
|
data
|
2026-03-25 01:22:30 -06:00
|
|
|
.as_bytes()
|
|
|
|
|
.iter()
|
|
|
|
|
.fold(String::new(), |mut acc, b| {
|
|
|
|
|
use std::fmt::Write as FmtWrite;
|
|
|
|
|
let _ = write!(acc, "{:02x}", b);
|
|
|
|
|
acc
|
2026-03-25 01:41:40 -06:00
|
|
|
})
|
2026-03-25 01:22:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Companion decode for encrypt_string.
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
fn decrypt_string(encrypted: String) -> Result<String, String> {
|
2026-03-25 01:41:40 -06:00
|
|
|
(0..encrypted.len())
|
2026-03-25 01:22:30 -06:00
|
|
|
.step_by(2)
|
|
|
|
|
.map(|i| u8::from_str_radix(&encrypted[i..i + 2], 16))
|
2026-03-25 01:41:40 -06:00
|
|
|
.collect::<Result<Vec<u8>, _>>()
|
2026-03-25 01:22:30 -06:00
|
|
|
.map_err(|e| format!("decrypt error: {e}"))
|
|
|
|
|
.and_then(|b| String::from_utf8(b).map_err(|e| format!("utf8 error: {e}")))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 00:58:57 -06:00
|
|
|
/// Ensure a Whisper model is downloaded, downloading it if not present.
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
async fn ensure_model(model_name: String) -> Result<String, String> {
|
|
|
|
|
tauri::async_runtime::spawn_blocking(move || {
|
|
|
|
|
transcription::ensure_model_downloaded(&model_name)
|
|
|
|
|
})
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| format!("Task error: {:?}", e))?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transcribe audio file using Whisper.cpp (runs on a background thread)
|
|
|
|
|
#[tauri::command]
|
|
|
|
|
async fn transcribe_audio(file_path: String, model_name: String, language: Option<String>) -> Result<transcription::TranscriptionResult, String> {
|
|
|
|
|
tauri::async_runtime::spawn_blocking(move || {
|
|
|
|
|
transcription::transcribe_audio(&file_path, &model_name, language.as_deref())
|
|
|
|
|
})
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| format!("Task error: {:?}", e))?
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:22:30 -06:00
|
|
|
// --- App entry point ---
|
|
|
|
|
|
2026-03-24 23:55:29 -06:00
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
|
|
|
pub fn run() {
|
2026-03-25 01:22:30 -06:00
|
|
|
tauri::Builder::default()
|
|
|
|
|
.plugin(tauri_plugin_dialog::init())
|
|
|
|
|
.plugin(tauri_plugin_fs::init())
|
|
|
|
|
.setup(|app| {
|
|
|
|
|
if cfg!(debug_assertions) {
|
|
|
|
|
app.handle().plugin(
|
|
|
|
|
tauri_plugin_log::Builder::default()
|
|
|
|
|
.level(log::LevelFilter::Info)
|
|
|
|
|
.build(),
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
.invoke_handler(tauri::generate_handler![
|
|
|
|
|
get_backend_url,
|
|
|
|
|
encrypt_string,
|
|
|
|
|
decrypt_string,
|
2026-03-26 00:58:57 -06:00
|
|
|
ensure_model,
|
|
|
|
|
transcribe_audio,
|
2026-03-25 01:22:30 -06:00
|
|
|
])
|
|
|
|
|
.run(tauri::generate_context!())
|
|
|
|
|
.expect("error while running tauri application");
|
2026-03-24 23:55:29 -06:00
|
|
|
}
|