Mirrors deploy/testnet/docker-compose.supplier-tts.yml and the simulation PiperTTS stack, co-located on vector-marketplace as a private internal service on marketplace-mainnet-net (no Traefik labels, no public DNS for Piper itself). Supplier reaches Piper at http://marketplace-mainnet-tts-piper:8000. Voice: en_US-lessac-high. New supplier wallet + on-chain advert are published out-of-band by the operator per the runbook header. Files: - deploy/mainnet/docker-compose.tts-piper.yml openedai-speech-min, private - deploy/mainnet/docker-compose.supplier-tts.yml CAPABILITY_KIND=tts supplier - deploy/mainnet/install-voice-extras.sh voice download + yaml mapping - deploy/mainnet/voice-mappings.py idempotent yaml editor - supplier/.env.tts.example operator env template - .gitignore whitelist .env.*.example Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.8 KiB
Bash
Executable File
75 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install-voice-extras.sh — runs ON THE HOST (vector-marketplace, as root)
|
|
# after `docker compose -f deploy/mainnet/docker-compose.tts-piper.yml up -d`
|
|
# to install Piper voices and yaml mappings beyond what the
|
|
# openedai-speech-min image ships with.
|
|
#
|
|
# Idempotent: every step is a no-op if it already finished previously.
|
|
# Safe to re-run after a host wipe — a fresh `data/` dir gets the same
|
|
# voices back.
|
|
#
|
|
# Mirrors deploy/simulation/install-voice-extras.sh; differs only in:
|
|
# - CONTAINER name (mainnet-prefixed)
|
|
# - resolves VOICES_DIR + voice-mappings.py relative to deploy/mainnet/
|
|
#
|
|
# What it does (in order):
|
|
# 1. Ensure the bind-mount voice files are present (curl -sSL with `[ -s ]` guard).
|
|
# 2. Copy voice-mappings.py into the container and execute it as root.
|
|
# The script edits /app/config/voice_to_speaker.yaml (host bind-mount) to
|
|
# add custom voice aliases. It prints "modified" or "unchanged" — we
|
|
# restart only on the former.
|
|
# 3. Restart the container if either step changed something.
|
|
#
|
|
# Usage:
|
|
# bash deploy/mainnet/install-voice-extras.sh
|
|
|
|
set -euo pipefail
|
|
|
|
MAINNET_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
VOICES_DIR="$MAINNET_DIR/data/tts-piper/voices"
|
|
CONTAINER="marketplace-mainnet-tts-piper"
|
|
|
|
mkdir -p "$VOICES_DIR"
|
|
changes=0
|
|
|
|
# --- 1. Voice files to install (filename → URL) ---
|
|
# Add entries here when you want another voice baked into the deploy.
|
|
# Each .onnx pairs with a .onnx.json — both must be downloaded.
|
|
voices=(
|
|
"en_US-lessac-high.onnx|https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/high/en_US-lessac-high.onnx"
|
|
"en_US-lessac-high.onnx.json|https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/high/en_US-lessac-high.onnx.json"
|
|
)
|
|
|
|
for entry in "${voices[@]}"; do
|
|
fn="${entry%%|*}"
|
|
url="${entry##*|}"
|
|
if [ -s "$VOICES_DIR/$fn" ]; then
|
|
echo "voice: already installed — $fn"
|
|
continue
|
|
fi
|
|
echo "voice: downloading $fn"
|
|
# `--fail` so HTTP 4xx/5xx aborts (HF returns html on 404 by default).
|
|
# Download to a tmp file then mv, so a partial download from a network
|
|
# blip doesn't leave a half-file that the next run treats as installed.
|
|
tmp="$VOICES_DIR/.${fn}.partial"
|
|
curl -sSL --fail --output "$tmp" "$url"
|
|
mv "$tmp" "$VOICES_DIR/$fn"
|
|
changes=1
|
|
done
|
|
|
|
# --- 2. Yaml mapping additions inside the container ---
|
|
docker cp "$MAINNET_DIR/voice-mappings.py" "$CONTAINER:/tmp/voice-mappings.py" >/dev/null
|
|
mapping_output="$(docker exec "$CONTAINER" python3 /tmp/voice-mappings.py)"
|
|
echo "mapping: $mapping_output"
|
|
if [[ "$mapping_output" == modified* ]]; then
|
|
changes=1
|
|
fi
|
|
|
|
# --- 3. Restart only if anything changed ---
|
|
if [ "$changes" -eq 1 ]; then
|
|
echo "→ restarting $CONTAINER to pick up new voices/mappings"
|
|
docker restart "$CONTAINER" >/dev/null
|
|
else
|
|
echo "✓ voice extras already up to date — no restart needed"
|
|
fi
|