- README "How it works" step 3: "not by any AI/ML step" -> "not by any model inference step", per AGENTS.md's terminology rule (no generic "AI" when describing system capability). - AppConfig gets a docstring spelling out that markers must be ordered smallest-bucket-boundary first, since determine_size_bucket trusts this order and a misordered config would silently produce a wrong (tax-relevant) size bucket. AppConfig.load() also now validates that marker area is non-decreasing across the list and raises ValueError if not, since this project's nested physical markers get larger as bucket size increases.
124 lines
5.2 KiB
Markdown
124 lines
5.2 KiB
Markdown
# Bookmark
|
|
|
|
A camera-driven book intake and checkout inventory system, built for
|
|
[Books in Hand](https://git.opensourcesolarpunk.com/books-in-hand), a
|
|
nonprofit that keeps books out of landfills and in people's hands.
|
|
|
|
Bookmark replaces manual book logging with a guided, camera-based workflow:
|
|
a volunteer places a book on a marked platform, the system photographs the
|
|
front and back, sorts it into a size category for tax/reporting purposes,
|
|
and later backfills the catalogue with title, author, and ISBN — all
|
|
running on local hardware, no cloud dependency.
|
|
|
|
This project is fully open source and is being built and donated as
|
|
volunteer/client work — it isn't part of any commercial product line.
|
|
|
|
## Status
|
|
|
|
**Phase 1 (intake station) is built, unit-tested, and ready for real-hardware validation.** Phase 2 (batch OCR/ISBN backfill) and Phase 3 (checkout station) are planned for later.
|
|
|
|
| Phase | What it does | Status |
|
|
|---|---|---|
|
|
| 1 — Intake station | Camera capture, guided front/back flow, deterministic size bucketing, CSV catalogue | Built, unit-tested — pending real-hardware validation |
|
|
| 2 — Batch OCR/ISBN backfill | Barcode decode + local vision-LLM fallback to fill in title/author/ISBN | Planned |
|
|
| 3 — Checkout station | Track books leaving inventory, reusing the intake identification pipeline | Planned |
|
|
|
|
## How it works (Phase 1)
|
|
|
|
1. A downward-facing webcam looks at a fixed platform with printed
|
|
nested size-boundary markers (small / medium / large).
|
|
2. A volunteer centers the book; capture fires automatically or on a
|
|
button press (configurable).
|
|
3. The system photographs the front, determines size — **deterministically**,
|
|
by checking which physical markers are covered, not by any model
|
|
inference step — then prompts the volunteer to flip the book and
|
|
photographs the back.
|
|
4. Every book gets a row in a CSV catalogue: images, size bucket, and a
|
|
status that later pipeline stages (OCR backfill, checkout) update.
|
|
|
|
Full design rationale lives in `AGENTS.md` (also readable as `CLAUDE.md` —
|
|
same file, symlinked for compatibility with different AI coding tools).
|
|
|
|
## Why this matters for a nonprofit
|
|
|
|
- **No cloud costs, no vendor lock-in.** Everything runs on donated
|
|
hardware; no per-book or per-scan fees.
|
|
- **Deterministic where it counts.** Size-bucket counts feed Books in
|
|
Hand's year-end tax and 501(c)(3) reporting — that number is computed
|
|
from physical measurements, not inferred by a model, so it can't drift
|
|
or hallucinate.
|
|
- **Volunteer-friendly.** The intake flow is designed to be usable by
|
|
volunteers with no technical background — guided steps, big buttons,
|
|
no login required.
|
|
|
|
## Development
|
|
|
|
Requires Python 3.11+.
|
|
|
|
### Setup
|
|
|
|
1. Create and activate a virtual environment:
|
|
```bash
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install -e ".[dev]"
|
|
```
|
|
|
|
2. Mount the USB webcam over the capture platform. See the design spec
|
|
(`circuitforge-plans/books-in-hand/superpowers/specs/2026-07-13-inventory-system-design.md`)
|
|
for physical setup details: nested size-boundary markers, guide box.
|
|
|
|
3. Run calibration once per physical install, with the platform empty:
|
|
```bash
|
|
.venv/bin/python calibrate.py <camera_device_index> reference.jpg
|
|
```
|
|
This captures a reference image of the empty platform for marker detection.
|
|
|
|
4. Copy `config.example.json` to `config.json` and fill in:
|
|
- `markers`: pixel coordinates (from the reference image)
|
|
- `guide_box`: capture region boundaries
|
|
- `trigger_strategy`: one of `manual`, `motion_stop`, or `stable_centered`
|
|
|
|
5. Run the backend:
|
|
```bash
|
|
.venv/bin/python run.py config.json
|
|
```
|
|
|
|
6. Open `http://<machine-ip>:8000` in a kiosk-mode browser on the station's monitor.
|
|
|
|
### Running tests
|
|
|
|
```bash
|
|
.venv/bin/pytest -v
|
|
```
|
|
|
|
All tests run without requiring real camera hardware — they use synthetic
|
|
NumPy frames and mocked `cv2.VideoCapture`.
|
|
|
|
### End-to-end smoke test (manual, requires real hardware)
|
|
|
|
This checklist is for whoever installs this system on real hardware. It
|
|
verifies that the intake workflow functions end-to-end.
|
|
|
|
1. Boot the station per Setup above with `trigger_strategy: "manual"`.
|
|
2. Place a book on the platform, click "Capture" — confirm the status
|
|
advances to "Front captured — flip it over" and a new row appears in
|
|
`catalogue.csv` with a `size_bucket` value and populated
|
|
`front_wide_path` / `front_cropped_path` columns pointing at real files
|
|
under `captures/<book_id>/`.
|
|
3. Flip the book, click "Capture" again — confirm status advances to
|
|
"Book complete!" and the same row now has `back_wide_path` /
|
|
`back_cropped_path` populated.
|
|
4. Click "Next Book" — confirm status returns to "Waiting for book..." and
|
|
the next capture gets a different `book_id`.
|
|
5. Repeat with a small book and a large book — confirm `size_bucket`
|
|
differs correctly between them, matching which physical markers each
|
|
book actually covers.
|
|
6. Switch `trigger_strategy` to `motion_stop` in `config.json`, restart,
|
|
and confirm placing a book and holding it still triggers capture
|
|
without pressing the button.
|
|
7. Switch to `stable_centered` and repeat, confirming capture fires once
|
|
the book is centered and steady in the guide box.
|
|
|
|
## License
|
|
|
|
MIT — see `LICENSE`.
|