lektor_ai_comfy — Polish AI Dubbing Tool
=========================================
FULL DOCUMENTATION: see docs/
docs/README.md start here — overview and quick start
docs/requirements.md hardware, software, dependencies
docs/installation.md installing ComfyUI + the TTS engine
docs/usage.md every CLI flag, working modes, recipes
docs/architecture.md how the pipeline works internally
docs/troubleshooting.md diagnosed failure modes and their fixes
Installer: ./install_comfyui.sh (see docs/installation.md)
This file remains as a condensed quick reference.
Converts SRT subtitles to AI voiceover (lektor style) using ComfyUI + Higgs Audio V3 TTS,
then mixes the result with the original video audio into a two-track MKV.
All subtitle tracks in the source video are carried over to the output.
Requirements
------------
- ComfyUI running at http://127.0.0.1:8189 with TTS-Audio-Suite custom node
- Model: higgs-audio-v3-tts-4b (bosonai/higgs-audio-v3)
- ffmpeg and ffprobe available on PATH
- Voice reference: a WAV file + matching .txt transcript in the voice directory
(default: voices/gudowski_short.wav + voices/gudowski_short.txt)
Settings
--------
Defaults live in settings.ini next to the script:
voice, speed, temperature, max_tokens, strip_leading_ms, trailing_fade_ms,
orig_volume, tts_volume, output_dir, dictionary, numbers, comfy_url
Precedence: command-line flag > settings.ini > built-in default.
Use --settings FILE to select a different profile.
See docs/usage.md for the full description.
Basic Usage
-----------
Full run with an external SRT file:
python3 lektor_ai_comfy.py input/film.srt input/film.mkv
Use subtitles embedded in the video (lists tracks, prompts for a choice):
python3 lektor_ai_comfy.py input/film.mkv --embedded-subs
Process only a time range (extracts a video fragment automatically):
python3 lektor_ai_comfy.py input/film.srt input/film.mkv --start 01:20 --end 05:40
Subtitle Handling
-----------------
Both external SRT files and embedded subtitle tracks go through the same cleaning:
- HTML tags stripped: , , , , etc.
- ASS override codes stripped: {\an8}, {\pos(x,y)}, {\c&H…&}, etc.
- ALL-CAPS blocks converted to Title Case (keeps proper nouns readable)
- Sentence fragments starting with a lowercase letter are capitalised
- Missing terminal punctuation added (… or . depending on context)
- Dictionary replacements applied (see below)
- Dialogue lines (prefixed with -) are split into separate clips with proportional timing
- Numbers spelled out as Polish words, in the right case (see below)
With --embedded-subs the extracted subtitles are saved to the job folder as embedded_sub.srt
so you can inspect them before or after the run.
The final MKV preserves all subtitle tracks from the source video — text-based
(SRT, ASS, SSA, WebVTT) and image-based (PGS Blu-ray, VOBSUB) alike — using
stream copy with no conversion.
Replacement Dictionary
----------------------
dictionary.txt next to the script rewrites words and phrases before they reach
the TTS engine — abbreviations, units, symbols, names the model mispronounces.
One rule per line:
km/h = kilometrów na godzinę
np. = na przykład
/(\d+)\s*%/ = \1 procent
Matching is case-sensitive and whole-word only, so "np." leaves "znp." alone and
"Joshua" leaves "joshua" alone. The replacement is inserted exactly as written.
The first letter of each block is capitalised before these rules run, so add a
capitalised variant for words that can start a subtitle.
Longer patterns win over shorter ones regardless of the order they are written
in, and replacement text is never rescanned, so rules cannot feed each other.
A pattern wrapped in slashes is a regular expression, with \1 \2 … referring to
its groups. Lines starting with # or ; are comments.
The result is visible in the job folder's tts_input.srt — check there if a rule
is not doing what you expect. --regen and --rebuild work from that file, so they
do not re-apply the dictionary; edit tts_input.srt directly, or rerun.
Use another list with --dictionary FILE (a relative name is looked for in the
current directory first, then next to the script) or turn it off with
--dictionary "". A missing file is not an error.
A second list can be merged in with --dictionary-extra FILE. The GUI writes one
per queue — the "Queue dictionary" button — into the first queued video's job
folder, for rules that belong to one batch rather than to Polish in general.
Number Normalization
--------------------
The TTS misreads long digit strings and sometimes turns them into non-words, so
after the dictionary every block containing a number is rewritten with the
numbers spelled out in Polish — in the correct grammatical case, which is why
this is a small neural model and not a lookup table:
Wygrał 1247 złotych. -> Wygrał tysiąc dwieście czterdzieści siedem złotych.
Mówimy o 25 psach. -> Mówimy o dwudziestu pięciu psach.
Mam 3 koty. -> Mam 3 koty. (single digits are read fine)
It runs in its own environment (transformers>=5, which must not be installed
next to ComfyUI's pinned versions). One-time install:
normalizer/setup.sh # venv + dependencies
HF_TOKEN=hf_... normalizer/setup.sh --model # gated weights, accept terms first
Terms: https://huggingface.co/Folx/qwen3-0.6b-pl-text-normalization
Everything after that runs offline. See normalizer/README.md.
Turn it off with numbers = no under [normalize] in settings.ini, or with
--no-normalize-numbers for one run. If the environment or the model is missing
the run continues with the digits untouched — it is never fatal.
Output Files
------------
Everything belonging to one video is kept together in a job folder named after
the video file. Only the finished video is written to the top level.
output/
clips/