animap-gpu / README.md
bluman1's picture
Publish services/inference
9d36f13 verified
|
Raw
History Blame Contribute Delete
7.42 kB
---
title: Animap Inference
emoji: πŸ„
colorFrom: green
colorTo: gray
sdk: gradio
sdk_version: 5.49.1
app_file: space_app.py
python_version: "3.12.12"
pinned: false
license: apache-2.0
short_description: Livestock models that refuse to invent a result.
---
# Animap inference
This runs validated livestock models against farm photographs and returns what
the model actually produced. Its most important property is what it **refuses**:
a capability with no checksummed artefact behind it answers `unavailable`, not a
placeholder and not a plausible-looking number.
Twenty-eight capabilities are registered. **Two run.** `cattle_detection` and
`poultry_count` execute a YOLOX-m ONNX artefact whose sha256 is verified against
its model card at start-up. The other twenty-six say so plainly, which is the
honest answer rather than a gap.
The source is `services/inference` in the Animap repository. `app.py` mounts
`app.main:app` β€” the same FastAPI service the Azure Container App runs β€” under a
Gradio page, so `/health`, `/capabilities` and `/jobs` behave exactly as they do
in production and the page is a demonstration of them.
**It was a Docker Space until 2026-08-24 and is a Gradio one now**, for one
reason: ZeroGPU is Gradio-SDK only. The Docker image ran the identical Azure
bytes, which was the better provenance story, and it could not be given a GPU at
any price β€” which left CountGD, the one capability a GPU actually unblocks,
unmeasurable. See **What this Space is not** for what the change cost.
## What is open and what is not
| Endpoint | Auth | Why |
|---|---|---|
| `GET /animap/health` | none | Carries no farm data, and a platform probe has to reach it |
| `GET /animap/capabilities` | none | The published contract: what may be claimed, and what may not |
| `POST /animap/jobs` | **bearer token** | Runs a model against a farm's photographs |
| `GET /animap/jobs/{id}` | **bearer token** | Returns a farm's result |
`space/publish.py --set-secret` mints `ANIMAP_INFERENCE_TOKEN` and sets it as a
Space secret. **Check it rather than assuming it**: `GET /health` reports
`"authenticated": false` when no token is configured, so a deployment that
reached the internet without one says so to anyone who asks.
curl -s https://bluman1-animap-inference.hf.space/animap/health
## Running a model
Two public-domain captures are baked in, so a real detection can be obtained
without an Azure account. `space/FIXTURES.md` in the repository lists their ids,
their sources and the human count on record for each.
```bash
curl -s -X POST https://bluman1-animap-inference.hf.space/animap/jobs \
-H "authorization: Bearer $ANIMAP_INFERENCE_TOKEN" \
-H 'content-type: application/json' \
-d '{"capability_key":"cattle_detection",
"subject_type":"herd",
"subject_id":"00000000-0000-0000-0000-000000000001",
"farm_id":"00000000-0000-0000-0000-000000000002",
"media_ids":["aa5e8481-8be6-509d-b1fa-f1a178c7cda0"],
"captured_at":"2026-08-22T10:00:00Z"}'
```
A frame that settles at the first grid answers in well under a second. A dense
one runs all three grids and takes a few seconds; there is no queue, because no
capability yet takes tens of seconds.
Read `warnings` before you read the number. A count is of the animals **visible
in one frame** β€” never the herd size, never a flock population, and never a
house reconciliation. When the count keeps rising as the frame is read more
finely, or exceeds twenty, the service publishes `count_withheld` and no number
at all. That refusal is a feature and it is measured: see the `known_limits` and
`validation_notes` on each model card.
## What the SDK change cost, and what it did not
**Lost: the image is no longer byte-identical to Azure's.** A Gradio Space has
no Dockerfile, so the claim *"this Space builds from the same Dockerfile"* is
gone and cannot be got back while ZeroGPU is Gradio-only. What runs is the same
`app/` tree with the same `requirements.txt`, which is close and is not the same
thing, and this file says so rather than letting the old sentence stand.
**Lost: a build-time licence gate.** The Docker build failed if an AGPL runtime
arrived. There is no build to fail now.
**Kept: every gate that actually protects a result.** `app.py` runs
`scripts/install_models.py --check` before it imports the service, so an
artefact that disagrees with its model card stops the Space at start-up rather
than being found by a farm's job. `providers.discover()` still refuses to serve
a capability whose artefact fingerprints as a copyleft runtime, and `/health`
still publishes `artefact_licenses` so a deployment in breach is visible from
outside.
**Gained: the ability to be given a GPU.** Nothing here reaches for CUDA yet β€”
YOLOX-m and DINOv3 are both ONNX on CPU β€” so this buys no speed-up today. It is
the prerequisite for CountGD, which gets MAE 14.84 on broiler houses against the
deployed detector's 156.80 and has never been runnable anywhere in this project.
## What this Space is not
**It is not the production media path, and it must not be read as evidence for
one.** This was true of the Docker Space and the SDK change did nothing to it. Production reads captures out of an Azure Blob container using the
Container App's managed identity β€” no key, no SAS, nothing stored. A Space is
not inside Azure and has no managed identity, so that credential is unavailable
to it. The alternatives a Space *could* use are a storage account key or a SAS
token in a secret, and neither is the production posture: one hands a public
Space full access to every farm's evidence, and the other expires.
So this Space serves `ANIMAP_MEDIA_PROVIDER=local` against the two baked-in
frames. Everything downstream of the pixels β€” the quality gate, the detection
pyramid, the counting guard, the observation vocabulary β€” is the production code
path exactly. Everything upstream of them is not.
**No farm data reaches this Space.** It cannot read `animapmedia`, and the only
captures it holds are two public-domain photographs from Wikimedia Commons.
## Weights
YOLOX-m, Apache-2.0, from the Megvii `0.1.1rc0` release, **vendored into this
repository under Git LFS rather than fetched at build time**. The service
verifies its sha256 against `models/cattle_detection/model_card.json` at
start-up and refuses to load an artefact that does not match. Vendoring is what
lets the build step stay `install_models.py --check` β€” verify, never fetch β€”
which is the posture ADR 0005 asks for and the same command the Azure build
runs.
`models/cattle_identity` is deliberately absent. Its artefact is DINOv3 under a
bespoke Meta licence whose two published texts disagree about an attribution
obligation, and publishing a copy into a public Space is redistribution. That
capability answers `unavailable` here, and correctly.
No AGPL-3.0 software is installed and none may be. `requirements.txt` omits
`ultralytics`, `.dockerignore` excludes `*.pt`, the build fails if one arrives
anyway, and `providers.discover()` refuses to serve a capability whose artefact
fingerprints as a copyleft runtime. `GET /health` publishes
`artefact_licenses`, so a deployment in breach is visible from outside.
## Attribution
Third-party notices travel with the image in `THIRD_PARTY_NOTICES.md`. The two
demonstration captures are CC0 and public domain; their sources are in
`space/FIXTURES.md`.