mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic (#5495)
* feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic Swap the 4 NER entity types (PERSON/LOCATION/NRP/DATE_TIME) to a single multilingual GLiNER zero-shot model when PII_ENGINE=gliner; spaCy stays the default and all ~36 regex/checksum recognizers are identical on both engines. Device-agnostic via PII_DEVICE / cuda auto-detect — same code on Fargate CPU now and EC2-GPU later. - engines.py: side-effect-free builders; SharedModelGLiNERRecognizer loads ONE model shared across the 5 per-language instances and restricts labels to the entities it owns; small spaCy models keep tokenization/lemmas for the regex recognizers; fail-fast on the lean image - pii.Dockerfile: multi-stage — default target unchanged (lean spaCy); --target gliner is a superset (torch CPU + gliner + baked model) where both engines work; gliner-gpu scaffold for the GPU fleet - CI publishes the gliner variant (:staging-gliner/:latest-gliner, amd64) - Helm: pii.engine / pii.device values wired to PII_ENGINE/PII_DEVICE - scripts/bench_engines.py: throughput + NER-parity diff harness - tests: unit (mocked GLiNER) + in-image integration for both engines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ * refactor(pii): ship both engines in one image — engine is a pure env flip Collapse the gliner build target into the single pii image: spaCy lg models, torch (CPU), gliner, and the baked GLiNER weights all ship in it, so PII_ENGINE switches engines with no image swap and no tag matrix. CI reverts to the single pii build (no -gliner tags). The GPU variant becomes the same Dockerfile built with --build-arg TORCH_INDEX_URL=.../cu128. Image grows ~6.1GB -> ~9.6GB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4aba3dc5b4
commit
4e6594dc54
+59
-1
@@ -1,5 +1,17 @@
|
||||
# ========================================
|
||||
# Combined Presidio service (analyzer + anonymizer) on a single port (5001)
|
||||
#
|
||||
# ONE image serves both NER engines — the engine is a pure runtime choice via
|
||||
# PII_ENGINE (spacy default | gliner). spaCy large models, torch (CPU), the
|
||||
# gliner package, and the baked GLiNER weights all ship in it, so flipping
|
||||
# engines never requires an image swap.
|
||||
#
|
||||
# GPU variant (EC2-GPU fleet follow-up): same Dockerfile, CUDA torch wheels —
|
||||
# docker build --build-arg TORCH_INDEX_URL=https://download.pytorch.org/whl/cu128 ...
|
||||
# (torch CUDA wheels bundle their own CUDA libs; the host only needs the
|
||||
# nvidia container runtime.)
|
||||
#
|
||||
# Source files are COPY'd last so code edits never re-download deps or models.
|
||||
# ========================================
|
||||
FROM python:3.12-slim-bookworm AS base
|
||||
|
||||
@@ -31,11 +43,55 @@ RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install /tmp/*.whl && \
|
||||
rm /tmp/*.whl
|
||||
|
||||
COPY apps/pii/server.py ./server.py
|
||||
# --- GLiNER engine deps -------------------------------------------------------
|
||||
# torch is pinned here (not requirements-gliner.txt) because the CPU and CUDA
|
||||
# builds install the same version from different wheel indexes. 2.11.0 is the
|
||||
# newest release published on both the cpu and cu128 indexes for py312.
|
||||
ARG TORCH_VERSION=2.11.0
|
||||
ARG TORCH_INDEX_URL=https://download.pytorch.org/whl/cpu
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install torch==${TORCH_VERSION} --index-url ${TORCH_INDEX_URL}
|
||||
|
||||
COPY apps/pii/requirements-gliner.txt ./requirements-gliner.txt
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install -r requirements-gliner.txt
|
||||
|
||||
# Small spaCy models (~60MB total) give the gliner engine tokenization +
|
||||
# lemmas for the regex recognizers; GLiNER does the NER (see engines.py).
|
||||
ARG SPACY_SM_MODELS="en_core_web_sm-3.8.0 es_core_news_sm-3.8.0 it_core_news_sm-3.8.0 pl_core_news_sm-3.8.0 fi_core_news_sm-3.8.0"
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
for model in ${SPACY_SM_MODELS}; do \
|
||||
whl="${model}-py3-none-any.whl"; \
|
||||
curl -fL --retry 5 --retry-delay 5 --retry-all-errors -C - \
|
||||
-o "/tmp/${whl}" \
|
||||
"https://github.com/explosion/spacy-models/releases/download/${model}/${whl}" || exit 1; \
|
||||
done && \
|
||||
pip install /tmp/*.whl && \
|
||||
rm /tmp/*.whl
|
||||
|
||||
# Bake the GLiNER weights at build time (cached layer) so startup never
|
||||
# touches the network. HF_HUB_OFFLINE makes a missing/overridden
|
||||
# PII_GLINER_MODEL fail fast at startup instead of silently downloading.
|
||||
ENV HF_HOME=/opt/hf-cache
|
||||
ARG GLINER_MODEL=urchade/gliner_multi_pii-v1
|
||||
RUN python -c "from gliner import GLiNER; GLiNER.from_pretrained('${GLINER_MODEL}')" && \
|
||||
chmod -R a+rX /opt/hf-cache
|
||||
ENV HF_HUB_OFFLINE=1
|
||||
|
||||
# pytest/httpx for the in-image test suites (tests/) — baked in because the
|
||||
# runtime user has no writable HOME for pip install --user.
|
||||
COPY apps/pii/requirements-dev.txt ./requirements-dev.txt
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install -r requirements-dev.txt
|
||||
|
||||
RUN groupadd -g 1001 pii && \
|
||||
useradd -u 1001 -g pii pii && \
|
||||
chown -R pii:pii /app
|
||||
|
||||
COPY --chown=pii:pii apps/pii/server.py apps/pii/engines.py ./
|
||||
COPY --chown=pii:pii apps/pii/scripts ./scripts
|
||||
COPY --chown=pii:pii apps/pii/tests ./tests
|
||||
|
||||
USER pii
|
||||
|
||||
# Listen on 5001. Runs as its own ECS service (separate task), reached via PII_URL;
|
||||
@@ -54,4 +110,6 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=300s --retries=3 \
|
||||
# `sh -c exec` expands the env var while keeping uvicorn as PID 1 for clean SIGTERM.
|
||||
# Quote the expansion so a malformed PII_WORKERS fails uvicorn arg-parsing rather
|
||||
# than being interpreted by the shell.
|
||||
# NB for the gliner engine: EACH worker loads its own GLiNER model copy (into GPU
|
||||
# memory when on cuda), so GPU deployments generally want PII_WORKERS=1 per GPU.
|
||||
CMD ["sh", "-c", "exec uvicorn server:app --host 0.0.0.0 --port 5001 --workers \"${PII_WORKERS:-1}\""]
|
||||
|
||||
Reference in New Issue
Block a user