Skip to content

Commit 9f9f925

Browse files
authored
Merge pull request #189 from superannotateai/attach_documnet
Added sdk/cli function attach_document_urls_to_project
2 parents 5523e64 + 0135ca2 commit 9f9f925

File tree

11 files changed

+262
-72
lines changed

11 files changed

+262
-72
lines changed

src/superannotate/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
from superannotate.lib.app.interface.sdk_interface import aggregate_annotations_as_df
4646
from superannotate.lib.app.interface.sdk_interface import assign_folder
4747
from superannotate.lib.app.interface.sdk_interface import assign_images
48+
from superannotate.lib.app.interface.sdk_interface import (
49+
attach_document_urls_to_project,
50+
)
4851
from superannotate.lib.app.interface.sdk_interface import attach_image_urls_to_project
4952
from superannotate.lib.app.interface.sdk_interface import attach_video_urls_to_project
5053
from superannotate.lib.app.interface.sdk_interface import benchmark
@@ -239,6 +242,7 @@
239242
"upload_images_from_folder_to_project",
240243
"attach_image_urls_to_project",
241244
"attach_video_urls_to_project",
245+
"attach_document_urls_to_project",
242246
# Video Section
243247
"upload_videos_from_folder_to_project",
244248
# Annotation Section

src/superannotate/lib/app/analytics/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def aggregate_annotations_as_df(
179179
and "___objects.json" not in json_paths[0].name
180180
):
181181
raise AppException(
182-
"The function does not support projects containing videos attached with URLs"
182+
"The function does not support projects containing videos / documents attached with URLs"
183183
)
184184

185185
if verbose:

src/superannotate/lib/app/input_converters/conversion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ def export_annotation(
143143
project_type="Vector",
144144
task="object_detection",
145145
):
146-
if project_type == "Video":
146+
if project_type == "Video" or project_type == "Text":
147147
raise AppValidationException(
148-
"The function does not support projects containing videos attached with URLs"
148+
f"The function does not support projects containing {project_type} attached with URLs"
149149
)
150150
"""Converts SuperAnnotate annotation formate to the other annotation formats. Currently available (project_type, task) combinations for converter
151151
presented below:

src/superannotate/lib/app/input_converters/sa_conversion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def sa_convert_project_type(input_dir, output_dir):
182182
img_names = from_vector_to_pixel(json_paths, output_dir)
183183
elif ".json" in json_paths[0].name:
184184
raise AppException(
185-
"The function does not support projects containing videos attached with URLs"
185+
"The function does not support projects containing videos / document attached with URLs"
186186
)
187187
else:
188188
raise AppException(

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from lib.app.helpers import split_project_path
1515
from lib.app.input_converters.conversion import import_annotation
1616
from lib.app.interface.base_interface import BaseInterfaceFacade
17+
from lib.app.interface.sdk_interface import attach_document_urls_to_project
1718
from lib.app.interface.sdk_interface import attach_image_urls_to_project
1819
from lib.app.interface.sdk_interface import attach_video_urls_to_project
1920
from lib.app.interface.sdk_interface import create_folder
@@ -263,6 +264,17 @@ def attach_video_urls(
263264
)
264265
sys.exit(0)
265266

267+
@staticmethod
268+
def attach_document_urls(
269+
project: str, attachments: str, annotation_status: Optional[Any] = None
270+
):
271+
attach_document_urls_to_project(
272+
project=project,
273+
attachments=attachments,
274+
annotation_status=annotation_status,
275+
)
276+
sys.exit(0)
277+
266278
def _attach_urls(
267279
self, project: str, attachments: str, annotation_status: Optional[Any] = None
268280
):

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3567,3 +3567,63 @@ def delete_annotations(project: str, image_names: List[str] = None):
35673567
)
35683568
if response.errors:
35693569
raise AppException(response.errors)
3570+
3571+
3572+
@Trackable
3573+
@validate_arguments
3574+
def attach_document_urls_to_project(
3575+
project: Union[NotEmptyStr, dict],
3576+
attachments: Union[Path, NotEmptyStr],
3577+
annotation_status: Optional[NotEmptyStr] = "NotStarted",
3578+
):
3579+
"""Link documents on external storage to SuperAnnotate.
3580+
3581+
:param project: project name or project folder path
3582+
:type project: str or dict
3583+
:param attachments: path to csv file on attachments metadata
3584+
:type attachments: Path-like (str or Path)
3585+
:param annotation_status: value to set the annotation statuses of the linked documents: NotStarted InProgress QualityCheck Returned Completed Skipped
3586+
:type annotation_status: str
3587+
3588+
:return: list of attached documents, list of not attached documents, list of skipped documents
3589+
:rtype: tuple
3590+
"""
3591+
project_name, folder_name = extract_project_folder(project)
3592+
3593+
image_data = pd.read_csv(attachments, dtype=str)
3594+
image_data = image_data[~image_data["url"].isnull()]
3595+
if "name" in image_data.columns:
3596+
image_data["name"] = (
3597+
image_data["name"]
3598+
.fillna("")
3599+
.apply(lambda cell: cell if str(cell).strip() else str(uuid.uuid4()))
3600+
)
3601+
else:
3602+
image_data["name"] = [str(uuid.uuid4()) for _ in range(len(image_data.index))]
3603+
3604+
image_data = pd.DataFrame(image_data, columns=["name", "url"])
3605+
img_names_urls = image_data.rename(columns={"url": "path"}).to_dict(
3606+
orient="records"
3607+
)
3608+
list_of_not_uploaded = []
3609+
duplicate_images = []
3610+
for i in range(0, len(img_names_urls), 500):
3611+
response = controller.attach_urls(
3612+
project_name=project_name,
3613+
folder_name=folder_name,
3614+
files=ImageSerializer.deserialize(
3615+
img_names_urls[i : i + 500] # noqa: E203
3616+
),
3617+
annotation_status=annotation_status,
3618+
)
3619+
if response.errors:
3620+
list_of_not_uploaded.append(response.data[0])
3621+
duplicate_images.append(response.data[1])
3622+
3623+
list_of_uploaded = [
3624+
image["name"]
3625+
for image in img_names_urls
3626+
if image["name"] not in list_of_not_uploaded
3627+
]
3628+
3629+
return list_of_uploaded, list_of_not_uploaded, duplicate_images

src/superannotate/lib/core/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ProjectType(BaseTitledEnum):
3232
VECTOR = "Vector", 1
3333
PIXEL = "Pixel", 2
3434
VIDEO = "Video", 3
35+
DOCUMENT = "Document", 4
3536

3637

3738
class UserRole(BaseTitledEnum):

0 commit comments

Comments
 (0)