# docker-compose.ollama.yml — Ollama LLM Runtime
# Usage: docker compose -f docker-compose.ollama.yml up -d
# Usage: ../scripts/claw.sh ollama:up
# Auto-pulls qwen3:1.7b on first start for routing.
# Requires: docker-compose.databases.yml running first (claw-network must exist)
#
# Reads environment variables from the root .env file.
# Copy .env.example to .env before running.

name: claw

services:
  ollama:
    image: ollama/ollama:latest
    container_name: claw-ollama
    restart: unless-stopped
    ports:
      - '11434:11434'
    volumes:
      - ollama-data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0
      - OLLAMA_KEEP_ALIVE=-1
      - OLLAMA_MAX_LOADED_MODELS=2
      - OLLAMA_NUM_PARALLEL=1
      - OLLAMA_FLASH_ATTENTION=1
      - OLLAMA_KV_CACHE_TYPE=q8_0
    entrypoint: ['/bin/sh', '-c']
    command:
      - |
        # Start ollama serve in the background
        ollama serve &
        SERVE_PID=$$!

        # Wait for Ollama to be ready
        echo "Waiting for Ollama to start..."
        until ollama list > /dev/null 2>&1; do
          sleep 1
        done
        echo "Ollama is ready."

        # Auto-pull models (configurable via AUTO_PULL_MODELS env var)
        DEFAULT_MODELS="qwen3:1.7b"
        MODELS_TO_PULL="$${AUTO_PULL_MODELS:-$$DEFAULT_MODELS}"
        for MODEL in $$MODELS_TO_PULL; do
          if ! ollama list | grep -q "$${MODEL%%:*}"; then
            echo "Pulling $$MODEL..."
            ollama pull $$MODEL
            echo "$$MODEL pulled successfully."
          else
            echo "$$MODEL already available."
          fi
        done

        DEPRECATED_MODELS="phi4-mini gemma3:4b gemma2:2b tinyllama phi3:mini llama3.2:3b"
        for INSTALLED in $$(ollama list | awk 'NR>1 {print $$1}'); do
          for MODEL in $$DEPRECATED_MODELS; do
            if [ "$$INSTALLED" = "$$MODEL" ] || printf '%s' "$$INSTALLED" | grep -Fq "$$MODEL:"; then
              echo "Removing deprecated model $$INSTALLED..."
              ollama rm "$$INSTALLED" || true
              break
            fi
          done
        done

        echo "All models ready."

        # Keep the container running by waiting on the serve process
        wait $$SERVE_PID
    healthcheck:
      test: ['CMD-SHELL', 'ollama list > /dev/null 2>&1 || exit 1']
      interval: 15s
      timeout: 10s
      retries: 10
      start_period: 30s
    networks:
      - claw-network

  # ---------------------------------------------------------------------------
  # Stable Diffusion (Local Image Generation)
  # ---------------------------------------------------------------------------
  stable-diffusion:
    image: ghcr.io/ai-dock/stable-diffusion-webui:latest
    container_name: claw-stable-diffusion
    restart: unless-stopped
    ports:
      - '7860:7860'
    volumes:
      - sd-models-data:/opt/stable-diffusion-webui/models
    environment:
      # CPU-mode flags: --skip-torch-cuda-test --use-cpu all lets SD start
      # without a GPU, and --no-half --precision full forces FP32 because
      # SDXL Turbo weights are FP16 and CPU torch can't mix
      # `c10::Half` bias with FP32 input — generation crashes with
      # `Input type (float) and bias type (c10::Half) should be the same`.
      # The NVIDIA overlay (docker-compose.dev.ollama.gpu-nvidia.yml)
      # overrides this to drop the CPU flags when a GPU is available.
      - COMMANDLINE_ARGS=--api --listen --skip-torch-cuda-test --use-cpu all --no-half --precision full
      # ai-dock wraps SD in a Caddy auth-proxy on port 7860 by default.
      # Without this flag every API call from claw-image-service gets a
      # 302 redirect to /login and image generation silently fails.
      # Auth isn't useful here — port 7860 is only reachable over the
      # internal claw-network.
      - WEB_ENABLE_AUTH=false
    healthcheck:
      test:
        ['CMD-SHELL', 'wget -qO- http://localhost:7860/sdapi/v1/sd-models 2>/dev/null || exit 1']
      interval: 30s
      timeout: 15s
      retries: 10
      start_period: 180s
    networks:
      - claw-network

  # ---------------------------------------------------------------------------
  # ComfyUI (Local Image Generation — FLUX, SD 3.5, SDXL-Lightning)
  # ---------------------------------------------------------------------------
  # The ollama-service container ALSO mounts `comfyui-models-data` (read-write)
  # so it can drop HuggingFace-downloaded weights into ComfyUI's models tree.
  # See claw-ollama-service entry in docker-compose.dev.services.yml.
  comfyui:
    image: ghcr.io/ai-dock/comfyui:latest
    container_name: claw-comfyui
    restart: unless-stopped
    ports:
      - '${COMFYUI_PORT:-8188}:8188'
    volumes:
      - comfyui-models-data:/opt/ComfyUI/models
    environment:
      # Force CPU runtime. ai-dock's base image hard-codes
      # XPU_TARGET=NVIDIA_GPU, which routes through CUDA init regardless of
      # CLI_ARGS — crashes with "Found no NVIDIA driver" when GPU isn't
      # passed through. Override to CPU at the image-target level + add
      # `--cpu` to CLI_ARGS as a second line of defence.
      # Reason for CPU-only on this stack: Blackwell (RTX 5090, SM 12.0)
      # is incompatible with the SM<=9.0 PyTorch kernels bundled in the
      # latest ai-dock image. Re-evaluate when ai-dock republishes with
      # PyTorch 2.7+/CUDA 12.8+.
      - XPU_TARGET=CPU
      - CLI_ARGS=--listen 0.0.0.0 --cpu
      # ai-dock wraps its services in a Caddy auth proxy by default. Disable it
      # because port 8188 is only reachable over the internal claw-network and
      # every request from claw-ollama-service / claw-image-service hits the
      # API directly.
      - WEB_ENABLE_AUTH=false
    healthcheck:
      test: ['CMD-SHELL', 'wget -qO- http://localhost:8188/system_stats 2>/dev/null || exit 1']
      interval: 30s
      timeout: 15s
      retries: 5
      start_period: 120s
    networks:
      - claw-network

volumes:
  ollama-data:
  sd-models-data:
  comfyui-models-data:

networks:
  claw-network:
    external: true
    name: claw-network
