docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# ClippyMe Docker Compose
#
# CPU / Apple Silicon / ARM (default):
# docker compose up --build
#
# NVIDIA GPU:
# docker compose -f docker-compose.yml -f docker-compose.gpu.yml up --build
name: clippyme
networks:
clippyme-net:
driver: bridge
services:
backend:
build:
context: .
args:
GPU_RUNTIME: ${GPU_RUNTIME:-cpu}
# Set ENABLE_WHISPER_DIARIZE=1 in your shell/.env to bake
# pyannote.audio into the image and enable speaker diarization on
# the Faster-Whisper fallback path. Adds ~500 MB to the image.
ENABLE_WHISPER_DIARIZE: ${ENABLE_WHISPER_DIARIZE:-0}
container_name: clippyme-backend
image: clippyme-backend
ports:
# Bound to loopback: security.py treats every RFC1918 peer as a trusted
# client for the config/state endpoints (key overwrite, cookie download,
# job deletion), so publishing on 0.0.0.0 hands that trust to the whole
# LAN. Override CLIPPYME_BIND (e.g. CLIPPYME_BIND=0.0.0.0) ONLY on a
# network where every device is trusted.
- "${CLIPPYME_BIND:-127.0.0.1}:8000:8000"
dns:
- 8.8.8.8
- 8.8.4.4
environment:
# HuggingFace token — required for pyannote diarization + Whisper
# model downloads without rate limits. Both names are accepted.
- HF_TOKEN=${HF_TOKEN:-}
- HUGGINGFACE_TOKEN=${HUGGINGFACE_TOKEN:-${HF_TOKEN:-}}
# ASR provider + credentials. TRANSCRIPTION_PROVIDER=deepgram|elevenlabs|whisper.
- TRANSCRIPTION_PROVIDER=${TRANSCRIPTION_PROVIDER:-deepgram}
- DEEPGRAM_API_KEY=${DEEPGRAM_API_KEY:-}
- DEEPGRAM_MODEL=${DEEPGRAM_MODEL:-nova-3}
# Default 'multi' enables Nova-3 native EN+IT code-switching.
# Users can override per-job from the Create tab dropdown.
- DEEPGRAM_LANGUAGE=${DEEPGRAM_LANGUAGE:-multi}
- DEEPGRAM_DIARIZE=${DEEPGRAM_DIARIZE:-true}
# ElevenLabs Scribe (3rd STT provider). scribe_v2 supports NO_VERBATIM
# filler-strip. AUDIO_ISOLATION=1 adds an opt-in pre-ASR noise/music
# removal pass (provider-agnostic; needs the ElevenLabs key).
- ELEVENLABS_API_KEY=${ELEVENLABS_API_KEY:-}
- ELEVENLABS_MODEL=${ELEVENLABS_MODEL:-scribe_v1}
- ELEVENLABS_LANGUAGE=${ELEVENLABS_LANGUAGE:-multi}
- ELEVENLABS_DIARIZE=${ELEVENLABS_DIARIZE:-true}
- ELEVENLABS_NO_VERBATIM=${ELEVENLABS_NO_VERBATIM:-false}
- ELEVENLABS_AUDIO_ISOLATION=${ELEVENLABS_AUDIO_ISOLATION:-false}
# Whisper fallback diarization. Requires ENABLE_WHISPER_DIARIZE=1
# at build time AND HF_TOKEN set at runtime.
- WHISPER_DIARIZE=${WHISPER_DIARIZE:-true}
# Gemini key is normally passed per-request via the X-Gemini-Key
# header, but can also be set here for CLI runs that shell into the
# container directly.
- GEMINI_API_KEY=${GEMINI_API_KEY:-}
- GEMINI_MODEL=${GEMINI_MODEL:-gemini-3.5-flash}
# yt-dlp hardening. NOCHECKCERT=1 disables SSL verification only in
# trusted sandboxes; THROTTLED_RATE is the bytes/sec floor below
# which yt-dlp re-fetches a slow segment (default 102400 = 100 KB/s).
- YTDLP_NOCHECKCERT=${YTDLP_NOCHECKCERT:-}
- YTDLP_THROTTLED_RATE=${YTDLP_THROTTLED_RATE:-}
# Auto-purge of output/ and uploads/ folders. 0 = disabled
# (recommended — the History tab's Delete button is the single
# source of truth). Default fallback in app.py is 30 days.
- JOB_RETENTION_SECONDS=${JOB_RETENTION_SECONDS:-0}
# Reframe camera tuning (all optional; defaults preserve current feel).
# REFRAME_SMOOTHER=euro switches the active-speaker camera to the 1€
# adaptive filter; leave blank for the proven two-speed EMA. The LOST_*
# knobs control lost-subject drift-to-center (always on). EURO_* tune the
# 1€ filter when enabled. See docs/architecture/reframe.md.
- REFRAME_SMOOTHER=${REFRAME_SMOOTHER:-}
- REFRAME_LOST_HOLD=${REFRAME_LOST_HOLD:-90}
- REFRAME_LOST_DRIFT=${REFRAME_LOST_DRIFT:-0.05}
- REFRAME_EURO_MINCUTOFF=${REFRAME_EURO_MINCUTOFF:-0.014}
- REFRAME_EURO_BETA=${REFRAME_EURO_BETA:-0.0008}
# Comfort mode (anti-nausea, DEFAULT ON): biases the camera toward a locked
# crop + fixed per-scene zoom (the research-backed fix for seasickness from
# continuous tracking). Costs a second decode pass. Set REFRAME_COMFORT=0
# to revert to the original single-pass streaming tracker. STATIONARY_THRESH
# / ZOOM_LOCK override the comfort defaults (0.30 / on) when set explicitly.
- REFRAME_COMFORT=${REFRAME_COMFORT:-1}
- REFRAME_STATIONARY_THRESH=${REFRAME_STATIONARY_THRESH:-}
- REFRAME_ZOOM_LOCK=${REFRAME_ZOOM_LOCK:-}
- REFRAME_SNAP_CENTER=${REFRAME_SNAP_CENTER:-0.10}
# AUTO static-framing policy (DEFAULT ON): collapse each scene to ONE fixed
# crop so the camera is a locked tripod within every shot — zero pan, zero
# mid-shot zoom. TRACK locks on the static face; a single subject that
# MOVES more than MOTION_WIDE_THRESH (fraction of frame) is demoted to WIDE
# (locked, zoomed-out) instead of being chased; 2+ faces also → WIDE. Set
# REFRAME_STATIC_AUTO=0 to fall back to the per-frame eased smoother.
- REFRAME_STATIC_AUTO=${REFRAME_STATIC_AUTO:-}
- REFRAME_MOTION_WIDE_THRESH=${REFRAME_MOTION_WIDE_THRESH:-0.12}
# Opt-in: content-aware crop for faceless (GENERAL) scenes instead of
# letterboxing (Sobel saliency). Default off = byte-identical letterbox.
- REFRAME_SALIENT_GENERAL=${REFRAME_SALIENT_GENERAL:-}
# Opt-in: in faceless (GENERAL) scenes, follow a weighted-object centroid
# (product/dog/car) by reusing the existing YOLO pass — no 2nd network.
# `1` = curated COCO defaults; `dog:3,car:2,bottle:1.5` = custom weights.
# Takes precedence over SALIENT_GENERAL; default off = byte-identical.
- REFRAME_OBJECT_WEIGHTS=${REFRAME_OBJECT_WEIGHTS:-}
# FrameShift face-first `object` reframe mode weights (defaults mirror the
# FrameShift GUI: face 1.0, person 0.8, default 0.5). Override per class,
# e.g. `face:1,person:0.8,default:0.5,dog:3`. Empty = GUI defaults.
- REFRAME_FRAMESHIFT_WEIGHTS=${REFRAME_FRAMESHIFT_WEIGHTS:-}
# Encode quality (shared by every libx264 render/compose pass — reframe,
# zoom, grade, subtitles, smart-cut, hook, logo). CRF 18 / preset medium is
# near-visually-lossless so the stacked re-encodes don't compound into soft
# output. Lower CRF = higher quality + bigger files (0-51); a faster preset
# (e.g. `fast`/`veryfast`) trades a little quality/size for render speed.
- CLIPPYME_X264_CRF=${CLIPPYME_X264_CRF:-18}
- CLIPPYME_X264_PRESET=${CLIPPYME_X264_PRESET:-medium}
# Transcription: strip to audio-only (FLAC) before sending to the provider.
# DEFAULT ON; set to false to upload/decode the full video.
- CLIPPYME_TRANSCRIBE_AUDIO_ONLY=${CLIPPYME_TRANSCRIBE_AUDIO_ONLY:-true}
# Optional shared-secret auth for /api. Unset (default) = no auth beyond
# the private-network trust model. Set together with CLIPPYME_BIND=0.0.0.0
# for a deliberate LAN deployment: every API request must then carry
# X-API-Token (the dashboard has a Settings field for it).
- CLIPPYME_API_TOKEN=${CLIPPYME_API_TOKEN:-}
volumes:
- .:/app
- /app/__pycache__
- ./data:/app/data
networks:
- clippyme-net
restart: unless-stopped
frontend:
build: ./dashboard
container_name: clippyme-frontend
image: clippyme-frontend
ports:
# Loopback too: the Vite dev proxy forwards /api to the backend from
# INSIDE the docker network, where the frontend container is itself a
# trusted private peer — so a LAN-exposed dashboard would reopen the
# exact hole the backend loopback binding closes. Same CLIPPYME_BIND
# override applies.
- "${CLIPPYME_BIND:-127.0.0.1}:5175:5175"
volumes:
- ./dashboard:/app
- /app/node_modules
networks:
- clippyme-net
restart: unless-stopped
depends_on:
- backend