Compare commits
3 Commits
main
...
codex/owne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb60c4db3b | ||
|
|
8562548571 | ||
|
|
db51bb92e6 |
36
.env.example
36
.env.example
@@ -29,17 +29,27 @@ BRIDGE_PORT=8765
|
||||
JARVIS_BRAIN_ENABLED=1
|
||||
JARVIS_TTS_ENABLED=1
|
||||
# faster-whisper device/compute. GPU by default (RTX 5050 / sm_120, verified).
|
||||
# Falls back to CPU automatically if no GPU is passed to the container.
|
||||
# On a NO-GPU host (e.g. an app host that offloads the LLM to a separate GPU box)
|
||||
# set WHISPER_DEVICE=cpu AND WHISPER_COMPUTE_TYPE=int8 — float16 is GPU-only, so
|
||||
# CPU needs int8 (STT is slower on CPU).
|
||||
WHISPER_DEVICE=cuda
|
||||
WHISPER_COMPUTE_TYPE=float16
|
||||
# Optional explicit Piper voice model (.onnx). If empty, the jarvis default is used.
|
||||
TTS_PIPER_MODEL_PATH=
|
||||
# TTS engine: "edge" (default) uses Microsoft Edge TTS, a natural Korean neural
|
||||
# voice. Set to "piper" for the offline English voice. NOTE: edge is ONLINE —
|
||||
# reply text is sent to Microsoft's servers and needs internet.
|
||||
TTS_ENGINE=edge
|
||||
# Edge voice + speaking rate. Rate is a percentage (+45% ≈ 1.45×). Korean voices:
|
||||
# ko-KR-HyunsuMultilingualNeural (M), ko-KR-InJoonNeural (M), ko-KR-SunHiNeural (F).
|
||||
# TTS engine:
|
||||
# melo (default) GPU MeloTTS — offline Korean voice, privacy-first (text never
|
||||
# leaves the host), synthesises on the GPU via the melo-worker. Needs a
|
||||
# GPU (MELO_DEVICE=cuda); falls back to CPU (slow) with MELO_DEVICE=cpu.
|
||||
# edge Microsoft Edge TTS — natural Korean neural voice, but ONLINE: reply
|
||||
# text is sent to Microsoft's servers and needs internet.
|
||||
# piper offline English voice (fallback).
|
||||
TTS_ENGINE=melo
|
||||
# GPU MeloTTS knobs (used when TTS_ENGINE=melo).
|
||||
MELO_DEVICE=cuda
|
||||
MELO_SPEED=1.5
|
||||
# Edge voice + speaking rate (used when TTS_ENGINE=edge). Rate is a percentage
|
||||
# (+45% ≈ 1.45×). Korean voices: ko-KR-HyunsuMultilingualNeural (M),
|
||||
# ko-KR-InJoonNeural (M), ko-KR-SunHiNeural (F).
|
||||
EDGE_TTS_VOICE=ko-KR-HyunsuMultilingualNeural
|
||||
EDGE_TTS_RATE=+45%
|
||||
# Neural-only by default: if synthesis fails the bridge returns no audio rather
|
||||
@@ -51,7 +61,13 @@ MELO_FALLBACK_PIPER=0
|
||||
# Jarvis brain (Ollama-backed). In Docker these populate the rendered
|
||||
# config (docker/jarvis-config.template.json). See src/jarvis/config.py.
|
||||
# ---------------------------------------------------------------------------
|
||||
# In docker-compose this is overridden to http://ollama:11434 automatically.
|
||||
# In docker-compose this defaults to the in-stack `ollama` service
|
||||
# (http://ollama:11434). To use an EXTERNAL Ollama on another LAN machine (e.g. a
|
||||
# GPU host), set it here to that host's IP — the compose now respects this value:
|
||||
# OLLAMA_BASE_URL=http://192.168.10.9:11434 # Ollama runs on the .9 host
|
||||
# In that split setup: do NOT start the in-stack ollama/ollama-init (run
|
||||
# `docker compose up -d javis`), pull the models on the LLM host, and make that
|
||||
# host's Ollama listen on the LAN (OLLAMA_HOST=0.0.0.0:11434).
|
||||
OLLAMA_BASE_URL=http://127.0.0.1:11434
|
||||
# qwen2.5:3b — small non-reasoning instruct model. ~2.4GB, runs 100% on the GPU
|
||||
# (the 8B offloads ~8% to CPU), warm voice turns ~2-4s vs ~5-7s on 8B. Clean
|
||||
@@ -197,6 +213,10 @@ VOICE_SILENCE_MS=800
|
||||
# full (default) everything in one container
|
||||
# browser ONLY the desktop + Chrome + control-server (driven over the LAN)
|
||||
# bot ONLY the bot + bridge + TTS (drives a REMOTE browser)
|
||||
# brain ONLY the bridge (STT + reply + TTS) on a GPU host — no bot/desktop.
|
||||
# The app host reaches it via BRIDGE_URL. See docs/DEPLOY.md "GPU split".
|
||||
# app the bot + desktop/Chrome, but NOT the local bridge: offloads
|
||||
# STT/LLM/TTS to a remote brain host (set BRIDGE_URL=http://<brain>:8765).
|
||||
JARVIS_ROLE=full
|
||||
|
||||
# --- GPU per OS: pick the matching compose override via COMPOSE_FILE ---
|
||||
|
||||
17
Dockerfile
17
Dockerfile
@@ -65,10 +65,19 @@ RUN ls -d /opt/venv/lib/python*/site-packages/nvidia/cublas/lib \
|
||||
> /etc/ld.so.conf.d/nvidia-cu12.conf 2>/dev/null \
|
||||
&& /sbin/ldconfig || true
|
||||
|
||||
# --- Korean voice: Microsoft Edge TTS (online neural). No model is baked — the
|
||||
# `edge-tts` pip package (in requirements-bridge.txt) calls the MS service at
|
||||
# runtime and the bridge transcodes the MP3 to PCM16 with ffmpeg. No heavy
|
||||
# TTS build layer is needed. ---
|
||||
# --- Korean voice: GPU MeloTTS (offline, privacy-first) in a separate /opt/melo
|
||||
# py3.11 venv; see docker/setup-melo.sh. Heavy layer (torch cu128 GPU +
|
||||
# transformers + MeCab + baked KR model), placed before the app COPY so it
|
||||
# stays cached across source-only changes. Runtime device is MELO_DEVICE=cuda
|
||||
# (compose), so TTS synthesises on the GPU next to Ollama + Whisper. Started
|
||||
# only in full/bot/brain roles (see docker/supervisord.conf). The offline
|
||||
# Edge TTS (`edge-tts`, in requirements-bridge.txt) remains available as an
|
||||
# opt-in fallback via TTS_ENGINE=edge, but it is ONLINE (text leaves the
|
||||
# host), so MeloTTS is the default. ---
|
||||
COPY docker/setup-melo.sh /app/docker/setup-melo.sh
|
||||
# Strip CR first: a Windows (autocrlf) checkout yields CRLF, which makes bash
|
||||
# read `set -euxo pipefail\r` and abort. Idempotent on an LF tree.
|
||||
RUN sed -i 's/\r$//' /app/docker/setup-melo.sh && bash /app/docker/setup-melo.sh
|
||||
|
||||
# --- Human input + window management for the on-screen Chrome control tool.
|
||||
# xdotool injects real X pointer/keyboard events (visible cursor,
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* Does not broadcast natively into Discord. Instead it shares a noVNC web URL
|
||||
* that anyone can open in a browser to watch (and optionally control) the VNC
|
||||
* desktop live. Set NOVNC_URL in .env (e.g. http://192.168.10.9:6080/vnc.html).
|
||||
* desktop live. Set NOVNC_URL in .env to the browser host's LAN IP
|
||||
* (e.g. http://<browser-host-ip>:6080/vnc.html).
|
||||
*
|
||||
* Stand up noVNC once on the host with websockify, e.g.:
|
||||
* websockify --web=/usr/share/novnc 6080 localhost:5901
|
||||
@@ -22,7 +23,7 @@ export class NoVncStreamer implements ScreenStreamer {
|
||||
|
||||
async start(_ctx: StreamContext): Promise<string> {
|
||||
if (!this.config.novncUrl) {
|
||||
return "NOVNC_URL이 설정되지 않았습니다 (.env). 예: http://192.168.10.9:6080/vnc.html";
|
||||
return "NOVNC_URL이 설정되지 않았습니다 (.env). 예: http://<브라우저호스트IP>:6080/vnc.html";
|
||||
}
|
||||
this.active = true;
|
||||
return `🖥️ VNC 화면 실시간 보기 (브라우저): ${this.config.novncUrl}`;
|
||||
|
||||
@@ -66,8 +66,13 @@ services:
|
||||
- path: .env
|
||||
required: false
|
||||
environment:
|
||||
# Point the brain at the ollama service and the bot at the in-container bridge.
|
||||
OLLAMA_BASE_URL: http://ollama:11434
|
||||
# Point the brain at Ollama. Default is the in-stack `ollama` service
|
||||
# (all-in-one). Override OLLAMA_BASE_URL in .env to reach an EXTERNAL Ollama
|
||||
# over the LAN (e.g. a GPU host at http://192.168.10.9:11434) — used when
|
||||
# this stack runs on a separate machine from the LLM. When overridden, do
|
||||
# NOT start the in-stack `ollama`/`ollama-init` services (bring the app up
|
||||
# with `docker compose up -d javis`) and pull the models on the LLM host.
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
OLLAMA_CHAT_MODEL: ${OLLAMA_CHAT_MODEL:-qwen2.5:3b}
|
||||
# Auxiliary small-model calls (intent judge, tool router, arg extraction,
|
||||
# query decomposition) run on this fast model so the big chat model only
|
||||
@@ -82,11 +87,17 @@ services:
|
||||
WHISPER_DEVICE: ${WHISPER_DEVICE:-cuda}
|
||||
WHISPER_COMPUTE_TYPE: ${WHISPER_COMPUTE_TYPE:-float16}
|
||||
# TTS engine. Rendered into /app/config/jarvis.json via envsubst (the
|
||||
# bridge reads that JSON BEFORE the env, so it must carry the real engine,
|
||||
# not a hardcoded one — otherwise Korean text is read by the English Piper
|
||||
# voice). Default edge; .env can override (e.g. piper for offline).
|
||||
TTS_ENGINE: ${TTS_ENGINE:-edge}
|
||||
# Edge TTS voice + rate (the chosen natural Korean voice). NOTE: edge is an
|
||||
# bridge reads that JSON BEFORE the env, so it must carry the real engine).
|
||||
# Default melo: GPU MeloTTS (offline, privacy-first) via the melo-worker.
|
||||
# Override with TTS_ENGINE=edge for the online Microsoft neural voice (text
|
||||
# leaves the host) or piper for the offline English voice.
|
||||
TTS_ENGINE: ${TTS_ENGINE:-melo}
|
||||
# GPU MeloTTS worker knobs. MELO_DEVICE=cuda runs synth on the GPU (next to
|
||||
# Ollama + Whisper); cpu is the no-GPU fallback. MELO_SPEED must always be
|
||||
# set — supervisord's melo-worker expands %(ENV_MELO_SPEED)s at startup.
|
||||
MELO_DEVICE: ${MELO_DEVICE:-cuda}
|
||||
MELO_SPEED: ${MELO_SPEED:-1.5}
|
||||
# Edge TTS voice + rate (used only when TTS_ENGINE=edge). NOTE: edge is an
|
||||
# ONLINE engine — reply text is sent to Microsoft and needs internet.
|
||||
EDGE_TTS_VOICE: ${EDGE_TTS_VOICE:-ko-KR-HyunsuMultilingualNeural}
|
||||
EDGE_TTS_RATE: ${EDGE_TTS_RATE:-+45%}
|
||||
@@ -101,10 +112,17 @@ services:
|
||||
# on short/noisy Discord speech. Lower to 1 for minimum latency.
|
||||
STT_BEAM_SIZE: ${STT_BEAM_SIZE:-5}
|
||||
VOICE_SILENCE_MS: ${VOICE_SILENCE_MS:-600}
|
||||
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.
|
||||
# Where the bot reaches the brain bridge (STT + reply + TTS). Loopback for
|
||||
# all-in-one. In a GPU-split layout the bot host (JARVIS_ROLE=app) points
|
||||
# this at the brain host: BRIDGE_URL=http://192.168.10.9:8765 (that host
|
||||
# runs JARVIS_ROLE=brain with BRIDGE_HOST=0.0.0.0 + SETTINGS_PUBLISH_BIND=0.0.0.0).
|
||||
BRIDGE_URL: ${BRIDGE_URL:-http://127.0.0.1:8765}
|
||||
# Split-deployment role (see docker/run-if-role.sh):
|
||||
# full (default) everything in one container
|
||||
# browser only desktop + Chrome + control-server (driven over the LAN)
|
||||
# bot only bot + bridge + TTS (drives a remote browser)
|
||||
# brain only the bridge (STT + reply + TTS) — GPU host, no bot/desktop
|
||||
# app bot + browser/desktop, NO local bridge (uses a remote brain)
|
||||
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
|
||||
@@ -112,7 +130,7 @@ services:
|
||||
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).
|
||||
# set CDP_HOST to the browser host's LAN IP (e.g. 192.168.10.5).
|
||||
CDP_HOST: ${CDP_HOST:-127.0.0.1}
|
||||
# Browser-control endpoint. The browser host serves it (BIND/PORT); a
|
||||
# remote bot sets BROWSER_CONTROL_URL=http://<browser-host>:8777 so its
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
# 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)
|
||||
# JARVIS_ROLE=brain only the bridge (STT + reply + TTS) on a GPU host; no
|
||||
# bot, no desktop. The app host reaches it via BRIDGE_URL.
|
||||
# JARVIS_ROLE=app the bot + desktop/Chrome, but NOT the local bridge:
|
||||
# offloads STT/LLM/TTS to a remote brain host (BRIDGE_URL)
|
||||
set -e
|
||||
want="$1"; shift
|
||||
role="${JARVIS_ROLE:-full}"
|
||||
|
||||
@@ -14,7 +14,7 @@ serverurl=unix:///run/supervisor.sock
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[program:xvnc]
|
||||
command=/app/docker/run-if-role.sh full,browser /app/docker/run-xvnc.sh
|
||||
command=/app/docker/run-if-role.sh full,browser,app /app/docker/run-xvnc.sh
|
||||
priority=100
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
@@ -23,7 +23,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:pulse]
|
||||
command=/app/docker/run-if-role.sh full,browser /app/docker/run-pulse.sh
|
||||
command=/app/docker/run-if-role.sh full,browser,app /app/docker/run-pulse.sh
|
||||
priority=150
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
@@ -32,7 +32,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:xfce]
|
||||
command=/app/docker/run-if-role.sh full,browser /app/docker/run-xfce.sh
|
||||
command=/app/docker/run-if-role.sh full,browser,app /app/docker/run-xfce.sh
|
||||
priority=200
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
@@ -41,7 +41,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:novnc]
|
||||
command=/app/docker/run-if-role.sh full,browser websockify --web=/usr/share/novnc 6080 localhost:5901
|
||||
command=/app/docker/run-if-role.sh full,browser,app websockify --web=/usr/share/novnc 6080 localhost:5901
|
||||
priority=250
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
@@ -49,11 +49,30 @@ stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
# (No TTS worker program: the default Edge TTS engine synthesises in-process in
|
||||
# the bridge via the `edge-tts` package — no warm model/worker is needed.)
|
||||
[program:melo-worker]
|
||||
; Warm GPU MeloTTS Korean voice (offline) in its own py3.11 venv (/opt/melo). The
|
||||
; bridge's synthesize() POSTs here when TTS_ENGINE=melo. Runs wherever the bridge
|
||||
; runs (full/bot/brain) so a GPU brain host serves TTS on the GPU. If TTS_ENGINE
|
||||
; =edge the bridge synthesises in-process and never calls this worker.
|
||||
command=/app/docker/run-if-role.sh full,bot,brain /opt/melo/bin/python /app/bridge/melo_worker.py
|
||||
directory=/app
|
||||
; HF_HOME points at the dedicated, image-baked melo cache (warmed in
|
||||
; setup-melo.sh). The whisper_cache volume is mounted over /root/.cache/huggingface,
|
||||
; so without this the pre-cached BERT + KR checkpoint would be shadowed and
|
||||
; re-downloaded (and would fail offline). HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE
|
||||
; force pure-cache reads. MELO_DEVICE/MELO_SPEED inherit from the container env
|
||||
; (compose sets both with defaults cuda / 1.5), so MELO_SPEED must always be set
|
||||
; in the env or this %(ENV_x)s expansion fails at startup (compose guarantees it).
|
||||
environment=MELO_LANGUAGE="KR",MELO_SPEED="%(ENV_MELO_SPEED)s",MELO_DEVICE="%(ENV_MELO_DEVICE)s",MELO_WORKER_HOST="127.0.0.1",MELO_WORKER_PORT="8770",HF_HOME="/opt/melo-cache",HF_HUB_OFFLINE="1",TRANSFORMERS_OFFLINE="1"
|
||||
priority=280
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:bridge]
|
||||
command=/app/docker/run-if-role.sh full,bot /opt/venv/bin/python -m bridge.server
|
||||
command=/app/docker/run-if-role.sh full,bot,brain /opt/venv/bin/python -m bridge.server
|
||||
directory=/app
|
||||
priority=300
|
||||
autorestart=true
|
||||
@@ -63,7 +82,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:chrome]
|
||||
command=/app/docker/run-if-role.sh full,browser /app/docker/run-chrome.sh
|
||||
command=/app/docker/run-if-role.sh full,browser,app /app/docker/run-chrome.sh
|
||||
priority=350
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
@@ -75,7 +94,7 @@ stderr_logfile_maxbytes=0
|
||||
; Browser-control HTTP endpoint on the BROWSER HOST. A remote `bot` posts
|
||||
; commands here so xdotool / CDP run on THIS machine (real input on this
|
||||
; screen). Only meaningful in full/browser roles. Internal network only.
|
||||
command=/app/docker/run-if-role.sh full,browser node /app/bot/scripts/stream-test/control-server.mjs
|
||||
command=/app/docker/run-if-role.sh full,browser,app node /app/bot/scripts/stream-test/control-server.mjs
|
||||
directory=/app/bot
|
||||
priority=360
|
||||
autorestart=true
|
||||
@@ -85,7 +104,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:bot]
|
||||
command=/app/docker/run-if-role.sh full,bot /app/docker/run-bot.sh
|
||||
command=/app/docker/run-if-role.sh full,bot,app /app/docker/run-bot.sh
|
||||
directory=/app/bot
|
||||
priority=400
|
||||
autorestart=true
|
||||
|
||||
@@ -30,7 +30,7 @@ The on-screen Chrome, real mouse/keyboard (xdotool) and screen live on the
|
||||
**browser host**. Your PC runs the **bot** and drives that browser over the
|
||||
internal network — no auth (internal only).
|
||||
|
||||
### Browser host (the LAN machine that shows Chrome, e.g. 192.168.10.9)
|
||||
### Browser host (the LAN machine that shows Chrome, e.g. 192.168.10.5)
|
||||
|
||||
```
|
||||
# .env
|
||||
@@ -50,7 +50,7 @@ Watch it on this machine’s VNC (`localhost:5901`) / noVNC (`localhost:6080`).
|
||||
```
|
||||
# .env
|
||||
JARVIS_ROLE=bot
|
||||
BROWSER_CONTROL_URL=http://192.168.10.9:8777 # the browser host's LAN IP
|
||||
BROWSER_CONTROL_URL=http://192.168.10.5:8777 # the browser host's LAN IP
|
||||
COMPOSE_FILE=docker-compose.yml:docker-compose.gpu-linux.yml # Ubuntu/macOS (":" )
|
||||
# COMPOSE_FILE=docker-compose.yml;docker-compose.gpu-windows.yml # Windows 11 (";" )
|
||||
DISCORD_SELFBOT_TOKEN=...
|
||||
@@ -63,6 +63,73 @@ The bot’s `controlBrowser` tool posts commands to `BROWSER_CONTROL_URL`, so
|
||||
"네이버에서 X 검색", "구글로 돌아가" etc. drive the **browser host’s** Chrome with real
|
||||
human-style input (visible on its VNC).
|
||||
|
||||
### External Ollama (LLM on a separate host)
|
||||
|
||||
To run Ollama on a different LAN machine (e.g. a dedicated GPU host at
|
||||
`192.168.10.9`) instead of inside this stack:
|
||||
|
||||
```
|
||||
# .env on the app host
|
||||
OLLAMA_BASE_URL=http://192.168.10.9:11434
|
||||
```
|
||||
|
||||
Then start the app WITHOUT the in-stack LLM services: `docker compose up -d javis`
|
||||
(do not `docker compose up -d`, which would also start `ollama`/`ollama-init`).
|
||||
On the LLM host, make Ollama listen on the LAN (`OLLAMA_HOST=0.0.0.0:11434`) and
|
||||
pull the models there (`ollama pull <chat>`, `<intent>`, `<embed>`). The compose
|
||||
respects `OLLAMA_BASE_URL`, defaulting to the in-stack `ollama` service when unset.
|
||||
|
||||
## C. GPU split: brain host (.9, GPU) + app host (.5, no GPU)
|
||||
|
||||
All the GPU-heavy compute (Whisper STT, the Ollama LLM, and TTS) runs on the
|
||||
**brain host** (a GPU box, e.g. `192.168.10.9`). The **app host** (no GPU, e.g.
|
||||
`192.168.10.5`) runs the Discord bot and the on-screen browser, and offloads
|
||||
every STT/LLM/TTS call to the brain over the LAN.
|
||||
|
||||
Flow: the bot (app host) POSTs captured voice to the brain's bridge; the brain
|
||||
runs STT -> LLM -> TTS on the GPU and returns the reply audio; when the LLM
|
||||
drives the browser, the brain's `controlBrowser` tool POSTs to the app host's
|
||||
control-server (port 8777), so Chrome moves on the app host's screen.
|
||||
|
||||
### Brain host (.9 — GPU: STT + LLM + TTS)
|
||||
|
||||
```
|
||||
# .env
|
||||
JARVIS_ROLE=brain
|
||||
BRIDGE_HOST=0.0.0.0 # bridge listens on the LAN
|
||||
SETTINGS_PUBLISH_BIND=0.0.0.0 # publish bridge port 8765 to the LAN
|
||||
OLLAMA_BASE_URL=http://192.168.10.9:11434 # Ollama on this host (bind 0.0.0.0)
|
||||
OLLAMA_CHAT_MODEL=qwen2.5:7b
|
||||
WHISPER_DEVICE=cuda # STT on the GPU
|
||||
WHISPER_COMPUTE_TYPE=float16
|
||||
TTS_ENGINE=melo # GPU MeloTTS (offline, privacy-first)
|
||||
MELO_DEVICE=cuda # TTS on the GPU (melo-worker)
|
||||
BROWSER_CONTROL_URL=http://192.168.10.5:8777 # drive the app host's Chrome
|
||||
COMPOSE_FILE=docker-compose.yml:docker-compose.gpu-linux.yml # GPU (":" on Linux)
|
||||
|
||||
# STT (Whisper), LLM (Ollama) and TTS (MeloTTS) all run on this host's GPU.
|
||||
# Ollama listens on 0.0.0.0:11434 (systemd or a container).
|
||||
docker compose up -d javis # brain bridge + melo-worker only (no bot, no desktop)
|
||||
```
|
||||
|
||||
### App host (.5 — bot + browser, no GPU)
|
||||
|
||||
```
|
||||
# .env
|
||||
JARVIS_ROLE=app
|
||||
BRIDGE_URL=http://192.168.10.9:8765 # offload STT/LLM/TTS to the brain
|
||||
CDP_PUBLISH_BIND=0.0.0.0 # publish control-server 8777 to the LAN
|
||||
STREAM_HW=0 # no NVENC on a no-GPU host
|
||||
DISCORD_SELFBOT_TOKEN=...
|
||||
DISCORD_GUILD_ID=...
|
||||
# no GPU → leave COMPOSE_FILE unset (base compose only)
|
||||
|
||||
docker compose up -d javis # bot + desktop + Chrome + control-server
|
||||
```
|
||||
|
||||
The `brain` and `app` roles are backward-compatible additions to `full`/`browser`
|
||||
/`bot`; see `docker/run-if-role.sh`.
|
||||
|
||||
## Windows 11 notes
|
||||
|
||||
- Install the NVIDIA driver on Windows and enable GPU in Docker Desktop
|
||||
|
||||
Reference in New Issue
Block a user