Skip to content

feat: add [transcription].vocabulary to bias whisper decoding - #33

Merged
OneNoted merged 5 commits into
OneNoted:mainfrom
xqqmdy:feat/vocabulary-initial-prompt
Nov 13, 2026
Merged

OneNoted merged 5 commits into
OneNoted:mainfrom
xqqmdy:feat/vocabulary-initial-prompt

Conversation

@xqqmdy

@xqqmdy xqqmdy commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Summary

New [transcription].vocabulary config: custom terms joined into an initial_prompt and injected into whisper_cpp decoding, biasing recognition toward domain vocabulary (proper nouns, jargon) that the model otherwise mishears — e.g. "Vulkan" → "Walk on", "RenderDoc" → "Render Dog".

toml
[transcription]
vocabulary = ["Vulkan", "RenderDoc"]

While vocabulary is active, flash attention is disabled automatically: whisper.cpp's vulkan flash-attn path mis-decodes (immediate EOT, empty output) whenever a KV prefill from initial_prompt is present. Reproducible with plain whisper.cpp on RADV RDNA4, independent of the prompt content. Measured cost of disabling FA on this GPU is nil (10.7s audio: 482ms without prompt, 494ms with a 96-term prompt).

Practical prompt budget: whisper.cpp injects at most n_text_ctx / 2 = 224 tokens (~60–90 English terms); overhead is ~12ms at that cap.

Verification

  • End-to-end dictation of domain terms; jfk.wav sample unaffected at any vocabulary size (identical transcript 0–96 terms)
  • No prompt-echo hallucination: 3s silence + 96-term prompt outputs no vocabulary terms

Stack note: This is one of four single-commit PRs reviewed bottom-up:

Until the lower PRs merge, "Files changed" also shows their commits. The stacking exists because the local pre-push hook runs full CI on the working tree: on clang >= 22 machines the vulkan feature check cannot build without PR 3, and clippy 1.99 fails without PR 1, so each branch needs the ones below it to be locally verifiable. PRs 1–2 are independently green on GitHub CI (clang 18).

clippy 1.99 (useless_borrows_in_formatting) denies these under -D warnings;
local pre-push CI runs clippy with a newer toolchain than the one that last
touched src/ui.rs, so the hook fails on main without this.
setup_label embeds ANSI styling via tier_token, so asserting on the raw
string fails on terminals that force colors (CLICOLOR_FORCE=1), e.g. when
the pre-push hook runs cargo test from an interactive shell. Strip the
escape codes before asserting.
Vulkan builds forced bindgen at build time (upstream 6a52094) to pick up
the ggml_backend_vk_* symbols. That regeneration is untrustworthy on
modern libclang: with clang >= 22, bindgen cannot lay out
whisper_full_params (nested anonymous structs) and emits an opaque
{ _address: u8 } stub, corrupting the params ABI passed to whisper_full
(known issue, see e.g. meetily#428; clang 23.1.3 reproduces). GitHub
CI's ubuntu-latest ships clang 18 and does not hit this, which is why
the regeneration path looked healthy there.

Instead, bake the ggml_backend_vk_* declarations into the bundled
bindings: regenerate src/bindings.rs once with bindgen 0.71.1 +
libclang 18.1.1 (instructions in build.rs) and commit it. This keeps
upstream's intent (vk symbols available) without any build-time bindgen.

The diff vs the previous bundled bindings is limited to the ggml-vulkan
additions and glibc 2.44-vs-2.41 header noise (_IO_FILE tail fields,
_POSIX_C_SOURCE); no whisper.h structure changed and none of the
glibc-touched fields are ever dereferenced. Verified on RADV RDNA4:
device enumeration and end-to-end transcription with GPU acceleration.

Also allow the rustc 1.99 unnecessary_transmutes lint for the generated
bitfield accessors (bindgen 0.71 still emits transmute style; switching
to cast_unsigned would raise the toolchain floor above the crate's
declared MSRV).
Custom vocabulary entries are joined into an initial_prompt and injected
into whisper_cpp decoding, biasing recognition toward domain terms
(e.g. Vulkan, RenderDoc).

Because whisper.cpp vulkan flash-attention mis-decodes (immediate EOT,
empty output) whenever a prompt prefill is present, flash_attn is
automatically disabled while vocabulary is active (no measurable cost:
10.7s audio = 482ms vs 494ms with 96 terms on RADV RDNA4).
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 58 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: dc4b7e4e-1924-4b55-89a7-7f473934e489
Commits

Reviewing files that changed from the base of the PR and between 5f07631 and 61c3e1e.

Files selected for processing: 9

  • config.example.toml
  • src/asr_model.rs
  • src/config/edit.rs
  • src/config/schema.rs
  • src/transcribe.rs
  • src/ui.rs
  • vendor/whisper-rs-sys/build.rs
  • vendor/whisper-rs-sys/src/bindings.rs
  • vendor/whisper-rs-sys/src/lib.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@OneNoted
OneNoted merged commit 6e59686 into OneNoted:main Nov 13, 2026
3 of 4 checks passed
@OneNoted

Copy link
Copy Markdown
Owner

Thanks for help! ❤️

@xqqmdy

xqqmdy commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for building such a great tool

@xqqmdy
xqqmdy deleted the feat/vocabulary-initial-prompt branch November 14, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants