rascore-api / Dockerfile
ilkhamfy's picture
Add SCScore (Coley) alongside RAScore
53ced7a verified
Raw
History Blame Contribute Delete
3.21 kB
# RAScore micro-service (ISOLATED) for MolParetoLab.
# Retrosynthetic Accessibility score (Thakkar et al., Chem. Sci. 2021): the
# probability that a CASP tool (AiZynthFinder) can find a synthesis route β€”
# 0 = no route found (hard) … 1 = readily synthesizable. A fast, learned
# make-ability signal that complements the Ertl SA score.
#
# WHY ITS OWN CONTAINER: RAScore's pretrained XGBoost model only unpickles under
# 2020-era pins (Python 3.7, scikit-learn 0.22.1, xgboost 1.0.2) that are
# incompatible with the modern ADMET-AI / Chemprop stack. Quarantining it here
# means it can never destabilise the ADMET endpoint.
#
# NOTE: these legacy pins are inherently finicky. If the build fails, check the
# logs β€” the usual culprit is a numpy/scikit-learn ABI mismatch; adjust the numpy
# pin to match the scikit-learn 0.22.1 era (1.18–1.19).
FROM continuumio/miniconda3
# A clean, consistent 2020-era env solved entirely by conda (binaries β€” so the
# old scikit-learn / xgboost do NOT get built from source by pip). Only the
# pure-python API stack + RAScore (--no-deps, so no TensorFlow) go through pip.
RUN conda create -y -n ra -c conda-forge \
python=3.7 pip "rdkit=2020.09.1" "numpy=1.19" "scikit-learn=0.22.1" "xgboost=1.0.2" && \
conda clean -afy
# Use the env's own pip/uvicorn by absolute path and put it first on PATH β€”
# avoids conda-run/base-PATH ambiguity (a bare `uvicorn` was otherwise resolving
# to the base Python 3.13 env, loading an incompatible fastapi/pydantic).
ENV PATH=/opt/conda/envs/ra/bin:$PATH
RUN /opt/conda/envs/ra/bin/pip install --no-cache-dir \
"fastapi==0.95.2" "uvicorn[standard]==0.22.0" "pydantic==1.10.13" && \
/opt/conda/envs/ra/bin/pip install --no-cache-dir --no-deps "git+https://github.com/reymond-group/RAscore.git@master"
# RAScore's pip install ships no model files; fetch the XGB model (~9 MB) into place.
RUN /opt/conda/envs/ra/bin/python -c "import os,urllib.request,RAscore; d=os.path.join(os.path.dirname(RAscore.__file__),'models','XGB_chembl_ecfp_counts'); os.makedirs(d,exist_ok=True); urllib.request.urlretrieve('https://raw.githubusercontent.com/reymond-group/RAscore/master/RAscore/models/XGB_chembl_ecfp_counts/model.pkl', os.path.join(d,'model.pkl')); print('RAScore model:', os.path.getsize(os.path.join(d,'model.pkl')), 'bytes')"
# SCScore (Coley et al. 2018): standalone numpy model (no TensorFlow) + 1024-bit
# weights, fetched into /app. A learned synthetic-complexity score (1 easy - 5 hard)
# that complements RAScore. The standalone imports six.
RUN /opt/conda/envs/ra/bin/pip install --no-cache-dir six && mkdir -p /app && \
/opt/conda/envs/ra/bin/python -c "import urllib.request as u; u.urlretrieve('https://raw.githubusercontent.com/connorcoley/scscore/master/scscore/standalone_model_numpy.py','/app/scscore_standalone.py'); u.urlretrieve('https://github.com/connorcoley/scscore/raw/master/models/full_reaxys_model_1024bool/model.ckpt-10654.as_numpy.json.gz','/app/scscore_1024bool.json.gz'); print('scscore standalone+weights fetched')"
COPY app.py /app/app.py
WORKDIR /app
EXPOSE 7860
CMD ["/opt/conda/envs/ra/bin/python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]