labeltify 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: labeltify
3
+ Version: 0.4.0
4
+ Summary: Upload frames and optional annotations into LabelTify with a pipeline token.
5
+ Author: CleverTify
6
+ Project-URL: Homepage, https://labeltify.com
7
+ Project-URL: Source, https://github.com/CleverTify/LabelTify/tree/main/clients/python
8
+ Keywords: labeltify,annotation,computer-vision,deepstream,active-learning,dataset
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest>=8; extra == "test"
19
+ Provides-Extra: images
20
+ Requires-Dist: Pillow>=10; extra == "images"
21
+
22
+ # labeltify
23
+
24
+ Upload frames, and optionally their annotations, into [LabelTify](https://labeltify.com) from DeepStream, OpenCV, Ultralytics, or any Python pipeline. The only thing it needs is a pipeline token.
25
+
26
+ ```sh
27
+ pip install labeltify
28
+ ```
29
+
30
+ 1. On the dataset **Upload** page, create a pipeline token.
31
+ 2. Upload:
32
+
33
+ ```python
34
+ from labeltify import LabelTifyClient
35
+
36
+ client = LabelTifyClient("labeltify_…") # or set LABELTIFY_TOKEN and call LabelTifyClient()
37
+
38
+ img = client.upload_image(
39
+ "DATASET_ID",
40
+ jpeg_bytes,
41
+ filename="cam01.jpg",
42
+ camera="cam-01",
43
+ pipeline="ds-prod",
44
+ trigger="low_confidence",
45
+ )
46
+ client.upload_file("DATASET_ID", "frames/cam02.jpg", camera="cam-02")
47
+ ```
48
+
49
+ The token knows its org, so you don't pass one. Timeouts, `429`, and `5xx` responses are retried with exponential backoff (`max_retries=4` by default). Anything else raises `LabelTifyError` with the API's message and `.status`.
50
+
51
+ Annotations are optional. When you pass `labels` (COCO, LabelTify, or YOLO JSON bytes), `work_state` is required: `done`, `in_progress`, `unsure`, or `untouched`. There is no default; the client raises `LabelTifyError` before sending if it is missing. Images with no labels stay untouched.
52
+
53
+ ### Upload a folder with its annotations
54
+
55
+ ```python
56
+ report = client.upload_directory(
57
+ "DATASET_ID",
58
+ "datasets/parking",
59
+ work_state="done",
60
+ )
61
+ print(len(report["items"]), "images stored in", report["requests"], "requests;", report["imported"])
62
+ ```
63
+
64
+ This sends the folder the way dropping it on the dataset's **Upload** page would: images, plus COCO (polygons and boxes), YOLO (`labels/*.txt` with `data.yaml` or `classes.txt`), Pascal VOC, LabelMe, CSV, `metadata.jsonl`, a folder per class, or a LabelTify export. The server reads the annotations; the client only splits the folder into requests (at most 100 images and 80 MB each). A COCO file is cut down to each request's images, so polygons stay polygons.
65
+
66
+ - The dataset must already exist. Create it on the site. Parking polygons need type **Instance segmentation**. Traffic boxes need **Object detection**.
67
+ - `work_state="done"` marks every image that received a shape. Images with no shape stay untouched. With any label file in the folder, `work_state` is required.
68
+ - Create the pipeline token on that dataset's **Upload** page.
69
+ - One credit covers 10,000 uploaded images. A free dataset holds 100 photos.
70
+ - Frame embeddings follow the dataset setting. Turn them off on the dataset before a large upload when you do not want that charge.
71
+ - Use the portable pixel COCO files. The raw Studio shards store boxes as fractions from 0 to 1, and the server divides by width and height again.
72
+ - Two images with the same file name in different folders stop the upload before anything is sent; rename one.
73
+ - Images over 20 MiB, empty files, and files that are neither images nor annotations are listed in `report["files"]` and not sent. A zip is sent as it is when it holds at most 200 files and 20 MB; unzip anything bigger.
74
+ - If a request fails after its retries, the error says how many images were already stored; run the folder again and exact duplicates are reported instead of stored twice.
75
+ - `compute_dhash=True` also skips near-duplicate frames, like the Upload page. It needs Pillow: `pip install "labeltify[images]"`.
76
+
77
+ `upload_bundle(dataset_id, files, work_state=…)` sends one such request from bytes you already have (`files` is a list of `{"filename", "data", "content_type"}`).
78
+
79
+ A deployment behind an access proxy can take extra headers on every request: `LabelTifyClient(token, base_url=…, headers={"CF-Access-Client-Id": …, "CF-Access-Client-Secret": …})`.
80
+
81
+ Send model proposals to the Loop review queue:
82
+
83
+ ```python
84
+ client.propose(
85
+ "DATASET_ID",
86
+ img["id"],
87
+ [{"type": "bbox", "id": "p1", "classId": "car", "box": {"x": 0.1, "y": 0.1, "w": 0.2, "h": 0.2}, "source": "model", "confidence": 0.4}],
88
+ model_ref="deepstream@1",
89
+ uncertainty=0.8,
90
+ )
91
+ ```
92
+
93
+ Boxes are normalized `[0,1]`. Camera, pipeline, and trigger are stored on the image so Loop can filter by them.
94
+
95
+ Local API: `LabelTifyClient("labeltify_…", base_url="http://localhost:8787")`.
96
+
97
+ ## Develop
98
+
99
+ ```sh
100
+ pip install -e "clients/python[test]"
101
+ pytest clients/python/tests
102
+ ```
103
+
104
+ Bump `version` in `pyproject.toml` to publish. Each new version that lands on `main` is published to PyPI by `.github/workflows/publish-python.yml`.
@@ -0,0 +1,83 @@
1
+ # labeltify
2
+
3
+ Upload frames, and optionally their annotations, into [LabelTify](https://labeltify.com) from DeepStream, OpenCV, Ultralytics, or any Python pipeline. The only thing it needs is a pipeline token.
4
+
5
+ ```sh
6
+ pip install labeltify
7
+ ```
8
+
9
+ 1. On the dataset **Upload** page, create a pipeline token.
10
+ 2. Upload:
11
+
12
+ ```python
13
+ from labeltify import LabelTifyClient
14
+
15
+ client = LabelTifyClient("labeltify_…") # or set LABELTIFY_TOKEN and call LabelTifyClient()
16
+
17
+ img = client.upload_image(
18
+ "DATASET_ID",
19
+ jpeg_bytes,
20
+ filename="cam01.jpg",
21
+ camera="cam-01",
22
+ pipeline="ds-prod",
23
+ trigger="low_confidence",
24
+ )
25
+ client.upload_file("DATASET_ID", "frames/cam02.jpg", camera="cam-02")
26
+ ```
27
+
28
+ The token knows its org, so you don't pass one. Timeouts, `429`, and `5xx` responses are retried with exponential backoff (`max_retries=4` by default). Anything else raises `LabelTifyError` with the API's message and `.status`.
29
+
30
+ Annotations are optional. When you pass `labels` (COCO, LabelTify, or YOLO JSON bytes), `work_state` is required: `done`, `in_progress`, `unsure`, or `untouched`. There is no default; the client raises `LabelTifyError` before sending if it is missing. Images with no labels stay untouched.
31
+
32
+ ### Upload a folder with its annotations
33
+
34
+ ```python
35
+ report = client.upload_directory(
36
+ "DATASET_ID",
37
+ "datasets/parking",
38
+ work_state="done",
39
+ )
40
+ print(len(report["items"]), "images stored in", report["requests"], "requests;", report["imported"])
41
+ ```
42
+
43
+ This sends the folder the way dropping it on the dataset's **Upload** page would: images, plus COCO (polygons and boxes), YOLO (`labels/*.txt` with `data.yaml` or `classes.txt`), Pascal VOC, LabelMe, CSV, `metadata.jsonl`, a folder per class, or a LabelTify export. The server reads the annotations; the client only splits the folder into requests (at most 100 images and 80 MB each). A COCO file is cut down to each request's images, so polygons stay polygons.
44
+
45
+ - The dataset must already exist. Create it on the site. Parking polygons need type **Instance segmentation**. Traffic boxes need **Object detection**.
46
+ - `work_state="done"` marks every image that received a shape. Images with no shape stay untouched. With any label file in the folder, `work_state` is required.
47
+ - Create the pipeline token on that dataset's **Upload** page.
48
+ - One credit covers 10,000 uploaded images. A free dataset holds 100 photos.
49
+ - Frame embeddings follow the dataset setting. Turn them off on the dataset before a large upload when you do not want that charge.
50
+ - Use the portable pixel COCO files. The raw Studio shards store boxes as fractions from 0 to 1, and the server divides by width and height again.
51
+ - Two images with the same file name in different folders stop the upload before anything is sent; rename one.
52
+ - Images over 20 MiB, empty files, and files that are neither images nor annotations are listed in `report["files"]` and not sent. A zip is sent as it is when it holds at most 200 files and 20 MB; unzip anything bigger.
53
+ - If a request fails after its retries, the error says how many images were already stored; run the folder again and exact duplicates are reported instead of stored twice.
54
+ - `compute_dhash=True` also skips near-duplicate frames, like the Upload page. It needs Pillow: `pip install "labeltify[images]"`.
55
+
56
+ `upload_bundle(dataset_id, files, work_state=…)` sends one such request from bytes you already have (`files` is a list of `{"filename", "data", "content_type"}`).
57
+
58
+ A deployment behind an access proxy can take extra headers on every request: `LabelTifyClient(token, base_url=…, headers={"CF-Access-Client-Id": …, "CF-Access-Client-Secret": …})`.
59
+
60
+ Send model proposals to the Loop review queue:
61
+
62
+ ```python
63
+ client.propose(
64
+ "DATASET_ID",
65
+ img["id"],
66
+ [{"type": "bbox", "id": "p1", "classId": "car", "box": {"x": 0.1, "y": 0.1, "w": 0.2, "h": 0.2}, "source": "model", "confidence": 0.4}],
67
+ model_ref="deepstream@1",
68
+ uncertainty=0.8,
69
+ )
70
+ ```
71
+
72
+ Boxes are normalized `[0,1]`. Camera, pipeline, and trigger are stored on the image so Loop can filter by them.
73
+
74
+ Local API: `LabelTifyClient("labeltify_…", base_url="http://localhost:8787")`.
75
+
76
+ ## Develop
77
+
78
+ ```sh
79
+ pip install -e "clients/python[test]"
80
+ pytest clients/python/tests
81
+ ```
82
+
83
+ Bump `version` in `pyproject.toml` to publish. Each new version that lands on `main` is published to PyPI by `.github/workflows/publish-python.yml`.
@@ -2,11 +2,23 @@
2
2
 
3
3
  from importlib.metadata import PackageNotFoundError, version
4
4
 
5
- from .client import DEFAULT_BASE_URL, LabelTifyClient, LabelTifyError
5
+ from .client import DEFAULT_BASE_URL, LabelTifyClient, LabelTifyError, UploadFile, UploadReport, slice_coco
6
+ from .dhash import dhash_from_gray9x8, format_dhash, parse_dhash
6
7
 
7
8
  try:
8
9
  __version__ = version("labeltify")
9
10
  except PackageNotFoundError: # running from a checkout
10
11
  __version__ = "0.0.0"
11
12
 
12
- __all__ = ["DEFAULT_BASE_URL", "LabelTifyClient", "LabelTifyError", "__version__"]
13
+ __all__ = [
14
+ "DEFAULT_BASE_URL",
15
+ "LabelTifyClient",
16
+ "LabelTifyError",
17
+ "UploadFile",
18
+ "UploadReport",
19
+ "__version__",
20
+ "dhash_from_gray9x8",
21
+ "format_dhash",
22
+ "parse_dhash",
23
+ "slice_coco",
24
+ ]