services: postgres: image: ${POSTGRES_IMAGE:-postgres:16-alpine} container_name: dashboard-nanobot-postgres restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_SUPERPASSWORD:?POSTGRES_SUPERPASSWORD is required} POSTGRES_DB: ${POSTGRES_BOOTSTRAP_DB:-postgres} volumes: - ./data/postgres:/var/lib/postgresql/data expose: - "5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""] interval: 10s timeout: 5s retries: 10 start_period: 20s logging: driver: json-file options: max-size: "20m" max-file: "3" redis: image: ${REDIS_IMAGE:-redis:7-alpine} container_name: dashboard-nanobot-redis restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} command: ["redis-server", "--appendonly", "yes", "--save", "60", "1000"] volumes: - ./data/redis:/data expose: - "6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 start_period: 10s logging: driver: json-file options: max-size: "20m" max-file: "3" backend: build: context: . dockerfile: backend/Dockerfile args: PYTHON_BASE_IMAGE: ${PYTHON_BASE_IMAGE:-python:3.12-slim} PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple} PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-} image: dashboard-nanobot/backend:${BACKEND_IMAGE_TAG:-latest} container_name: dashboard-nanobot-backend restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: TZ: ${TZ:-Asia/Shanghai} APP_HOST: 0.0.0.0 APP_PORT: 8000 APP_RELOAD: "false" DATABASE_ECHO: "false" DATABASE_POOL_SIZE: ${DATABASE_POOL_SIZE:-20} DATABASE_MAX_OVERFLOW: ${DATABASE_MAX_OVERFLOW:-40} DATABASE_POOL_TIMEOUT: ${DATABASE_POOL_TIMEOUT:-30} DATABASE_POOL_RECYCLE: ${DATABASE_POOL_RECYCLE:-1800} UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100} DATA_ROOT: /app/data BOTS_WORKSPACE_ROOT: ${HOST_BOTS_WORKSPACE_ROOT} DATABASE_URL: postgresql+psycopg://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_APP_DB} REDIS_ENABLED: ${REDIS_ENABLED:-true} REDIS_URL: redis://redis:6379/${REDIS_DB:-8} REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot} REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60} CHAT_PULL_PAGE_SIZE: ${CHAT_PULL_PAGE_SIZE:-60} COMMAND_AUTO_UNLOCK_SECONDS: ${COMMAND_AUTO_UNLOCK_SECONDS:-10} DEFAULT_BOT_SYSTEM_TIMEZONE: ${DEFAULT_BOT_SYSTEM_TIMEZONE:-Asia/Shanghai} PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-} WORKSPACE_DOWNLOAD_EXTENSIONS: ${WORKSPACE_DOWNLOAD_EXTENSIONS:-} STT_ENABLED: ${STT_ENABLED:-true} STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin} STT_MODEL_DIR: ${STT_MODEL_DIR:-/app/data/model} STT_DEVICE: ${STT_DEVICE:-cpu} STT_MAX_AUDIO_SECONDS: ${STT_MAX_AUDIO_SECONDS:-20} STT_DEFAULT_LANGUAGE: ${STT_DEFAULT_LANGUAGE:-zh} STT_FORCE_SIMPLIFIED: ${STT_FORCE_SIMPLIFIED:-true} STT_AUDIO_PREPROCESS: ${STT_AUDIO_PREPROCESS:-true} STT_AUDIO_FILTER: ${STT_AUDIO_FILTER:-highpass=f=120,lowpass=f=7600,afftdn=nf=-20} STT_INITIAL_PROMPT: ${STT_INITIAL_PROMPT:-以下内容可能包含简体中文和英文术语。请优先输出简体中文,英文单词、缩写、品牌名和数字保持原文,不要翻译。} volumes: - /var/run/docker.sock:/var/run/docker.sock - ./data:/app/data - ${HOST_BOTS_WORKSPACE_ROOT}:${HOST_BOTS_WORKSPACE_ROOT} expose: - "8000" healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=3).read()"] interval: 15s timeout: 5s retries: 5 start_period: 20s logging: driver: json-file options: max-size: "20m" max-file: "3" nginx: build: context: ./frontend dockerfile: Dockerfile args: NODE_BASE_IMAGE: ${NODE_BASE_IMAGE:-node:22-alpine} NGINX_BASE_IMAGE: ${NGINX_BASE_IMAGE:-nginx:alpine} NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/} VITE_API_BASE: /api VITE_WS_BASE: /ws/monitor image: dashboard-nanobot/nginx:${FRONTEND_IMAGE_TAG:-latest} container_name: dashboard-nanobot-nginx restart: unless-stopped environment: TZ: ${TZ:-Asia/Shanghai} UPLOAD_MAX_MB: ${UPLOAD_MAX_MB:-100} depends_on: backend: condition: service_healthy ports: - "${NGINX_PORT}:80" healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"] interval: 15s timeout: 5s retries: 5 start_period: 10s logging: driver: json-file options: max-size: "20m" max-file: "3" networks: default: name: dashboard-nanobot-network