Web Application (React)
The React app in breed-classifier-react/ is the primary human-facing surface:
a public capture-and-classify page plus a developer control plane. It talks to
the same Flask API (server/, port 5000) that the Colab and test_model.py
workflows use.
| Aspect | Detail |
|---|---|
| Stack | React 18 (hooks only), Vite 5, React Router 7, socket.io-client, hand-written CSS design system |
| Routes | / → public app (UserPage), /dev → developer control plane (DevPage) |
| Styling | 4 bespoke themes (field-parchment default, obsidian-loam, clinical-slate, night-telemetry) via CSS custom properties, persisted in agri_theme |
| Languages | English + தமிழ் (src/i18n/), persisted, no external service |
| Tests | npm test → node --test, 30 tests across 3 spec files (no test framework dependency) |
| Build | npm run build → static bundle served by any web server; dev proxy forwards /api and /socket.io to the backend |
1. Quick start
# terminal 1 — backend
python server/app.py --port 5000
# terminal 2 — web app
cd breed-classifier-react
npm install
npm run dev # http://localhost:5173
Other useful commands:
npm test # unit tests (crop math, optimizer layout, session store)
npm run build # production bundle
npm run preview # serve the built bundle
2. The capture → classify path
file / camera
└─ ImageUpload
├─ keeps the ORIGINAL image (never replaced by the model input)
├─ optional framing via ImageCropper (1:1, pan on both axes, 1–3× zoom)
└─ useImageOptimizer → 260×260 zero-crop file
├─ stretch (default) | pad · ImageNet mean | pad · ambient blur | pad · black
├─ EXIF-upright decode, progressive halving
└─ meta: original size, inner scaled size, padding, payload, time
↓
POST /api/predict (image, model, original filename)
↓
ResultWorkspace
- Big-4 species / breed / gender / age cards
- read-only gender / age estimates
- farmer / public advisory tabs
- quality gate + OOD explainer + printable report card
- technical diagnostics
↓
Herd session log (localStorage) → CSV / JSON / ODT export
Why the client optimises
The server evaluates with Resize(260) → CenterCrop(260). A 16:9 upload would
lose ~44% of the long axis. Because the client already sends a 260×260 square,
both server steps become identity transforms and the animal is never cropped.
The pad colour is the ImageNet mean rgb(124,116,104), which normalises to
approximately zero.
3. User surface
3.1 Upload
- The card shows only the original image.
- Actions: Adjust framing, Remove, Choose another, and the primary Identify Breed button — which becomes Identify Framed Breed after a crop, so the classify step is always explicit.
- Applying a new upload, crop or fit change clears the previous prediction (a stale result is never shown next to a new input).
3.2 Live camera
- Full-frame viewfinder (
object-fit: contain) with a guide framing the whole sensor frame and the badge “Full Frame Active • Auto-Optimized to 260×260 (Zero Crop)”. - On-device quality gate (sharpness, exposure, framing) drives a guidance pill.
- Auto-capture after 3 stable checks (~750 ms) with a countdown ring.
- Burst ×3 keeps the sharpest frame; torch is exposed when the device supports it.
- The review screen shows the 260×260 result, the telemetry
(
1920×1080 → 260×260 • 0% Cropped • 22 KB), Pad/Strict switch and an optional manual framing pass.
3.3 Result card
| Tier | Condition | Presentation |
|---|---|---|
| 1 — verified | not OOD, confidence ≥ 0.72, top-1/top-2 margin ≥ 0.12 | green badge, “top match well separated” |
| 2 — look-alike | not OOD, otherwise | amber badge + trait comparison + retake action |
| 3 — abstention | OOD | red badge, the exact trigger (energy / MSP / binary floor) and a retake action |
3.4 Herd session
Every confirmed classification is appended to a local session with a thumbnail, timestamp, model, species, breed, confidence, OOD flag and capture quality. The drawer shows totals, the cattle/buffalo split, flagged count and averages, and exports CSV, JSON and ODT.
4. Advanced panel (header, next to Connected)
Everything technical is one click away:
| Block | Contents |
|---|---|
| Preview | View model input ⇄ View original |
| Metadata | ORIGINAL, MODEL INPUT, SCALED, PADDING, PAYLOAD, TIME, original file name |
| Fit mode | Stretch 260×260 (default), Pad · ImageNet mean, Pad · Ambient blur, Pad · Black |
| Batch test | Multi-image run with the selected model and fit configuration, per-image results, payload saved, optional append to the herd session |
5. Developer control plane (/dev)
| Tab | Purpose |
|---|---|
| Models | Registry, active-model switch, per-model spec (parameters, layer breakdown, ONNX I/O), checkpoint upload |
| OOD Safety | Enable/disable, profile select/upload, live threshold sliders, manual recalibration from a breed-named folder |
| Config | Shared settings database (display, dataset, inference, OOD) |
| Logs | Live server log tail |
Manual OOD recalibration
- Pick the model that is deployed.
- Pick a folder of breed-named images — flat (
Deoni_01.jpg) or nested (cattle/deoni/…). The picker is pre-filled with the folders found in the repository. - Choose the percentile (default 95) and the maximum number of images.
- Recalibrate. The response reports the new thresholds, the number of samples,
matched/unmatched/unreadable counts and the per-breed coverage, and the
profile is written to
outputs/ood/<model>.json.
Unmatched names are reported instead of being used, so a mis-named folder is
visible rather than silently skewing the thresholds. Calibration requires a
PyTorch .pt checkpoint (ONNX models return a clear error).
6. Module map
| Path | Responsibility |
|---|---|
src/pages/UserPage.jsx |
Public page: tabs, preview, explicit classify action, result, session, Advanced panel |
src/pages/DevPage.jsx |
Control plane shell |
src/components/ImageUpload.jsx |
Minimal upload surface (original image + actions) |
src/components/CameraCapture.jsx |
Full-frame camera, quality gate, capture review, handoff |
src/components/ImageCropper.jsx |
Shared 1:1 framing cropper (both-axis pan, zoom, quality) |
src/components/AdvancedPanel.jsx |
Model input, metadata, fit modes, batch entry point |
src/components/AdvancedBatchTester.jsx |
Batch inference with the selected configuration |
src/components/ResultWorkspace.jsx |
User results: Big-4 hero grid (read-only gender/age), dual-persona tabs, report card |
src/components/HeroFourGrid.jsx |
Species / Breed / Gender / Age cards (read-only estimates) |
src/components/FarmerAdvisoryCard.jsx |
Milk, feeding, market value, schemes, vaccination, warnings |
src/components/BreedEncyclopedia.jsx |
Native tract, heritage, climate resilience, conservation note |
src/components/VoiceReaderButton.jsx |
speechSynthesis readout in en-IN / ta-IN / hi-IN |
src/components/PhotoGuideModal.jsx |
Three-card "how to snap" guide (side profile, daylight, one animal) |
src/components/EstimatedAttributes.jsx, FarmerAdvisory.jsx, PhotoGuidance.jsx |
Advanced-drawer attribute, advisory and quality/OOD panels |
src/utils/reportCard.js |
Printable "Pashu Aadhaar" farmer report card (no PDF dependency) |
src/i18n/LanguageContext.jsx |
Reactive lang/t/tBreed/tDynamic/renderAdvisory/speakText; persists agri_lang |
src/i18n/dictionaries.js |
70 breed names, trait values, dynamic terms + localized advisory templates |
src/styles/themes.css |
4 themes, native-script typography, mobile/touch rules, split-color switcher |
src/components/ThemeSwitcher.jsx |
4-theme pill persisted under agri_theme |
src/utils/userVisibility.js |
hidden_user_sections ids + isUserSectionVisible() used by the farmer page |
src/components/DevModelPanel.jsx |
Dev model registry plus inspect / embed / model-specific test |
../vet-portal/src/UserVisibilityPanel.jsx |
Vet-controlled user-page visibility and display flags |
../vet-portal/ |
Standalone Veterinary Review Portal (own Vite app, port 5174) |
src/components/TraitComparison.jsx |
Shared look-alike trait table |
src/components/QualityBadge.jsx |
0–100 sharpness / lighting / framing breakdown |
src/components/HerdSessionDrawer.jsx |
Session log, statistics, CSV/JSON/ODT export |
src/components/DevOODPanel.jsx |
OOD laboratory incl. manual folder recalibration |
src/components/DevModelPanel.jsx |
Model registry and spec viewer |
src/components/ThemeToggle.jsx, LanguageToggle.jsx |
4 themes + ThemeSwitcher; EN / Tamil / Hindi (reactive LanguageContext) |
src/hooks/useImageOptimizer.js |
Original vs optimized state, fit config, crop lifecycle |
src/hooks/useSharedConfig.js, useSocket.js |
Server settings and realtime events |
src/utils/imageOptimizer.js |
260×260 zero-crop optimizer |
src/utils/cropAndQuality.js |
Crop math, quality gate, share-card renderer |
src/utils/sessionStore.js |
Herd session persistence and exports |
src/data/breedTraits.js |
44 curated breeds × 8 trait fields |
src/i18n/ |
Translations and the provider |
src/styles.css |
Themeable design system |
7. Deployment notes
- The built bundle (
dist/) is static — serve it from any web server and point it at the API host (same-origin/apior a reverse proxy). - The dev proxy forwards
/apiand/socket.iotohttp://localhost:5000. - For an offline kiosk, open
/?mode=camerato start straight in the camera. - The app never uploads an image the user did not submit, and the herd session never leaves the browser unless the user exports it.
8. Developer model tools (/dev)
The Models tab now covers the full model lifecycle without leaving the UI:
| Tool | What it does | API |
|---|---|---|
| Inspect | Shows architecture, class-map source, preprocessing, normalization mode and embedded OOD | POST /api/models/inspect |
| Embed | Writes class maps/resolution/normalization and optional OOD into the file; defaults to a copy under outputs/export/embedded/ |
POST /api/models/embed |
| Test | Runs only the selected model on a test image, with repeats, raw soft-routing top-5, OOD and latency | POST /api/models/test |
The UI uses the existing dev-card / spec-details-table / toggle styling and
the universal theme tokens — no bespoke styles.
9. User-page visibility
The vet portal’s User Page tab writes two shared-config keys:
{
"display": {
"hidden_user_sections": ["herdSession", "devLink", "footer"],
"show_species_badge": true,
"show_species_confidence": true,
"show_escalation_warning": true,
"show_technical_details": false
}
}
hidden_user_sections accepts the ids exported by
src/utils/userVisibility.js:
photoGuide, specStrip, herdSession, advanced, devLink, escalation,
footer, voice, reportCard, advisory, photoGuidance.
Hidden blocks are removed from the DOM (not merely collapsed) and every
connected user page updates instantly over /ws config_changed. The
language/theme toggles were removed from the farmer view and live in the vet
portal header.
For one-off/kiosk links, append a comma-separated list:
The URL list is merged with the vet-controlled hidden_user_sections.