170 lines
6.9 KiB
YAML
170 lines
6.9 KiB
YAML
services:
|
|
db:
|
|
image: ankane/pgvector:latest
|
|
container_name: pmflow-db
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: ${POSTGRES_DB:-pmflow}
|
|
POSTGRES_USER: ${POSTGRES_USER:-pmflow}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-pmflow_pass}
|
|
TZ: Asia/Shanghai
|
|
PGTZ: Asia/Shanghai
|
|
ports:
|
|
- "${DB_PORT:-5435}:5432"
|
|
volumes:
|
|
- pg_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-pmflow} -d ${POSTGRES_DB:-pmflow}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 20
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: pmflow-redis
|
|
restart: unless-stopped
|
|
command:
|
|
[
|
|
"redis-server",
|
|
"--appendonly",
|
|
"yes",
|
|
"--requirepass",
|
|
"${REDIS_PASSWORD:-pmflow_redis_pass}",
|
|
"--maxmemory",
|
|
"512mb",
|
|
"--maxmemory-policy",
|
|
"allkeys-lru"
|
|
]
|
|
ports:
|
|
- "${REDIS_PORT:-6379}:6379"
|
|
volumes:
|
|
- redis_data:/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD:-pmflow_redis_pass} ping | grep PONG"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 20
|
|
|
|
backend:
|
|
build:
|
|
context: .
|
|
dockerfile: backend/Dockerfile
|
|
container_name: pmflow-backend
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
TZ: Asia/Shanghai
|
|
PGTZ: Asia/Shanghai
|
|
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:?missing_POSTGRES_USER}:${POSTGRES_PASSWORD:?missing_POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:?missing_POSTGRES_DB}
|
|
REDIS_URL: redis://:${REDIS_PASSWORD:?missing_REDIS_PASSWORD}@redis:6379/0
|
|
PMFLOW_EXPECTED_DB_DIALECT: ${PMFLOW_EXPECTED_DB_DIALECT:?missing_PMFLOW_EXPECTED_DB_DIALECT}
|
|
CORS_ORIGINS: ${CORS_ORIGINS:?missing_CORS_ORIGINS}
|
|
LLM_PROVIDER: ${LLM_PROVIDER:?missing_LLM_PROVIDER}
|
|
LLM_FALLBACK_PROVIDER: ${LLM_FALLBACK_PROVIDER:?missing_LLM_FALLBACK_PROVIDER}
|
|
OPENAI_BASE_URL: ${OPENAI_BASE_URL:?missing_OPENAI_BASE_URL}
|
|
OPENCLAW_ROUTING_ENABLED: ${OPENCLAW_ROUTING_ENABLED:?missing_OPENCLAW_ROUTING_ENABLED}
|
|
OPENCLAW_ROUTING_RULES_PATH: ${OPENCLAW_ROUTING_RULES_PATH:?missing_OPENCLAW_ROUTING_RULES_PATH}
|
|
OPENCLAW_AGENTS_DEFAULT_TIMEOUT_SECONDS: ${OPENCLAW_AGENTS_DEFAULT_TIMEOUT_SECONDS:?missing_OPENCLAW_AGENTS_DEFAULT_TIMEOUT_SECONDS}
|
|
LLM_MIXED_ROUTING_ENABLED: ${LLM_MIXED_ROUTING_ENABLED:?missing_LLM_MIXED_ROUTING_ENABLED}
|
|
LLM_ROUTING_DEFAULT_TIER: ${LLM_ROUTING_DEFAULT_TIER:?missing_LLM_ROUTING_DEFAULT_TIER}
|
|
LLM_LOW_TO_HIGH_ESCALATION_ENABLED: ${LLM_LOW_TO_HIGH_ESCALATION_ENABLED:?missing_LLM_LOW_TO_HIGH_ESCALATION_ENABLED}
|
|
LLM_ROUTING_LOW_PROVIDER: ${LLM_ROUTING_LOW_PROVIDER:?missing_LLM_ROUTING_LOW_PROVIDER}
|
|
LLM_ROUTING_LOW_MODEL: ${LLM_ROUTING_LOW_MODEL:?missing_LLM_ROUTING_LOW_MODEL}
|
|
LLM_ROUTING_HIGH_PROVIDER: ${LLM_ROUTING_HIGH_PROVIDER:?missing_LLM_ROUTING_HIGH_PROVIDER}
|
|
LLM_ROUTING_HIGH_MODEL: ${LLM_ROUTING_HIGH_MODEL:?missing_LLM_ROUTING_HIGH_MODEL}
|
|
LLM_ROUTING_SAFETY_PROVIDER: ${LLM_ROUTING_SAFETY_PROVIDER:?missing_LLM_ROUTING_SAFETY_PROVIDER}
|
|
LLM_ROUTING_SAFETY_MODEL: ${LLM_ROUTING_SAFETY_MODEL:?missing_LLM_ROUTING_SAFETY_MODEL}
|
|
LLM_DIRECT_EMERGENCY_ENABLED: ${LLM_DIRECT_EMERGENCY_ENABLED:?missing_LLM_DIRECT_EMERGENCY_ENABLED}
|
|
LLM_REQUEST_TIMEOUT: ${LLM_REQUEST_TIMEOUT:?missing_LLM_REQUEST_TIMEOUT}
|
|
AI_PMO_INTENT_LLM_ENABLED: ${AI_PMO_INTENT_LLM_ENABLED:-true}
|
|
AI_PMO_INTENT_ARBITRATION_ENABLED: ${AI_PMO_INTENT_ARBITRATION_ENABLED:-true}
|
|
AI_PMO_INTENT_CONFLICT_POLICY: ${AI_PMO_INTENT_CONFLICT_POLICY:-pending_manual}
|
|
AI_PMO_INTENT_LLM_TIMEOUT_SECONDS: ${AI_PMO_INTENT_LLM_TIMEOUT_SECONDS:-30}
|
|
AI_PMO_INTENT_LLM_TIMEOUT_COMPLEX_SECONDS: ${AI_PMO_INTENT_LLM_TIMEOUT_COMPLEX_SECONDS:-55}
|
|
AI_PMO_INTENT_LLM_TIMEOUT_FALLBACK_SECONDS: ${AI_PMO_INTENT_LLM_TIMEOUT_FALLBACK_SECONDS:-45}
|
|
AI_PMO_INTENT_LLM_TOTAL_BUDGET_SECONDS: ${AI_PMO_INTENT_LLM_TOTAL_BUDGET_SECONDS:-70}
|
|
AI_PMO_INTENT_LLM_STAGE2_CONFIDENCE_THRESHOLD: ${AI_PMO_INTENT_LLM_STAGE2_CONFIDENCE_THRESHOLD:-0.72}
|
|
AI_PMO_INTENT_LLM_STAGE2_MIN_REMAINING_SECONDS: ${AI_PMO_INTENT_LLM_STAGE2_MIN_REMAINING_SECONDS:-12}
|
|
AI_PMO_INTENT_STAGE1_TIMEOUT_CAP_SECONDS: ${AI_PMO_INTENT_STAGE1_TIMEOUT_CAP_SECONDS:-8}
|
|
AI_PMO_INTENT_LLM_MAX_TOKENS_LOW: ${AI_PMO_INTENT_LLM_MAX_TOKENS_LOW:-260}
|
|
AI_PMO_INTENT_LLM_MAX_TOKENS_HIGH: ${AI_PMO_INTENT_LLM_MAX_TOKENS_HIGH:-360}
|
|
LLM_HTTP_STATUS_RETRY_BUDGET: ${LLM_HTTP_STATUS_RETRY_BUDGET:-2}
|
|
LLM_INTENT_HTTP_RETRY_BUDGET: ${LLM_INTENT_HTTP_RETRY_BUDGET:-0}
|
|
LLM_INTENT_EMPTY_RETRY_BUDGET: ${LLM_INTENT_EMPTY_RETRY_BUDGET:-2}
|
|
LLM_INTENT_STRUCTURED_REPAIR_ENABLED: ${LLM_INTENT_STRUCTURED_REPAIR_ENABLED:-true}
|
|
AUTO_CREATE_TABLES: "false"
|
|
GLM_API_KEY: ${GLM_API_KEY:?missing_GLM_API_KEY}
|
|
GLM_BASE_URL: ${GLM_BASE_URL:?missing_GLM_BASE_URL}
|
|
GLM_MODEL: ${GLM_MODEL:?missing_GLM_MODEL}
|
|
OPENAI_API_KEY: ${OPENAI_API_KEY:?missing_OPENAI_API_KEY}
|
|
OPENAI_MODEL: ${OPENAI_MODEL:?missing_OPENAI_MODEL}
|
|
DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY}
|
|
OLLAMA_HOST: ${OLLAMA_HOST:?missing_OLLAMA_HOST}
|
|
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:?missing_OLLAMA_BASE_URL}
|
|
OLLAMA_MODEL: ${OLLAMA_MODEL:?missing_OLLAMA_MODEL}
|
|
PYTHONUNBUFFERED: "1"
|
|
HTTP_PROXY: ""
|
|
HTTPS_PROXY: ""
|
|
ALL_PROXY: ""
|
|
http_proxy: ""
|
|
https_proxy: ""
|
|
all_proxy: ""
|
|
NO_PROXY: "localhost,127.0.0.1,db,redis,backend,frontend,api.edgefn.net,open.bigmodel.cn"
|
|
no_proxy: "localhost,127.0.0.1,db,redis,backend,frontend,api.edgefn.net,open.bigmodel.cn"
|
|
command:
|
|
[
|
|
"uvicorn",
|
|
"app.main:app",
|
|
"--host",
|
|
"0.0.0.0",
|
|
"--port",
|
|
"8000",
|
|
"--reload",
|
|
"--reload-dir",
|
|
"app",
|
|
"--reload-exclude",
|
|
"*/__pycache__/*",
|
|
"--reload-exclude",
|
|
"*.pyc",
|
|
"--reload-exclude",
|
|
"alembic/versions/*"
|
|
]
|
|
volumes:
|
|
- ./backend:/app/backend
|
|
- ./.openclaw:/app/.openclaw:ro
|
|
- ./logs:/app/logs
|
|
ports:
|
|
- "${BACKEND_PORT:?missing_BACKEND_PORT}:8000"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "curl -fsS http://localhost:8000/healthz >/dev/null || exit 1"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 15
|
|
|
|
frontend:
|
|
image: node:20-alpine
|
|
container_name: pmflow-frontend
|
|
restart: unless-stopped
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
working_dir: /app
|
|
environment:
|
|
CHOKIDAR_USEPOLLING: "true"
|
|
VITE_DEV_API_PROXY_TARGET: "http://backend:8000"
|
|
command: ["/bin/sh", "-c", "npm ci && npm run dev -- --host 0.0.0.0 --port 5174"]
|
|
volumes:
|
|
- ./frontend:/app
|
|
- frontend_node_modules:/app/node_modules
|
|
ports:
|
|
- "${FRONTEND_PORT:-5174}:5174"
|
|
|
|
volumes:
|
|
pg_data:
|
|
redis_data:
|
|
frontend_node_modules:
|