Files
docker-compose/ai/compose.yaml

326 lines
17 KiB
YAML

services:
# PostgreSQL with pgvector for AI/RAG workloads
ai_postgres:
image: ${AI_POSTGRES_IMAGE:-pgvector/pgvector:pg16}
container_name: ${AI_COMPOSE_PROJECT_NAME}_postgres
restart: unless-stopped
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
POSTGRES_USER: ${AI_DB_USER}
POSTGRES_PASSWORD: ${AI_DB_PASSWORD}
POSTGRES_DB: ${AI_DB_NAME}
POSTGRES_HOST_AUTH_METHOD: scram-sha-256
POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256
volumes:
- ai_postgres_data:/var/lib/postgresql/data
- ./postgres/init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AI_DB_USER}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- compose_network
# Open WebUI - ChatGPT-like interface for AI models
webui:
image: ${AI_WEBUI_IMAGE:-ghcr.io/open-webui/open-webui:main}
container_name: ${AI_COMPOSE_PROJECT_NAME}_webui
restart: unless-stopped
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
# Database configuration
DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/${AI_DB_NAME}
# OpenAI API configuration (pointing to LiteLLM proxy)
OPENAI_API_BASE_URLS: http://litellm:4000
OPENAI_API_KEYS: ${AI_LITELLM_API_KEY}
# Disable Ollama (we only use LiteLLM)
ENABLE_OLLAMA_API: false
OLLAMA_BASE_URLS: ""
# WebUI configuration
WEBUI_NAME: ${AI_WEBUI_NAME:-Pivoine AI}
WEBUI_URL: https://${AI_TRAEFIK_HOST}
WEBUI_SECRET_KEY: ${AI_WEBUI_SECRET_KEY}
# Feature flags
ENABLE_SIGNUP: ${AI_ENABLE_SIGNUP:-true}
ENABLE_RAG_WEB_SEARCH: ${AI_ENABLE_RAG_WEB_SEARCH:-true}
ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION: ${AI_ENABLE_RAG_SSL_VERIFY:-true}
# RAG configuration
RAG_EMBEDDING_ENGINE: ${AI_RAG_EMBEDDING_ENGINE:-openai}
RAG_EMBEDDING_MODEL: ${AI_RAG_EMBEDDING_MODEL:-text-embedding-3-small}
VECTOR_DB: ${AI_VECTOR_DB:-pgvector}
# Email configuration (Mailpit SMTP relay)
SMTP_HOST: net_mailpit
SMTP_PORT: 1025
SMTP_FROM_EMAIL: ${EMAIL_FROM}
SMTP_USE_TLS: false
SMTP_USE_SSL: false
volumes:
- ai_webui_data:/app/backend/data
- ./functions:/app/backend/data/functions:ro
depends_on:
- ai_postgres
- litellm
networks:
- compose_network
labels:
- "traefik.enable=${AI_TRAEFIK_ENABLED}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.rule=Host(`${AI_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.entrypoints=web"
# HTTPS router
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${AI_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=8080"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
# LiteLLM - Proxy to convert Anthropic API to OpenAI-compatible format
litellm:
image: ghcr.io/berriai/litellm:main-latest
container_name: ${AI_COMPOSE_PROJECT_NAME}_litellm
restart: unless-stopped
network_mode: "service:tailscale"
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
LITELLM_MASTER_KEY: ${AI_LITELLM_API_KEY}
DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/litellm
GPU_VLLM_LLAMA_URL: ${GPU_VLLM_LLAMA_URL}
# LITELLM_DROP_PARAMS: 'true' # DISABLED: Was breaking streaming
NO_DOCS: "true"
NO_REDOC: "true"
# Performance optimizations
LITELLM_LOG: "DEBUG" # Enable detailed logging for debugging streaming issues
LITELLM_MODE: "PRODUCTION" # Production mode for better performance
volumes:
- ./litellm-config.yaml:/app/litellm-config.yaml:ro
command:
[
"--config",
"/app/litellm-config.yaml",
"--host",
"0.0.0.0",
"--port",
"4000",
]
depends_on:
- ai_postgres
networks:
- compose_network
healthcheck:
disable: true
labels:
- "traefik.enable=${AI_TRAEFIK_ENABLED}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.entrypoints=web"
# HTTPS router
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.loadbalancer.server.port=4000"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
# Facefusion - AI face swapping and enhancement
facefusion:
build:
context: .
dockerfile: Dockerfile
image: facefusion-patched:3.5.0-cpu
container_name: ${AI_COMPOSE_PROJECT_NAME}_facefusion
restart: unless-stopped
tty: true
command: ["python", "-u", "facefusion.py", "run"]
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
GRADIO_SERVER_NAME: "0.0.0.0"
GRADIO_SERVER_PORT: "7860"
volumes:
- ai_facefusion_data:/workspace
networks:
- compose_network
labels:
- "traefik.enable=${AI_FACEFUSION_TRAEFIK_ENABLED}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.entrypoints=web"
# HTTPS router with Authelia
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress,net-authelia,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.loadbalancer.server.port=7860"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower - disabled for custom local image
- "com.centurylinklabs.watchtower.enable=false"
# ComfyUI - Node-based UI for Flux image generation (proxies to RunPod GPU)
comfyui:
image: nginx:alpine
container_name: ${AI_COMPOSE_PROJECT_NAME}_comfyui
restart: unless-stopped
network_mode: "service:tailscale"
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST}
GPU_SERVICE_PORT: ${COMFYUI_BACKEND_PORT:-8188}
volumes:
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
networks:
- compose_network
labels:
- "traefik.enable=${AI_COMFYUI_TRAEFIK_ENABLED:-true}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.entrypoints=web"
# HTTPS router with Authelia SSO
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress,net-authelia,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.loadbalancer.server.port=80"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
audiocraft:
image: nginx:alpine
container_name: ${AI_COMPOSE_PROJECT_NAME}_audiocraft
restart: unless-stopped
network_mode: "service:tailscale"
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST}
GPU_SERVICE_PORT: ${AUDIOCRAFT_BACKEND_PORT:-7860}
volumes:
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
networks:
- compose_network
labels:
- "traefik.enable=${AI_AUDIOCRAFT_TRAEFIK_ENABLED:-true}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.entrypoints=web"
# HTTPS router with Authelia SSO
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress,net-authelia,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.loadbalancer.server.port=80"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
upscale:
image: nginx:alpine
container_name: ${AI_COMPOSE_PROJECT_NAME}_upscale
restart: unless-stopped
network_mode: "service:tailscale"
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST}
GPU_SERVICE_PORT: ${UPSCALE_BACKEND_PORT:-8080}
volumes:
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
networks:
- compose_network
labels:
- "traefik.enable=${AI_UPSCALE_TRAEFIK_ENABLED:-true}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-upscale-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-upscale-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.rule=Host(`${AI_UPSCALE_TRAEFIK_HOST:-upscale.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.entrypoints=web"
# HTTPS router with Authelia SSO
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.rule=Host(`${AI_UPSCALE_TRAEFIK_HOST:-upscale.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure-compress,net-authelia,security-headers@file"
# Service
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.loadbalancer.server.port=80"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
# Supervisor UI - Modern web interface for RunPod process management
supervisor:
image: dev.pivoine.art/valknar/supervisor-ui:latest
container_name: ${AI_COMPOSE_PROJECT_NAME}_supervisor_ui
restart: unless-stopped
network_mode: "service:tailscale"
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
NODE_ENV: production
# Connect to RunPod Supervisor via Tailscale
SUPERVISOR_HOST: ${GPU_TAILSCALE_HOST}
SUPERVISOR_PORT: ${SUPERVISOR_BACKEND_PORT:-9001}
# No auth needed - Supervisor has auth disabled (protected by Authelia)
networks:
- compose_network
labels:
- "traefik.enable=${AI_SUPERVISOR_TRAEFIK_ENABLED:-true}"
# HTTP to HTTPS redirect
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.entrypoints=web"
# HTTPS router with Authelia SSO
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.entrypoints=web-secure"
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress.compress=true"
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress,net-authelia,security-headers@file"
# Service (port 3000 for Next.js app)
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.loadbalancer.server.port=3000"
- "traefik.docker.network=${NETWORK_NAME}"
# Watchtower
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
volumes:
ai_postgres_data:
name: ${AI_COMPOSE_PROJECT_NAME}_postgres_data
ai_webui_data:
name: ${AI_COMPOSE_PROJECT_NAME}_webui_data
ai_facefusion_data:
name: ${AI_COMPOSE_PROJECT_NAME}_facefusion_data