# ============================================================================== # NyxClaw - Docker Compose Configuration # ============================================================================== # # Usage: # Production: docker-compose up -d # Development: docker-compose --profile dev up # Logs: docker-compose logs -f # Stop: docker-compose down # # ============================================================================== services: # ============================================================================ # NyxClaw (Production) # ============================================================================ server: build: context: . target: production args: INSTALL_LOCAL_VOICE: ${INSTALL_LOCAL_VOICE:-false} container_name: nyxclaw extra_hosts: - "host.docker.internal:host-gateway" ports: - "8081:8080" environment: - ASSISTANT_INSTRUCTIONS=${ASSISTANT_INSTRUCTIONS:-You are a helpful and friendly AI assistant.} - ONNX_MODEL_PATH=/app/pretrained_models/wav2arkit/wav2arkit_cpu.onnx - SERVER_HOST=0.0.0.0 - SERVER_PORT=8080 - AUTH_ENABLED=${AUTH_ENABLED:-false} - AUTH_ENABLE_RATE_LIMITING=${AUTH_ENABLE_RATE_LIMITING:-true} - AUTH_SETUP_CODE_URL=${AUTH_SETUP_CODE_URL:-} - AUTH_STORE_PATH=/app/data/auth_store.json - AUTH_REGENERATE_SETUP_CODE=${AUTH_REGENERATE_SETUP_CODE:-false} # Cloudflare Tunnel provisioning - PROVISIONING_API_URL=${PROVISIONING_API_URL:-https://nyxclaw-provisioner.nyxclaw.workers.dev} - DEVICE_ID_PATH=/app/data/device_id - TUNNEL_CONFIG_PATH=/app/data/tunnel.json - DEBUG=${DEBUG:-false} - DEBUG_AUDIO_CAPTURE=${DEBUG_AUDIO_CAPTURE:-false} # Agent Configuration - AGENT_TYPE=${AGENT_TYPE:-openclaw} - VOICE_MODE=${VOICE_MODE:-openai} # OpenAI Voice Mode - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENAI_REALTIME_MODEL=${OPENAI_REALTIME_MODEL:-gpt-realtime} - OPENAI_VAD_TYPE=${OPENAI_VAD_TYPE:-semantic_vad} - OPENAI_TRANSCRIPTION_MODEL=${OPENAI_TRANSCRIPTION_MODEL:-gpt-4o-transcribe} - OPENAI_TRANSCRIPTION_LANGUAGE=${OPENAI_TRANSCRIPTION_LANGUAGE:-en} - OPENAI_TRANSCRIPTION_PROMPT=${OPENAI_TRANSCRIPTION_PROMPT:-} - OPENAI_TTS_MODEL=${OPENAI_TTS_MODEL:-tts-1} - OPENAI_VOICE=${OPENAI_VOICE:-alloy} - OPENAI_TTS_SPEED=${OPENAI_TTS_SPEED:-1.0} # Agent Backend Configuration - BASE_URL=${BASE_URL:-http://host.docker.internal:19001} - AUTH_TOKEN=${AUTH_TOKEN} - AGENT_MODEL=${AGENT_MODEL:-openclaw:main} - USER_ID=${USER_ID} - THINKING_MODE=${THINKING_MODE:-minimal} - SESSION_KEY=${SESSION_KEY} - AGENT_ID=${AGENT_ID} - MAX_RETRIES=${MAX_RETRIES:-2} # Avatar endpoint (patched OpenClaw/ZeroClaw) - AVATAR_ENDPOINT=${AVATAR_ENDPOINT:-/v1/chat/completions/avatar} - USE_AVATAR_ENDPOINT=${USE_AVATAR_ENDPOINT:-false} # STT/TTS Configuration - STT_ENABLED=${STT_ENABLED:-true} - STT_MODEL=${STT_MODEL:-small.en} - STT_VAD_START_THRESHOLD=${STT_VAD_START_THRESHOLD:-0.60} - STT_VAD_END_THRESHOLD=${STT_VAD_END_THRESHOLD:-0.35} - STT_VAD_MIN_SILENCE_MS=${STT_VAD_MIN_SILENCE_MS:-500} - STT_INITIAL_PROMPT=${STT_INITIAL_PROMPT:-} - TTS_ENABLED=${TTS_ENABLED:-true} - TTS_ONNX_MODEL_DIR=${TTS_ONNX_MODEL_DIR:-/app/pretrained_models/piper} - TTS_VOICE_NAME=${TTS_VOICE_NAME:-en_US-hfc_female-medium} - TTS_VOICE_PATH=${TTS_VOICE_PATH} - TTS_NOISE_SCALE=${TTS_NOISE_SCALE:-0.75} - TTS_NOISE_W_SCALE=${TTS_NOISE_W_SCALE:-0.8} - TTS_LENGTH_SCALE=${TTS_LENGTH_SCALE:-0.95} volumes: # Uncomment to override baked-in models without rebuilding: # - ./pretrained_models/wav2arkit:/app/pretrained_models/wav2arkit:ro # - ./pretrained_models/piper:/app/pretrained_models/piper:ro # - ./pretrained_models/faster_whisper_small_en:/app/pretrained_models/faster_whisper_small_en:ro - ./data:/app/data # Persistent auth store + tunnel config dns: - 1.1.1.1 - 8.8.8.8 restart: unless-stopped healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"] interval: 30s timeout: 10s retries: 3 start_period: 120s # ============================================================================ # Cloudflare Tunnel (automatic TLS — wss:// access from anywhere) # ============================================================================ tunnel: image: cloudflare/cloudflared:latest container_name: nyxclaw-tunnel command: tunnel run --token-file /data/tunnel_token volumes: - ./data:/data:ro depends_on: server: condition: service_healthy restart: unless-stopped # ============================================================================ # NyxClaw (Development with hot reload) # ============================================================================ server-dev: build: context: . target: development args: INSTALL_LOCAL_VOICE: ${INSTALL_LOCAL_VOICE:-false} container_name: nyxclaw-dev profiles: - dev ports: - "${SERVER_PORT:-8080}:8080" environment: - ASSISTANT_INSTRUCTIONS=${ASSISTANT_INSTRUCTIONS:-You are a helpful and friendly AI assistant.} - ONNX_MODEL_PATH=/app/pretrained_models/wav2arkit/wav2arkit_cpu.onnx - SERVER_HOST=0.0.0.0 - SERVER_PORT=8080 - AUTH_ENABLED=${AUTH_ENABLED:-false} - AUTH_ENABLE_RATE_LIMITING=${AUTH_ENABLE_RATE_LIMITING:-true} - AUTH_SETUP_CODE_URL=${AUTH_SETUP_CODE_URL:-} - AUTH_STORE_PATH=/app/data/auth_store.json - AUTH_REGENERATE_SETUP_CODE=${AUTH_REGENERATE_SETUP_CODE:-false} - DEBUG=true # Agent Configuration - AGENT_TYPE=${AGENT_TYPE:-openclaw} - VOICE_MODE=${VOICE_MODE:-openai} # OpenAI Voice Mode - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENAI_REALTIME_MODEL=${OPENAI_REALTIME_MODEL:-gpt-realtime} - OPENAI_VAD_TYPE=${OPENAI_VAD_TYPE:-semantic_vad} - OPENAI_TRANSCRIPTION_MODEL=${OPENAI_TRANSCRIPTION_MODEL:-gpt-4o-transcribe} - OPENAI_TRANSCRIPTION_LANGUAGE=${OPENAI_TRANSCRIPTION_LANGUAGE:-en} - OPENAI_TRANSCRIPTION_PROMPT=${OPENAI_TRANSCRIPTION_PROMPT:-} - OPENAI_TTS_MODEL=${OPENAI_TTS_MODEL:-tts-1} - OPENAI_VOICE=${OPENAI_VOICE:-alloy} - OPENAI_TTS_SPEED=${OPENAI_TTS_SPEED:-1.0} # Agent Backend Configuration - BASE_URL=${BASE_URL:-http://host.docker.internal:19001} - AUTH_TOKEN=${AUTH_TOKEN} - AGENT_MODEL=${AGENT_MODEL:-openclaw:main} - USER_ID=${USER_ID} - THINKING_MODE=${THINKING_MODE:-minimal} - SESSION_KEY=${SESSION_KEY} - AGENT_ID=${AGENT_ID} - MAX_RETRIES=${MAX_RETRIES:-2} # Avatar endpoint (patched OpenClaw/ZeroClaw) - AVATAR_ENDPOINT=${AVATAR_ENDPOINT:-/v1/chat/completions/avatar} - USE_AVATAR_ENDPOINT=${USE_AVATAR_ENDPOINT:-false} # STT/TTS Configuration - STT_ENABLED=${STT_ENABLED:-true} - STT_MODEL=${STT_MODEL:-small.en} - STT_VAD_START_THRESHOLD=${STT_VAD_START_THRESHOLD:-0.60} - STT_VAD_END_THRESHOLD=${STT_VAD_END_THRESHOLD:-0.35} - STT_VAD_MIN_SILENCE_MS=${STT_VAD_MIN_SILENCE_MS:-500} - STT_INITIAL_PROMPT=${STT_INITIAL_PROMPT:-} - TTS_ENABLED=${TTS_ENABLED:-true} - TTS_ONNX_MODEL_DIR=${TTS_ONNX_MODEL_DIR:-/app/pretrained_models/piper} - TTS_VOICE_NAME=${TTS_VOICE_NAME:-en_US-hfc_female-medium} - TTS_VOICE_PATH=${TTS_VOICE_PATH} - TTS_NOISE_SCALE=${TTS_NOISE_SCALE:-0.75} - TTS_NOISE_W_SCALE=${TTS_NOISE_W_SCALE:-0.8} - TTS_LENGTH_SCALE=${TTS_LENGTH_SCALE:-0.95} volumes: - .:/app # Uncomment to override baked-in models without rebuilding: # - ./pretrained_models/wav2arkit:/app/pretrained_models/wav2arkit:ro # - ./pretrained_models/piper:/app/pretrained_models/piper:ro # - ./pretrained_models/faster_whisper_small_en:/app/pretrained_models/faster_whisper_small_en:ro - ./data:/app/data # Persistent auth store command: uv run uvicorn src.main:app --host 0.0.0.0 --port 8080 --reload