feat(kon): add full transcript provenance — enriched schema, metadata pipeline, error log

Schema enrichment:
- transcripts table: +engine, +model_id, +inference_ms, +sample_rate, +audio_channels,
  +format_mode, +remove_fillers, +british_english, +anti_hallucination
- New error_log table: context, error_code, message, metadata (JSON)
- 5 indices on frequently queried columns

Metadata pipeline:
- TranscriptMetadata struct in kon-core for full provenance capture
- LocalEngine tracks loaded ModelId, returns TimedTranscript with inference_ms
- std::time::Instant timing around transcribe-rs inference calls
- Tauri transcription commands emit inference_ms in event payloads
- InsertTranscriptParams accepts all provenance fields
- log_error() for structured error logging to SQLite

Every transcript is now fully reproducible from its stored metadata.
23 tests passing, clippy clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jake
2026-03-16 21:36:44 +00:00
parent 29ff91d3f6
commit 292f9716ff
9 changed files with 276 additions and 100 deletions

View File

@@ -1,9 +1,9 @@
use std::sync::Arc;
use kon_core::error::{KonError, Result};
use kon_core::types::{AudioSamples, Transcript, TranscriptionOptions};
use kon_core::types::{AudioSamples, TranscriptionOptions};
use crate::local_engine::LocalEngine;
use crate::local_engine::{LocalEngine, TimedTranscript};
/// Runs inference on a blocking thread. Encapsulates all threading concerns.
/// Callers never see spawn_blocking — they call this async function.
@@ -11,10 +11,12 @@ pub async fn run_inference(
engine: Arc<LocalEngine>,
audio: AudioSamples,
options: TranscriptionOptions,
) -> Result<Transcript> {
) -> Result<TimedTranscript> {
tokio::task::spawn_blocking(move || {
engine.transcribe_sync(&audio, &options)
})
.await
.map_err(|e| KonError::TranscriptionFailed(format!("Task join error: {e}")))?
.map_err(|e| {
KonError::TranscriptionFailed(format!("Task join error: {e}"))
})?
}