# Annotator Tool Gradio annotation tool for facade frame detection. Deployed to HF Spaces as `Infin8-AI/Annotation`. ## Files - `app.py` — Gradio UI (3 tabs: Detect, Review & Edit, Send to Backend) + hidden machine API - `detection.py` — YOLO inference wrapper (tiled for full sheets) with OpenCV fallback - `requirements.txt` — Python deps for local dev and HF Spaces - `packages.txt` — System deps (poppler-utils) for HF Spaces - `best.pt` — YOLO11n weights (not in git — download from HF Hub or train locally) ## Detection Full drawing sheets are detected with **tiled inference** (`detect_tiled`: 640×640 windows, stride 480, cross-tile NMS IoU 0.5) at **200 DPI** — whole-sheet single-pass inference finds nothing because mullions shrink below detectable size. `detect_rectangles()` tiles automatically for images larger than one tile. Constants live in `detection.py` (`TILE_SIZE`, `TILE_STRIDE`, `TILE_MERGE_IOU`, `DETECTION_DPI`) and must match the training dataset builder. Model resolution order: `FACADE_MODEL_PATH` (local file) → `FACADE_MODEL_REPO` (HF Hub, e.g. `Infin8-AI/estimat8-vm-v1`, pin with `FACADE_MODEL_REVISION`, auth with `HF_TOKEN`) → `best.pt` next to `detection.py`. ## Machine API (for backends) Hidden endpoints exposed via the Gradio API, called with `gradio_client`: ```python from gradio_client import Client, handle_file client = Client("Infin8-AI/Annotation", hf_token=...) # or http://localhost:7860 result = client.predict(handle_file("page.png"), 0.25, api_name="/detect_image") # -> {"width_px", "height_px", "model_version", "boxes": [{x1,y1,x2,y2,conf}]} ``` - `/detect_image (image_file, conf)` — primary: caller renders the PDF page and uploads one PNG. - `/detect_page (pdf_file, page_number, dpi, conf)` — testing/fallback; avoid for big PDFs (gradio_client re-uploads the file every call). ## Label JSON import/export (Review & Edit tab) `↓ Labels` exports every annotated page as canonical per-page label JSON (coordinates in **PDF points**, provenance + rejected boxes preserved), zipped. The Import field loads such JSONs back (audited → approved, machine bootstrap → pending, rejected → rejected). This is the audit interchange format consumed by `scripts/annotation/` at the repo root. ## Deploying to HF Spaces HF Spaces builds from `hf/main`. The Space expects files at the repo root, so use git subtree: ```bash # Add remote once git remote add hf https://YOUR_HF_TOKEN@huggingface.co/spaces/Infin8-AI/Annotation # Push this subdirectory as the Space root git subtree push --prefix=tools/annotator hf main ``` ## Training loop See `scripts/build_dataset_from_events.py` and `scripts/train_facade_detector.py` at the repo root. ```bash # From repo root — after exporting events.jsonl from the Gradio tool python scripts/build_dataset_from_events.py --events events.jsonl --pdf source.pdf python scripts/train_facade_detector.py --version v2 cp models/yolo_facade_v2/best.pt tools/annotator/best.pt ```