From be49bc4374714c2cc38e5347e693662ef8759c7a Mon Sep 17 00:00:00 2001 From: Jake Date: Sat, 25 Apr 2026 19:48:10 +0100 Subject: [PATCH] feat(auto-title): generate_title_cmd Tauri wrapper + register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bridge LlmEngine::generate_title across the Tauri boundary. Same shape as the existing extract_content_tags_cmd — `is_loaded` short-circuit so the frontend can detect the "no model" case without firing a synchronous inference, then spawn_blocking + PowerAssertion guard for the heavy work. - src-tauri/src/commands/llm.rs: new generate_title_cmd that wraps `state.llm_engine.generate_title(transcript)`. Returns Result — the engine's own InvalidJson / Inference / PromptTooLong errors are stringified at the boundary, same pattern as extract_content_tags_cmd at line 408. - src-tauri/src/lib.rs: register the command in invoke_handler!, immediately after extract_content_tags_cmd in the LLM block. Verified: `cargo check -p kon` passes after a `rm -rf target/.../tauri-*` to clear stale OUT_DIR paths from the project's pre-rename location (transcription-app used to live at ~/CORBEL-Projects/kon/). No code behaviour change from that cleanup — Cargo just needed the cache rebuilt. The frontend wiring follows in the next commit. --- src-tauri/src/commands/llm.rs | 34 ++++++++++++++++++++++++++++++++++ src-tauri/src/lib.rs | 2 ++ 2 files changed, 36 insertions(+) diff --git a/src-tauri/src/commands/llm.rs b/src-tauri/src/commands/llm.rs index e83183a..2689d21 100644 --- a/src-tauri/src/commands/llm.rs +++ b/src-tauri/src/commands/llm.rs @@ -421,3 +421,37 @@ pub async fn extract_content_tags_cmd( .map_err(|e| e.to_string())? .map_err(|e| e.to_string()) } + +/// Auto-generate a 4-8 word title for a transcript. Mirrors the +/// `extract_content_tags_cmd` shape: `is_loaded` short-circuit, then +/// `spawn_blocking` for the synchronous llama-cpp generation, with +/// the same `PowerAssertion` guard used by the other LLM paths. +/// +/// Two callers expected: +/// 1. Frontend `addToHistory` — fires this fire-and-forget after a +/// successful save, gated on the same `aiTier !== "off"` / +/// `formatMode !== "Raw"` conditions that drive auto-cleanup. +/// 2. HistoryPage per-row + bulk on-demand button — explicit user +/// trigger for retroactively titling old transcripts. +/// +/// Returns the post-sanitised title; an `Err` from +/// `LlmEngine::generate_title` (empty transcript, model output that +/// sanitises to nothing) is propagated as a string so the frontend +/// can surface it in the bulk progress UI. +#[tauri::command] +pub async fn generate_title_cmd( + state: State<'_, AppState>, + transcript: String, +) -> Result { + if !state.llm_engine.is_loaded() { + return Err("LLM not loaded. Download an AI model in Settings.".to_string()); + } + let engine = state.llm_engine.clone(); + tokio::task::spawn_blocking(move || { + let _power_guard = PowerAssertion::begin("kon LLM title generation"); + engine.generate_title(&transcript) + }) + .await + .map_err(|e| e.to_string())? + .map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0bf9b65..b7c8b31 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -419,6 +419,8 @@ pub fn run() { commands::fs::write_text_file_cmd, // LLM content tags (Phase 9) commands::llm::extract_content_tags_cmd, + // Auto-title generation (also via per-row + bulk in History) + commands::llm::generate_title_cmd, // Paste (auto-insert at cursor) commands::paste::paste_text, commands::paste::paste_text_replacing,