The model is great, but I'm not aware of a good way to run this model in portable way, I ended up with 1GB of installation bloat to get inference going.
import os
import sys
import subprocess
import urllib.request
import zipfile
import time
# --- Configuration & Paths ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
PORTABLE_DIR = os.path.join(BASE_DIR, "portable_python")
PYTHON_EXE = os.path.join(PORTABLE_DIR, "python.exe")
# Force models to download into a local folder, NOT C:\Users\...
os.environ["HF_HOME"] = os.path.join(BASE_DIR, "model_cache")
# URLs
PYTHON_ZIP_URL = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-embed-amd64.zip"
GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
KITTEN_WHEEL = "https://github.com/KittenML/KittenTTS/releases/download/0.8.1/kittentts-0.8.1-py3-none-any.whl"
def build_minimal_sandbox():
"""Builds the portable Python environment with aggressive space-saving."""
print("⬇️ Downloading minimal Windows Embeddable Python 3.11...")
os.makedirs(PORTABLE_DIR, exist_ok=True)
zip_path = os.path.join(PORTABLE_DIR, "python.zip")
urllib.request.urlretrieve(PYTHON_ZIP_URL, zip_path)
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall(PORTABLE_DIR)
os.remove(zip_path) # Clean up
print("🔧 Unlocking environment for pip...")
pth_file = os.path.join(PORTABLE_DIR, "python311._pth")
with open(pth_file, 'r') as f:
content = f.read()
with open(pth_file, 'w') as f:
f.write(content.replace('#import site', 'import site'))
print("⬇️ Installing pip...")
pip_script = os.path.join(PORTABLE_DIR, "get-pip.py")
urllib.request.urlretrieve(GET_PIP_URL, pip_script)
subprocess.run([PYTHON_EXE, pip_script], check=True)
os.remove(pip_script) # Clean up
print("🚀 Installing dependencies (Optimized for minimal footprint)...")
# 1. Install CPU-only PyTorch explicitly without caching to save ~150MB+
subprocess.run([
PYTHON_EXE, "-m", "pip", "install", "--no-cache-dir",
"torch", "--index-url", "https://download.pytorch.org/whl/cpu"
], check=True)
# 2. Install KittenTTS and Soundfile without caching
subprocess.run([
PYTHON_EXE, "-m", "pip", "install", "--no-cache-dir",
"soundfile", KITTEN_WHEEL
], check=True)
print("✅ Sandbox build complete!\n")
def interactive_tts_loop():
"""Runs the actual TTS interface (Only executes inside the sandbox)."""
from kittentts import KittenTTS
print("🧠 Loading KittenTTS Nano model (INT8)...")
model = KittenTTS("KittenML/kitten-tts-nano-0.8-int8")
print("\n" + "="*50)
print("🎙️ PORTABLE TTS ENGINE ACTIVE")
print("Type your text below to generate audio. Type 'exit' to quit.")
print("="*50)
file_counter = 1
while True:
try:
text = input("\n📝 Text to speak: ")
if text.strip().lower() in ['exit', 'quit']:
break
if not text.strip():
continue
output_file = f"output_{file_counter}.wav"
start_time = time.time()
model.generate_to_file(text=text, output_path=output_file, voice="Luna", speed=1.0)
elapsed = time.time() - start_time
print(f"🎉 Done! Saved '{output_file}' in {elapsed:.2f} seconds.")
file_counter += 1
except KeyboardInterrupt:
break
if __name__ == "__main__":
# 1. Check if the portable Python exists. If not, build it.
if not os.path.exists(PYTHON_EXE):
build_minimal_sandbox()
# 2. Check WHICH Python is currently running this script.
current_python = os.path.abspath(sys.executable).lower()
portable_python = os.path.abspath(PYTHON_EXE).lower()
if current_python != portable_python:
# We are running via your system Python.
# Relaunch THIS script using the portable Python instead.
print("🔄 Switching to portable sandbox environment...")
subprocess.run([PYTHON_EXE, __file__])
else:
# We are safely inside the portable Python! Run the AI.
interactive_tts_loop()
The model is great, but I'm not aware of a good way to run this model in portable way, I ended up with 1GB of installation bloat to get inference going.