1- import concurrent .futures
21import json
32import logging
43import os
54import sys
65import tempfile
76import uuid
8- from collections import Counter
9- from collections import namedtuple
10- from io import BytesIO
11- from pathlib import Path
127from typing import Any
138from typing import Optional
149
1914from lib .app .helpers import split_project_path
2015from lib .app .input_converters .conversion import import_annotation
2116from lib .app .interface .base_interface import BaseInterfaceFacade
17+ from lib .app .interface .sdk_interface import attach_image_urls_to_project
18+ from lib .app .interface .sdk_interface import attach_video_urls_to_project
19+ from lib .app .interface .sdk_interface import create_folder
20+ from lib .app .interface .sdk_interface import create_project
21+ from lib .app .interface .sdk_interface import upload_images_from_folder_to_project
22+ from lib .app .interface .sdk_interface import upload_videos_from_folder_to_project
2223from lib .app .serializers import ImageSerializer
2324from lib .core .entities import ConfigEntity
25+ from lib .infrastructure .controller import Controller
2426from lib .infrastructure .repositories import ConfigRepository
2527from tqdm import tqdm
2628
29+
2730logger = logging .getLogger ()
31+ controller = Controller (logger )
2832
2933
3034class CLIFacade (BaseInterfaceFacade ):
@@ -72,18 +76,14 @@ def create_project(self, name: str, description: str, type: str):
7276 """
7377 To create a new project
7478 """
75- response = self .controller .create_project (name , description , type )
76- if response .errors :
77- return response .errors
78- return response .data
79+ create_project (name , description , type )
80+ sys .exit (0 )
7981
8082 def create_folder (self , project : str , name : str ):
8183 """
8284 To create a new folder
8385 """
84- response = self .controller .create_folder (project = project , folder_name = name )
85- if response .errors :
86- logger .critical (response .errors )
86+ create_folder (project , name )
8787 sys .exit (0 )
8888
8989 def upload_images (
@@ -104,79 +104,16 @@ def upload_images(
104104 Optional argument extensions accepts comma separated list of image extensions to look for.
105105 If the argument is not given then value jpg,jpeg,png,tif,tiff,webp,bmp is assumed.
106106 """
107- uploaded_image_entities = []
108- failed_images = []
109- project_name , folder_name = split_project_path (project )
110- ProcessedImage = namedtuple ("ProcessedImage" , ["uploaded" , "path" , "entity" ])
111-
112- def upload_image (image_path : str ):
113- with open (image_path , "rb" ) as image :
114- image_bytes = BytesIO (image .read ())
115- upload_response = self .controller .upload_image_to_s3 (
116- project_name = project_name ,
117- image_path = image_path ,
118- image_bytes = image_bytes ,
119- folder_name = folder_name ,
120- image_quality_in_editor = image_quality_in_editor ,
121- )
122-
123- if not upload_response .errors and upload_response .data :
124- entity = upload_response .data
125- return ProcessedImage (
126- uploaded = True , path = entity .path , entity = entity
127- )
128- else :
129- return ProcessedImage (uploaded = False , path = image_path , entity = None )
130-
131- paths = []
132-
133- if isinstance (extensions , str ):
134- extensions = extensions .strip ().split ("," )
135-
136- for extension in extensions :
137- if recursive_subfolders :
138- paths += list (Path (folder ).rglob (f"*.{ extension .lower ()} " ))
139- if os .name != "nt" :
140- paths += list (Path (folder ).rglob (f"*.{ extension .upper ()} " ))
141- else :
142- paths += list (Path (folder ).glob (f"*.{ extension .lower ()} " ))
143- if os .name != "nt" :
144- paths += list (Path (folder ).glob (f"*.{ extension .upper ()} " ))
145-
146- filtered_paths = []
147- for path in paths :
148- not_in_exclude_list = [
149- x not in Path (path ).name for x in exclude_file_patterns
150- ]
151- if all (not_in_exclude_list ):
152- filtered_paths .append (path )
153-
154- duplication_counter = Counter (filtered_paths )
155- images_to_upload , duplicated_images = (
156- set (filtered_paths ),
157- [item for item in duplication_counter if duplication_counter [item ] > 1 ],
107+ upload_images_from_folder_to_project (
108+ project ,
109+ folder_path = folder ,
110+ extensions = extensions ,
111+ annotation_status = set_annotation_status ,
112+ from_s3_bucket = None ,
113+ exclude_file_patterns = exclude_file_patterns ,
114+ recursive_subfolders = recursive_subfolders ,
115+ image_quality_in_editor = image_quality_in_editor ,
158116 )
159- with tqdm (total = len (images_to_upload )) as progress_bar :
160- with concurrent .futures .ThreadPoolExecutor (max_workers = 10 ) as executor :
161- results = [
162- executor .submit (upload_image , image_path )
163- for image_path in images_to_upload
164- ]
165- for future in concurrent .futures .as_completed (results ):
166- processed_image = future .result ()
167- if processed_image .uploaded and processed_image .entity :
168- uploaded_image_entities .append (processed_image .entity )
169- else :
170- failed_images .append (processed_image .path )
171- progress_bar .update (1 )
172-
173- for i in range (0 , len (uploaded_image_entities ), 500 ):
174- self .controller .upload_images (
175- project_name = project_name ,
176- folder_name = folder_name ,
177- images = uploaded_image_entities [i : i + 500 ], # noqa: E203
178- annotation_status = set_annotation_status ,
179- )
180117 sys .exit (0 )
181118
182119 def export_project (
@@ -305,13 +242,22 @@ def attach_image_urls(
305242 """
306243 To attach image URLs to project use:
307244 """
308- self ._attach_urls (project , attachments , annotation_status )
245+
246+ attach_image_urls_to_project (
247+ project = project ,
248+ attachments = attachments ,
249+ annotation_status = annotation_status ,
250+ )
309251 sys .exit (0 )
310252
311253 def attach_video_urls (
312254 self , project : str , attachments : str , annotation_status : Optional [Any ] = None
313255 ):
314- self ._attach_urls (project , attachments , annotation_status )
256+ attach_video_urls_to_project (
257+ project = project ,
258+ attachments = attachments ,
259+ annotation_status = annotation_status ,
260+ )
315261 sys .exit (0 )
316262
317263 def _attach_urls (
@@ -372,58 +318,17 @@ def upload_videos(
372318 start-time specifies time (in seconds) from which to start extracting frames, default is 0.0.
373319 end-time specifies time (in seconds) up to which to extract frames. If it is not specified, then up to end is assumed.
374320 """
375- project_name , folder_name = split_project_path (project )
376-
377- uploaded_image_entities = []
378- failed_images = []
379-
380- def _upload_image (image_path : str ) -> str :
381- with open (image_path , "rb" ) as image :
382- image_bytes = BytesIO (image .read ())
383- upload_response = self .controller .upload_image_to_s3 (
384- project_name = project_name ,
385- image_path = image_path ,
386- image_bytes = image_bytes ,
387- folder_name = folder_name ,
388- )
389- if not upload_response .errors :
390- uploaded_image_entities .append (upload_response .data )
391- else :
392- return image_path
393321
394- video_paths = []
395- for extension in extensions :
396- if not recursive :
397- video_paths += list (Path (folder ).glob (f"*.{ extension .lower ()} " ))
398- if os .name != "nt" :
399- video_paths += list (Path (folder ).glob (f"*.{ extension .upper ()} " ))
400- else :
401- video_paths += list (Path (folder ).rglob (f"*.{ extension .lower ()} " ))
402- if os .name != "nt" :
403- video_paths += list (Path (folder ).rglob (f"*.{ extension .upper ()} " ))
404- video_paths = [str (path ) for path in video_paths ]
405-
406- for path in video_paths :
407- with tempfile .TemporaryDirectory () as temp_path :
408- res = self .controller .extract_video_frames (
409- project_name = project_name ,
410- folder_name = folder_name ,
411- video_path = path ,
412- extract_path = temp_path ,
413- target_fps = int (target_fps ),
414- start_time = float (start_time ),
415- end_time = end_time if not end_time else float (end_time ),
416- annotation_status = set_annotation_status ,
417- )
418- if not res .errors :
419- extracted_frame_paths = res .data
420- for image_path in extracted_frame_paths :
421- failed_images .append (_upload_image (image_path ))
422- for i in range (0 , len (uploaded_image_entities ), 500 ):
423- self .controller .upload_images (
424- project_name = project_name ,
425- folder_name = folder_name ,
426- images = uploaded_image_entities [i : i + 500 ], # noqa: E203
427- annotation_status = set_annotation_status ,
428- )
322+ upload_videos_from_folder_to_project (
323+ project = project ,
324+ folder_path = folder ,
325+ extensions = extensions ,
326+ exclude_file_patterns = (),
327+ recursive_subfolders = recursive ,
328+ target_fps = target_fps ,
329+ start_time = start_time ,
330+ end_time = end_time ,
331+ annotation_status = set_annotation_status ,
332+ image_quality_in_editor = None ,
333+ )
429334 sys .exit (0 )
0 commit comments