# Self-contained compose for Sanad Package 4 (Custom AI Guide Tour, sanad-guide). # docker compose up -d --build # -> http://:8014 # # TWO-CONTAINER architecture: this `sanad-guide` (Python) bridges over HTTP to the # SEPARATE `sanad-nav` = the existing web_nav3 / Nav2 / rosbridge ROS2 stack # (Nav2_Projects/web_nav3, :8765). sanad-nav is NOT built here — run it separately # and point WEB_NAV3_URL at it. Without it, tours degrade to preset (narrate-in-place) # stops (WebNav3Client never raises). services: p4: build: context: . dockerfile: Dockerfile args: BASE_OS_IMAGE: "${BASE_OS_IMAGE:-python:3.10-slim-bookworm}" WITH_UNITREE_SDK: "${WITH_UNITREE_SDK:-1}" image: "${SANAD_IMAGE:-sanad-p4:latest}" container_name: sanad-p4 network_mode: host restart: unless-stopped cap_add: - NET_ADMIN group_add: - video environment: SANAD_PACKAGE: P4 SANAD_DASHBOARD_PORT: "8014" SANAD_DASHBOARD_HOST: "0.0.0.0" SANAD_VOICE_BRAIN: gemini SANAD_AUDIO_PROFILE: "${SANAD_AUDIO_PROFILE:-builtin}" SANAD_DDS_INTERFACE: "${SANAD_DDS_INTERFACE:-eth0}" # Plugged/Bluetooth audio (Anker USB, JBL BT) route through the HOST # PulseAudio server — chest ("builtin") uses DDS and needs none of this. PULSE_SERVER: "${PULSE_SERVER:-unix:/run/user/1000/pulse/native}" PULSE_COOKIE: "${PULSE_COOKIE:-/run/user/1000/pulse/cookie}" # root→uid-1000 PA auth SANAD_MASK_DIR: /app/mask SANAD_TOURS_DIR: /app/Sanad/data/tours # Nav bridge → the separate sanad-nav (web_nav3) stack: WEB_NAV3_URL: "${WEB_NAV3_URL:-http://127.0.0.1:8765}" SANAD_ROBOT_NAME: "${SANAD_ROBOT_NAME:-sanad}" SANAD_NAV_GOAL_TIMEOUT_S: "${SANAD_NAV_GOAL_TIMEOUT_S:-240}" SANAD_LICENSE: /etc/sanad/sanad.lic SANAD_PUBKEY: /etc/sanad/pubkey.ed25519 SANAD_LICENSE_BIND: "${SANAD_LICENSE_BIND:-0}" devices: - "/dev/snd:/dev/snd" - "/dev/bus/usb:/dev/bus/usb" # - "/dev/video0:/dev/video0" # OPTIONAL recognition — uncomment + set your camera node volumes: - "${SANAD_LICENSE_FILE:-./license/sanad.lic.example}:/etc/sanad/sanad.lic:ro" # Plugged/Bluetooth audio (Anker/JBL): mount the host PulseAudio runtime dir # (socket + auth cookie) so the container sets ANY sink's volume/output — the # volume slider then drives chest (DDS) AND plugged (PA), exactly like SanadV3. # Chest ("builtin") audio uses DDS only and needs none of this. One-time host # setup for a stable boot-time socket: `loginctl enable-linger unitree`. - "${SANAD_PULSE_DIR:-/run/user/1000/pulse}:/run/user/1000/pulse" - "./data:/app/Sanad/data" # persist tours / zones / faces / recordings - "./config/mask_config.json:/app/Sanad/config/mask_config.json" - "/var/run/dbus:/var/run/dbus" # - "/etc/machine-id:/etc/machine-id:ro" # for SANAD_LICENSE_BIND=1