import os
from dotenv import load_dotenv
Box21 api
Interact with your Box21
load_dotenv()= os.environ.get('EMAIL')
API_USERNAME = os.environ.get('PASSWORD')
API_PASSWORD = os.environ.get('PROJECT_ID') API_PROJECT_ID
Box21Api
Box21Api (email:str, password:str, host:str, port:int, project_id:int)
Box21 Api class
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID) # type: ignore box21_api
Retrieve assets
Box21Api.get_asset
Box21Api.get_asset (asset_id:int)
Box21Api.get_assets
Box21Api.get_assets (offset:int=0, limit:Optional[int]=None)
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID) # type: ignore
box21_api = box21_api.get_assets()
assets print('Number of assets retrieved', len(assets))
= assets[0]
first_asset print(first_asset)
1
Number of assets retrieved 3
Asset({"testing": true})
= box21_api.get_asset(first_asset.id)
first_asset print(first_asset)
Asset({"testing": true})
Box21Api.download_asset
Box21Api.download_asset (asset_id:int)
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.get_assets(limit=10)
assets = box21_api.download_asset(assets[0].id) image
1
image
Filter assets
Box21Api.get_assets_not_containing_meta
Box21Api.get_assets_not_containing_meta (meta:List[str], in_validation_set:bool=False, validated:Optional[bool]=None)
Box21Api.get_assets_containing_meta
Box21Api.get_assets_containing_meta (meta:List[str], in_validation_set:bool=False, validated:Optional[bool]=None)
Box21Api.get_assets_with_filters
Box21Api.get_assets_with_filters (filters:List[Dict[str,str]])
print(assets[0].meta)
= box21_api.get_assets_containing_meta(['testing'])
assets print(len(assets), assets[0].meta)
= box21_api.get_assets_not_containing_meta(['testing'])
assets print(len(assets), assets[0].meta)
{"testing": true}
2 {"testing": true}
1 {"filename": "6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png", "import": "true", "description": "Chital"}
Filter annotations
Box21Api.get_annotations
Box21Api.get_annotations (asset_id:int)
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.get_annotations(assets[0].id)
annotations print(len(annotations))
print(annotations[0].project_id)
2
1
@patch
def get_annotations_with_label_name(self:Box21Api, label_name :str, validated : bool, asset_validated: bool, meta_contains: str, unclear: bool = False) -> List[Box21Annotation]:
self.token = self.get_token()
dict[str, Union[str, int]]] = []
filters : List[
= [
filters
{"type": 27,
"value": label_name
},
{"type": 17, "value": "Yes" if validated else "No"
},
{"type": 9, "value": "Yes" if asset_validated else "No"
},
{"type": 11, "value": "Yes" if unclear else "No"
}
]
if meta_contains:
filters.append({"type": 7,
"value": meta_contains
})
= []
annotations
= '/api/asset/annotations'
url = {
payload "asset_id": asset_id,
}= self.post(url, payload)
response
= []
annotations
for annotation_json in response.json():
= annotation_json['asset_id']
asset_id = annotation_json['id']
annotation_id = annotation_json['certainty']
certainty = annotation_json['label_id']
label_id = annotation_json['relationships']['label']['name']
label_name = annotation_json['project_id']
project_id = annotation_json['validated']
validated = json.loads(annotation_json['coords'])
coords
if annotation_json['type'] == 1:
= coords
x, y, w, h
annotations.append(
Box21BoundingBox(asset_id, annotation_id, certainty, label_id, project_id, validated, x, y, w, h))else:
= coords
x, y
annotations.append(
Box21Keypoint(asset_id, annotation_id, certainty, label_id, project_id, validated, x, y))
return annotations
Update asset meta
An asset has meta which is a list of key value pairs. You can add, update and delete them via the api
Box21Api.delete_asset_meta_key
Box21Api.delete_asset_meta_key (asset_id:int, key:str)
Box21Api.update_asset_meta
Box21Api.update_asset_meta (asset_id:int, key:str, value:str)
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.update_asset_meta(assets[0].id, 'some_new_key', 'some new value')
updated_asset
print(json.loads(updated_asset.meta))
{'filename': '6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png', 'import': 'true', 'description': 'Chital', 'some_new_key': 'some new value'}
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.delete_asset_meta_key(assets[0].id, 'some_new_key')
updated_asset
print(json.loads(updated_asset.meta))
{'filename': '6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png', 'import': 'true', 'description': 'Chital'}
Get labels
Get all labels for a specific project
Box21Api.get_labels
Box21Api.get_labels ()
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.get_labels()
labels print(labels[0])
print(labels[0].annotation_stats[0])
print(labels[0].annotation_stats[1])
Label(('Bounding box', 'Chital', 1))
AnnotationStat(1, 400065, 1, 2, 0)
AnnotationStat(2, 400066, 1, 0, 0)
Get all annotations for a label:
Box21Api.get_label_annotations
Box21Api.get_label_annotations (label:box21_api.label.Box21Label)
= Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.get_label_annotations(labels[0])
annotations print(len(annotations))
for annotation in annotations:
print(annotation)
2
BoundingBox(1, (0.525, 0.3911, 0.3484, 0.3532))
BoundingBox(1, (0.1641, 0.5291, 0.2766, 0.3381))
from typing import Any, Dict, List
import json
@patch
def re_label(self:Box21Api, annotations: List[Box21Annotation], label_name: str) -> None:
= '/api/re-label'
url int] = [annotation.id for annotation in annotations]
annotation_ids : List[str, Any] = {
payload : Dict['annotation_ids': json.dumps(annotation_ids),
'label': label_name
}self.post(url, payload)
@patch
def delete_label(self:Box21Api, label_id: str) -> None:
= '/api/label/delete'
url str, Any] = {
payload : Dict['label_id': label_id,
'project_id': box21_api.project_id
}self.post(url, payload)
Adding and deleting assets
Box21Api.delete_assets
Box21Api.delete_assets (asset_ids:List[int])
Box21Api.add_asset
Box21Api.add_asset (file_path:pathlib.Path, meta:Dict[str,Any], annotations:List[box21_api.annotation.Annotation]=[], validated:bool=False, in_validation_set:bool=False, no_duplicate_filename:bool=False)
'example.png')
image.save(= Path('example.png')
file_path = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.add_asset(file_path, {'testing': True}) asset
print('Number of assets before delete', len(box21_api.get_assets()))
1
[{"deleted":null,"filename":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","id":234898,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","id":234899,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"bce7d4f9-9f36-4c50-b546-c176b0f54d70_example.png","id":235889,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"bce7d4f9-9f36-4c50-b546-c176b0f54d70_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","id":1,"in_validation_set":false,"liked":false,"meta":"{\"filename\": \"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png\", \"import\": \"true\", \"description\": \"Chital\"}","original_category":"","path":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","project_id":1,"relationships":{"annotations":[{"asset_id":1,"certainty":"1","coords":"[0.525, 0.3911, 0.3484, 0.3532]","format":"normalized_xywh","id":11,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true},{"asset_id":1,"certainty":"1","coords":"[0.1641, 0.5291, 0.2766, 0.3381]","format":"normalized_xywh","id":12,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true}]},"unclear":false,"validated":"true"}]
Number of assets before delete 4
id])
box21_api.delete_assets([asset.print('Number of assets after delete', len(box21_api.get_assets()))
1
[{"deleted":null,"filename":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","id":234898,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","id":234899,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","id":1,"in_validation_set":false,"liked":false,"meta":"{\"filename\": \"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png\", \"import\": \"true\", \"description\": \"Chital\"}","original_category":"","path":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","project_id":1,"relationships":{"annotations":[{"asset_id":1,"certainty":"1","coords":"[0.525, 0.3911, 0.3484, 0.3532]","format":"normalized_xywh","id":11,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true},{"asset_id":1,"certainty":"1","coords":"[0.1641, 0.5291, 0.2766, 0.3381]","format":"normalized_xywh","id":12,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true}]},"unclear":false,"validated":"true"}]
Number of assets after delete 3
Example adding a bounding box
= BoundingBox(
bounding_box =0.9,
certainty='Testing adding label',
label_name= 0.0,
x= 0.3,
y= 0.1,
width= 0.1
height
)
'example.png')
image.save(= Path('example.png')
file_path = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
box21_api = box21_api.add_asset(file_path, {'testing': True}, annotations=[bounding_box])
asset print(asset)
Asset({"testing": true})
= box21_api.get_annotations(asset.id)
asset_annotations asset_annotations
[BoundingBox(130, (0.0, 0.3, 0.1, 0.1))]
print('Number of assets before delete', len(box21_api.get_assets()))
id])
box21_api.delete_assets([asset.print('Number of assets after delete', len(box21_api.get_assets()))
1
[{"deleted":null,"filename":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","id":234898,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","id":234899,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","id":1,"in_validation_set":false,"liked":false,"meta":"{\"filename\": \"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png\", \"import\": \"true\", \"description\": \"Chital\"}","original_category":"","path":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","project_id":1,"relationships":{"annotations":[{"asset_id":1,"certainty":"1","coords":"[0.525, 0.3911, 0.3484, 0.3532]","format":"normalized_xywh","id":11,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true},{"asset_id":1,"certainty":"1","coords":"[0.1641, 0.5291, 0.2766, 0.3381]","format":"normalized_xywh","id":12,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true}]},"unclear":false,"validated":"true"},{"deleted":null,"filename":"1b606e85-12fb-475b-b4f1-0ab41d375d00_example.png","id":235890,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"1b606e85-12fb-475b-b4f1-0ab41d375d00_example.png","project_id":1,"relationships":{"annotations":[{"asset_id":235890,"certainty":"0.9","coords":"[0.0, 0.3, 0.1, 0.1]","format":"normalized_xywh","id":726109,"label_id":130,"project_id":1,"relationships":{},"type":1,"validated":false}]},"unclear":null,"validated":"false"}]
Number of assets before delete 4
1
[{"deleted":null,"filename":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","id":234898,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"8aa70857-ce54-4a02-a1ea-ed2a60d13340_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","id":234899,"in_validation_set":false,"liked":false,"meta":"{\"testing\": true}","original_category":"","path":"6e309b62-43fa-4185-a55f-6e01174ee57d_example.png","project_id":1,"relationships":{"annotations":[]},"unclear":null,"validated":"false"},{"deleted":null,"filename":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","id":1,"in_validation_set":false,"liked":false,"meta":"{\"filename\": \"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png\", \"import\": \"true\", \"description\": \"Chital\"}","original_category":"","path":"6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png","project_id":1,"relationships":{"annotations":[{"asset_id":1,"certainty":"1","coords":"[0.525, 0.3911, 0.3484, 0.3532]","format":"normalized_xywh","id":11,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true},{"asset_id":1,"certainty":"1","coords":"[0.1641, 0.5291, 0.2766, 0.3381]","format":"normalized_xywh","id":12,"label_id":1,"project_id":1,"relationships":{},"type":1,"validated":true}]},"unclear":false,"validated":"true"}]
Number of assets after delete 3
Adding and deleting annotations
Box21Api.add_annotation
Box21Api.add_annotation (annotation:box21_api.annotation.Annotation, asset:box21_api.asset.Asset)
Box21Api.detete_annotations
Box21Api.detete_annotations (annotations:List[box21_api.annotation.Box21 Annotation])
Updating jobs
Box21Api.update_job
Box21Api.update_job (job_id:int, processing:Optional[bool]=None, processed:Optional[bool]=None, progress:Optional[int]=None)
Suggestions
Box21Api.delete_suggestions
Box21Api.delete_suggestions (asset_id:int)