RunningHub VoxCPM Dataset Build (Batch)
Turn a whole folder of clips into a VoxCPM training set at once
- audios
- manifest_path
- num_samples
- transcripts
If you're training a real voice on VoxCPM, this is the node you want - the one that makes the difference between "curate eight clips by hand" and "dump 200 clips and walk away." RunningHub VoxCPM Dataset Build (Batch) builds the same train.jsonl manifest as plain Dataset Build, but it consumes a list of AUDIO inputs instead of fixed entry sockets, and it does the boring data-prep work for you: optional denoising, auto-transcription, resampling, and filtering out clips that are too short or too long.
The intended chain, per the code comments, is a batch audio loader (the author name-drops HAIGC_LoadImagesFromZip-style loaders) feeding a zip or folder of clips straight into this node, then out to Train LoRA. You go from "raw audio files" to "training manifest" in one graph segment.
How it processes each clip
For every clip in the list, in order:
- Denoise (
denoise, default on) - runs ZipEnhancer to strip background music and room tone. It's the same denoiser the Generate node uses for reference clips, and if it fails on one clip it logs a warning and falls back to the raw audio rather than aborting the batch. - Transcribe (
auto_asr, default on) - runs SenseVoiceSmall unless you supplied a matching transcript intexts. Per-clip failures are skipped, not fatal. - Filter - clips under
min_duration(default 0.5s) or overmax_duration(default 30s) get dropped with a warning. - Write - resampled to
sample_rate(16000), saved assample_XXXXX.wav, and a JSONL record is appended.
That filtering is the quietly important part. A training loop has no taste - a 0.2s "uh" or a 4-minute song will pollute the run, and dropping them at build time is far cheaper than discovering them mid-training. The node's three outputs tell you what survived: manifest_path (the jsonl), num_samples, and transcripts (a numbered text blob of everything it transcribed, so you can eyeball the ASR output in one place instead of trusting it blind).
The texts input
It's a STRING with forceInput, meaning you wire in a parallel list of transcripts rather than typing. Each transcript pairs with the corresponding clip by index, and any entry with a non-empty provided text skips ASR. If you already have transcripts (say, from a prior Whisper pass), supplying them beats re-running SenseVoiceSmall - and it sidesteps the model dependency entirely for the clips you cover.
Setup and the catch
Install is the same as every node in this pack:
cd ComfyUI/custom_nodes
git clone https://github.com/RH-RunningHub/ComfyUI_RH_VoxCPM.git
cd ComfyUI_RH_VoxCPM && pip install -r requirements.txt
The catch is the dependency stack: with denoise and auto_asr both on by default, this node drags in FunASR and ZipEnhancer. ZipEnhancer needs iic/speech_zipenhancer_ans_multiloss_16k_base downloaded, SenseVoiceSmall needs iic/SenseVoiceSmall - both via modelscope, both into specific folders. If the node fails on your first batch, the most likely culprit is a missing model, and the error will say so. And note the defaults can bite on short clips: with min_duration at 0.5s, a dataset full of quick sound bites will silently shed samples. Check num_samples against your input count before you trust the batch.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| audios | AUDIO | — | |
| textsopt | STRING | — | |
| denoiseopt | BOOLEAN | true | — |
| auto_asropt | BOOLEAN | true | — |
| sample_rateopt | INT | 160008000–48000 | — |
| dataset_idopt | INT | 00–1024 | — |
| dataset_nameopt | STRING | voxcpm_dataset | — |
| min_durationopt | FLOAT | 0.50–60 | — |
| max_durationopt | FLOAT | 301–300 | — |
| extra_manifestopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| manifest_path | STRING | — |
| num_samples | INT | — |
| transcripts | STRING | — |