Skip to content

Commit 7df2212

Browse files
authored
Merge branch 'develop' into FRIDAY_3645
2 parents e23b925 + 69ed551 commit 7df2212

File tree

18 files changed

+229
-32
lines changed

18 files changed

+229
-32
lines changed

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ History
66

77
All release highlights of this project will be documented in this file.
88

9+
4.4.32 - March 4, 2025
10+
_____________________
11+
12+
**Fixed**
13+
14+
- ``SAClient.item_context`` Fixed an issue where setting a component value would overwrite existing comments and other associated data.
915

1016
4.4.31 - Feb 27, 2025
1117
_____________________

src/superannotate/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import sys
44

55

6-
__version__ = "4.4.33dev1"
6+
__version__ = "4.4.32dev3"
7+
78

89
os.environ.update({"sa_version": __version__})
910
sys.path.append(os.path.split(os.path.realpath(__file__))[0])

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,7 +1699,8 @@ def prepare_export(
16991699
17001700
- integration_name: The name of the integration within the platform that is being used.
17011701
- format: The format in which the data will be exported in multimodal projects.
1702-
It can be either CSV or JSON. If None, the data will be exported in the default JSON format.
1702+
The data can be exported in CSV, JSON, or JSONL format. If None, the data will be exported
1703+
in the default JSON format.
17031704
:return: metadata object of the prepared export
17041705
:rtype: dict
17051706
@@ -1737,6 +1738,8 @@ def prepare_export(
17371738
export_type = export_type.lower()
17381739
if export_type == "csv":
17391740
_export_type = 3
1741+
elif export_type == "jsonl":
1742+
_export_type = 4
17401743
response = self.controller.prepare_export(
17411744
project_name=project_name,
17421745
folder_names=folders,
@@ -3440,7 +3443,7 @@ def list_items(
34403443
exclude = {"meta", "annotator_email", "qa_email"}
34413444
if not include_custom_metadata:
34423445
exclude.add("custom_metadata")
3443-
return BaseSerializer.serialize_iterable(res, exclude=exclude)
3446+
return BaseSerializer.serialize_iterable(res, exclude=exclude, by_alias=False)
34443447

34453448
def list_projects(
34463449
self,
@@ -3828,6 +3831,7 @@ def download_annotations(
38283831
items: Optional[List[NotEmptyStr]] = None,
38293832
recursive: bool = False,
38303833
callback: Callable = None,
3834+
data_spec: Literal["default", "multimodal"] = "default",
38313835
):
38323836
"""Downloads annotation JSON files of the selected items to the local directory.
38333837
@@ -3853,6 +3857,31 @@ def download_annotations(
38533857
The function receives each annotation as an argument and the returned value will be applied to the download.
38543858
:type callback: callable
38553859
3860+
:param data_spec: Specifies the format for processing and transforming annotations before upload.
3861+
3862+
Options are:
3863+
- default: Retains the annotations in their original format.
3864+
- multimodal: Converts annotations for multimodal projects, optimizing for
3865+
compact and multimodal-specific data representation.
3866+
3867+
:type data_spec: str, optional
3868+
3869+
Example Usage of Multimodal Projects::
3870+
3871+
from superannotate import SAClient
3872+
3873+
3874+
sa = SAClient()
3875+
3876+
# Call the get_annotations function
3877+
response = sa.download_annotations(
3878+
project="project1/folder1",
3879+
path="path/to/download",
3880+
items=["item_1", "item_2"],
3881+
data_spec='multimodal'
3882+
)
3883+
3884+
38563885
:return: local path of the downloaded annotations folder.
38573886
:rtype: str
38583887
"""
@@ -3865,6 +3894,7 @@ def download_annotations(
38653894
recursive=recursive,
38663895
item_names=items,
38673896
callback=callback,
3897+
transform_version="llmJsonV2" if data_spec == "multimodal" else None,
38683898
)
38693899
if response.errors:
38703900
raise AppException(response.errors)

src/superannotate/lib/core/entities/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from lib.core.entities.classes import AnnotationClassEntity
55
from lib.core.entities.folder import FolderEntity
66
from lib.core.entities.integrations import IntegrationEntity
7+
from lib.core.entities.items import CategoryEntity
78
from lib.core.entities.items import ClassificationEntity
89
from lib.core.entities.items import DocumentEntity
910
from lib.core.entities.items import ImageEntity
@@ -12,7 +13,6 @@
1213
from lib.core.entities.items import TiledEntity
1314
from lib.core.entities.items import VideoEntity
1415
from lib.core.entities.project import AttachmentEntity
15-
from lib.core.entities.project import CategoryEntity
1616
from lib.core.entities.project import ContributorEntity
1717
from lib.core.entities.project import CustomFieldEntity
1818
from lib.core.entities.project import ProjectEntity

src/superannotate/lib/core/entities/filters.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class ItemFilters(BaseFilters):
2929
assignments__user_role__in: Optional[List[str]]
3030
assignments__user_role__ne: Optional[str]
3131
assignments__user_role__notin: Optional[List[str]]
32+
categories__value: Optional[str]
33+
categories__value__in: Optional[List[str]]
3234

3335

3436
class ProjectFilters(BaseFilters):

src/superannotate/lib/core/entities/items.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Optional
33

44
from lib.core.entities.base import BaseItemEntity
5-
from lib.core.entities.base import TimedBaseModel
5+
from lib.core.entities.project import TimedBaseModel
66
from lib.core.enums import ApprovalStatus
77
from lib.core.enums import ProjectType
88
from lib.core.pydantic_v1 import Extra
@@ -18,9 +18,17 @@ class Config:
1818
extra = Extra.ignore
1919

2020

21+
class CategoryEntity(TimedBaseModel):
22+
id: int
23+
value: str = Field(None, alias="name")
24+
25+
class Config:
26+
extra = Extra.ignore
27+
28+
2129
class MultiModalItemCategoryEntity(TimedBaseModel):
2230
id: int = Field(None, alias="category_id")
23-
name: str = Field(None, alias="category_name")
31+
value: str = Field(None, alias="category_name")
2432

2533
class Config:
2634
extra = Extra.ignore

src/superannotate/lib/core/entities/project.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,3 @@ def is_system(self):
187187

188188
class Config:
189189
extra = Extra.ignore
190-
191-
192-
class CategoryEntity(BaseModel):
193-
id: Optional[int]
194-
name: Optional[str]

src/superannotate/lib/core/serviceproviders.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ async def download_big_annotation(
506506
download_path: str,
507507
item: entities.BaseItemEntity,
508508
callback: Callable = None,
509+
transform_version: str = None,
509510
):
510511
raise NotImplementedError
511512

@@ -518,6 +519,7 @@ async def download_small_annotations(
518519
download_path: str,
519520
item_ids: List[int],
520521
callback: Callable = None,
522+
transform_version: str = None,
521523
):
522524
raise NotImplementedError
523525

@@ -701,6 +703,12 @@ class BaseServiceProvider:
701703
def get_role_id(self, project: entities.ProjectEntity, role_name: str) -> int:
702704
raise NotImplementedError
703705

706+
@abstractmethod
707+
def get_category_id(
708+
self, project: entities.ProjectEntity, category_name: str
709+
) -> int:
710+
raise NotImplementedError
711+
704712
@abstractmethod
705713
def get_role_name(self, project: entities.ProjectEntity, role_id: int) -> str:
706714
raise NotImplementedError

src/superannotate/lib/core/usecases/annotations.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ def __init__(
16341634
item_names: List[str],
16351635
service_provider: BaseServiceProvider,
16361636
callback: Callable = None,
1637+
transform_version=None,
16371638
):
16381639
super().__init__(reporter)
16391640
self._config = config
@@ -1645,6 +1646,7 @@ def __init__(
16451646
self._service_provider = service_provider
16461647
self._callback = callback
16471648
self._big_file_queue = None
1649+
self._transform_version = transform_version
16481650

16491651
def validate_items(self):
16501652
if self._item_names:
@@ -1724,6 +1726,7 @@ async def download_small_annotations(
17241726
reporter=self.reporter,
17251727
download_path=f"{export_path}{'/' + self._folder.name if not self._folder.is_root else ''}",
17261728
callback=self._callback,
1729+
transform_version=self._transform_version,
17271730
)
17281731

17291732
async def run_workers(
@@ -2098,8 +2101,10 @@ def execute(self):
20982101
if categorization_enabled:
20992102
item_id_category_map = {}
21002103
for item_name in uploaded_annotations:
2101-
category = name_annotation_map[item_name]["metadata"].get(
2102-
"item_category"
2104+
category = (
2105+
name_annotation_map[item_name]["metadata"]
2106+
.get("item_category", {})
2107+
.get("value")
21032108
)
21042109
if category:
21052110
item_id_category_map[name_item_map[item_name].id] = category

src/superannotate/lib/infrastructure/controller.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ def download(
972972
recursive: bool,
973973
item_names: Optional[List[str]],
974974
callback: Optional[Callable],
975+
transform_version: str,
975976
):
976977
use_case = usecases.DownloadAnnotations(
977978
config=self._config,
@@ -983,6 +984,7 @@ def download(
983984
item_names=item_names,
984985
service_provider=self.service_provider,
985986
callback=callback,
987+
transform_version=transform_version,
986988
)
987989
return use_case.execute()
988990

0 commit comments

Comments
 (0)