F5-TTS: drop per-sentence split — single infer() call avoids ref-to-gen artifact per chunk

This commit is contained in:
russell@unturf.com 2026-05-24 11:12:57 -04:00
parent 482b17960c
commit fc5af2b653
No known key found for this signature in database

View file

@ -1295,39 +1295,33 @@ async def generate_speech(request: GenerateSpeechRequest):
logger.info(f"Loading F5-TTS model on device '{device}'")
f5_model = await asyncio.to_thread(f5_wrapper, device=device)
# Split text into sentences for streaming (first audio arrives faster)
sentences = simple_sentence_split(input_text, max_length=500)
logger.info(f"Split text into {len(sentences)} sentences for F5-TTS streaming")
# F5-TTS handles long text via internal chunking. Per-sentence splitting
# produces a ref-to-gen transition artifact at the start of EACH chunk
# (audible as gibberish/tinny prefix). Pass full text as one inference.
logger.info(f"F5-TTS processing {len(input_text)} chars as single inference")
# F5-TTS outputs float32 PCM at 24kHz
ffmpeg_args = build_ffmpeg_args(response_format, input_format="f32le", sample_rate="24000")
# F5-TTS accepts speed natively; only apply atempo as a fallback when ffmpeg can do it cheaper
# (we pass speed to the model below, leaving ffmpeg speed at 1.0)
ffmpeg_args.extend(["-"])
ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
in_q = queue.Queue()
def generator():
"""Process sentences sequentially and feed to queue"""
"""Run F5-TTS once for the full input text"""
try:
for idx, sentence in enumerate(sentences):
logger.debug(f"F5-TTS processing sentence {idx+1}/{len(sentences)}: {len(sentence)} chars")
audio_bytes = f5_model.tts(
text=sentence,
ref_audio=ref_audio,
ref_text=ref_text,
speed=speed,
)
in_q.put(audio_bytes)
logger.debug(f"F5-TTS: queued sentence {idx+1}/{len(sentences)}")
audio_bytes = f5_model.tts(
text=input_text,
ref_audio=ref_audio,
ref_text=ref_text,
speed=speed,
)
in_q.put(audio_bytes)
except Exception as e:
logger.error(f"F5-TTS streaming error: {e}")
logger.error(f"F5-TTS generation error: {e}")
finally:
in_q.put(None)
logger.info(f"F5-TTS streaming complete: {len(sentences)} sentences processed")
logger.info("F5-TTS generation complete")
def out_writer():
"""Write audio from queue to ffmpeg stdin"""