feat: hallucination filter — strip known ASR boilerplate before writing (#98)#99
Merged
Merged
Conversation
在 CommandCore.transcribe 的單一輸出 choke point 加 backend-agnostic 的後處理 pass,寫檔前剝除已知幻覺 boilerplate(Whisper 家族靜音段的罐頭字幕)、空 cue、 相鄰重複 cue,並重編 segment id + 用 engine 同款 .joined() 重建 flat text,讓 srt/txt/json/vtt 四種輸出一致乾淨。 新增 --hallucination-filter <off|denylist>(CLI)與 hallucination_filter(MCP transcribe tool),預設 denylist(逐字稿 out-of-box 就乾淨;off 還原 raw 輸出)。 denylist 內容為 Whisper 家族特有,對不產生這些字串的 backend(Parakeet 等)是 無害 no-op;空/相鄰重複 collapse 則全 backend 通用。 Refs #98
原本用「包含」比對:短的通用 outro(感謝觀看/請訂閱)會誤中含該子字串的 長真句(如「非常感謝觀看今天的展覽」),在預設開啟的 filter 下靜默剔除真實 語音。改為片語需覆蓋 cue 正規化長度 ≥ 60% 才算命中——長 boilerplate 照剔、 容忍 decoder 前後贅字,但短 outro 只佔長句一小部分時保留。對 default-on 的 破壞性操作偏向 precision(漏抓由下游 srt-proofread 補)。 Refs #98
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a backend-agnostic post-decode pass that strips known ASR hallucinations before a transcript is written, so silent-segment boilerplate no longer reaches the output and downstream
srt-proofreaddoesn't have to clean it.Refs #98.
What it does
HallucinationFilter.filter(_:mode:denylist:)— a pure function over aTranscript, applied at the singleCommandCore.transcribechoke point, after diarization:1…Nand re-derives the flattextthe same way an engine does (segments.map(\.text).joined()), sosrt/txt/json/vttall come out consistent. Speaker labels on surviving cues are preserved.Surfaces
--hallucination-filter <off|denylist>ontranscribe(defaultdenylist).hallucination_filteron thetranscribetool (defaultdenylist).CommandCoresignature (no code change).Behavior change
Transcription now runs the filter in
denylistmode by default — known boilerplate no longer reaches the output. Pass--hallucination-filter off(CLI) /hallucination_filter: "off"(MCP) to restore raw output. Documented in CHANGELOG.Design notes
HallucinationFilterModelives inBestASRKit(ArgumentParser-free); the CLI adds theExpressibleByArgumentconformance, so--helpauto-lists the cases and rejects unknown values.Out of scope (tracked in #98)
full/ confidence-gated filtering (needsno_speech_prob/compression_ratioplumbed through the segment model, per-backend fallback).Tests
HallucinationFilterTests(6 cases): boilerplate drop + reindex, look-alike legitimate speech retained,.offpass-through, empty/adjacent-duplicate collapse, clean no-op, speaker labels preserved. Fixture uses the exact 3-cue evidence string from #98.Full suite green: 341 tests / 73 suites.
swift buildclean across all targets (Kit / CLI / MCP / GUI).Manual smoke test (recommended — needs model download)
Re-transcribe a recording with a known silent-segment hallucination and compare default vs
--hallucination-filter off: the boilerplate should be absent by default and present withoff.