mindfull / simple_audio_gen.py
IamSamk
Mindfull Gradio Space deploy
27caffe
Raw
History Blame Contribute Delete
5.4 kB
"""
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
# ── paths (all relative to this file) ────────────────────────────────────────
_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 fallback voice ────────────────────────────────────────────────────
EDGE_TTS_VOICE = "en-US-JennyNeural"
# ─────────────────────────────────────────────────────────────────────────────
# Internal helpers
# ─────────────────────────────────────────────────────────────────────────────
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)
# Use a temp dir so we can rename the output to the exact path
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
# ─────────────────────────────────────────────────────────────────────────────
# Public API (called by mindfull_pipeline.py)
# ─────────────────────────────────────────────────────────────────────────────
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)
# Always start fresh
if out.exists():
out.unlink()
# ── 1. try finetuned F5-TTS ──────────────────────────────────────────────
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
# ── 2. fallback: edge-tts ────────────────────────────────────────────────
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)