Add voice assistant convenience scripts
- enable-voice.sh: One-command setup for voice assistant - Automatic prerequisite checking (Poetry, piper-tts, voice models) - Voice model download with progress indicators - Server startup with health testing - Auto-generates disable-voice.sh for cleanup 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
231
scripts/enable-voice.sh
Executable file
231
scripts/enable-voice.sh
Executable file
@@ -0,0 +1,231 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Enable Voice Mode - Start voice server and configure voice-mode
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
HOMELAB_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
VOICE_SERVER_DIR="$HOMELAB_ROOT/voice-server"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_prerequisites() {
|
||||||
|
log_info "Checking prerequisites..."
|
||||||
|
|
||||||
|
# Check if poetry is installed
|
||||||
|
if ! command -v poetry &> /dev/null; then
|
||||||
|
log_error "Poetry is not installed. Please install it first:"
|
||||||
|
log_error "curl -sSL https://install.python-poetry.org | python3 -"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if piper-tts is installed
|
||||||
|
if ! command -v piper-tts &> /dev/null; then
|
||||||
|
log_error "piper-tts is not installed. Please install it first:"
|
||||||
|
log_error "yay -S piper-tts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if voice server directory exists
|
||||||
|
if [[ ! -d "$VOICE_SERVER_DIR" ]]; then
|
||||||
|
log_error "Voice server directory not found: $VOICE_SERVER_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if voice models exist
|
||||||
|
VOICES_DIR="$HOME/.local/share/piper-voices"
|
||||||
|
RYAN_MODEL="$VOICES_DIR/en_US-ryan-medium.onnx"
|
||||||
|
|
||||||
|
if [[ ! -f "$RYAN_MODEL" ]]; then
|
||||||
|
log_warn "Ryan voice model not found: $RYAN_MODEL"
|
||||||
|
log_info "Downloading voice models..."
|
||||||
|
|
||||||
|
mkdir -p "$VOICES_DIR"
|
||||||
|
cd "$VOICES_DIR"
|
||||||
|
|
||||||
|
log_info "Downloading Ryan voice (male US English)..."
|
||||||
|
wget -q --show-progress \
|
||||||
|
"https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ryan/medium/en_US-ryan-medium.onnx" \
|
||||||
|
"https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/ryan/medium/en_US-ryan-medium.onnx.json"
|
||||||
|
|
||||||
|
log_info "Voice models downloaded successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Prerequisites check completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_voice_server() {
|
||||||
|
log_info "Setting up voice server..."
|
||||||
|
|
||||||
|
cd "$VOICE_SERVER_DIR"
|
||||||
|
|
||||||
|
# Install dependencies if needed
|
||||||
|
if [[ ! -d ".venv" ]] || ! poetry check &> /dev/null; then
|
||||||
|
log_info "Installing voice server dependencies..."
|
||||||
|
poetry install --only=main
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Voice server setup completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_voice_server() {
|
||||||
|
log_info "Starting voice server..."
|
||||||
|
|
||||||
|
cd "$VOICE_SERVER_DIR"
|
||||||
|
|
||||||
|
# Check if server is already running
|
||||||
|
if curl -s http://127.0.0.1:8880/health > /dev/null 2>&1; then
|
||||||
|
log_warn "Voice server is already running on port 8880"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start server in background
|
||||||
|
log_info "Starting voice server on http://127.0.0.1:8880"
|
||||||
|
poetry run voice-server &
|
||||||
|
SERVER_PID=$!
|
||||||
|
|
||||||
|
# Save PID for cleanup
|
||||||
|
echo $SERVER_PID > /tmp/voice-server.pid
|
||||||
|
|
||||||
|
# Wait for server to start
|
||||||
|
log_info "Waiting for server to start..."
|
||||||
|
for i in {1..30}; do
|
||||||
|
if curl -s http://127.0.0.1:8880/health > /dev/null 2>&1; then
|
||||||
|
log_info "Voice server started successfully (PID: $SERVER_PID)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
log_error "Failed to start voice server"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test_voice_server() {
|
||||||
|
log_info "Testing voice server..."
|
||||||
|
|
||||||
|
# Test health endpoint
|
||||||
|
if ! curl -s http://127.0.0.1:8880/health | grep -q "healthy"; then
|
||||||
|
log_error "Voice server health check failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test TTS endpoint
|
||||||
|
if ! curl -s -X POST "http://127.0.0.1:8880/v1/audio/speech" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"input": "Voice server test", "voice": "ryan"}' \
|
||||||
|
--output /tmp/voice-test.wav > /dev/null 2>&1; then
|
||||||
|
log_error "Voice server TTS test failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if audio file was created
|
||||||
|
if [[ ! -f "/tmp/voice-test.wav" ]] || [[ ! -s "/tmp/voice-test.wav" ]]; then
|
||||||
|
log_error "Generated audio file is invalid"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/voice-test.wav
|
||||||
|
log_info "Voice server test completed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_usage() {
|
||||||
|
log_info "Voice mode is now enabled!"
|
||||||
|
echo
|
||||||
|
echo "Server Details:"
|
||||||
|
echo " URL: http://127.0.0.1:8880"
|
||||||
|
echo " Health: http://127.0.0.1:8880/health"
|
||||||
|
echo " API Docs: http://127.0.0.1:8880/docs"
|
||||||
|
echo
|
||||||
|
echo "Available commands:"
|
||||||
|
echo " # Test TTS"
|
||||||
|
echo " curl -X POST 'http://127.0.0.1:8880/v1/audio/speech' \\"
|
||||||
|
echo " -H 'Content-Type: application/json' \\"
|
||||||
|
echo " -d '{\"input\": \"Hello world!\", \"voice\": \"ryan\"}' \\"
|
||||||
|
echo " --output test.wav"
|
||||||
|
echo
|
||||||
|
echo " # Stop server"
|
||||||
|
echo " $SCRIPT_DIR/disable-voice.sh"
|
||||||
|
echo
|
||||||
|
echo " # View server logs"
|
||||||
|
echo " tail -f $VOICE_SERVER_DIR/voice-server.log"
|
||||||
|
echo
|
||||||
|
log_info "You can now use voice commands in Claude Code!"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_disable_script() {
|
||||||
|
cat > "$SCRIPT_DIR/disable-voice.sh" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Disable Voice Mode - Stop voice server
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -f "/tmp/voice-server.pid" ]]; then
|
||||||
|
PID=$(cat /tmp/voice-server.pid)
|
||||||
|
if kill -0 "$PID" 2>/dev/null; then
|
||||||
|
log_info "Stopping voice server (PID: $PID)..."
|
||||||
|
kill "$PID"
|
||||||
|
rm -f /tmp/voice-server.pid
|
||||||
|
log_info "Voice server stopped"
|
||||||
|
else
|
||||||
|
log_error "Voice server process not found"
|
||||||
|
rm -f /tmp/voice-server.pid
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "Voice server PID file not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also try to kill any remaining voice-server processes
|
||||||
|
pkill -f "voice-server" && log_info "Cleaned up remaining voice-server processes"
|
||||||
|
|
||||||
|
log_info "Voice mode disabled"
|
||||||
|
EOF
|
||||||
|
chmod +x "$SCRIPT_DIR/disable-voice.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
log_info "Enabling Voice Mode for Claude Code..."
|
||||||
|
|
||||||
|
check_prerequisites
|
||||||
|
setup_voice_server
|
||||||
|
start_voice_server
|
||||||
|
test_voice_server
|
||||||
|
create_disable_script
|
||||||
|
show_usage
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle cleanup on exit
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "${SERVER_PID:-}" ]]; then
|
||||||
|
log_info "Cleaning up..."
|
||||||
|
kill "$SERVER_PID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user