574 lines
20 KiB
YAML
574 lines
20 KiB
YAML
services:
|
|
# PostgreSQL Database
|
|
postgres:
|
|
image: postgres:15-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: library
|
|
POSTGRES_USER: mediamanager
|
|
# REQUIRED: Set POSTGRES_PASSWORD in .env file
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
ports:
|
|
# Bind to localhost only to prevent external access
|
|
- "127.0.0.1:5432:5432"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U mediamanager -d library"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- media-network
|
|
|
|
# API Server
|
|
api:
|
|
build:
|
|
context: .
|
|
dockerfile: packages/api/Dockerfile
|
|
ports:
|
|
- "3001:3001"
|
|
volumes:
|
|
- ./data:/app/data
|
|
# Docker socket for container management (JoyCaption start/stop)
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
# Mount local library for organization (read-write for scripts)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local:/media/local
|
|
# Mount studios for scanning (includes OnlyFans as subdirectory)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local/studios:/media/studios
|
|
# Mount public curated content (read-write for copy operations)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/curated:/media/public/curated
|
|
# Mount playback directory for compilation output (read-write)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/playback:/media/playback
|
|
# Mount compilations directory for symlinks (read-write)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/compilations:/media/compilations
|
|
# Mount videos directory for public videos (read-write for copy operations)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/videos:/media/videos
|
|
# Mount quickies directory for short-form videos (read-write)
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/quickies:/media/quickies
|
|
# Mount gifs directory for compilation scripts
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local/gifs:/media/gifs
|
|
# Mount inbox directory for downloaded files
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local/inbox:/media/inbox
|
|
# Mount scripts directory (read-only)
|
|
- ./scripts:/app/scripts:ro
|
|
# Mount anime models directory for model status checking (read-only)
|
|
- ./models/anime-pipe:/app/models/anime-pipe:ro
|
|
# Mount JoyTag models directory for tag seeding (read-only)
|
|
- ./models/joytag:/app/models/joytag:ro
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
environment:
|
|
- DATABASE_URL=postgresql://mediamanager:${POSTGRES_PASSWORD}@postgres:5432/library
|
|
- DATA_DIR=/app/data
|
|
- MEDIA_PATH=/media
|
|
- PUBLIC_DIR=/media/public/curated
|
|
- SOURCE_LIBRARY=/media/studios
|
|
- GIFS_PATH=/media/gifs
|
|
- INBOX_PATH=/media/inbox
|
|
- PLAYBACK_PATH=/media/playback
|
|
- COMPILATIONS_PATH=/media/compilations
|
|
- VIDEOS_PATH=/media/videos
|
|
- QUICKIES_PATH=/media/quickies
|
|
- SCRIPTS_PATH=/app/scripts
|
|
- PORT=3001
|
|
# JWT Authentication - REQUIRED: Set JWT_SECRET in .env file
|
|
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET must be set in .env}
|
|
# Initial admin user (created on first startup if no admin exists)
|
|
- INITIAL_ADMIN_EMAIL=${INITIAL_ADMIN_EMAIL:-}
|
|
- INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD:-}
|
|
# SMTP Configuration (for email verification and password reset)
|
|
- SMTP_HOST=${SMTP_HOST:-}
|
|
- SMTP_PORT=${SMTP_PORT:-587}
|
|
- SMTP_SECURE=${SMTP_SECURE:-false}
|
|
- SMTP_USER=${SMTP_USER:-}
|
|
- SMTP_PASS=${SMTP_PASS:-}
|
|
- SMTP_FROM=${SMTP_FROM:-noreply@example.com}
|
|
- SMTP_FROM_NAME=${SMTP_FROM_NAME:-Media Manager}
|
|
- EMAIL_VERIFICATION_EXPIRY_HOURS=${EMAIL_VERIFICATION_EXPIRY_HOURS:-24}
|
|
- PASSWORD_RESET_EXPIRY_HOURS=${PASSWORD_RESET_EXPIRY_HOURS:-1}
|
|
- APP_BASE_URL=${APP_BASE_URL:-http://localhost:3080}
|
|
# CORS allowed origins (comma-separated list of allowed domains)
|
|
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-http://localhost:3080,http://localhost:8080}
|
|
# Timezone
|
|
- TZ=${TZ:-UTC}
|
|
# MaxMind GeoIP Configuration (optional - for session geographic data)
|
|
# Register free at: https://www.maxmind.com/en/geolite2/signup
|
|
- MAXMIND_ACCOUNT_ID=${MAXMIND_ACCOUNT_ID:-}
|
|
- MAXMIND_LICENSE_KEY=${MAXMIND_LICENSE_KEY:-}
|
|
# Content Safety (Ollama) Configuration
|
|
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://ollama:11434}
|
|
- OLLAMA_MODEL=${OLLAMA_MODEL:-llama-guard3:1b}
|
|
- SAFETY_CHECK_ENABLED=${SAFETY_CHECK_ENABLED:-true}
|
|
# Digest Feature Configuration
|
|
- DIGEST_OLLAMA_URL=${DIGEST_OLLAMA_URL:-http://ollama:11434}
|
|
- DIGEST_WHISPER_URL=${DIGEST_WHISPER_URL:-http://whisper:5000}
|
|
# Use abliterated qwen3 models for uncensored scene analysis
|
|
- DIGEST_VISION_MODEL=${DIGEST_VISION_MODEL:-huihui_ai/qwen3-vl-abliterated:2b}
|
|
- DIGEST_TEXT_MODEL=${DIGEST_TEXT_MODEL:-huihui_ai/qwen3-abliterated:4b}
|
|
- DIGEST_FRAME_INTERVAL=${DIGEST_FRAME_INTERVAL:-30}
|
|
- DIGEST_TEMP_DIR=/app/data/digest_temp
|
|
# JoyCaption Vision Backend Configuration (alternative to Ollama vision)
|
|
- DIGEST_VISION_BACKEND=${DIGEST_VISION_BACKEND:-ollama}
|
|
- JOYCAPTION_URL=${JOYCAPTION_URL:-http://joycaption:8080}
|
|
- JOYCAPTION_MODEL=${JOYCAPTION_MODEL:-llama-joycaption-beta-one-hf-llava}
|
|
- JOYCAPTION_FALLBACK_TO_OLLAMA=${JOYCAPTION_FALLBACK_TO_OLLAMA:-true}
|
|
# Face Recognition Service Configuration
|
|
- FACE_RECOGNITION_URL=${FACE_RECOGNITION_URL:-http://face-recognition:5001}
|
|
# YOLO11 Person Detection Service Configuration
|
|
- YOLO_DETECTION_URL=${YOLO_DETECTION_URL:-http://yolo-detection:5002}
|
|
# JoyTag Visual Tagging Service Configuration
|
|
- JOYTAG_URL=${JOYTAG_URL:-http://joytag:5003}
|
|
- JOYTAG_ENABLED=${JOYTAG_ENABLED:-true}
|
|
- JOYTAG_THRESHOLD=${JOYTAG_THRESHOLD:-0.35}
|
|
- JOYTAG_TOP_K=${JOYTAG_TOP_K:-50}
|
|
# Scene Detection Service Configuration
|
|
- SCENE_DETECTION_URL=${SCENE_DETECTION_URL:-http://scene-detection:5004}
|
|
- SCENE_DETECTION_ENABLED=${SCENE_DETECTION_ENABLED:-true}
|
|
# TransNetV2 Neural Scene Detection Configuration (fast pipeline)
|
|
- TRANSNET_URL=${TRANSNET_URL:-http://transnetv2:5005}
|
|
- TRANSNET_ENABLED=${TRANSNET_ENABLED:-true}
|
|
- TRANSNET_THRESHOLD=${TRANSNET_THRESHOLD:-0.5}
|
|
# CLIP Embeddings Configuration (fast pipeline diversity scoring)
|
|
- CLIP_EMBEDDINGS_URL=${CLIP_EMBEDDINGS_URL:-http://clip-embeddings:5006}
|
|
- CLIP_EMBEDDINGS_ENABLED=${CLIP_EMBEDDINGS_ENABLED:-true}
|
|
- CLIP_FRAME_BATCH_SIZE=${CLIP_FRAME_BATCH_SIZE:-512}
|
|
# Container Lifecycle Configuration
|
|
# Set to 'true' when AI containers run continuously (models fit in VRAM)
|
|
- DISABLE_CONTAINER_LIFECYCLE=${DISABLE_CONTAINER_LIFECYCLE:-false}
|
|
# Combined Scene Detection Configuration
|
|
- ENABLE_COMBINED_SCENE_DETECTION=${ENABLE_COMBINED_SCENE_DETECTION:-true}
|
|
- SCENE_MERGE_STRATEGY=${SCENE_MERGE_STRATEGY:-weighted}
|
|
- SCENE_MERGE_TOLERANCE=${SCENE_MERGE_TOLERANCE:-0.75}
|
|
- SCENE_DETECTION_PARALLEL=${SCENE_DETECTION_PARALLEL:-false}
|
|
- SCENE_WEIGHT_TRANSNET=${SCENE_WEIGHT_TRANSNET:-1.0}
|
|
- SCENE_WEIGHT_PYSCENEDETECT=${SCENE_WEIGHT_PYSCENEDETECT:-0.8}
|
|
- SCENE_WEIGHT_CLIP=${SCENE_WEIGHT_CLIP:-0.9}
|
|
- CLIP_BOUNDARY_FRAME_INTERVAL=${CLIP_BOUNDARY_FRAME_INTERVAL:-0.5}
|
|
- CLIP_BOUNDARY_SIMILARITY_THRESHOLD=${CLIP_BOUNDARY_SIMILARITY_THRESHOLD:-0.7}
|
|
- CLIP_BOUNDARY_MIN_GAP=${CLIP_BOUNDARY_MIN_GAP:-2.0}
|
|
# Payment System IMAP Configuration
|
|
- PAYMENT_IMAP_HOST=${PAYMENT_IMAP_HOST:-}
|
|
- PAYMENT_IMAP_PORT=${PAYMENT_IMAP_PORT:-993}
|
|
- PAYMENT_IMAP_USER=${PAYMENT_IMAP_USER:-}
|
|
- PAYMENT_IMAP_PASS=${PAYMENT_IMAP_PASS:-}
|
|
- PAYMENT_IMAP_TLS=${PAYMENT_IMAP_TLS:-true}
|
|
- PAYMENT_POLL_INTERVAL_MS=${PAYMENT_POLL_INTERVAL_MS:-60000}
|
|
- PAYMENT_PROCESSED_FOLDER=${PAYMENT_PROCESSED_FOLDER:-Processed}
|
|
# PornDB API Configuration (metadata enrichment)
|
|
- PORNDB_API_KEY=${PORNDB_API_KEY:-}
|
|
# Inbox File Watcher Configuration (real-time auto-digest)
|
|
- FILE_WATCHER_ENABLED=${FILE_WATCHER_ENABLED:-false}
|
|
- FILE_WATCHER_DEBOUNCE_MS=${FILE_WATCHER_DEBOUNCE_MS:-2000}
|
|
# FFmpeg parallel encoding (default 1 sequential — NVENC is fastest single-stream)
|
|
- FFMPEG_ENCODE_CONCURRENCY=${FFMPEG_ENCODE_CONCURRENCY:-1}
|
|
# NVIDIA GPU support for NVENC encoding
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu, video]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
# Admin UI - directly exposed for local dev
|
|
admin:
|
|
build:
|
|
context: .
|
|
dockerfile: packages/admin/Dockerfile
|
|
ports:
|
|
- "8080:3000"
|
|
environment:
|
|
- VITE_API_URL=http://api:3001
|
|
depends_on:
|
|
- api
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
|
|
# Public gallery
|
|
public:
|
|
build:
|
|
context: .
|
|
dockerfile: packages/public/Dockerfile
|
|
args:
|
|
- VITE_API_URL=${VITE_API_URL:-http://api:3001}
|
|
- VITE_VIDEO_URL=${VITE_VIDEO_URL:-http://localhost:8081}
|
|
ports:
|
|
- "3080:80"
|
|
environment:
|
|
- VITE_API_URL=${VITE_API_URL:-http://api:3001}
|
|
- VITE_VIDEO_URL=${VITE_VIDEO_URL:-http://localhost:8081}
|
|
depends_on:
|
|
- api
|
|
- nginx
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
|
|
# Nginx for video streaming (public and library content)
|
|
nginx:
|
|
image: nginx:alpine
|
|
ports:
|
|
- "8081:80"
|
|
environment:
|
|
- APP_BASE_URL=${APP_BASE_URL:-http://localhost:3080}
|
|
volumes:
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/curated:/media/public/curated:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/playback:/media/playback:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/compilations:/media/compilations:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/videos:/media/videos:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public/quickies:/media/quickies:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local:/media/local:ro
|
|
- ./data/thumbnails:/media/thumbnails:ro
|
|
- ./data/ads:/media/ads:ro
|
|
- ./data/gallery:/media/gallery:ro
|
|
- ./data/digest_frames:/media/digest_frames:ro
|
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf.template:ro
|
|
command: /bin/sh -c "envsubst '$$APP_BASE_URL' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
|
|
# Ollama LLM Server
|
|
# For safety: Uses Llama Guard 3 1B (~1.6GB) for content moderation
|
|
# For digest: Uses qwen3-vl (vision) and qwen3 (text) for video analysis
|
|
# Models are automatically pulled on first startup based on OLLAMA_MODELS env var
|
|
ollama:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./ollama
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "11435:11434"
|
|
volumes:
|
|
- ollama-data:/root/.ollama
|
|
environment:
|
|
- OLLAMA_KEEP_ALIVE=24h
|
|
# Comma-separated list of models to pull on startup
|
|
# Abliterated qwen3 models for uncensored analysis
|
|
- OLLAMA_MODELS=${OLLAMA_MODELS:-llama-guard3:1b,huihui_ai/qwen3-vl-abliterated:2b,huihui_ai/qwen3-abliterated:4b}
|
|
- OLLAMA_CONTEXT_LENGTH=${OLLAMA_CONTEXT_LENGTH:-4096}
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:11434/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 180s
|
|
|
|
# Whisper Transcription Service
|
|
# Uses faster-whisper for GPU-accelerated speech recognition
|
|
whisper:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./whisper
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5000:5000"
|
|
volumes:
|
|
- whisper-models:/root/.cache
|
|
environment:
|
|
- WHISPER_MODEL=${WHISPER_MODEL:-base}
|
|
- WHISPER_DEVICE=${WHISPER_DEVICE:-cuda}
|
|
- WHISPER_COMPUTE=${WHISPER_COMPUTE:-float16}
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
# JoyCaption Vision Model Server
|
|
# Uses llama.cpp server with JoyCaption GGUF for image captioning
|
|
# Requires model files in ./models directory:
|
|
# - llama-joycaption-beta-one-hf-llava.Q2_K.gguf (~2GB)
|
|
# - llama-joycaption-beta-one-llava-mmproj-model-f16.gguf (~600MB)
|
|
# Download from: https://huggingface.co/Mungert/llama-joycaption-beta-one-hf-llava-GGUF
|
|
joycaption:
|
|
profiles: ["ai"]
|
|
image: ghcr.io/ggml-org/llama.cpp:server-cuda
|
|
ports:
|
|
- "11436:8080"
|
|
volumes:
|
|
- ./models:/models:ro
|
|
command:
|
|
- "--model"
|
|
- "${JOYCAPTION_MODEL_PATH:-/models/llama-joycaption-beta-one-hf-llava.Q2_K.gguf}"
|
|
- "--mmproj"
|
|
- "${JOYCAPTION_MMPROJ_PATH:-/models/llama-joycaption-beta-one-llava-mmproj-model-f16.gguf}"
|
|
- "--host"
|
|
- "0.0.0.0"
|
|
- "--port"
|
|
- "8080"
|
|
- "--ctx-size"
|
|
- "${JOYCAPTION_CTX_SIZE:-4096}"
|
|
- "--n-gpu-layers"
|
|
- "${JOYCAPTION_GPU_LAYERS:-999}"
|
|
- "--parallel"
|
|
- "${JOYCAPTION_PARALLEL:-1}"
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 120s
|
|
|
|
# Face Recognition Service
|
|
# Uses InsightFace with ONNX Runtime for face detection and embedding generation
|
|
# Provides face counting, gender detection, and performer recognition
|
|
face-recognition:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./face-recognition
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5001:5001"
|
|
volumes:
|
|
- face-models:/root/.insightface
|
|
environment:
|
|
- CUDA_VISIBLE_DEVICES=0
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
# YOLO11 Person Detection Service (for performer counting)
|
|
yolo-detection:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./yolo-detection
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5002:5002"
|
|
environment:
|
|
- MODEL=yolo11s.pt
|
|
- CONF_THRESHOLD=0.5
|
|
- DEVICE=0
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5002/health')"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 120s
|
|
|
|
# JoyTag Visual Tagging Service (for multi-label image tagging)
|
|
# Uses JoyTag ViT-B/16 for 5000+ Danbooru-style tags with confidence scores
|
|
# Model auto-downloaded from HuggingFace on first startup (~366MB ONNX)
|
|
joytag:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./joytag
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5003:5003"
|
|
environment:
|
|
- CUDA_VISIBLE_DEVICES=0
|
|
- CUDA_DEVICE=0
|
|
- MODEL_DIR=/models/joytag
|
|
- PORT=5003
|
|
volumes:
|
|
- ./models:/models
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5003/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 120s
|
|
|
|
# Scene Detection Service (for hard cut detection in videos)
|
|
# Uses PySceneDetect to find scene boundaries for cleaner clip transitions
|
|
# CPU-based - no GPU required
|
|
scene-detection:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./scene-detection
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5004:5004"
|
|
volumes:
|
|
# Mount media directories (read-only) for video access
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local:/media/local:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public:/media/public:ro
|
|
# Mount inbox for videos pending processing
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local/inbox:/media/inbox:ro
|
|
# Mount digest temp for chunked video processing
|
|
- ./data/digest_temp:/app/data/digest_temp:ro
|
|
environment:
|
|
- SCENE_CONTENT_THRESHOLD=${SCENE_CONTENT_THRESHOLD:-27.0}
|
|
- SCENE_MIN_LENGTH=${SCENE_MIN_LENGTH:-15}
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5004/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
# TransNetV2 Neural Shot Boundary Detection Service
|
|
# Uses TransNetV2 for faster and more accurate scene detection
|
|
# Especially good at detecting soft transitions (dissolves, fades)
|
|
# Used by fast digest pipeline for scene-based keyframe extraction
|
|
transnetv2:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./transnetv2
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5005:5005"
|
|
volumes:
|
|
# Mount media directories (read-only) for video access
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local:/media/local:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/public:/media/public:ro
|
|
- /media/bunker-admin/Internal/plex/xxx/media/local/inbox:/media/inbox:ro
|
|
# Mount digest temp for chunked video processing
|
|
- ./data/digest_temp:/app/data/digest_temp:ro
|
|
environment:
|
|
- TRANSNET_THRESHOLD=${TRANSNET_THRESHOLD:-0.5}
|
|
- TRANSNET_MIN_SCENE_LENGTH=${TRANSNET_MIN_SCENE_LENGTH:-1.0}
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5005/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
# CLIP Embeddings Service for Visual Diversity Scoring
|
|
# Uses OpenAI CLIP ViT-B/32 to extract 512-D visual embeddings
|
|
# Enables diversity-based clip selection without LLM calls
|
|
# Used by fast digest pipeline for visual similarity measurement
|
|
clip-embeddings:
|
|
profiles: ["ai"]
|
|
build:
|
|
context: ./clip-embeddings
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5006:5006"
|
|
environment:
|
|
- CLIP_MODEL=${CLIP_MODEL:-ViT-B/32}
|
|
# GPU batch size for embedding extraction (increase if VRAM allows, decrease if OOM)
|
|
- CLIP_GPU_BATCH_SIZE=${CLIP_GPU_BATCH_SIZE:-512}
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: 1
|
|
capabilities: [gpu]
|
|
networks:
|
|
- media-network
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5006/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
# Newt client for Pangolin tunnel
|
|
newt:
|
|
image: fosrl/newt
|
|
container_name: newt
|
|
restart: unless-stopped
|
|
environment:
|
|
- PANGOLIN_ENDPOINT=${PANGOLIN_ENDPOINT}
|
|
- NEWT_ID=${NEWT_ID}
|
|
- NEWT_SECRET=${NEWT_SECRET}
|
|
networks:
|
|
- media-network
|
|
|
|
volumes:
|
|
postgres-data:
|
|
ollama-data:
|
|
whisper-models:
|
|
face-models:
|
|
|
|
networks:
|
|
media-network:
|
|
external: true
|