Skip to content

Whisper invents text on silence in meetings and short dictations; the -50 dBFS gate does not catch it #193

Closed

Description

@0xCaso

HEX version: 2.3.0 for the recording, installed from the signed DMG. The same code is in 2.3.1; source checked again at main f8774a5.
Platform: macOS
System details: macOS 26.4.1, Apple M1 Pro, built-in microphone. Whisper large-v3-turbo, language Italian, recognition hints set (five product names).

What happened?

When I do not speak, Whisper still returns text. The text is a closing phrase ("Grazie a tutti", "Grazie"), my recognition hints copied word for word, or short fragments.

Meetings (beta). I recorded a 63-minute call and mostly listened. In transcript.ndjson, 152 of 185 microphone entries are text I did not say:

Invented text Entries
"Grazie" / "Grazie a tutti" 104
the exact recognition-hints string 29
a URL made from one hint word 2
short fragments on quiet audio ("e", "o", "nada", "vo, vo, vo") 17

The system track has 10 more (8 "Grazie", 2 hints string) during remote silence. Echo suppression does not remove them, because no remote speech matches them.

Dictation. This is the case from #108, still on 2.3.0. A short press without speech (1–3 s) pastes "Grazie" or "Grazie a tutti". Today's history.json has 8 of these, and process.log for the same hours has no discarded near-silent dictation line, so the gate did not discard them.

Expected: no text when nobody speaks.

