Spaces:
Running on Zero
Running on Zero
File size: 7,420 Bytes
d16b6da 4b98524 d16b6da 4b98524 d16b6da 4b98524 d16b6da 4b98524 d16b6da 4b98524 9d36f13 4b98524 9d36f13 4b98524 9d36f13 4b98524 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | ---
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`.
|