Skip to content

feat: hallucination filter — strip known ASR boilerplate before writing (#98)#99

Merged
kiki830621 merged 2 commits into
mainfrom
feature/98-hallucination-filter
Jul 16, 2026
Merged

feat: hallucination filter — strip known ASR boilerplate before writing (#98)#99
kiki830621 merged 2 commits into
mainfrom
feature/98-hallucination-filter

Conversation

@kiki830621

Copy link
Copy Markdown
Member

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-proofread doesn't have to clean it.

Refs #98.

What it does

HallucinationFilter.filter(_:mode:denylist:) — a pure function over a Transcript, applied at the single CommandCore.transcribe choke point, after diarization:

  • Denylist strip — drops cues matching a curated list of known boilerplate. Default set is Whisper-family (the "please like & subscribe" outros that surface verbatim over silence). Matching is normalized (whitespace + punctuation folded), so decoder spacing jitter doesn't need a new entry.
  • Empty / adjacent-duplicate collapse — drops empty cues and adjacent exact-duplicate cues (rolling-caption / token echo). Universal across backends.
  • Re-indexes surviving cue ids 1…N and re-derives the flat text the same way an engine does (segments.map(\.text).joined()), so srt / txt / json / vtt all come out consistent. Speaker labels on surviving cues are preserved.
  • No-op path returns the input untouched (ids + text byte-identical).

Surfaces

  • CLI: --hallucination-filter <off|denylist> on transcribe (default denylist).
  • MCP: hallucination_filter on the transcribe tool (default denylist).
  • GUI: inherits the default via the CommandCore signature (no code change).

Behavior change

Transcription now runs the filter in denylist mode 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

  • Placed at the single choke point after diarization → covers CLI/MCP/GUI in one place, backend-agnostic, and keeps speaker labels aligned.
  • The denylist content is Whisper-family, so it is a harmless no-op for backends that never emit those strings (e.g. Parakeet); the empty/duplicate collapse is universal.
  • HallucinationFilterMode lives in BestASRKit (ArgumentParser-free); the CLI adds the ExpressibleByArgument conformance, so --help auto-lists the cases and rejects unknown values.

Out of scope (tracked in #98)

  • Phase 2: full / confidence-gated filtering (needs no_speech_prob / compression_ratio plumbed through the segment model, per-backend fallback).
  • Phase 3: decode-param knobs (WhisperKit-only).

Tests

HallucinationFilterTests (6 cases): boilerplate drop + reindex, look-alike legitimate speech retained, .off pass-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 build clean 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 with off.

在 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
@kiki830621 kiki830621 merged commit 9de4944 into main Jul 16, 2026
1 check passed
@kiki830621 kiki830621 deleted the feature/98-hallucination-filter branch July 16, 2026 02:10
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.

1 participant