MeloTTS's single Korean speaker sounded non-native ("foreign accent"). Swap it
for Coqui XTTS-v2 with the built-in female studio speaker "Ana Florence"
(language ko), the natural voice used in earlier local runs.
- bridge/xtts_worker.py: new warm HTTP worker (own /opt/xtts venv), same
/synth + /health contract and PCM16 output as the old melo worker
- docker/setup-xtts.sh: builds the venv with cu128 torch (Blackwell) + Coqui
TTS and bakes the XTTS-v2 model offline. Pins transformers>=4.57,<5 (5.x
removed isin_mps_friendly, breaking XTTS) and installs the [codec] extra
(torch>=2.9 needs torchcodec) — both verified by a real host synth
- Dockerfile: replace the melo build layer with the xtts layer
- supervisord.conf: melo-worker -> xtts-worker, env passthrough for
XTTS_DEVICE/SPEAKER/LANGUAGE (always set via compose defaults)
- bridge/server.py: default TTS_ENGINE=xtts, route to the xtts worker, generic
worker-synth helper, neural-only fallback flag (XTTS_FALLBACK_PIPER)
- settings UI: engine dropdown xtts/piper, drop the dead melo_speed field, fix
the supervisorctl restart target to xtts-worker
- compose/.env.example/README: XTTS_* vars, speaker/language knobs, remove melo
- remove bridge/melo_worker.py and docker/setup-melo.sh
- tests: xtts treated as multilingual (not English-only)
Verified on host: coqui-tts loads XTTS-v2 and synthesises Korean as
"Ana Florence" to a 16-bit mono 24kHz WAV.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
supervisord.conf passed MELO_DEVICE through as %(ENV_MELO_DEVICE)s but pinned
MELO_SPEED="1.5", so lowering MELO_SPEED in .env had no effect — the worker
always got 1.5. Pass MELO_SPEED through with %(ENV_MELO_SPEED)s and set a
compose default (MELO_SPEED=${MELO_SPEED:-1.5}, same pattern as MELO_DEVICE) so
the supervisord expansion always resolves and an .env value actually changes
the speaking rate. Default rate is unchanged (1.5). melo_worker logs the
resolved speed at startup, so the env->worker path is verifiable.
Verified: _resolve_speed() returns 1.1 for MELO_SPEED=1.1 (1.5 otherwise), and
`MELO_SPEED=1.1 docker compose config` renders MELO_SPEED: "1.1" into the env.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- control-server.mjs runs chrome-control.mjs LOCALLY on the browser host, so a
remote bot's controlBrowser (BROWSER_CONTROL_URL) drives real xdotool input
on THIS screen instead of the bot machine. Published on the LAN.
- controlBrowser tool posts to BROWSER_CONTROL_URL when set, else runs locally.
- Drop hard depends_on ollama so a browser-host doesn't start Ollama.
- gitignore .env.bak*/*.bak (a backup with tokens had been left untracked).
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).
supervisord hardcoded MELO_DEVICE=cpu, overriding the compose MELO_DEVICE=cuda
so MeloTTS stayed on CPU even after the GPU torch swap. Interpolate the
container env instead.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a dedicated MeloTTS Korean voice (speed 1.5) as the primary TTS engine,
served by a long-lived in-container worker so each Discord turn pays only
inference cost, not model-load cost.
- bridge/melo_worker.py: tiny HTTP service in its own /opt/melo py3.11 venv,
keeps the KR model warm, returns PCM16 WAV on POST /synth.
- bridge/server.py: synthesize() routes to the melo worker first; Piper stays
as an opt-in fallback (MELO_FALLBACK_PIPER, default off so Korean is never
mangled through the English voice). /health reports tts_engine.
- docker/setup-melo.sh: builds the isolated venv (pinned torch 2.12.0 /
torchaudio 2.11.0 CPU, MeloTTS pinned to a commit for reproducible rebuilds),
pre-fetches mecab-ko, and warms a dedicated HF cache (/opt/melo-cache) with a
real KR synth so all BERT + KR checkpoint assets are baked into the image.
- docker/supervisord.conf: runs melo-worker before the bridge with
HF_HOME=/opt/melo-cache (the whisper_cache volume shadows the default HF
cache) plus HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE so it reads the baked cache
and never retries the network on load.
- Dockerfile/.env.example: wire the melo build layer and config knobs.
Verified: offline synth passes with --network none and the prod volume mounted;
prod container recreated, all supervisord services up, bot logged in, and an
end-to-end /tts call returns a 44.1kHz mono PCM16 WAV.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Makes the all-in-one image actually run the new real-time-search features and
closes review gaps:
- Gemini OAuth path: install Node 22 + @google/gemini-cli (pinned 0.46.0) in the
image; mount a DEDICATED host dir (~/.config/javis/gemini) holding only the
OAuth creds to /root/.gemini (not the whole ~/.gemini). Verified in-container:
`gemini -p ... -o json` returns a grounded answer with no API key.
- Broadcast audio: add PulseAudio + a headless null-sink (run-pulse.sh, new
supervisor program); export XDG_RUNTIME_DIR/PULSE_SERVER so Chrome playback
and the selfbot `ffmpeg -f pulse -i @DEFAULT_MONITOR@` share one daemon.
Verified: default sink virtual_speaker, monitor present, ffmpeg capture OK.
- Bind the brain bridge to 127.0.0.1 only (internal, unauthenticated API).
- VNC host port is overridable; this server pins VNC_PORT=5902 (.env) since the
host already runs Xvnc on 5901.
Verified in-container with CDI GPU passthrough: RTX 5050 visible, NVENC
encoders (h264/hevc/av1) available.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`docker compose up -d --build` now brings up the whole thing automatically —
no host setup needed:
- All-in-one javis image: TigerVNC+XFCE desktop, Chrome, Python brain bridge,
Node/bun bot, managed by supervisord (verified: all 6 programs RUNNING).
- ollama service + one-shot ollama-init that auto-pulls chat+embed models
(verified end-to-end; `ollama list` shows pulled models).
- Discord token deferred: without DISCORD_BOT_TOKEN the desktop, bridge,
Ollama and models all run; only the bot waits (no crash loop).
- Slim container deps (bridge/requirements-bridge.txt) drop the unused
PyQt6/torch/chatterbox/sounddevice stack. Piper voice + Whisper models
auto-download into named volumes.
- Configurable host ports (VNC_PORT/NOVNC_PORT/BRIDGE_PORT) to avoid clashing
with a host VNC already on 5901. Bridge binds 0.0.0.0 in-container.
Verified: image builds; brain imports; bridge /health 200; noVNC 200;
X display :1 @1920x1080; auto-pull completes; supervisorctl status all RUNNING.