# Lexsi Data Science Agent — image for the Lexsi agent-deployment platform. # The platform exposes ONE container via a public *.lexsi.ai URL, and that # container MUST listen on port 7850 (host AND container). This image runs the # Gradio app on 7850 (GRADIO_PORT below; the compose maps "7850:7850"). # # Build for the platform host arch (linux/amd64) even on an Apple-silicon Mac, # then push to Docker Hub (bplexsi): # docker buildx build --platform linux/amd64 \ # -t bplexsi/lexsi-ds-agent:prod_v1 --push . FROM python:3.10-slim ENV PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 \ # main() reads GRADIO_PORT; the app already binds server_name=0.0.0.0. GRADIO_PORT=7850 \ GRADIO_ANALYTICS_ENABLED=False WORKDIR /app # curl is only needed for the compose healthcheck. RUN apt-get update \ && apt-get install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/* # --- Dependencies --- # The pinned requirements.txt drags in GPU PyTorch + the full nvidia-*-cu13 / # cuda-toolkit / triton stack (~10-15 GB) — useless without a GPU (the heavy ML # runs on Lexsi pods). We keep sentence-transformers, pgserver, pymongo, etc., # but install CPU-only PyTorch from PyTorch's CPU wheel index so none of the # CUDA packages come along. Two steps so torch is satisfied before # sentence-transformers is resolved (otherwise pip would pull the CUDA wheel). # CPU-only PyTorch. Use --extra-index-url (NOT --index-url) so torch's deps # (typing-extensions, jinja2, fsspec, …) still resolve from PyPI; the explicit # "+cpu" local version forces the CPU wheel (only on the pytorch index), so no # CUDA/nvidia packages come along. RUN pip install --extra-index-url https://download.pytorch.org/whl/cpu "torch==2.11.0+cpu" # Everything else pinned to the tested lock (Python 3.10 variants) so the image # behaves exactly like local. duckdb==1.5.2 is required — newer DuckDB's CSV # reader fails to parse the headerless PKDD TSVs at build time. RUN pip install \ "gradio==5.50.0" \ "lexsi-sdk==0.1.51" \ "sentence-transformers==5.5.0" \ "pgserver>=0.1.4" \ "pymongo>=4.6" \ "duckdb==1.5.2" \ "pandas==2.3.3" \ "numpy==2.2.6" \ "pyyaml==6.0.3" \ "networkx==3.4.2" \ "rapidfuzz==3.14.5" \ "pydantic==2.12.5" \ "rich==15.0.0" \ "typer==0.25.1" # App code + the prebuilt artifacts/financial.duckdb (re-included in # .dockerignore). The bundled PKDD source TSVs are Git-LFS pointers, so the DB # can't be rebuilt at build time — we ship the already-built one instead. COPY . . # Sanity-check the bundled DuckDB opened correctly (fails the build early if the # 35 MB file didn't get copied). At runtime `_ensure_pkdd_duckdb()` sees it # present and skips any rebuild, so the Git-LFS TSVs are never parsed. RUN python -c "import duckdb; duckdb.connect('artifacts/financial.duckdb', read_only=True).execute('select count(*) from fin_trans')" EXPOSE 7850 # Runs app/gradio_app.py main() -> demo.launch(server_name=0.0.0.0, port=7850). CMD ["python", "-m", "app.gradio_app"]