Identify Speakers using Silence Breaks
Fake speaker detection that actually works for AI dialogue
- fullaudio
- diarization
- speakersTrackInfo1
- speakersTrackInfo2
Real speaker diarization - the "who spoke when" problem - usually needs a heavyweight model. This node takes a shortcut that's dumb and effective: it assumes the silence between lines is where one speaker stops and the next starts. For AI-generated dialogue that's often exactly right, because generated conversations have clean gaps built in. The author's own framing says it plainly: primarily for AI generated audio, make sure you put breaks in the audio for this to work.
The output isn't audio and isn't a fancy UI. It's the timing map the rest of this pack's speaker workflow is built on: a diarization JSON, plus two comma-separated track strings (speakersTrackInfo1, speakersTrackInfo2) that you can feed straight into TKSpeakerAudioTrackExtractor to slice the actual audio per speaker.
How it works
Under the hood it's pydub finding non-silent chunks, then walking the gaps between them. Every chunk boundary closes the current segment; if the gap between chunks is at least silence_threshold seconds, the speaker toggles (1→2, 2→1). Small consecutive segments from the same speaker get merged so you don't get a dozen 1-second micro-tracks. That's it - no embedding model, no clustering, just silence math.
The required inputs are silence_threshold (a FLOAT, default 1.0s - how long a pause must be to count as a speaker switch), fullaudio (the AUDIO), and duration. There are also fourteen hidden track_start_N / track_end_N boxes - they're invisible until you need manual override. Flip track_state to DataChange and the node will use the times you typed instead of the silence detection, which is the escape hatch when detection misfires.
How you actually run it
This is where it gets a little odd, so read carefully: the node's first detection run happens through a built-in HTTP endpoint (/tk/detect_speakers on ComfyUI's server) that a companion UI/button calls - it scans the audio file, caches the result, and the node itself then reads that cached segment list. It also supports an Audacity label file as an override: drop a name.txt tab-separated label file next to your audio in ComfyUI/input (or in Documents) and it'll use those exact timings instead of guessing.
Common issues
The honest limitations: it toggles between exactly two speakers, and it only works when there really are pauses between them - overlapping dialogue or continuous speech makes it chop mid-thought and mislabel. That's the price of the silence shortcut, and it's why the manual track boxes exist. Also note the pack pulls in sherpa-onnx in its requirements and has code paths that download segmentation/embedding ONNX models into ComfyUI/models/onnx - if you see model downloads on first use, that's expected, not a hang.
Installing it
Part of trashkollector/TKNodes ("ComfyUI Handy Nodes"). Install via ComfyUI Manager (search "Handy Nodes") or:
cd ComfyUI/custom_nodes
git clone https://github.com/trashkollector/TKNodes
Restart, and it's under TKNodes. Needs pydub (bundled in the pack's requirements) and FFmpeg on your PATH for compressed audio.
Inputs (33)
| Name | Type | Default | Description |
|---|---|---|---|
| silence_threshold | FLOAT | 1.000.2–4 | — |
| fullaudio | AUDIO | — | |
| duration | FLOAT | 0.00 | — |
| track_start_1 | FLOAT | 0.00 | — |
| track_end_1 | FLOAT | 0.00 | — |
| speaker_timesopt | STRING | [] | — |
| track_stateopt | STRING | DataUnchanged | — |
| track_start_2opt | FLOAT | 0.00 | — |
| track_end_2opt | FLOAT | 0.00 | — |
| track_start_3opt | FLOAT | 0.00 | — |
| track_end_3opt | FLOAT | 0.00 | — |
| track_start_4opt | FLOAT | 0.00 | — |
| track_end_4opt | FLOAT | 0.00 | — |
| track_start_5opt | FLOAT | 0.00 | — |
| track_end_5opt | FLOAT | 0.00 | — |
| track_start_6opt | FLOAT | 0.00 | — |
| track_end_6opt | FLOAT | 0.00 | — |
| track_start_7opt | FLOAT | 0.00 | — |
| track_end_7opt | FLOAT | 0.00 | — |
| track_start_8opt | FLOAT | 0.00 | — |
| track_end_8opt | FLOAT | 0.00 | — |
| track_start_9opt | FLOAT | 0.00 | — |
| track_end_9opt | FLOAT | 0.00 | — |
| track_start_10opt | FLOAT | 0.00 | — |
| track_end_10opt | FLOAT | 0.00 | — |
| track_start_11opt | FLOAT | 0.00 | — |
| track_end_11opt | FLOAT | 0.00 | — |
| track_start_12opt | FLOAT | 0.00 | — |
| track_end_12opt | FLOAT | 0.00 | — |
| track_start_13opt | FLOAT | 0.00 | — |
| track_end_13opt | FLOAT | 0.00 | — |
| track_start_14opt | FLOAT | 0.00 | — |
| track_end_14opt | FLOAT | 0.00 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| diarization | STRING | — |
| speakersTrackInfo1 | STRING | — |
| speakersTrackInfo2 | STRING | — |