CoolFace
Apppublic

anurag-raapid/clinical-code-retrieval

sourceHugging Faceapache-2.0updated 3mo agoView on Hugging Face
0likes
App README

Clinical Code Retrieval API

Hybrid semantic + graph retrieval for ICD-10-CM and CPT/HCPCS clinical codes, served from a single Hugging Face Space (Docker SDK, free CPU basic).

The Space runs three processes inside one container:

ProcessBackingPortURL on the Space
ICD-10-CM APIicd/api/main.py (FastAPI)127.0.0.1:8000/, /docs, /retrieve
CPT/HCPCS APIcpt/api/main.py (FastAPI)127.0.0.1:8001/cpt/, /cpt/docs, /cpt/retrieve
Reverse proxyproxy/app.py (aiohttp)0.0.0.0:7860the public HF URL

A tiny aiohttp proxy on 7860 (HF's exposed port) routes:

  • /cpt/*http://127.0.0.1:8001/* (strips /cpt prefix)
  • everything else → http://127.0.0.1:8000/*

Endpoints

URLWhat you get
/Landing page with links to both APIs
/healthICD API: corpus size, checkpoint, device
/docsICD API: Swagger UI
/retrieve (POST)ICD {"conditional_evidence": "...", "k": 5}
/retrieve/batch (POST)ICD batch (≤64 queries)
/cpt/healthCPT API: corpus size, checkpoint, device
/cpt/docsCPT API: Swagger UI
/cpt/retrieve (POST)CPT {"query_text": "...", "k": 5}
/cpt/retrieve/batch (POST)CPT batch (≤64 queries)
/healthzProxy: pings both backends

Quick test

bash
# ICD
curl -s https://<user>-<space>.hf.space/health | python -m json.tool
curl -s https://<user>-<space>.hf.space/retrieve \
  -H "Content-Type: application/json" \
  -d '{"conditional_evidence": "Chest pain radiating to left arm; hypertension", "k": 5}'

# CPT
curl -s https://<user>-<space>.hf.space/cpt/health | python -m json.tool
curl -s https://<user>-<space>.hf.space/cpt/retrieve \
  -H "Content-Type: application/json" \
  -d '{"query_text": "Abdomen CT Scan", "k": 5}'

What this Space downloads at startup

ArtifactSourceSizeUsed for
checkpoints/hybrid/best.pt (ICD)S3 (ICD_S3_CHECKPOINT_URI)~150 MBICD hybrid encoder
data/embeddings/graphmae/emb_graphmae.npy (ICD)S3 (ICD_S3_GRAPHMAE_EMB_URI)~9.4 GBICD online query graph
checkpoints/cpt/hybrid/best.pt (CPT)S3 (CPT_S3_CHECKPOINT_URI)~? MBCPT hybrid encoder
data/embeddings/graphmae/emb_graphmae_cpt.npy (CPT)S3 (CPT_S3_GRAPHMAE_EMB_URI)~? GBCPT online query graph
UFNLP/gatortron-base (transformer)Hugging Face Hub~440 MBShared encoder

If an artifact is already on disk inside /data/, download_artifacts.sh skips it.

Secrets & environment variables

See [HF_SPACE_SETUP.md](HF_SPACE_SETUP.md) for the full step-by-step (creating the Space, adding secrets, adding variables, what to expect on first boot).

The TL;DR:

  • Secrets (never in the repo): AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  • Variables: AWS_DEFAULT_REGION, ICD_S3_CHECKPOINT_URI, ICD_S3_GRAPHMAE_EMB_URI, CPT_S3_CHECKPOINT_URI, CPT_S3_GRAPHMAE_EMB_URI

Everything else (device=cpu, ports, QuickUMLS=off, ...) has safe defaults baked into entrypoint.sh.

Repository layout

.
├── Dockerfile                # single image, three services
├── entrypoint.sh             # downloads S3, starts uvicorns, runs proxy
├── .dockerignore  .gitignore
├── README.md                 # this file (also the HF Space README)
├── HF_SPACE_SETUP.md         # detailed Space setup walkthrough
├── proxy/
│   ├── app.py                # aiohttp reverse proxy on :7860
│   └── requirements.txt
├── icd/                      # ICD-10-CM FastAPI service
│   ├── api/  src/  config/  data/
│   ├── pyproject.toml  uv.lock
│   ├── .env.example
│   └── download_artifacts.sh
└── cpt/                      # CPT/HCPCS FastAPI service
    └── ... (mirrors icd/)

Docker build notes

The Dockerfile copies pyproject.toml, uv.lock, and README.md for each subproject before running uv sync, so Hatchling can resolve readme = "README.md" while dependency layers are cached. The full icd/ and cpt/ trees are copied in a later layer.

bash
docker build -t clinical-codes .

Local development (optional)

bash
docker build -t clinical-codes .
docker run --rm -p 7860:7860 \
  -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... -e AWS_DEFAULT_REGION=... \
  -e ICD_S3_CHECKPOINT_URI=... -e ICD_S3_GRAPHMAE_EMB_URI=... \
  -e CPT_S3_CHECKPOINT_URI=... -e CPT_S3_GRAPHMAE_EMB_URI=... \
  clinical-codes
# open http://localhost:7860

Cold-start note

The first request on a fresh Space boot takes 5–15 minutes (loads GatorTron from HF Hub, builds two FAISS indices, downloads ~20 GB of S3 artifacts). On free CPU the Space sleeps after 48 h of inactivity; the next cold start pays this cost again. The 9.4 GB emb_graphmae.npy files are downloaded as part of the same startup; they are memory-mapped (mmap_mode="r") at runtime so they do not consume 9.4 GB of RAM.