version: '3.8' services: # ============ Infrastructure ============ # PostgreSQL (Chatwoot Database) postgres: build: context: . dockerfile: postgres-with-pgvector.Dockerfile container_name: ai_postgres environment: POSTGRES_DB: ${POSTGRES_DB:-chatwoot} POSTGRES_USER: ${POSTGRES_USER:-chatwoot} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data networks: - ai_network healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-chatwoot}"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # Redis (Cache & Queue) redis: image: redis:7-alpine container_name: ai_redis command: redis-server --appendonly yes volumes: - redis_data:/data networks: - ai_network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 restart: unless-stopped # Nginx (Static File Server) nginx: image: nginx:alpine container_name: ai_nginx ports: - "8080:80" volumes: - ./docs:/usr/share/nginx/html/docs:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro networks: - ai_network restart: unless-stopped healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/test-chat.html"] interval: 30s timeout: 10s retries: 3 # ============ Messaging Platform ============ # Chatwoot chatwoot: image: chatwoot/chatwoot:latest container_name: ai_chatwoot command: bundle exec rails s -p 3000 -b 0.0.0.0 environment: RAILS_ENV: production SECRET_KEY_BASE: ${CHATWOOT_SECRET_KEY_BASE} FRONTEND_URL: ${CHATWOOT_FRONTEND_URL:-http://localhost:3000} # 允许 Widget 从多个域名访问(逗号分隔) ALLOWED_DOMAINS_FOR_WIDGET: ${CHATWOOT_ALLOWED_DOMAINS:-http://localhost:3000,http://localhost:8080,http://127.0.0.1:3000,http://127.0.0.1:8080} POSTGRES_HOST: postgres POSTGRES_DATABASE: ${POSTGRES_DB:-chatwoot} POSTGRES_USERNAME: ${POSTGRES_USER:-chatwoot} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} REDIS_URL: redis://redis:6379 INSTALLATION_NAME: B2B AI Assistant ports: - "3000:3000" volumes: - chatwoot_data:/app/storage depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - ai_network restart: unless-stopped # Chatwoot Sidekiq Worker chatwoot_worker: image: chatwoot/chatwoot:latest container_name: ai_chatwoot_worker command: bundle exec sidekiq -C config/sidekiq.yml environment: RAILS_ENV: production SECRET_KEY_BASE: ${CHATWOOT_SECRET_KEY_BASE} POSTGRES_HOST: postgres POSTGRES_DATABASE: ${POSTGRES_DB:-chatwoot} POSTGRES_USERNAME: ${POSTGRES_USER:-chatwoot} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} REDIS_URL: redis://redis:6379 INSTALLATION_NAME: B2B AI Assistant volumes: - chatwoot_data:/app/storage depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - ai_network restart: unless-stopped # ============ AI Agent Layer ============ # LangGraph Agent Main Service agent: build: context: ./agent dockerfile: Dockerfile container_name: ai_agent environment: # AI Model ZHIPU_API_KEY: ${ZHIPU_API_KEY} ZHIPU_MODEL: ${ZHIPU_MODEL:-glm-4} # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_DB: 0 # Chatwoot CHATWOOT_API_URL: http://chatwoot:3000 CHATWOOT_API_TOKEN: ${CHATWOOT_API_TOKEN} CHATWOOT_WEBHOOK_SECRET: ${CHATWOOT_WEBHOOK_SECRET} # External APIs STRAPI_API_URL: ${STRAPI_API_URL} STRAPI_API_TOKEN: ${STRAPI_API_TOKEN} HYPERF_API_URL: ${HYPERF_API_URL} HYPERF_API_TOKEN: ${HYPERF_API_TOKEN} # MCP Servers STRAPI_MCP_URL: http://strapi_mcp:8001 ORDER_MCP_URL: http://order_mcp:8002 AFTERSALE_MCP_URL: http://aftersale_mcp:8003 PRODUCT_MCP_URL: http://product_mcp:8004 # Config LOG_LEVEL: ${LOG_LEVEL:-INFO} MAX_CONVERSATION_STEPS: ${MAX_CONVERSATION_STEPS:-10} CONVERSATION_TIMEOUT: ${CONVERSATION_TIMEOUT:-3600} ports: - "8000:8000" volumes: - ./agent:/app - agent_logs:/app/logs depends_on: - redis - strapi_mcp - order_mcp - aftersale_mcp - product_mcp networks: - ai_network restart: unless-stopped # ============ MCP Servers ============ # Strapi MCP (FAQ/Knowledge Base) strapi_mcp: build: context: ./mcp_servers/strapi_mcp dockerfile: Dockerfile container_name: ai_strapi_mcp environment: STRAPI_API_URL: ${STRAPI_API_URL} STRAPI_API_TOKEN: ${STRAPI_API_TOKEN} LOG_LEVEL: ${LOG_LEVEL:-INFO} ports: - "8001:8001" volumes: - ./mcp_servers/strapi_mcp:/app - ./mcp_servers/shared:/app/shared networks: - ai_network restart: unless-stopped # Order MCP order_mcp: build: context: ./mcp_servers/order_mcp dockerfile: Dockerfile container_name: ai_order_mcp env_file: - .env environment: HYPERF_API_URL: ${HYPERF_API_URL} HYPERF_API_TOKEN: ${HYPERF_API_TOKEN} MALL_API_URL: ${MALL_API_URL} MALL_API_TOKEN: ${MALL_API_TOKEN} MALL_TENANT_ID: ${MALL_TENANT_ID:-2} MALL_CURRENCY_CODE: ${MALL_CURRENCY_CODE:-EUR} MALL_LANGUAGE_ID: ${MALL_LANGUAGE_ID:-1} MALL_SOURCE: ${MALL_SOURCE:-us.qa1.gaia888.com} LOG_LEVEL: ${LOG_LEVEL:-INFO} ports: - "8002:8002" volumes: - ./mcp_servers/order_mcp:/app - ./mcp_servers/shared:/app/shared networks: - ai_network restart: unless-stopped # Aftersale MCP aftersale_mcp: build: context: ./mcp_servers/aftersale_mcp dockerfile: Dockerfile container_name: ai_aftersale_mcp environment: HYPERF_API_URL: ${HYPERF_API_URL} HYPERF_API_TOKEN: ${HYPERF_API_TOKEN} LOG_LEVEL: ${LOG_LEVEL:-INFO} ports: - "8003:8003" volumes: - ./mcp_servers/aftersale_mcp:/app - ./mcp_servers/shared:/app/shared networks: - ai_network restart: unless-stopped # Product MCP product_mcp: build: context: ./mcp_servers/product_mcp dockerfile: Dockerfile container_name: ai_product_mcp environment: HYPERF_API_URL: ${HYPERF_API_URL} HYPERF_API_TOKEN: ${HYPERF_API_TOKEN} LOG_LEVEL: ${LOG_LEVEL:-INFO} ports: - "8004:8004" volumes: - ./mcp_servers/product_mcp:/app - ./mcp_servers/shared:/app/shared networks: - ai_network restart: unless-stopped networks: ai_network: driver: bridge volumes: postgres_data: redis_data: chatwoot_data: agent_logs: