dotfiles/scripts/bin/speak

48 lines
1.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# Script Name: speak
# Description: Text-to-speech with ElevenLabs/Piper/espeak support
# Source: Enhanced from https://evanhahn.com/scripts-i-wrote-that-i-use-all-the-time/
# Usage: echo "text" | speak
# speak < file.txt
# cat README.md | speak
# Strip markdown if pandoc is available
if command -v pandoc &>/dev/null; then
text=$(pandoc -f commonmark -t plain --wrap=preserve)
else
text=$(cat)
fi
# Try voice systems in order of preference:
# 1. ElevenLabs (best quality, requires API)
# 2. Piper (good quality, local)
# 3. espeak-ng (fallback)
# 4. say (macOS)
if command -v elevenlabs &>/dev/null && [[ -n "${ELEVENLABS_API_KEY:-}" ]]; then
# Use ElevenLabs (highest quality)
echo "$text" | elevenlabs tts --voice "Adam" --play
elif command -v piper &>/dev/null; then
# Use Piper (good local TTS)
# Look for installed voice models
piper_voice_dir="$HOME/.local/share/piper/voices"
if [[ -f "$piper_voice_dir/en_US-amy-medium.onnx" ]]; then
echo "$text" | piper --model "$piper_voice_dir/en_US-amy-medium.onnx" --output-raw | aplay -r 22050 -f S16_LE -t raw -
else
echo "Error: Piper voice model not found at $piper_voice_dir" >&2
echo "Download with: piper --download-dir $piper_voice_dir --download en_US-amy-medium" >&2
exit 1
fi
elif hash espeak-ng 2>/dev/null; then
# Use espeak-ng (basic but reliable)
echo "$text" | espeak-ng
elif hash say 2>/dev/null; then
# Use macOS say
echo "$text" | say
else
echo "Error: No TTS program found" >&2
echo "Install one of: piper, espeak-ng, or set ELEVENLABS_API_KEY" >&2
exit 1
fi