| """ |
| Audio Generation |
| Primary: F5-TTS with finetuned model (my_finetuned_model/model.pth) |
| Fallback: edge-tts (Microsoft Neural voice) β no existing audio files ever copied |
| """ |
| import os |
| import sys |
| import asyncio |
| import subprocess |
| import tempfile |
| from pathlib import Path |
|
|
| |
| _ROOT = Path(__file__).parent.absolute() |
| _INFER_CLI = _ROOT / "infer_cli.py" |
| _CKPT = _ROOT / "my_finetuned_model" / "model.pth" |
| _REF_AUDIO = _ROOT / "segment_43.wav" |
| _REF_TEXT = "are you feeling mentally alert?" |
|
|
| |
| EDGE_TTS_VOICE = "en-US-JennyNeural" |
|
|
|
|
| |
| |
| |
|
|
| async def _edge_tts_generate(text: str, output_path: str) -> bool: |
| try: |
| import edge_tts |
| communicate = edge_tts.Communicate(text, EDGE_TTS_VOICE) |
| await communicate.save(output_path) |
| return os.path.exists(output_path) and os.path.getsize(output_path) > 500 |
| except Exception as e: |
| print(f" edge-tts error: {e}") |
| return False |
|
|
|
|
| def _f5tts_generate(text: str, output_path: str) -> bool: |
| """Call the local infer_cli.py with the finetuned model checkpoint.""" |
| try: |
| if not _CKPT.exists(): |
| print(f" F5-TTS checkpoint not found: {_CKPT}") |
| return False |
| if not _REF_AUDIO.exists(): |
| print(f" F5-TTS reference audio not found: {_REF_AUDIO}") |
| return False |
|
|
| out_path = Path(output_path) |
| out_path.parent.mkdir(parents=True, exist_ok=True) |
|
|
| |
| with tempfile.TemporaryDirectory() as tmp: |
| out_file = "tts_output.wav" |
| cmd = [ |
| sys.executable, str(_INFER_CLI), |
| "--ckpt_file", str(_CKPT), |
| "--ref_audio", str(_REF_AUDIO), |
| "--ref_text", _REF_TEXT, |
| "--gen_text", text, |
| "--output_dir", tmp, |
| "--output_file", out_file, |
| "--remove_silence", |
| "--speed", "1.0", |
| ] |
| result = subprocess.run( |
| cmd, capture_output=True, text=True, timeout=120, |
| cwd=str(_ROOT) |
| ) |
|
|
| generated = Path(tmp) / out_file |
| if result.returncode == 0 and generated.exists() and generated.stat().st_size > 500: |
| import shutil |
| shutil.move(str(generated), str(out_path)) |
| return True |
| else: |
| if result.stderr: |
| print(f" F5-TTS stderr: {result.stderr[-400:]}") |
| return False |
|
|
| except Exception as e: |
| print(f" F5-TTS exception: {e}") |
| return False |
|
|
|
|
| |
| |
| |
|
|
| def generate_audio_simple(text: str, output_path: str) -> bool: |
| """ |
| Generate audio from text. |
| Tries finetuned F5-TTS first; falls back to edge-tts. |
| Never copies existing audio files. |
| """ |
| out = Path(output_path) |
| out.parent.mkdir(parents=True, exist_ok=True) |
| |
| if out.exists(): |
| out.unlink() |
|
|
| |
| print(f"[audio] F5-TTS generating: {text[:60]}...") |
| if _f5tts_generate(text, output_path) and out.exists(): |
| print(f" β F5-TTS ready: {out.name} ({out.stat().st_size:,} bytes)") |
| return True |
|
|
| |
| print("[audio] F5-TTS failed β falling back to edge-tts...") |
| success = asyncio.run(_edge_tts_generate(text, output_path)) |
| if success: |
| print(f" β edge-tts ready: {out.name} ({out.stat().st_size:,} bytes)") |
| else: |
| print(" β Both audio methods failed.") |
| return success |
|
|
|
|
| def generate_audio_minimal(text: str, output_path: str) -> bool: |
| """Alias kept for backward compatibility.""" |
| return generate_audio_simple(text, output_path) |
|
|
|
|
|
|