F5-TTS: drop per-sentence split — single infer() call avoids ref-to-gen artifact per chunk
This commit is contained in:
parent
482b17960c
commit
fc5af2b653
1 changed files with 14 additions and 20 deletions
34
speech.py
34
speech.py
|
|
@ -1295,39 +1295,33 @@ async def generate_speech(request: GenerateSpeechRequest):
|
||||||
logger.info(f"Loading F5-TTS model on device '{device}'")
|
logger.info(f"Loading F5-TTS model on device '{device}'")
|
||||||
f5_model = await asyncio.to_thread(f5_wrapper, device=device)
|
f5_model = await asyncio.to_thread(f5_wrapper, device=device)
|
||||||
|
|
||||||
# Split text into sentences for streaming (first audio arrives faster)
|
# F5-TTS handles long text via internal chunking. Per-sentence splitting
|
||||||
sentences = simple_sentence_split(input_text, max_length=500)
|
# produces a ref-to-gen transition artifact at the start of EACH chunk
|
||||||
logger.info(f"Split text into {len(sentences)} sentences for F5-TTS streaming")
|
# (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
|
# F5-TTS outputs float32 PCM at 24kHz
|
||||||
ffmpeg_args = build_ffmpeg_args(response_format, input_format="f32le", sample_rate="24000")
|
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_args.extend(["-"])
|
||||||
ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||||
|
|
||||||
in_q = queue.Queue()
|
in_q = queue.Queue()
|
||||||
|
|
||||||
def generator():
|
def generator():
|
||||||
"""Process sentences sequentially and feed to queue"""
|
"""Run F5-TTS once for the full input text"""
|
||||||
try:
|
try:
|
||||||
for idx, sentence in enumerate(sentences):
|
audio_bytes = f5_model.tts(
|
||||||
logger.debug(f"F5-TTS processing sentence {idx+1}/{len(sentences)}: {len(sentence)} chars")
|
text=input_text,
|
||||||
audio_bytes = f5_model.tts(
|
ref_audio=ref_audio,
|
||||||
text=sentence,
|
ref_text=ref_text,
|
||||||
ref_audio=ref_audio,
|
speed=speed,
|
||||||
ref_text=ref_text,
|
)
|
||||||
speed=speed,
|
in_q.put(audio_bytes)
|
||||||
)
|
|
||||||
in_q.put(audio_bytes)
|
|
||||||
logger.debug(f"F5-TTS: queued sentence {idx+1}/{len(sentences)}")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"F5-TTS streaming error: {e}")
|
logger.error(f"F5-TTS generation error: {e}")
|
||||||
finally:
|
finally:
|
||||||
in_q.put(None)
|
in_q.put(None)
|
||||||
logger.info(f"F5-TTS streaming complete: {len(sentences)} sentences processed")
|
logger.info("F5-TTS generation complete")
|
||||||
|
|
||||||
def out_writer():
|
def out_writer():
|
||||||
"""Write audio from queue to ffmpeg stdin"""
|
"""Write audio from queue to ffmpeg stdin"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue