feat(auto-title): generate_title_cmd Tauri wrapper + register

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<String, String> — 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.
This commit is contained in:
2026-04-25 19:48:10 +01:00
parent 3410d3c586
commit be49bc4374
2 changed files with 36 additions and 0 deletions

View File

@@ -421,3 +421,37 @@ pub async fn extract_content_tags_cmd(
.map_err(|e| e.to_string())? .map_err(|e| e.to_string())?
.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<String, String> {
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())
}

View File

@@ -419,6 +419,8 @@ pub fn run() {
commands::fs::write_text_file_cmd, commands::fs::write_text_file_cmd,
// LLM content tags (Phase 9) // LLM content tags (Phase 9)
commands::llm::extract_content_tags_cmd, 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) // Paste (auto-insert at cursor)
commands::paste::paste_text, commands::paste::paste_text,
commands::paste::paste_text_replacing, commands::paste::paste_text_replacing,