From af59e9b83d488384975876ad088c2e2ba2324d9a Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Mon, 21 Sep 2026 13:25:26 -0700 Subject: [PATCH] Add local engine installer and requirements, ignore .DS_Store --- .gitignore | 1 + install-local.sh | 79 ++++++++++++++++++++++++++++++++++++++++++ requirements-local.txt | 7 ++++ 3 files changed, 87 insertions(+) create mode 100755 install-local.sh create mode 100644 requirements-local.txt diff --git a/.gitignore b/.gitignore index 788f058..d7b024e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ client_secret.json __pycache__/ *.pyc .venv/ +.DS_Store diff --git a/install-local.sh b/install-local.sh new file mode 100755 index 0000000..719715f --- /dev/null +++ b/install-local.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "$0")" + +info() { printf '\n\033[1;34m==>\033[0m %s\n' "$1"; } +fail() { printf '\033[1;31mError:\033[0m %s\n' "$1"; exit 1; } + +[ -x .venv/bin/python ] || fail "Run ./install.sh first" + +if [ -n "${PIP_CACHE_DIR:-}" ]; then + mkdir -p "$PIP_CACHE_DIR" + info "Using pip cache at $PIP_CACHE_DIR" +fi + +info "Installing local image generation packages (a few GB)" +.venv/bin/python -m pip install --upgrade pip +.venv/bin/python -m pip install -r requirements-local.txt + +if [ "$(uname -s)" = "Linux" ] && ! command -v espeak-ng >/dev/null 2>&1; then + info "Installing espeak-ng for text to speech" + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get install -y espeak-ng + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y espeak-ng + elif command -v pacman >/dev/null 2>&1; then + sudo pacman -Sy --needed --noconfirm espeak-ng + elif command -v zypper >/dev/null 2>&1; then + sudo zypper --non-interactive install espeak-ng + fi +fi + +info "Installing Piper for natural sounding narration" +.venv/bin/python -m pip install piper-tts || echo "Piper install failed, narration will fall back to the system voice" + +VOICE_DIR="${VOICE_DIR:-}" +if [ -z "$VOICE_DIR" ]; then + VOICE_DIR="$(.venv/bin/python - <<'PY' +import json +from pathlib import Path +base = Path(__file__).resolve().parent if "__file__" in dir() else Path.cwd() +try: + g = json.loads((Path("data") / "settings.json").read_text()) +except Exception: + g = {} +models = str(g.get("models_dir") or "").strip() +storage = str(g.get("storage_dir") or "videos").strip() +root = Path(models) if models else Path(storage) / "models" +print(root / "voices") +PY +)" +fi +mkdir -p "$VOICE_DIR" +VOICE_BASE="https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/medium/en_US-lessac-medium" +if [ ! -f "$VOICE_DIR/en_US-lessac-medium.onnx" ]; then + info "Downloading the Piper voice into $VOICE_DIR" + curl -fL --progress-bar -o "$VOICE_DIR/en_US-lessac-medium.onnx" "$VOICE_BASE.onnx" \ + && curl -fL --progress-bar -o "$VOICE_DIR/en_US-lessac-medium.onnx.json" "$VOICE_BASE.onnx.json" \ + || echo "Voice download failed, narration will fall back to the system voice" +else + info "Piper voice already downloaded" +fi + +info "Checking torch" +.venv/bin/python - <<'EOF' +import torch +if torch.backends.mps.is_available(): + device = "mps (Apple GPU)" +elif torch.cuda.is_available(): + device = "cuda" +else: + device = "cpu (slow)" +print(f"torch {torch.__version__} will run on {device}") +EOF + +info "Done" +echo "In Settings set Video engine to local, set Models folder and Temp folder, then Save" +echo "The first run downloads about 7 GB into your Models folder" +echo "Narration uses Piper automatically when a voice is present in the voices folder" diff --git a/requirements-local.txt b/requirements-local.txt new file mode 100644 index 0000000..ae3260b --- /dev/null +++ b/requirements-local.txt @@ -0,0 +1,7 @@ +torch +diffusers +transformers +accelerate +safetensors +sentencepiece +protobuf