feat: split-deployment roles (browser-host on LAN + remote bot)
Add JARVIS_ROLE (full|browser|bot) via a run-if-role.sh supervisord guard so one image serves three layouts. Make Chrome CDP bind configurable (CDP_BIND) and publishable on the LAN (CDP_PUBLISH_BIND) so a bot on another PC can drive this host's on-screen Chrome over the internal network (no auth, as requested).
This commit is contained in:
@@ -79,6 +79,18 @@ services:
|
|||||||
STT_LANGUAGE: ${STT_LANGUAGE:-ko}
|
STT_LANGUAGE: ${STT_LANGUAGE:-ko}
|
||||||
VOICE_SILENCE_MS: ${VOICE_SILENCE_MS:-600}
|
VOICE_SILENCE_MS: ${VOICE_SILENCE_MS:-600}
|
||||||
BRIDGE_URL: http://127.0.0.1:8765
|
BRIDGE_URL: http://127.0.0.1:8765
|
||||||
|
# Split-deployment role: full (default, all-in-one), browser (only the
|
||||||
|
# desktop + Chrome + CDP, reused over the LAN), or bot (only bot + bridge
|
||||||
|
# + TTS, driving a remote browser via CDP_HOST). See docker/run-if-role.sh.
|
||||||
|
JARVIS_ROLE: ${JARVIS_ROLE:-full}
|
||||||
|
# Chrome CDP bind address INSIDE the container. 0.0.0.0 lets a remote bot
|
||||||
|
# (JARVIS_ROLE=bot on another PC) drive this host's browser. Loopback by
|
||||||
|
# default so the all-in-one layout stays unreachable off-host.
|
||||||
|
CDP_BIND: ${CDP_BIND:-127.0.0.1}
|
||||||
|
CDP_PORT: ${CDP_PORT:-9222}
|
||||||
|
# Where the bot drives Chrome. Loopback for full/browser; on a remote bot
|
||||||
|
# set CDP_HOST to the browser host's LAN IP (e.g. 192.168.10.9).
|
||||||
|
CDP_HOST: ${CDP_HOST:-127.0.0.1}
|
||||||
depends_on:
|
depends_on:
|
||||||
- ollama
|
- ollama
|
||||||
# GPU: accelerates Whisper STT (and anything else CUDA) in this container.
|
# GPU: accelerates Whisper STT (and anything else CUDA) in this container.
|
||||||
@@ -95,6 +107,9 @@ services:
|
|||||||
# .env pins VNC_PORT=5902.
|
# .env pins VNC_PORT=5902.
|
||||||
- "${VNC_BIND:-127.0.0.1}:${VNC_PORT:-5901}:5901" # VNC
|
- "${VNC_BIND:-127.0.0.1}:${VNC_PORT:-5901}:5901" # VNC
|
||||||
- "${VNC_BIND:-127.0.0.1}:${NOVNC_PORT:-6080}:6080" # noVNC (browser)
|
- "${VNC_BIND:-127.0.0.1}:${NOVNC_PORT:-6080}:6080" # noVNC (browser)
|
||||||
|
# Chrome CDP for a remote bot (JARVIS_ROLE=bot). Loopback by default; for a
|
||||||
|
# LAN browser-host set CDP_PUBLISH_BIND=0.0.0.0 (internal network, no auth).
|
||||||
|
- "${CDP_PUBLISH_BIND:-127.0.0.1}:${CDP_PORT:-9222}:9222" # Chrome CDP
|
||||||
# The brain bridge is NOT published: it binds the container's loopback
|
# The brain bridge is NOT published: it binds the container's loopback
|
||||||
# (BRIDGE_HOST=127.0.0.1) and is only consumed by the bot in this same
|
# (BRIDGE_HOST=127.0.0.1) and is only consumed by the bot in this same
|
||||||
# container, so it needs no host port and stays unreachable off-container.
|
# container, so it needs no host port and stays unreachable off-container.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ exec google-chrome \
|
|||||||
--disable-translate \
|
--disable-translate \
|
||||||
--disable-features=Translate,TranslateUI,InfoBars \
|
--disable-features=Translate,TranslateUI,InfoBars \
|
||||||
--remote-debugging-port="${CDP_PORT:-9222}" \
|
--remote-debugging-port="${CDP_PORT:-9222}" \
|
||||||
--remote-debugging-address=127.0.0.1 \
|
--remote-debugging-address="${CDP_BIND:-127.0.0.1}" \
|
||||||
--user-data-dir="${CHROME_PROFILE_DIR:-/root/chrome-profile}" \
|
--user-data-dir="${CHROME_PROFILE_DIR:-/root/chrome-profile}" \
|
||||||
--password-store=basic --start-maximized \
|
--password-store=basic --start-maximized \
|
||||||
"${CHROME_START_URL:-about:blank}"
|
"${CHROME_START_URL:-about:blank}"
|
||||||
|
|||||||
22
docker/run-if-role.sh
Executable file
22
docker/run-if-role.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Role guard for split deployments.
|
||||||
|
#
|
||||||
|
# run-if-role.sh <roles-csv> <command...>
|
||||||
|
#
|
||||||
|
# Runs <command> only when JARVIS_ROLE is one of <roles-csv> (or "full"/unset).
|
||||||
|
# Otherwise it idles so supervisord keeps the program slot "running" without
|
||||||
|
# doing any work. This lets ONE image serve three layouts:
|
||||||
|
#
|
||||||
|
# JARVIS_ROLE=full (default) everything in one container
|
||||||
|
# JARVIS_ROLE=browser only the desktop + Chrome + CDP (reused over the LAN)
|
||||||
|
# JARVIS_ROLE=bot only the bot + bridge + TTS (drives a remote browser
|
||||||
|
# via CDP_HOST/CDP_PORT)
|
||||||
|
set -e
|
||||||
|
want="$1"; shift
|
||||||
|
role="${JARVIS_ROLE:-full}"
|
||||||
|
if [ "$role" = "full" ]; then exec "$@"; fi
|
||||||
|
case ",$want," in
|
||||||
|
*",$role,"*) exec "$@" ;;
|
||||||
|
esac
|
||||||
|
echo "[role-guard] JARVIS_ROLE=$role not in '$want' — idling: $*" >&2
|
||||||
|
exec sleep infinity
|
||||||
@@ -14,7 +14,7 @@ serverurl=unix:///run/supervisor.sock
|
|||||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||||
|
|
||||||
[program:xvnc]
|
[program:xvnc]
|
||||||
command=/app/docker/run-xvnc.sh
|
command=/app/docker/run-if-role.sh full,browser /app/docker/run-xvnc.sh
|
||||||
priority=100
|
priority=100
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
@@ -23,7 +23,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:pulse]
|
[program:pulse]
|
||||||
command=/app/docker/run-pulse.sh
|
command=/app/docker/run-if-role.sh full,browser /app/docker/run-pulse.sh
|
||||||
priority=150
|
priority=150
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
@@ -32,7 +32,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:xfce]
|
[program:xfce]
|
||||||
command=/app/docker/run-xfce.sh
|
command=/app/docker/run-if-role.sh full,browser /app/docker/run-xfce.sh
|
||||||
priority=200
|
priority=200
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
@@ -41,7 +41,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:novnc]
|
[program:novnc]
|
||||||
command=websockify --web=/usr/share/novnc 6080 localhost:5901
|
command=/app/docker/run-if-role.sh full,browser websockify --web=/usr/share/novnc 6080 localhost:5901
|
||||||
priority=250
|
priority=250
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
@@ -52,7 +52,7 @@ stderr_logfile_maxbytes=0
|
|||||||
[program:melo-worker]
|
[program:melo-worker]
|
||||||
; Warm MeloTTS Korean voice (speed 1.5) in its own py3.11 venv. The bridge's
|
; Warm MeloTTS Korean voice (speed 1.5) in its own py3.11 venv. The bridge's
|
||||||
; synthesize() POSTs here; if this is down the bridge falls back to Piper.
|
; synthesize() POSTs here; if this is down the bridge falls back to Piper.
|
||||||
command=/opt/melo/bin/python /app/bridge/melo_worker.py
|
command=/app/docker/run-if-role.sh full,bot /opt/melo/bin/python /app/bridge/melo_worker.py
|
||||||
directory=/app
|
directory=/app
|
||||||
; HF_HOME points at the dedicated, image-baked melo cache (warmed in
|
; HF_HOME points at the dedicated, image-baked melo cache (warmed in
|
||||||
; setup-melo.sh). The brain's whisper_cache volume is mounted over
|
; setup-melo.sh). The brain's whisper_cache volume is mounted over
|
||||||
@@ -73,7 +73,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:bridge]
|
[program:bridge]
|
||||||
command=/opt/venv/bin/python -m bridge.server
|
command=/app/docker/run-if-role.sh full,bot /opt/venv/bin/python -m bridge.server
|
||||||
directory=/app
|
directory=/app
|
||||||
priority=300
|
priority=300
|
||||||
autorestart=true
|
autorestart=true
|
||||||
@@ -83,7 +83,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:chrome]
|
[program:chrome]
|
||||||
command=/app/docker/run-chrome.sh
|
command=/app/docker/run-if-role.sh full,browser /app/docker/run-chrome.sh
|
||||||
priority=350
|
priority=350
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
@@ -92,7 +92,7 @@ stderr_logfile=/dev/stderr
|
|||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:bot]
|
[program:bot]
|
||||||
command=/app/docker/run-bot.sh
|
command=/app/docker/run-if-role.sh full,bot /app/docker/run-bot.sh
|
||||||
directory=/app/bot
|
directory=/app/bot
|
||||||
priority=400
|
priority=400
|
||||||
autorestart=true
|
autorestart=true
|
||||||
|
|||||||
Reference in New Issue
Block a user