Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions docs/source/userguide/SDK_Functions_sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Topic,Function,MM(GenAI/LLM),CSV,JSON,JSONL,INTEGRATION
Projects,create_project,No,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,search_projects,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,clone_project,No,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,rename_project,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_project,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_project_by_id,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_project_status,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_project_metadata,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_images_to_project,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,attach_items_from_integrated_storage,Yes,Not Relevant,Not Relevant,Not Relevant,"AWS, GCP, Azure"
,upload_image_to_project,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_images_from_folder_to_project,Not Relevant,Not Relevant,Not Relevant,Not Relevant,AWS
,upload_video_to_project,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_videos_from_folder_to_project,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_project_custom_field,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,add_contributors_to_project,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_project_settings,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_project_default_image_quality_in_editor,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_project_steps,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_project_steps,Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_component_config,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Folders,search_folders(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_folder_status(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,assign_folder(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,unassign_folder(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_folder_by_id(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_folder_metadata(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,create_folder(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_folders(,Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Items,query(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_item_by_id(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,list_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,search_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,attach_items(),Not Relevant,Not Relevant,No,No,Not Relevant
,item_context(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,copy_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,move_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,assign_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,unassign_items(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_item_metadata(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_approval_statuses(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Annotations,upload_annotations(),Yes,Yes,Yes,Yes,Not Relevant
,get_annotations(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,download_annotations(),Yes,No,Yes,No,Not Relevant
,get_annotations_per_frame(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_annotation_statuses(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_annotations(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_annotations_from_folder_to_project(),No,No,Yes,No,AWS
"Annotation
Classes",create_annotation_class(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,create_annotation_classes_from_classes_json(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,AWS
,search_annotation_classes(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,download_annotation_classes_json(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_annotation_class(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Exports,prepare_export(),Yes,Yes,Yes,No,Not Relevant
,download_export(),Yes,Yes,Yes,Yes,AWS
,get_exports(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
"Custom
Metadata
",create_custom_fields(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_custom_fields(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_custom_fields(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_custom_values(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,delete_custom_values(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Subsets,get_subsets(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,add_items_to_subset(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Images,download_image(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,download_image_annotations(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_image_annotations(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,pin_image(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,upload_priority_scores(),Yes,Not Relevant,Not Relevant,Not Relevant,Not Relevant
Team,get_team_metadata(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_integrations(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,invite_contributors_to_team(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,search_team_contributors(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,get_user_metadata(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,set_user_custom_field(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,list_users(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
"Converting
Annotations",import_annotation(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,export_annotation(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,convert_project_type(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
"Working w/
Annotations",validate_annotations(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
,aggregate_annotations_as_df(),Not Relevant,Not Relevant,Not Relevant,Not Relevant,Not Relevant
171 changes: 170 additions & 1 deletion docs/source/userguide/utilities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ Utilities
=========


Compatibility with multimodal projects
--------------------------------------

.. csv-table:: Support for CSV, JSON, JSONL formats
:file: SDK_Functions_sheet.csv
:widths: 20, 2, 15, 10, 10, 10, 25
:header-rows: 1

Converting annotation format
----------------------------

Expand Down Expand Up @@ -106,10 +114,171 @@ You can find more information annotation format conversion :ref:`here <ref_conve
)


Converting CSV and JSONL Formats for Annotation Management in SuperAnnotate
---------------------------------------------------------------------------
SuperAnnotate primarily uses the **JSONL format** for annotation import/export. However,
many external tools use **CSV**, requiring users to convert between these formats for seamless data management.

This guide provides:

- CSV to JSONL conversion** for annotation uploads.
- Fetching annotations from SuperAnnotate** and converting them into JSONL/CSV.
- Correct metadata mappings** to ensure consistency in the annotation format.


SuperAnnotate JSONL Schema Overview
===================================
Before diving into conversions, here's a breakdown of SuperAnnotate's JSONL schema:

.. code-block:: json

{
"metadata": {
"name": "sample_image.jpg",
"item_category": { "value": "category1" },
"folder_name": "dataset_folder"
},
"data": {
"attribute1": { "value": "label1" },
"attribute2": { "value": "label2" }
}
}

Key Fields:
- **metadata.name** → The item's name (e.g., image file name).
- **metadata.item_category** → Optional category assigned to the item.
- **metadata.folder_name** → The dataset folder name (previously `_folder` in CSV).
- **data** → Stores key-value pairs for attributes.


Converting CSV to JSONL and Uploading Annotations
=================================================

Steps to Convert CSV to JSONL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. Read the **CSV file** and extract annotation fields.
2. Map metadata (`_item_name`, `_item_category`, `_folder`) to **SuperAnnotate's JSONL format**.
3. Convert remaining fields into JSONL **data attributes**.
4. Upload the JSONL file to **SuperAnnotate using SAClient**.

Example Python Script:

.. code-block:: python

import csv
import json
from pathlib import Path
from superannotate import SAClient

def csv_to_jsonl(csv_path, jsonl_path):
"""Convert CSV annotations to JSONL format with correct mappings."""
with open(csv_path, newline='', encoding='utf-8') as csv_file, open(jsonl_path, 'w', encoding='utf-8') as jsonl_file:
reader = csv.DictReader(csv_file)

for row in reader:
jsonl_entry = {
"metadata": {
"name": row["_item_name"],
"item_category": {"value": row["_item_category"]},
"folder_name": row["_folder"]
},
"data": {}
}

for key, value in row.items():
if key not in ["_item_name", "_item_category", "_folder"]:
jsonl_entry["data"][key] = {"value": json.loads(value)}

json.dump(jsonl_entry, jsonl_file)
jsonl_file.write('\n')

# Convert CSV to JSONL
csv_to_jsonl("annotations.csv", "annotations.jsonl")

# Upload to SuperAnnotate
sa = SAClient()
annotations = [json.loads(line) for line in Path("annotations.jsonl").open("r", encoding="utf-8")]

response = sa.upload_annotations(
project="project1/folder1",
annotations=annotations,
keep_status=True,
data_spec="multimodal"
)


Fetching Annotations and Converting to JSONL/CSV
================================================

Steps to Retrieve and Convert Annotations:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. Fetch **annotations from SuperAnnotate** using `sa.get_annotations()`.
2. Convert the **annotation list into JSONL format**.
3. Convert the **JSONL data into CSV** for external use.

Python Script to Convert Annotations to JSONL:

.. code-block:: python

def convert_annotations_to_jsonl(annotations, jsonl_path):
"""Convert SuperAnnotate annotations list to JSONL format."""
with open(jsonl_path, 'w', encoding='utf-8') as jsonl_file:
for annotation in annotations:
json.dump(annotation, jsonl_file)
jsonl_file.write('\n')

# Fetch annotations from SuperAnnotate
sa = SAClient()
annotations = sa.get_annotations("project", data_spec="multimodal")

# Convert to JSONL
convert_annotations_to_jsonl(annotations, "fetched_annotations.jsonl")

Python Script to Convert JSONL to CSV:

.. code-block:: python

def convert_jsonl_to_csv(jsonl_path, csv_path):
"""Convert JSONL file to CSV format with correct mappings."""
with open(jsonl_path, 'r', encoding='utf-8') as jsonl_file, open(csv_path, 'w', newline='', encoding='utf-8') as csv_file:
data = [json.loads(line) for line in jsonl_file]

if not data:
return

# Extract field names from the first entry
fieldnames = ["_item_name", "_item_category", "_folder"] + list(data[0]["data"].keys())

writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()

for entry in data:
row = {
"_item_name": entry["metadata"]["name"],
"_item_category": entry["metadata"].get("item_category", {}).get("value"),
"_folder": entry["metadata"].get("folder_name", None)
}

for key in entry["data"]:
value = entry["data"][key]
row[key] = value["value"] if isinstance(value, dict) else value

writer.writerow(row)

# Convert JSONL to CSV
convert_jsonl_to_csv("fetched_annotations.jsonl", "converted_annotations.csv")

Conclusion
==========
This guide provides a **seamless way to convert** annotations between CSV and JSONL formats while maintaining
compatibility with **SuperAnnotate's platform**.
By following these steps, users can efficiently **import, export, and manage annotation data** in their projects.

pandas DataFrame out of project annotations and annotation instance filtering
-----------------------------------------------------------------------------


To create a `pandas DataFrame <https://pandas.pydata.org/>`_ from project
SuperAnnotate format annotations:

Expand Down
2 changes: 1 addition & 1 deletion src/superannotate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys


__version__ = "4.4.30"
__version__ = "4.4.31dev1"

os.environ.update({"sa_version": __version__})
sys.path.append(os.path.split(os.path.realpath(__file__))[0])
Expand Down
17 changes: 8 additions & 9 deletions src/superannotate/lib/app/interface/sdk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,20 +505,19 @@ def retrieve_context(
) -> Tuple[bool, typing.Any]:
try:
for component in component_data:
if (
component["type"] == "webComponent"
and component["id"] == component_pk
):
return True, component.get("context")
if (
component["type"] in ("group", "grid")
and "children" in component
):
if "children" in component:
found, val = retrieve_context(
component["children"], component_pk
)
if found:
return found, val
if (
"id" in component
and component["id"] == component_pk
and component["type"] == "webComponent"
):
return True, json.loads(component.get("context"))

except KeyError as e:
logger.debug("Got key error:", component_data)
raise e
Expand Down