- Add engine_utils for TensorRT compatibility verification, auto-recompilation from .pt models, and YAML auto-updates - Add mortality detection pipeline (mortality.py, test_run_mortality.sh, mortality_config.yaml) - Add multi-execution batch modes (parallel_processes, tensor_batching, hybrid) in batch_runner.py - Add daily test run automation scripts and video processing runners - Add dashboard REST API, live stream endpoints, and web UI templates - Clean up git tracking by ignoring __pycache__, .pyc, and build artifacts
307 lines
7.8 KiB
Markdown
307 lines
7.8 KiB
Markdown
# Chicken Counter API
|
||
|
||
Base URL: `http://<jetson-ip>:8080`
|
||
|
||
## System Status & Live Monitoring
|
||
|
||
### `GET /api/status`
|
||
Returns real-time pipeline activity status, active streaming cameras, latest processed date, and all-time total counts.
|
||
|
||
```json
|
||
{
|
||
"status": "running",
|
||
"is_counting_active": true,
|
||
"active_cameras": ["CC1", "CC2", "CC3", "CC4"],
|
||
"latest_counted_date": "2026-06-18",
|
||
"total_chickens_all_time": 146418,
|
||
"cycle_start_date": "2026-05-22",
|
||
"timestamp": "2026-08-14T08:30:00.000000+00:00"
|
||
}
|
||
```
|
||
|
||
### `GET /`
|
||
Returns the dashboard HTML page.
|
||
|
||
### `GET /api/cameras`
|
||
List cameras currently writing to `/dev/shm`.
|
||
|
||
```json
|
||
{"cameras": ["CC1", "CC2", "CC3"]}
|
||
```
|
||
|
||
### `GET /shm/<camera_id>/stats.json`
|
||
Live stats for the active pipeline.
|
||
|
||
```json
|
||
{
|
||
"frame_index": 5120,
|
||
"inside_box_count": 42,
|
||
"total_entered_count": 1858,
|
||
"track_count": 99,
|
||
"backward_active": false,
|
||
"smoothed_speed": 4.3,
|
||
"count_events": 0,
|
||
"run_date": "2026-06-10"
|
||
}
|
||
```
|
||
|
||
### `GET /shm/<camera_id>/frame.jpg`
|
||
Live JPEG frame from the active pipeline.
|
||
|
||
---
|
||
|
||
## Database
|
||
|
||
All endpoints require the dashboard to be started with `--db <path>`. If no DB exists, endpoints return `[]` or `{}`.
|
||
|
||
### `GET /api/config/cycle_start_date`
|
||
Returns or updates the active Day 0 (`cycle_start_date`).
|
||
|
||
```bash
|
||
# Query active Day 0
|
||
GET /api/config/cycle_start_date
|
||
→ {"cycle_start_date": "2026-05-22"}
|
||
|
||
# Override Day 0 dynamically via query param or POST payload
|
||
GET /api/config/cycle_start_date?set=2026-05-22
|
||
POST /api/config/cycle_start_date {"cycle_start_date": "2026-05-22"}
|
||
→ {"status": "ok", "cycle_start_date": "2026-05-22"}
|
||
```
|
||
|
||
### `GET /api/db/summary`
|
||
Overall totals across all dates and locations.
|
||
|
||
```json
|
||
{
|
||
"days": 12,
|
||
"locations": 2,
|
||
"total_runs": 48,
|
||
"total_chickens": 125000,
|
||
"total_hours": 8.5
|
||
}
|
||
```
|
||
|
||
### `GET /api/db/history`
|
||
Per-date summary, newest first (max 50 rows).
|
||
|
||
```json
|
||
[
|
||
{
|
||
"date": "2026-06-10",
|
||
"location": "kandang-atas",
|
||
"cams": 4,
|
||
"total": 5570,
|
||
"minutes": 40.2
|
||
}
|
||
]
|
||
```
|
||
|
||
### `GET /api/db/date/<date>`
|
||
Detail for a specific date. Format: `YYYY-MM-DD`.
|
||
|
||
```json
|
||
{
|
||
"date": "2026-06-10",
|
||
"total": {"total": 5570, "minutes": 40.2},
|
||
"cameras": [
|
||
{
|
||
"camera_id": "CC1",
|
||
"total_entered": 1500,
|
||
"frames_processed": 24800,
|
||
"elapsed_seconds": 600.5,
|
||
"stopped_reason": "backward",
|
||
"source_video": "kandang_1_camera_1_2026-06-10_120056.mp4",
|
||
"location": "kandang-atas"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### `GET /api/db/camera/<camera_id>`
|
||
History for a specific camera across all dates (max 50 rows).
|
||
|
||
```json
|
||
[
|
||
{
|
||
"date": "2026-06-10",
|
||
"location": "kandang-atas",
|
||
"total_entered": 1500,
|
||
"frames_processed": 24800,
|
||
"elapsed_seconds": 600.5,
|
||
"stopped_reason": "backward"
|
||
}
|
||
]
|
||
```
|
||
|
||
### `GET /api/db/location/<location>`
|
||
Summary and history for a specific location.
|
||
|
||
```json
|
||
{
|
||
"location": "kandang-atas",
|
||
"summary": {"days": 5, "total": 25000, "hours": 3.2},
|
||
"history": [
|
||
{
|
||
"date": "2026-06-10",
|
||
"cameras": "CC1, CC2, CC3, CC4",
|
||
"total": 5570,
|
||
"minutes": 40.2
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Database Schema
|
||
|
||
```sql
|
||
CREATE TABLE batch_runs (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
date TEXT NOT NULL,
|
||
location TEXT NOT NULL,
|
||
camera_id TEXT NOT NULL,
|
||
total_entered INTEGER NOT NULL DEFAULT 0,
|
||
frames_processed INTEGER NOT NULL DEFAULT 0,
|
||
elapsed_seconds REAL NOT NULL DEFAULT 0.0,
|
||
stopped_reason TEXT NOT NULL DEFAULT '',
|
||
source_video TEXT NOT NULL DEFAULT '',
|
||
generated_at TEXT NOT NULL DEFAULT '',
|
||
UNIQUE(date, location, camera_id)
|
||
);
|
||
```
|
||
|
||
Data is inserted automatically by the batch runner when `location` and `db_path` are configured in the batch YAML, or manually via:
|
||
|
||
```bash
|
||
python3 store_results.py output/counts_2026-06-10.json --location kandang-atas --db chicken_counts.db
|
||
```
|
||
|
||
---
|
||
|
||
## Mortality Detection
|
||
|
||
Mortality endpoints require the dashboard to be started with `--mortality-dir <path>`. The path must contain a `mortality_report.json` file generated by `./test_run_mortality.sh`. Multiple directories can be registered with repeated `--mortality-dir` flags.
|
||
|
||
If multiple images are captured in a single day (e.g. morning and afternoon scans), the pipeline processes all images in the input directory, generates marked output JPEGs (`output_<name>.jpg`), and aggregates the daily total carcass count into `total_mortality_count`.
|
||
|
||
### `GET /api/mortality/latest`
|
||
Returns the most recently modified `mortality_report.json` across all registered mortality directories.
|
||
|
||
```json
|
||
{
|
||
"date": "2026-07-09",
|
||
"mode": "similarity_two_pass",
|
||
"model_path": "...",
|
||
"conf_threshold": 0.7,
|
||
"iou_threshold": 0.8,
|
||
"total_images": 2,
|
||
"total_mortality_count": 35,
|
||
"_dir": "/path/to/mortality",
|
||
"results": [
|
||
{
|
||
"input_image": "scan_01.jpg",
|
||
"output_image": "output_scan_01.jpg",
|
||
"count": 19,
|
||
"detections": [
|
||
{
|
||
"id": 1,
|
||
"box": [177, 161, 288, 347],
|
||
"confidence": 0.9597,
|
||
"area": 20646
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"input_image": "scan_02.jpg",
|
||
"output_image": "output_scan_02.jpg",
|
||
"count": 16,
|
||
"detections": [...]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### `GET /api/mortality/history`
|
||
Returns all `mortality_report.json` files from all registered directories, sorted newest first. Each report contains `total_mortality_count` (grand total across all images in that run) and `total_images`.
|
||
|
||
### `GET /api/mortality/date/<YYYY-MM-DD>`
|
||
Returns all mortality scans and total carcass counts recorded on a specific date:
|
||
|
||
```json
|
||
{
|
||
"date": "2026-07-09",
|
||
"total_mortality_count": 35,
|
||
"total_images": 2,
|
||
"reports": [...],
|
||
"results": [...]
|
||
}
|
||
```
|
||
|
||
### `GET /api/mortality/image/<filename>`
|
||
Serves an annotated output JPEG by filename securely. Only files beginning with `output_` are accessible for security.
|
||
|
||
```
|
||
GET /api/mortality/image/output_scan_01.jpg
|
||
→ Content-Type: image/jpeg
|
||
```
|
||
|
||
---
|
||
|
||
## Starting the Dashboard
|
||
|
||
Use the portable launcher script which auto-discovers the mortality directory:
|
||
|
||
```bash
|
||
./start_dashboard.sh
|
||
```
|
||
|
||
Optional environment variables:
|
||
|
||
| Variable | Default | Description |
|
||
| :--- | :--- | :--- |
|
||
| `PORT` | `8080` | Port to listen on |
|
||
| `DB_PATH` | `db/chicken_counts.db` | Path to SQLite database |
|
||
| `MORTALITY_DIRS` | auto-detected | Comma-separated mortality dirs |
|
||
|
||
Or start manually with full control:
|
||
|
||
```bash
|
||
PYTHONPATH=src venv/bin/python dashboard.py \
|
||
--port 8080 \
|
||
--db db/chicken_counts.db \
|
||
--mortality-dir /path/to/mortality \
|
||
--mortality-dir /path/to/another/mortality
|
||
```
|
||
|
||
---
|
||
|
||
## Outbound System Notifications & Webhooks
|
||
|
||
When integrating with external management systems or cloud backends, you can query status or send automated event notifications (e.g. `STARTED`, `COMPLETED`, `MORTALITY_DETECTED`).
|
||
|
||
### 1. Polling Pipeline State
|
||
External systems can poll `GET http://<jetson-ip>:8080/api/status` every 5–10 seconds to detect if counting or mortality runs are currently in progress or finished.
|
||
|
||
### 2. Sending Outbound Webhook from Shell / Batch Scripts
|
||
To notify an external endpoint (e.g. `https://your-server.com/api/notify`) upon run lifecycle events:
|
||
|
||
```bash
|
||
# Example: Notify external server when counting starts
|
||
curl -X POST https://your-server.com/api/notify \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"event": "COUNTING_STARTED", "date": "2026-06-18", "device": "jetson-sukawarna"}'
|
||
|
||
# Example: Notify external server when counting completes with JSON payload
|
||
curl -X POST https://your-server.com/api/notify \
|
||
-H "Content-Type: application/json" \
|
||
-d @/home/asus/.Codes/VIDEOS/cycle7/kandang-atas/2026-06-18/output/counts_2026-06-18.json
|
||
|
||
# Example: Notify external server when mortality scan finishes
|
||
curl -X POST https://your-server.com/api/notify \
|
||
-H "Content-Type: application/json" \
|
||
-d @/home/asus/.Codes/VIDEOS/cycle7/kandang-atas/mortality/mortality_report.json
|
||
```
|
||
|
||
|