diff --git a/scripts/enable-voice.sh b/scripts/enable-voice.sh new file mode 100755 index 0000000..91ccf4e --- /dev/null +++ b/scripts/enable-voice.sh @@ -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 "$@" \ No newline at end of file