VoiceTut-TTS / handler.py
oaattia's picture
Upgrade transformers at runtime for OmniVoice HiggsAudioV2TokenizerModel support
830d400
Raw
History Blame Contribute Delete
3.77 kB
import io
import base64
import logging
import subprocess
import sys
import numpy as np
import soundfile as sf
logger = logging.getLogger(__name__)
def _install_deps():
"""Install OmniVoice and voicetut-tts with --no-deps to avoid conflicts
with the HF Inference Endpoint base image.
Then upgrade transformers (WITH deps) because OmniVoice needs
HiggsAudioV2TokenizerModel which only exists in transformers>=4.50.
The HF Inference Toolkit already loaded successfully with the old
transformers at this point, so upgrading is safe."""
# 1. Install OmniVoice and voicetut-tts without their dep trees
pkgs = [
"git+https://github.com/k2-fsa/OmniVoice.git",
"voicetut-tts>=0.1.0",
]
for pkg in pkgs:
try:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "--no-deps", pkg],
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
)
logger.info(f"Installed {pkg}")
except subprocess.CalledProcessError as e:
stderr = e.stderr.decode() if e.stderr else ""
if "already satisfied" not in stderr.lower():
logger.warning(f"Failed to install {pkg}: {stderr[:200]}")
# 2. Upgrade transformers to get HiggsAudioV2TokenizerModel (needed by OmniVoice)
try:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "--upgrade",
"transformers>=4.50.0", "tokenizers>=0.21.0"],
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
)
logger.info("Upgraded transformers for OmniVoice compatibility")
except subprocess.CalledProcessError as e:
stderr = e.stderr.decode() if e.stderr else ""
logger.warning(f"Failed to upgrade transformers: {stderr[:200]}")
# Install deps before importing voicetut_tts
_install_deps()
from voicetut_tts import VoiceTutTTS, GenerationParams
class EndpointHandler:
def __init__(self, model_dir=""):
logger.info(f"Loading VoiceTut-TTS from {model_dir or 'mohammedaly22/VoiceTut-TTS'}...")
self.tts = VoiceTutTTS.from_pretrained(
model_dir or "mohammedaly22/VoiceTut-TTS",
dtype="float16",
)
self.sampling_rate = self.tts.sampling_rate
logger.info(f"VoiceTut-TTS loaded. Sampling rate: {self.sampling_rate}")
def __call__(self, data: dict) -> dict:
inputs = data.get("inputs", data)
text = inputs.get("text", "").strip()
if not text:
return {"error": "text is required"}
voice = inputs.get("voice", "Mohamed")
language = inputs.get("language", "arz")
normalize = inputs.get("normalize", True)
num_step = int(inputs.get("num_step", 32))
guidance_scale = float(inputs.get("guidance_scale", 2.0))
speed = float(inputs.get("speed", 1.0))
params = GenerationParams(
num_step=num_step,
guidance_scale=guidance_scale,
speed=speed,
)
try:
wav = self.tts.synthesize(
text,
speaker=voice,
language=language,
normalize=normalize,
params=params,
)
except Exception as e:
logger.exception("Synthesis failed")
return {"error": str(e)}
buf = io.BytesIO()
sf.write(buf, wav, self.sampling_rate, format="WAV")
wav_bytes = buf.getvalue()
wav_b64 = base64.b64encode(wav_bytes).decode("utf-8")
return {
"audio_base64": wav_b64,
"sampling_rate": self.sampling_rate,
"duration_sec": float(len(wav) / self.sampling_rate),
}