feat: persist transcripts permanently

This commit is contained in:
2026-01-29 13:21:51 -08:00
parent 43a544a886
commit 9bf92d3365
4 changed files with 457 additions and 42 deletions
+83
View File
@@ -12,11 +12,13 @@ use tauri::{Emitter, Manager, State};
use tracing::{debug, info};
pub mod ml;
pub mod storage;
use ml::summarizer::{get_model_filename, LlamaSummarizer};
use ml::transcriber::{TranscriptSegment, WhisperTranscriber};
use ml::vad::SpeakerSeparator;
use ml::audio::AudioCapture;
use storage::{RecordingStorage, StoredRecording};
/// Application state containing the ML models and audio capture.
struct AppState {
@@ -25,6 +27,7 @@ struct AppState {
speaker_separator: Mutex<Option<SpeakerSeparator>>,
audio_capture: Mutex<Option<AudioCapture>>,
logs: Arc<Mutex<Vec<String>>>,
storage: Mutex<Option<RecordingStorage>>,
}
impl AppState {
@@ -35,6 +38,7 @@ impl AppState {
speaker_separator: Mutex::new(None),
audio_capture: Mutex::new(None),
logs: Arc::new(Mutex::new(Vec::new())),
storage: Mutex::new(None),
}
}
}
@@ -273,6 +277,20 @@ async fn initialize_models(
}
}
// Initialize storage
emit_log(&app_handle, &logs, "[Init] Initializing recording storage...");
if let Ok(app_data_dir) = app_handle.path().app_data_dir() {
match RecordingStorage::new(&app_data_dir) {
Ok(storage) => {
*state.storage.lock() = Some(storage);
emit_log(&app_handle, &logs, "[Init] Recording storage initialized successfully");
}
Err(e) => {
emit_log(&app_handle, &logs, &format!("[Init WARNING] Storage initialization failed: {}", e));
}
}
}
emit_log(&app_handle, &logs, "[Init] Model initialization complete");
Ok("Models initialized".to_string())
}
@@ -501,6 +519,67 @@ fn check_ready(state: State<'_, AppState>) -> Result<bool, String> {
Ok(ready)
}
/// Save a recording to persistent storage.
#[tauri::command]
fn save_recording(
state: State<'_, AppState>,
recording: StoredRecording,
) -> Result<(), String> {
let storage_guard = state.storage.lock();
let storage = storage_guard.as_ref()
.ok_or("Storage not initialized")?;
storage.save_recording(&recording)
.map_err(|e| format!("Failed to save recording: {}", e))?;
Ok(())
}
/// Load all recordings from persistent storage.
#[tauri::command]
fn load_recordings(
state: State<'_, AppState>,
) -> Result<Vec<StoredRecording>, String> {
let storage_guard = state.storage.lock();
let storage = storage_guard.as_ref()
.ok_or("Storage not initialized")?;
storage.load_all_recordings()
.map_err(|e| format!("Failed to load recordings: {}", e))
}
/// Delete a recording from persistent storage.
#[tauri::command]
fn delete_recording(
state: State<'_, AppState>,
recording_id: String,
) -> Result<(), String> {
let storage_guard = state.storage.lock();
let storage = storage_guard.as_ref()
.ok_or("Storage not initialized")?;
storage.delete_recording(&recording_id)
.map_err(|e| format!("Failed to delete recording: {}", e))?;
Ok(())
}
/// Update a recording (e.g., to add summary).
#[tauri::command]
fn update_recording(
state: State<'_, AppState>,
recording: StoredRecording,
) -> Result<(), String> {
let storage_guard = state.storage.lock();
let storage = storage_guard.as_ref()
.ok_or("Storage not initialized")?;
storage.update_recording(&recording)
.map_err(|e| format!("Failed to update recording: {}", e))?;
Ok(())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
// Initialize tracing
@@ -523,6 +602,10 @@ pub fn run() {
summarize,
get_backend_logs,
check_ready,
save_recording,
load_recordings,
delete_recording,
update_recording,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");