Box21 api

Interact with your Box21
import os
from dotenv import load_dotenv
load_dotenv()
API_USERNAME = os.environ.get('EMAIL')
API_PASSWORD = os.environ.get('PASSWORD')
API_PROJECT_ID = os.environ.get('PROJECT_ID')

source

Box21Api

 Box21Api (email:str, password:str, host:str, port:int, project_id:int)

Box21 Api class

box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID) # type: ignore

Retrieve assets


source

Box21Api.get_asset

 Box21Api.get_asset (asset_id:int)

source

Box21Api.get_assets

 Box21Api.get_assets (offset:int=0, limit:Optional[int]=None)
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID) # type: ignore
assets = box21_api.get_assets()
print('Number of assets retrieved', len(assets))
first_asset = assets[0]
print(first_asset)
1
Number of assets retrieved 3
Asset({"testing": true})
first_asset = box21_api.get_asset(first_asset.id)
print(first_asset)
Asset({"testing": true})

source

Box21Api.download_asset

 Box21Api.download_asset (asset_id:int)
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
assets = box21_api.get_assets(limit=10)
image = box21_api.download_asset(assets[0].id)
1
image

Filter assets


source

Box21Api.get_assets_not_containing_meta

 Box21Api.get_assets_not_containing_meta (meta:List[str],
                                          in_validation_set:bool=False,
                                          validated:Optional[bool]=None)

source

Box21Api.get_assets_containing_meta

 Box21Api.get_assets_containing_meta (meta:List[str],
                                      in_validation_set:bool=False,
                                      validated:Optional[bool]=None)

source

Box21Api.get_assets_with_filters

 Box21Api.get_assets_with_filters (filters:List[Dict[str,str]])
print(assets[0].meta)

assets = box21_api.get_assets_containing_meta(['testing'])
print(len(assets), assets[0].meta)

assets = box21_api.get_assets_not_containing_meta(['testing'])
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


source

Box21Api.get_annotations

 Box21Api.get_annotations (asset_id:int)
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
annotations = box21_api.get_annotations(assets[0].id)
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()

    filters : List[dict[str, Union[str, int]]] = []

    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 = []
    
    url = '/api/asset/annotations'
    payload = {
        "asset_id": asset_id,
    }
    response = self.post(url, payload)

    annotations = []

    for annotation_json in response.json():
        asset_id = annotation_json['asset_id']
        annotation_id = annotation_json['id']
        certainty = annotation_json['certainty']
        label_id = annotation_json['label_id']
        label_name = annotation_json['relationships']['label']['name']
        project_id = annotation_json['project_id']
        validated = annotation_json['validated']
        coords = json.loads(annotation_json['coords'])

        if annotation_json['type'] == 1:
            x, y, w, h = coords
            annotations.append(
                Box21BoundingBox(asset_id, annotation_id, certainty, label_id, project_id, validated, x, y, w, h))
        else:
            x, y = coords
            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


source

Box21Api.delete_asset_meta_key

 Box21Api.delete_asset_meta_key (asset_id:int, key:str)

source

Box21Api.update_asset_meta

 Box21Api.update_asset_meta (asset_id:int, key:str, value:str)
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
updated_asset = box21_api.update_asset_meta(assets[0].id, 'some_new_key', 'some new value')

print(json.loads(updated_asset.meta))
{'filename': '6d0a5af1-720e-47ee-86e5-bc0c15fe2015_chitals.png', 'import': 'true', 'description': 'Chital', 'some_new_key': 'some new value'}
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
updated_asset = box21_api.delete_asset_meta_key(assets[0].id, 'some_new_key')

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


source

Box21Api.get_labels

 Box21Api.get_labels ()
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
labels = box21_api.get_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:


source

Box21Api.get_label_annotations

 Box21Api.get_label_annotations (label:box21_api.label.Box21Label)
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
annotations = box21_api.get_label_annotations(labels[0])
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:
    url = '/api/re-label'
    annotation_ids : List[int] = [annotation.id for annotation in annotations]
    payload : Dict[str, Any] = {
        'annotation_ids': json.dumps(annotation_ids),
        'label': label_name
    }
    self.post(url, payload)
@patch
def delete_label(self:Box21Api, label_id: str) -> None:
    url = '/api/label/delete'
    payload : Dict[str, Any] = {
        'label_id': label_id,
        'project_id': box21_api.project_id
    }
    self.post(url, payload)

Adding and deleting assets


source

Box21Api.delete_assets

 Box21Api.delete_assets (asset_ids:List[int])

source

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)
image.save('example.png')
file_path = Path('example.png')
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
asset = box21_api.add_asset(file_path, {'testing': True})
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
box21_api.delete_assets([asset.id])
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

bounding_box = BoundingBox(
    certainty=0.9,
    label_name='Testing adding label',
    x= 0.0,
    y= 0.3,
    width= 0.1,
    height= 0.1
)

image.save('example.png')
file_path = Path('example.png')
box21_api = Box21Api(API_USERNAME, API_PASSWORD, 'https://box21.ai', 443, API_PROJECT_ID)
asset = box21_api.add_asset(file_path, {'testing': True}, annotations=[bounding_box])
print(asset)
Asset({"testing": true})
asset_annotations = box21_api.get_annotations(asset.id)
asset_annotations
[BoundingBox(130, (0.0, 0.3, 0.1, 0.1))]
print('Number of assets before delete', len(box21_api.get_assets()))
box21_api.delete_assets([asset.id])
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


source

Box21Api.add_annotation

 Box21Api.add_annotation (annotation:box21_api.annotation.Annotation,
                          asset:box21_api.asset.Asset)

source

Box21Api.detete_annotations

 Box21Api.detete_annotations
                              (annotations:List[box21_api.annotation.Box21
                              Annotation])

Updating jobs


source

Box21Api.update_job

 Box21Api.update_job (job_id:int, processing:Optional[bool]=None,
                      processed:Optional[bool]=None,
                      progress:Optional[int]=None)

Suggestions


source

Box21Api.delete_suggestions

 Box21Api.delete_suggestions (asset_id:int)