File size: 3,023 Bytes
43ad530
 
 
 
 
 
 
 
 
 
 
470f937
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
---
title: Takeoff AI Annotator
emoji: πŸ“
colorFrom: blue
colorTo: indigo
sdk: gradio
sdk_version: 5.9.1
app_file: app.py
pinned: false
---

# Takeoff AI Annotator

A self-improving annotation tool for detecting facade frame (curtain wall panel) units on architectural construction drawings. Every human correction becomes a training signal that feeds back into the YOLO model over time.

Deployed as a Hugging Face Space: `Infin8-AI/Annotation`

## Tabs

### Detect
Upload a construction plan image (PNG/JPG) or a PDF page and click **Detect Panels**. The detected bounding boxes are drawn on the image and a JSON payload is shown for review.

### Review & Edit
Upload a PDF and use the HTML5 canvas to inspect detections page by page:

| Action | Effect | Training signal logged |
|--------|--------|----------------------|
| **Detect This Page** | Run YOLO/OpenCV on the current page | β€” |
| **Approve All** | Mark all boxes green | N Γ— `accepted` events |
| **Reject All** | Mark all boxes red | N Γ— `rejected` events |
| **Approve Selected** | Click a table row, then approve | 1 Γ— `accepted` |
| **Delete Selected** | Remove a single box | 1 Γ— `rejected` |
| **Add Box Manually** | Draw a new ground-truth box | 1 Γ— `created` |
| **Export Events (JSON)** | Download `events.jsonl` with full before/after coords | β€” |
| **Export Dataset (YOLO)** | Download a zip of 640Γ—640 tiles + YOLO labels | β€” |

Box colours: orange = pending, green = approved, red = rejected.

### Send to Backend
POST approved detections to a running tenant-core-api instance using the `from-annotation` endpoint.

Endpoint: `POST /api/v1/tenants/documents/{document_id}/frame-instances/from-annotation`

## Continuous learning loop

```
Gradio Review UI
   ↓  every approve / reject / add / delete
events.jsonl  (exported from the Review tab)
   ↓
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
   ↓
Restart Gradio β€” model version shown in header
```

## Detection engine

The app loads `best.pt` (YOLO11n weights) from the same directory at startup. If not found, it falls back to OpenCV contour detection automatically. The status bar shows which engine is active.

To point to a custom model path:
```bash
FACADE_MODEL_PATH=/path/to/best.pt python app.py
```

## Local development

```bash
cd tools/annotator
pip install -r requirements.txt
python app.py
```

PDF rendering uses PyMuPDF β€” no Poppler required locally (packages.txt installs it on HF Spaces / Linux).

## Deploying to HF Spaces

The Space (`Infin8-AI/Annotation`) expects the root of the repo to contain `app.py`. Use git subtree to push just this subdirectory:

```bash
# First time β€” add the remote
git remote add hf https://YOUR_HF_TOKEN@huggingface.co/spaces/Infin8-AI/Annotation

# Push (maps this subdirectory to the Space root)
git subtree push --prefix=tools/annotator hf main
```