FROM python:3.12-slim WORKDIR /app # Install OS-level deps: curl (healthcheck), redis-server, Java 17 (for Neo4j) RUN apt-get update && \ apt-get install -y --no-install-recommends \ curl redis-server default-jre-headless wget && \ rm -rf /var/lib/apt/lists/* # Configure Redis for embedded use (no persistence needed, low memory) RUN mkdir -p /var/run/redis && chown redis:redis /var/run/redis && \ sed -i 's/^daemonize no/daemonize yes/' /etc/redis/redis.conf && \ sed -i 's/^# maxmemory /maxmemory 512mb/' /etc/redis/redis.conf && \ echo "maxmemory-policy allkeys-lru" >> /etc/redis/redis.conf && \ echo "save \"\"" >> /etc/redis/redis.conf && \ echo "appendonly no" >> /etc/redis/redis.conf # Install Neo4j Community Edition (embedded graph database) ARG NEO4J_VERSION=5.26.0 RUN wget -q "https://dist.neo4j.org/neo4j-community-${NEO4J_VERSION}-unix.tar.gz" -O /tmp/neo4j.tar.gz && \ tar xzf /tmp/neo4j.tar.gz -C /opt/ && \ mv "/opt/neo4j-community-${NEO4J_VERSION}" /opt/neo4j && \ rm /tmp/neo4j.tar.gz # Configure Neo4j for embedded use (localhost only, low memory, no auth) ENV NEO4J_HOME=/opt/neo4j RUN echo 'server.default_listen_address=127.0.0.1' >> /opt/neo4j/conf/neo4j.conf && \ echo 'server.memory.heap.initial_size=2g' >> /opt/neo4j/conf/neo4j.conf && \ echo 'server.memory.heap.max_size=2g' >> /opt/neo4j/conf/neo4j.conf && \ echo 'server.memory.pagecache.size=1g' >> /opt/neo4j/conf/neo4j.conf && \ echo 'dbms.security.auth_enabled=false' >> /opt/neo4j/conf/neo4j.conf && \ echo 'server.bolt.listen_address=:7687' >> /opt/neo4j/conf/neo4j.conf && \ echo 'server.http.listen_address=:7474' >> /opt/neo4j/conf/neo4j.conf # Install uv (fast Python package installer) RUN pip install --no-cache-dir uv # Install Python dependencies COPY requirements.txt /app/requirements.txt RUN uv pip install --system --no-cache -r requirements.txt # Pre-cache built-in ONNX MiniLM embedding model (default, runs locally) RUN python -c "from chromadb.utils.embedding_functions import ONNXMiniLM_L6_V2; ONNXMiniLM_L6_V2()" # Create persistent ChromaDB data directory RUN mkdir -p /data/chroma # Copy application code COPY . /app/backend # Create startup script: start Redis + Neo4j + ChromaDB, then start app RUN printf '#!/bin/bash\nset -e\n\n# Start Redis\nredis-server /etc/redis/redis.conf\necho "[docker] Redis started on localhost:6379"\n\n# Start Neo4j\n/opt/neo4j/bin/neo4j start\necho "[docker] Neo4j starting..."\nfor i in $(seq 1 30); do\n if /opt/neo4j/bin/neo4j status >/dev/null 2>&1; then\n echo "[docker] Neo4j ready on bolt://localhost:7687"\n break\n fi\n sleep 1\ndone\n\n# Start ChromaDB\nchroma run --path /data/chroma --host 127.0.0.1 --port 8100 &\necho "[docker] ChromaDB starting..."\nfor i in $(seq 1 15); do\n if curl -sf http://localhost:8100/api/v1/heartbeat >/dev/null 2>&1; then\n echo "[docker] ChromaDB ready on localhost:8100"\n break\n fi\n sleep 1\ndone\n\ncd /app/backend && exec python run.py\n' > /app/start.sh && \ chmod +x /app/start.sh # Run setup in check-free mode: create .env from example, write marker # (HF Spaces secrets are injected as env vars at runtime, so .env is just defaults) RUN cd /app/backend && cp .env.example .env && python -c "open('.setup_done','w').write('ok\n')" # Hugging Face Spaces requires port 7860 EXPOSE 7860 HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \ CMD curl -f http://localhost:7860/healthz || exit 1 CMD ["/app/start.sh"]