Steps to reproduce

  1. Select Whisper large-v3-turbo and enter some recognition hints. Any language should do: I use Italian, and in English the closing phrase is usually "Thank you." (as in Inserting 'thank you' at the end of dictation sometimes #108).
  2. Meetings: record a call and stay silent for a few minutes. Dictation: press the shortcut for 1–3 s without speaking.
  3. Read the transcript or the pasted text. Expect the hints string, a closing phrase in the selected language, or short fragments.

Additional context

Where it comes from in the code

  1. Meeting chunks have no silence gate. Every rolling chunk (transcribe_pending) and every chunk of transcribe_file goes to the model.
  2. The dictation gate (is_near_silent) checks only the loudest 30 ms window against -50 dBFS. A click, the key press or room noise passes it.
  3. The recognition hints are Whisper's initial_prompt. Each meeting chunk is a separate run, so each chunk starts with the prompt. On silence, Whisper often just repeats it.
  4. Whisper's own no-speech check is already active with the transcribe-cpp defaults (no_speech_thold 0.6, logprob_thold -1.0). It does not stop these, because it skips a segment only when the logprob is also low.

Why a level threshold is not enough

I checked each microphone entry of the meeting against the audio under it. A gate "keeps" an entry when it would let that audio reach the model.

Check on the entry's audio Invented entries kept (of 152) Real entries kept (of 33)
current gate: loudest 30 ms window ≥ -50 dBFS 130 32
stricter level rule: ≥ 250 ms of 30 ms windows above -40 dBFS 1 31
Silero VAD v6.2 via transcribe-cpp 0.4.0 VadSession, threshold 0.4, min_speech_ms 160 1 32
  • The current gate keeps almost all invented text.
  • A stricter level rule removes it, but also drops real speech. It would also go against silence_gate_discards_only_near_silent_captures, which keeps 100 ms of whispered speech at -43 dBFS.
  • I also tried the PauseSegmenter speech test (12 dB above the adaptive floor). It marks speech in most of my silent stretches, because of room and keyboard noise.
  • Silero separates the two groups. The one invented entry it keeps is a "Grazie a tutti." over 16 s of silence. I use threshold 0.4, not the default 0.5, because at 0.5 a whisper at -43 dBFS is not heard. The one real entry it misses is a 40 ms "Certo." at a chunk boundary. With Silero's default min_speech_ms of 250, 3 short real replies on the system track ("Ok", "Ciao") were lost; 160 keeps them.
  • It scans the 63 minutes in 1.6 s on the CPU.

Notes on this test:

  • one recording, one machine, entries checked one by one, not the real chunk path (the PR has a run on the real chunk path);
  • the GGUF model is handy-computer/silero-vad-v6.2-gguf, F32.

Proposed fix

transcribe-cpp 0.4.0 has a Silero VAD (VadSession, with Silero v5.1.2 / v6.2.0 in GGUF or whisper.cpp .bin format). HEX pins =0.2.4. #129 also needs 0.4.0.

  1. Run the VAD before the model. Discard a dictation clip with no speech segment. In meetings, skip chunks with no speech, or send only the speech spans.
  2. Drop any Whisper segment whose text is the same as the initial prompt. This needs no threshold. Here it removes 29 microphone entries and 2 system entries.

I opened #194 with both parts, on transcribe-cpp 0.4.0. Open questions:

  • Should the VAD model ship with the app, or download with the transcription model (as in the PR)?
  • Should the VAD run for every model, or only for Whisper?

Related: #108 (same symptom in dictation, closed after the -50 dBFS gate), #129 (transcribe-cpp 0.4.0). The English live draft in meetings (#182, #185) is a separate problem and is not touched.

Activity

  1. thdxr commented on Oct 28, 2026

    @thdxr
    Member

    Thanks for reporting this! We're working on a brand-new version of Hex (rebuilt from the ground up), and it'll be out soon. This issue is about the current release, so we're closing it to keep the tracker focused on the new version. You can try the new dev build now — download links are in the README: https://github.com/anomalyco/hex#install-hex. If this still happens on the dev build, please open a new issue (or reply here) and we'll take a look.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  2. 0xCaso commented on Oct 28, 2026

    @0xCaso
    ContributorAuthor

    This still happens on the dev build, so I'm replying here as suggested.

    Build: Hex 0.0.0-dev-155, the signed DMG from the dev channel, on macOS 27.0.1, M1 Pro, built-in microphone. Whisper large-v3-turbo, Italian, recognition hints set.

    Dictation. I pressed the shortcut 6 times for 1–4 s without speaking:

    • the -50 dBFS gate discarded 1 of them (discarded near-silent dictation, loudest window at -50.02 dBFS);
    • the other 5 pasted text I did not say, mostly from the recognition hints: the whole hints string word for word (2 times), one or two hint words (2 times), one unrelated word (1 time).

    On dev, dictation has the same gate as the release (is_near_silent in src/dictation.rs). Meeting chunks now skip audio below -60 dBFS (SILENT_DB in src/meeting_transcript.rs). That is a level check too, and the table above shows that room noise passes a level check. I did not record a meeting on the dev build.

    #194 targets dev and still merges into it cleanly. Could you reopen this issue?

  3. thdxr commented on Oct 28, 2026

    @thdxr
    Member

    Thanks for the careful retest on 0.0.0-dev-155 — the per-press breakdown and the level-vs-VAD comparison make this very clear. Reopening; we're reviewing #194 now.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  4. reopened this on Oct 28, 2026
  5. thdxr commented on Oct 28, 2026

    @thdxr
    Member

    #194 is merged into dev (e68d4e6). Before transcribing, Hex now runs the Silero speech detector on dictation captures and meeting chunks and drops the ones with no speech in them. It also drops Whisper output that only repeats the recognition hints. The detector (1.2 MB) downloads in the background the first time you dictate or when a model downloads, so the very first press after updating may still go to the model.

    @0xCaso, could you try your silent-press test again on the next dev build, the first one after 0.0.0-dev-155 that includes e68d4e6, and let us know how it goes? Discarded captures log discarded dictation without detected speech in process.log.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  6. 0xCaso commented on Oct 28, 2026

    @0xCaso
    ContributorAuthor

    Tried it on 0.0.0-dev-167, which includes e68d4e6. The setup is the same as before: macOS 27.0.1, M1 Pro, built-in microphone, Whisper large-v3-turbo, Italian, recognition hints set.

    • First, one warm-up press with speech. The detector downloaded during it, and the press transcribed normally.
    • Then 11 presses of 2–6 s without speaking. All 11 logged discarded dictation without detected speech, and nothing was pasted.
    • Their loudest window was between -49.2 and -48.6 dBFS, so the old -50 dBFS gate would have let every one through. The detector took 6–31 ms per capture.

    I did not test meetings on this build. Thanks for merging!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions