Commit Graph

19 Commits

Author SHA1 Message Date
ce2b4fdac6 feat(ai B.1 #15 + A.1 #28): cleanup presets and sequential-GPU guard
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Two new Settings → AI knobs that compose cleanly with what already
shipped (aiTier, LLM model, translator prompt framing).

**B.1 #15 — Named cleanup presets.** LlmPromptPreset enum
(Default / Email / Notes / Code) appends a short context hint onto
the CLEANUP_PROMPT just before generation. Presets shape tone and
structure ("email paragraph", "bulleted meeting notes", "preserve
technical terms") without licensing the content-editing the
translator-not-editor framing forbids. cleanup_transcript_text_cmd
now takes `preset: Option<String>` which runs through the new
LlmPromptPreset::parse (normalises aliases like "meeting-notes",
collapses unknown values to Default).

**A.1 #28 — Sequential-GPU guard.** New LocalEngine::unload drops
the backend + model_id so a subsequent load actually reclaims VRAM.
load_llm_model, load_model, and load_parakeet_model Tauri commands
grow an optional `concurrent: bool` argument. When concurrent is
Some(false), loading LLM first unloads whisper+parakeet, and vice
versa — prevents VRAM OOM on tight-VRAM setups. Default is the
previous parallel behaviour so nothing changes for multi-GB cards.
Transcribe-in-progress paths (transcribe_pcm, transcribe_file, live)
pass None, so mid-dictation model loads don't accidentally tear
down the LLM.

Settings UI (AI section):
- Cleanup preset segmented button + descriptive copy for each option.
- GPU concurrency segmented button with explicit trade-off text
  ("faster transitions vs fits in tight VRAM").

Frontend wiring:
- settings.llmPromptPreset flows from DictationPage's
  cleanupTranscriptIfEnabled into the Tauri command.
- settings.aiGpuConcurrency flows from both DictationPage (auto-load
  on record) and SettingsPage (manual load/unload buttons) as
  `concurrent: "parallel" === true` to the load commands.

Tests: three new preset cases in crates/ai-formatting/src/llm_client.rs
(parse aliases, suffix non-empty for non-default, default suffix
empty). All 139 existing lib tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:12:48 +01:00
Cursor Agent
9266bf5463 feat(A.1 #8): harden transcription model downloads with sha + resume tests
Ports the kon-llm model_manager resume pattern the rest of the way
into kon-transcription::model_manager:
  - download() now validates an existing complete file against its
    sha256 before skipping; a hash mismatch removes the file and
    re-fetches, instead of serving a corrupt file to whisper.cpp.
  - download_file() now distinguishes 206 Partial Content, 200 OK
    (resume silently ignored by server), and other statuses, rather
    than treating any non-206 as 'just use it as a fresh start'.
    200-on-Range is handled by discarding the partial and starting
    over cleanly.
  - New tests: download_file_resumes_from_partial_and_verifies_sha
    (TcpListener fixture, same shape as kon-llm's), and
    download_file_fails_on_sha_mismatch_and_cleans_part_file.
  - sha256_of_file helper + unit test for the existing-file guard.

Dev-deps: tempfile + tokio(net/io-util/macros). Total workspace
lib-test count: 116 → 123.

Co-authored-by: jars <jakejars@users.noreply.github.com>
2026-04-21 15:54:15 +01:00
Cursor Agent
1bb39699f5 feat(A.1 #6): fail Windows build when tokenizers enters the dep graph
Adds a build.rs guard that parses Cargo.lock and panics on Windows
if the tokenizers crate ever appears in the workspace dependency
tree, mirroring the MSVC C-runtime conflict that broke Whispering
v7.11.0 when they linked whisper-rs-sys + tokenizers in the same
binary.

On non-Windows hosts the guard downgrades to a cargo:warning so
cross-compilation or CI from Linux surfaces the issue before a
Windows build attempt actually panics.

No tokenizers crate is in the tree today; the guard is preemptive.
If we ever legitimately need HF tokenizers on Windows, the escape
hatch is an out-of-process sidecar (separate CRT).

Co-authored-by: jars <jakejars@users.noreply.github.com>
2026-04-21 15:54:15 +01:00
34fce3cf9e feat: OpenWhispr-inspired transcription polish pass
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Major quality pass on top of Phase 2. Five substantive changes plus
cross-cutting touches across audio, hotkey, transcription, and Tauri
command layers.

  Transcription quality

  - Long-audio chunking in commands/transcription.rs: Parakeet and large
    file transcription now chunk-and-recompose with overlap trimming, so
    the live-path chunking advantage extends to file-based workflows.
  - Stateful live speech gate in commands/live.rs on top of the earlier
    duplicate-boundary filtering — distinguishes start-of-speech from
    mid-speech and holds state across chunks.

  Auto-learning corrections

  - New crates/ai-formatting/src/correction_learning.rs: extracts user
    text corrections from viewer edits and proposes additions to the
    active profile's vocabulary.
  - src-tauri/src/commands/profiles.rs bridge for frontend-driven
    confirmation of learned terms.
  - src/routes/viewer/+page.svelte hooks the learning path into the
    segment-edit flow so corrections feed profile_terms without a
    separate 'train this profile' UX.

  Transcript profile provenance

  - Migration v8 (crates/storage/src/migrations.rs) adds profile_id to
    transcripts, defaulting to DEFAULT_PROFILE_ID so existing rows stay
    valid.
  - crates/storage/src/database.rs: TranscriptRow + CRUD carry profile_id.
  - src-tauri/src/commands/transcripts.rs: add_transcript accepts and
    persists profile_id.
  - DictationPage.svelte + FilesPage.svelte send activeProfileId on
    capture so learned corrections are attributed to the right profile.

  Cleanup prompt contract

  - crates/ai-formatting/src/llm_client.rs hardened: the CLEANUP_PROMPT
    now specifies concrete do/do-not rules, ready for a real model-backed
    cleanup pass. The llm_client is still a stub — kon-llm remains unwired
    — but the prompt shape is final.

  Cross-cutting polish

  - Minor touches in audio (capture/decode/resample), hotkey (lib/linux/stub),
    core, transcription (concurrency/model_manager/local_engine/whisper_rs),
    and the rest of src-tauri/src/commands/*: error-path tightening, log
    clarity, TS-migration follow-ups (@ts-nocheck additions for incremental
    typing).

Verified locally: npm run check, cargo test -p kon-ai-formatting,
cargo test -p kon-storage, cargo test -p kon --lib commands::live::tests,
cargo check — all green.

Scope boundary: kon-llm crate is still a stub; task extraction remains
rule-based. Bundled local-LLM runtime is the next clean step and is not
in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 22:39:08 +01:00
e5661b9111 deps(transcription): drop whisper-cpp features from transcribe-rs — whisper-rs is sole Whisper backend 2026-04-19 20:23:31 +01:00
381f236bf8 obs(transcription): log initial_prompt presence at WhisperRsBackend boundary 2026-04-19 20:21:40 +01:00
4256383a5b refactor(transcription): LocalEngine dispatches SpeechBackend enum — Whisper now on whisper-rs 2026-04-19 20:20:03 +01:00
c426fa7eb2 feat(transcription): add WhisperRsBackend wrapping whisper-rs with initial_prompt support 2026-04-19 20:16:07 +01:00
6b44570b04 test(transcription): probe whisper-rs 0.16 load + transcribe + initial_prompt 2026-04-19 20:14:17 +01:00
8b9a569b76 deps(transcription): add whisper-rs 0.16 alongside transcribe-rs for Whisper backend swap 2026-04-19 20:10:18 +01:00
52551e6666 fix(parakeet): request word-granularity segments (was per-subword 'T Est Ing')
transcribe-rs 0.3.10's ParakeetModel::transcribe_raw ignores its
options argument and calls self.infer(samples, &TimestampGranularity::default())
where default is TimestampGranularity::Token — per-subword segments.

That surfaces in Kon as output like 'T Est Ing One , Two , Three . W Ow ,
This Is T  Ri Ble .' because DictationPage joins segment texts with ' '.

Introduce a thin ParakeetWordGranularity wrapper that implements
SpeechModel and overrides transcribe_raw to call the concrete
ParakeetModel::transcribe_with() with ParakeetParams { timestamp_granularity:
Some(Word) }. Pre-existing bug unrelated to Phase 2 work — surfaced during
Group 1 dogfooding because Parakeet was being tested for the first time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:19:45 +01:00
ac46949b01 feat(transcription): enable Vulkan GPU acceleration for Whisper inference 2026-04-18 10:32:09 +01:00
cca79dec4c fix: SQL trigger-aware migration splitter, SpeechModel re-export, i64 type alignment
crates/storage/src/migrations.rs:
  Replace naive sql.split(';') with split_statements() that tracks
  BEGIN...END depth, so migrations containing trigger definitions
  execute correctly instead of being split mid-block.

crates/transcription/src/lib.rs:
  Re-export transcribe_rs::SpeechModel so callers in src-tauri can
  reference it without adding transcribe-rs as a direct dependency.

src-tauri/src/commands/models.rs:
  Use Box<dyn SpeechModel + Send> as the load_model_from_disk return
  type, matching the trait object that transcription crates produce.

src-tauri/src/commands/transcripts.rs:
  Remove the stale .map(|v| v as i32) casts on sample_rate and
  audio_channels. InsertTranscriptParams now stores these as i64
  (ebf449b), matching the i64 fields on CreateTranscriptRequest;
  casting to i32 first would silently truncate large sample rates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 09:03:01 +01:00
9e05f698da agent: fix — add missing transcribe-rs fields (leading/trailing silence)
Upstream transcribe-rs 0.3.10 added required fields to TranscribeOptions.
Set both to None (use engine defaults).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:58:04 +01:00
8e70cf9ff9 agent: wayland — evdev hotkey backend, download resume, SHA256 integrity
Add kon-hotkey crate with evdev-based global hotkey capture that works on
Wayland (and X11). Patterns from whisper-overlay: per-device async listeners,
inotify hotplug with udev permission retry, watch channel for live config
updates. Frontend detects Wayland at startup and selects evdev or
tauri-plugin-global-shortcut automatically.

Model downloads now support HTTP Range resume for interrupted downloads and
optional SHA256 integrity verification (incremental, no second pass).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:50:48 +01:00
jake
4c0fd0aeda agent: foundation — sync incremental changes from legacy codebase
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:50:32 +00:00
jake
292f9716ff 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>
2026-03-16 21:36:44 +00:00
jake
100ecb4eae feat(kon): add transcription crate — transcribe-rs wrapper, model manager
- LocalEngine wraps transcribe-rs SpeechModel behind Kon's own abstraction
- load_parakeet() and load_whisper() factory functions
- Unified model manager: download with progress callback, check, list, path resolution
- Atomic downloads: .part suffix with rename on completion
- run_inference() encapsulates spawn_blocking threading
- Zero Tauri dependency in this crate (progress via callback, not events)
- transcribe-rs v0.3.2 with onnx + whisper-cpp features
- 4 tests passing, clippy clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:39:37 +00:00
jake
9926a42b7a feat(kon): scaffold hybrid modular workspace
- Cargo workspace with 6 domain crates: core, audio, transcription, ai-formatting, storage, cloud-providers
- Minimal Tauri shell (lib.rs + main.rs) with plugin registration
- Svelte 5 frontend copied from Ramble v0.2
- All crates compile as empty stubs
- App identifier: uk.co.corbel.kon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:21:38 +00:00