ComfyUI Node

SRT Generator

Transcription is half the job — this node makes it a subtitle file

By livepeer·Created 2 years ago·Updated 11 months ago· 22
SRT Generator
    • srt_content
    transcription_data
    segment_start_time0.000
    segment_duration3.0
    use_absolute_timefalse
    minimum_duration1.0

    SRT Generator is the node you chain after the Audio Transcription (Real-time) node when raw Whisper text isn't enough - when you actually want timed, numbered subtitles you can burn into a video or hand to a streaming overlay. Raw transcription gives you words; this node gives you entries with HH:MM:SS,mmm start/end times. It's from livepeer/ComfyUI-Stream-Pack, the pack the Livepeer team built around ComfyStream, so it's tuned for the streaming case where transcription arrives in chunks rather than as one finished file.

    It does one thing and does it without any extra models or downloads: it parses whatever text it's handed, figures out timing, and returns a STRING of subtitle entries. Feed it the json_segments or json_words output from AudioTranscriptionNode and it'll reconstruct timing from the Whisper timestamps. Feed it plain text and it'll give you a single subtitle with a default 3-second duration. Both work; you just get much better timing with the JSON formats.

    How it works

    Under the hood it's a parser plus a timer. It tries to parse transcription_data as JSON - a list of segments (text + start/end) or words (word + start/end) - and if that fails, it falls back to treating the whole string as one 3-second segment. Then it formats each entry's times to SRT's HH:MM:SS,mmm style and numbers them. Two timing modes, controlled by use_absolute_time:

    • false (default) - times are relative to the segment Whisper gave you, so a chunk transcribed at 0–3 s stays at 0–3 s. Right for per-chunk streaming where each transcription is its own island.
    • true - it offsets everything by segment_start_time, so you can build one continuous timeline across chunks (you feed it the stream-relative start of each segment as it arrives).

    There's also minimum_duration (default 1 s): any subtitle shorter than that gets stretched to it, so captions don't flash by too fast to read. And it handles the AudioTranscriptionNode's __WARMUP_SENTINEL__ by passing it through untouched so the rest of the pipeline can detect the warmup and filter it.

    The inputs that matter

    • transcription_data - feed it the STRING output of AudioTranscriptionNode (ideally json_segments). This is the one you'll always connect.
    • use_absolute_time + segment_start_time - flip to true and supply the current stream position if you want one continuous subtitle timeline; leave both alone for per-chunk streaming.
    • minimum_duration - bump it up (2–3 s) if captions feel too flashy.
    • segment_duration - the fallback duration used when there's no timing info at all.

    Output: one STRING named srt_content.

    One gotcha worth knowing

    The node's display name says "SRT Generator," and the output is called srt_content, but read the source before you assume: it actually emits a JSON array of subtitle entries ([{"id":1,"start":"00:00:00,000","end":"00:00:03,000","text":"..."}]) rather than literal .srt block text with sequential 1\n00:00:00,000 --> ... lines. If you're pointing it at a player or an encoder that expects a real .srt file, you'll need one tiny conversion step (parse the JSON, join the entries) - or save the raw string and transform it outside the graph. It's a real quirk, not a bug; knowing it saves you a confusing ten minutes.

    Installing

    It ships in ComfyUI-Stream-Pack, so you install the pack once - ComfyUI Manager → search "ComfyUI-Stream-Pack", or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/livepeer/ComfyUI-Stream-Pack
    # restart ComfyUI
    

    This node itself is pure Python - no models, no extra downloads. The heavy install cost lives in the pack's faster_whisper/opencv-contrib-python/mediapipe dependencies (installed on first load), which you're pulling anyway if you use its sibling nodes.

    Where people get burned

    • Empty input is fine, but not silent. If transcription_data is too short, it returns an empty string - harmless for the graph, but a bit confusing if you're debugging and see nothing.
    • Segment IDs keep counting up. The subtitle counter is instance state, so IDs increment across calls rather than resetting per batch. Doesn't matter for playback (players ignore IDs), but it looks odd in raw output.
    • Timing quality is inherited. If you feed it plain text with no Whisper timestamps, every entry gets the same 3-second default - feed it json_segments for real timing.
    Categorytext_utils

    Inputs (5)

    NameTypeDefaultDescription
    transcription_dataSTRINGTranscription text or JSON with timing data from AudioTranscriptionNode
    segment_start_timeFLOAT0.0000–86400Start time of this segment in seconds (for absolute timing)
    segment_durationFLOAT3.00.1–60Duration of this segment in seconds
    use_absolute_timeBOOLEANfalseUse absolute timing (True) or segment-relative timing (False)
    minimum_durationFLOAT1.00.1–10Minimum subtitle duration in seconds

    Outputs (1)

    NameTypeDescription
    srt_contentSTRING