--- 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`.