diff --git a/.env.example b/.env.example index 97ffa5a..0ddbc51 100644 --- a/.env.example +++ b/.env.example @@ -1,37 +1,36 @@ # ─── Chrysopedia Environment Variables ─── +# Copy to .env and fill in secrets before docker compose up # PostgreSQL POSTGRES_USER=chrysopedia POSTGRES_PASSWORD=changeme POSTGRES_DB=chrysopedia -DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@chrysopedia-db:5432/${POSTGRES_DB} -# Redis (Celery broker) +# Redis (Celery broker) — container-internal, no secret needed REDIS_URL=redis://chrysopedia-redis:6379/0 -# LLM endpoint (OpenAI-compatible) -LLM_API_URL=https://friend-openwebui.example.com/api +# LLM endpoint (OpenAI-compatible — OpenWebUI on FYN DGX) +LLM_API_URL=https://chat.forgetyour.name/api/v1 LLM_API_KEY=sk-changeme -LLM_MODEL=qwen2.5-72b -LLM_FALLBACK_URL=http://localhost:11434/v1 -LLM_FALLBACK_MODEL=qwen2.5:14b-q8_0 +LLM_MODEL=FYN-QWEN35 +LLM_FALLBACK_URL=https://chat.forgetyour.name/api/v1 +LLM_FALLBACK_MODEL=fyn-qwen35-chat -# Embedding endpoint -EMBEDDING_API_URL=http://localhost:11434/v1 +# Embedding endpoint (Ollama container in the compose stack) +EMBEDDING_API_URL=http://chrysopedia-ollama:11434/v1 EMBEDDING_MODEL=nomic-embed-text -# Qdrant -QDRANT_URL=http://qdrant:6333 +# Qdrant (container-internal) +QDRANT_URL=http://chrysopedia-qdrant:6333 QDRANT_COLLECTION=chrysopedia # Application APP_ENV=production APP_LOG_LEVEL=info -APP_SECRET_KEY=changeme-generate-a-real-secret -# File storage paths (inside container) +# File storage paths (inside container, bind-mounted to /vmPool/r/services/chrysopedia_data) TRANSCRIPT_STORAGE_PATH=/data/transcripts VIDEO_METADATA_PATH=/data/video_meta -# Review mode toggle +# Review mode toggle (true = moments require admin review before publishing) REVIEW_MODE=true diff --git a/docker-compose.yml b/docker-compose.yml index 198ac9f..3be778b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,6 @@ # Chrysopedia — Docker Compose # XPLTD convention: xpltd_chrysopedia project, bind mounts, dedicated bridge +# Deployed to: /vmPool/r/compose/xpltd_chrysopedia/ (symlinked) name: xpltd_chrysopedia services: @@ -23,12 +24,14 @@ services: interval: 10s timeout: 5s retries: 5 + stop_grace_period: 30s - # ── Redis (Celery broker) ── + # ── Redis (Celery broker + runtime config) ── chrysopedia-redis: image: redis:7-alpine container_name: chrysopedia-redis restart: unless-stopped + command: redis-server --save 60 1 --loglevel warning volumes: - /vmPool/r/services/chrysopedia_redis:/data networks: @@ -38,6 +41,41 @@ services: interval: 10s timeout: 5s retries: 5 + stop_grace_period: 15s + + # ── Qdrant vector database ── + chrysopedia-qdrant: + image: qdrant/qdrant:v1.13.2 + container_name: chrysopedia-qdrant + restart: unless-stopped + volumes: + - /vmPool/r/services/chrysopedia_qdrant:/qdrant/storage + networks: + - chrysopedia + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:6333/healthz || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + start_period: 10s + stop_grace_period: 30s + + # ── Ollama (embedding model server) ── + chrysopedia-ollama: + image: ollama/ollama:latest + container_name: chrysopedia-ollama + restart: unless-stopped + volumes: + - /vmPool/r/services/chrysopedia_ollama:/root/.ollama + networks: + - chrysopedia + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:11434/api/tags || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + start_period: 30s + stop_grace_period: 15s # ── FastAPI application ── chrysopedia-api: @@ -50,22 +88,27 @@ services: - path: .env required: false environment: - DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-chrysopedia}:${POSTGRES_PASSWORD}@chrysopedia-db:5432/${POSTGRES_DB:-chrysopedia} + DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-chrysopedia}:${POSTGRES_PASSWORD:-changeme}@chrysopedia-db:5432/${POSTGRES_DB:-chrysopedia} REDIS_URL: redis://chrysopedia-redis:6379/0 + QDRANT_URL: http://chrysopedia-qdrant:6333 + EMBEDDING_API_URL: http://chrysopedia-ollama:11434/v1 volumes: - - ./backend:/app - /vmPool/r/services/chrysopedia_data:/data - ports: - - "127.0.0.1:8000:8000" + - ./config:/config:ro depends_on: chrysopedia-db: condition: service_healthy chrysopedia-redis: condition: service_healthy + chrysopedia-qdrant: + condition: service_healthy + chrysopedia-ollama: + condition: service_healthy networks: - chrysopedia + stop_grace_period: 15s - # ── Celery worker (pipeline stages 2-5) ── + # ── Celery worker (pipeline stages 2-6) ── chrysopedia-worker: build: context: . @@ -76,38 +119,52 @@ services: - path: .env required: false environment: - DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-chrysopedia}:${POSTGRES_PASSWORD}@chrysopedia-db:5432/${POSTGRES_DB:-chrysopedia} + DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-chrysopedia}:${POSTGRES_PASSWORD:-changeme}@chrysopedia-db:5432/${POSTGRES_DB:-chrysopedia} REDIS_URL: redis://chrysopedia-redis:6379/0 - command: ["celery", "-A", "worker", "worker", "--loglevel=info"] + QDRANT_URL: http://chrysopedia-qdrant:6333 + EMBEDDING_API_URL: http://chrysopedia-ollama:11434/v1 + command: ["celery", "-A", "worker", "worker", "--loglevel=info", "--concurrency=2"] volumes: - - ./backend:/app - /vmPool/r/services/chrysopedia_data:/data - ./prompts:/prompts:ro + - ./config:/config:ro depends_on: chrysopedia-db: condition: service_healthy chrysopedia-redis: condition: service_healthy + chrysopedia-qdrant: + condition: service_healthy + chrysopedia-ollama: + condition: service_healthy networks: - chrysopedia + stop_grace_period: 30s # ── React web UI (nginx) ── chrysopedia-web: build: context: . dockerfile: docker/Dockerfile.web - container_name: chrysopedia-web + container_name: chrysopedia-web-8096 restart: unless-stopped ports: - - "127.0.0.1:3000:80" + - "0.0.0.0:8096:80" depends_on: - chrysopedia-api networks: - chrysopedia + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:80/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + stop_grace_period: 15s networks: chrysopedia: driver: bridge ipam: config: - - subnet: 172.24.0.0/24 + - subnet: "172.32.0.0/24" diff --git a/docker/Dockerfile.api b/docker/Dockerfile.api index b0760ae..94c0a23 100644 --- a/docker/Dockerfile.api +++ b/docker/Dockerfile.api @@ -4,7 +4,7 @@ WORKDIR /app # System deps RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc libpq-dev \ + gcc libpq-dev curl \ && rm -rf /var/lib/apt/lists/* # Python deps (cached layer) @@ -13,7 +13,12 @@ RUN pip install --no-cache-dir -r requirements.txt # Application code COPY backend/ /app/ +COPY prompts/ /prompts/ +COPY config/ /config/ EXPOSE 8000 +HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=10s \ + CMD curl -f http://localhost:8000/health || exit 1 + CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]