# ============================================================================ # Javis Bot — all-in-one container # VNC + XFCE desktop + Chrome + Python brain bridge + Node/bun Discord bot. # Ollama (the LLM backend) runs as a separate service (see docker-compose.yml). # ============================================================================ FROM ubuntu:24.04 ENV DEBIAN_FRONTEND=noninteractive \ LANG=C.UTF-8 \ DISPLAY=:1 \ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \ PATH=/opt/venv/bin:/root/.bun/bin:/usr/local/bin:/usr/bin:/bin \ NVIDIA_VISIBLE_DEVICES=all # `video` is REQUIRED for NVENC/NVDEC: it tells the NVIDIA Container Toolkit to # inject libnvidia-encode.so.1 / libnvidia-decode.so.1 into the container. With # only `compute,utility` you get CUDA (ollama/whisper/melo) + nvidia-smi, but the # Go-Live broadcast's h264_nvenc fails with "Cannot load libnvidia-encode.so.1". # Applies on both Linux (CDI) and Windows Docker Desktop (WSL2). ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility,video # --- System packages: desktop, VNC, Chrome deps, ffmpeg, python, ocr --- RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates curl wget gnupg unzip procps \ tigervnc-standalone-server tigervnc-common tigervnc-tools \ xfce4 xfce4-goodies dbus-x11 x11-utils xfonts-base \ fonts-noto-cjk fonts-noto-cjk-extra fonts-nanum \ ffmpeg tesseract-ocr \ pulseaudio pulseaudio-utils \ python3 python3-venv python3-pip \ novnc websockify supervisor gettext-base \ && rm -rf /var/lib/apt/lists/* # --- Google Chrome (stable) --- RUN wget -q -O /tmp/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ && (apt-get update && apt-get install -y --no-install-recommends /tmp/chrome.deb || (apt-get -f install -y)) \ && rm -f /tmp/chrome.deb && rm -rf /var/lib/apt/lists/* # --- bun (Discord bot runtime/package manager) --- RUN curl -fsSL https://bun.sh/install | bash # --- Node.js + Gemini CLI (the GEMINI_AUTH=oauth real-time search path shells # out to `gemini`; it needs a real Node runtime, not bun). The account # login itself is provided at runtime via the mounted ~/.gemini (see # docker-compose.yml); here we only install the binary. --- ARG GEMINI_CLI_VERSION=0.46.0 RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ && npm install -g "@google/gemini-cli@${GEMINI_CLI_VERSION}" \ && rm -rf /var/lib/apt/lists/* \ && gemini --version # --- Python brain/bridge deps (slim set) --- COPY bridge/requirements-bridge.txt /app/bridge/requirements-bridge.txt RUN python3 -m venv /opt/venv \ && /opt/venv/bin/pip install --no-cache-dir --upgrade pip \ && /opt/venv/bin/pip install --no-cache-dir -r /app/bridge/requirements-bridge.txt # faster-whisper>=1.1 / ctranslate2 self-locates these pip CUDA libs at runtime, # so no hardcoded LD_LIBRARY_PATH is needed. We also register them with the # dynamic linker (full path to ldconfig; PATH excludes /sbin) as a robust # fallback. Path-glob is python-version agnostic. RUN ls -d /opt/venv/lib/python*/site-packages/nvidia/cublas/lib \ /opt/venv/lib/python*/site-packages/nvidia/cudnn/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. --- # --- Human input + window management for the on-screen Chrome control tool. # xdotool injects real X pointer/keyboard events (visible cursor, # char-by-char typing) into the broadcast; wmctrl lists/moves windows. --- RUN apt-get update && apt-get install -y --no-install-recommends \ xdotool wmctrl \ && rm -rf /var/lib/apt/lists/* # --- Discord bot deps (cache layer on lockfile) --- COPY bot/package.json bot/bun.lock /app/bot/ RUN cd /app/bot && bun install --frozen-lockfile || bun install # --- App source --- COPY . /app WORKDIR /app # Normalise all container shell scripts to LF. On a Windows checkout (autocrlf) # these arrive as CRLF, which would break their shebangs at runtime (entrypoint, # run-*.sh) the same way it broke setup-melo.sh at build time. RUN find /app/docker /app/scripts -name '*.sh' -exec sed -i 's/\r$//' {} + # --- Default Piper voice (best-effort at build; entrypoint retries if absent) --- RUN bash docker/download-piper.sh || true EXPOSE 5901 6080 8765 ENTRYPOINT ["/app/docker/entrypoint.sh"]