# Runtime shim for KittenTTS on a CPU-only, disk-constrained host. # # kittentts/onnx_model.py opens with `from misaki import en, espeak` — a dead import: # every code path that produces audio from text goes through phonemizer-fork's # EspeakBackend (espeak-ng via espeakng-loader); misaki.en/espeak are never called. # If misaki[en] were installed for real, those two imports would be a hook for the # whole spacy → thinc → torch → CUDA chain (~5.6 GB verified). This stub registers # `misaki.en` and `misaki.espeak` as import-time-only placeholders instead. # # Written into site-packages by the derivation (see pkgs/kittentts-env.nix) under # `sitecustomize.py`-style auto-load — actually via a `kitten_tts_stub.py` + a `.pth` # pointing at it, so any Python process in this env gets the stub registered before # any kittentts import. If KittenTTS upstream ever starts USING misaki, this shim # will fail loudly at import of the missing attributes (better than silent distortion), # and the fix becomes "install the real misaki[en]" — a deliberate, reviewed change. import sys import types _misaki = sys.modules.get("misaki") if _misaki is None: # Avoid registering a fake parent before the real misaki loads — the base misaki # (addict/regex only) is installed normally, so usually already here. import misaki # noqa: F401 (raises if base misaki is missing — loud, not silent) _misaki = sys.modules["misaki"] if getattr(_misaki, "en", None) is None: _stub = types.ModuleType("misaki.en") sys.modules.setdefault("misaki.en", _stub) _misaki.en = _stub if getattr(_misaki, "espeak", None) is None: _stub2 = types.ModuleType("misaki.espeak") sys.modules.setdefault("misaki.espeak", _stub2) _misaki.espeak = _stub2