# kokoro_utils.py import os import tempfile import soundfile as sf from kokoro_onnx import Kokoro # Resolve paths relative to project root BASE_DIR = os.path.dirname(os.path.abspath(__file__)) MODEL_PATH = os.path.join(BASE_DIR, "kokoro-v1.0.onnx") VOICES_PATH = os.path.join(BASE_DIR, "voices-v1.0.bin") _kokoro_instance = None def get_kokoro_engine(): global _kokoro_instance if _kokoro_instance is None: if os.path.exists(MODEL_PATH) and os.path.exists(VOICES_PATH): _kokoro_instance = Kokoro(MODEL_PATH, VOICES_PATH) return _kokoro_instance def generate_local_speech(text: str, voice_name: str = "af_bella", speed: float = 1.0) -> str: """ Synthesizes speech locally using Kokoro and saves to a temp file, returning the path to the generated audio file with correct language routing. """ engine = get_kokoro_engine() if not engine: raise FileNotFoundError( f"Kokoro model files not found at root directory.\nExpected:\n- {MODEL_PATH}\n- {VOICES_PATH}" ) # Route language code explicitly based on voice prefix if voice_name.startswith("es") or voice_name.startswith("ef") or voice_name.startswith("em"): lang_code = "es" else: lang_code = "en-us" samples, sample_rate = engine.create( text, voice=voice_name, speed=speed, lang=lang_code ) temp_file = os.path.join(tempfile.gettempdir(), "kokoro_review_audio.wav") sf.write(temp_file, samples, sample_rate) return temp_file