def batch_file_classify(image_file): try: files = [] total_batch_size = 0 for file in image_file: file_obj = self.filereader.get_file(file) file_size = os.fstat(file_obj.fileno()).st_size if file_size > MAX_LOCAL_IMAGE_SIZE: raise error.InvalidQueryError( message= 'File %s is larger than the limit of %d megabytes' % (file_obj.name, self.bytes_to_mb(MAX_LOCAL_IMAGE_BATCH_SIZE))) files.append(('file', file_obj)) total_batch_size += file_size if total_batch_size > MAX_LOCAL_IMAGE_BATCH_SIZE: raise error.InvalidQueryError( message='Max batch upload size is %d megabytes.' % (self.bytes_to_mb(MAX_LOCAL_IMAGE_BATCH_SIZE))) return requests.request( method, endpoint, **{ 'headers': headers, 'files': files, 'data': data }) finally: for file_tuple in files: (key, file) = file_tuple file.close()
def classify_video(self, detector_id, video_url=None, video_file=None): """ Classify a video from a url with a detector detector_id: a unique id for the detector video_url: internet URL for the video to classify """ MAX_LOCAL_VIDEO_SIZE = 300 * 1024 * 1024 (endpoint, method) = self.endpoints['classify_video'] if not video_url and not video_file: raise error.InvalidQueryError( message='Missing required parameter: video_url or video_file') if video_url and video_file: raise error.InvalidQueryError( message= 'Cannot classify a URL and local file in the same request') if isinstance(video_file, list): raise error.InvalidQueryError( message='Only one video can be uploaded at a time') endpoint = endpoint.replace(':key', detector_id) try: headers = {'Authorization': self.token.authorization_header()} data = {'detector_id': detector_id} if video_url: data['url'] = video_url return requests.request(method, endpoint, **{ 'headers': headers, 'data': data }) elif video_file: with self.filereader.get_file(video_file) as file_to_upload: files = {'file': file_to_upload} file_size = os.fstat(file_to_upload.fileno()).st_size if file_size > MAX_LOCAL_VIDEO_SIZE: raise error.InvalidQueryError( message= 'File %s is larger than the limit of %d megabytes' % (file_to_upload.name, self.bytes_to_mb(MAX_LOCAL_VIDEO_SIZE))) return requests.request( method, endpoint, **{ 'headers': headers, 'files': files, 'data': data }) except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e)
def classify_video(self, detectorId, url=None, file=None, **options): """ Classify a video from a url with a detector detectorId: a unique id for the detector url: internet URL for the video to classify """ MAX_LOCAL_VIDEO_SIZE = 300 * 1024 * 1024 (endpoint, method) = self.endpoints["classify_video"] if not url and not file: raise error.InvalidQueryError(message="Missing required parameter: url or file") if url and file: raise error.InvalidQueryError( message="Cannot classify a URL and local file in the same request" ) if isinstance(file, list): raise error.InvalidQueryError( message="Only one video can be uploaded at a time" ) endpoint = endpoint.replace(":key", detectorId) try: headers = {"Authorization": self.token.authorization_header()} data = {"detectorId": detectorId} data.update(options) if url: data["url"] = url return requests.request( method, endpoint, **{"headers": headers, "data": data} ) elif file: with self.filereader.get_file(file) as file_to_upload: files = {"file": file_to_upload} file_size = os.fstat(file_to_upload.fileno()).st_size if file_size > MAX_LOCAL_VIDEO_SIZE: raise error.InvalidQueryError( message="File %s is larger than the limit of %d megabytes" % (file_to_upload.name, self.bytes_to_mb(MAX_LOCAL_VIDEO_SIZE)) ) return requests.request( method, endpoint, **{"headers": headers, "files": files, "data": data}, ) except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e)
def batch_file_request(uploaded_files, method, endpoint, headers, data, file_keyword="file"): # pylint: disable = no-value-for-parameter filereader = FileReader() try: files = [] total_batch_size = 0 for file in uploaded_files: file_obj = filereader.get_file(file) file_size = check_file_size(file_obj) files.append((file_keyword, file_obj)) total_batch_size += file_size if total_batch_size > MAX_LOCAL_IMAGE_BATCH_SIZE: raise error.InvalidQueryError( message="Max batch upload size is %d megabytes." % (bytes_to_mb(MAX_LOCAL_IMAGE_BATCH_SIZE))) return requests.request( method, endpoint, **{ "headers": headers, "files": files, "data": data }) finally: for file_tuple in files: (key, file) = file_tuple file.close()
def create_detector(self, zip_file, name, detector_type): """ Create a new detector with the contents of the zip file detector_type: general, facial_recognition, or facial_characteristics name: the detector's display name zip_file: a zip file containing the images to be used in the detector creation the root folder should contain only directories which will become the labels for detection each of these directories should contain only images corresponding to that label. However, there is an exception if you want to add negative examples to a label. In that case, put the negative images for the label in a folder called "negative" inside the corresponding label. To include bounding boxes, include one file called bbox.csv in the top level directory. Each line of this file should be formatted as follows: 0.25, 0.3, 0.75, 0.8, cat, positive, image.jpg 0.25, 0.4, 0.55, 0.7, dog, positive, picture.jpg 0.0, 0.1, 0.2, 0.3, cat, negative, raccoon.jpg Column definitions: top left X coordinate, top left Y coordinate, bottom right X coordinate, bottom right Y coordinate, label, positive or negative example, file name Max 300 MB zip file upload structure example: cat/ garfield.jpg nermal.png dog/ odie.TIFF negative/ lobo.jpg bbox.csv """ MAX_LOCAL_ZIP_SIZE = 300 * 1024 * 1024 (endpoint, method) = self.endpoints['create_detector'] try: headers = {'Authorization': self.token.authorization_header()} data = {'name': name, 'detector_type': detector_type} with self.filereader.get_file(zip_file) as file_to_upload: files = {'file': file_to_upload} file_size = os.fstat(file_to_upload.fileno()).st_size if file_size > MAX_LOCAL_ZIP_SIZE: raise error.InvalidQueryError( message= 'File %s is larger than the limit of %d megabytes' % (file_to_upload.name, self.bytes_to_mb(MAX_LOCAL_ZIP_SIZE))) return requests.request( method, endpoint, **{ 'headers': headers, 'files': files, 'data': data }) except Exception as e: raise error.APIConnectionError(message=e)
def get_annotations(self, **options): """Get annotations. Requires processing=false. Note: you need to provide at least one of the three ids to query""" (endpoint, method) = self.endpoints["get_annotations"] detector_id = options.get("detectorId") label_ids = options.get("labelIds") image_id = options.get("imageId") if not detector_id and not label_ids and not image_id: raise error.InvalidQueryError( message= "Missing required parameter: detectorId, labelIds or imageId") try: headers = {"Authorization": self.token.authorization_header()} params = { "detectorId": detector_id, "labelIds": label_ids, "imageId": image_id, } return requests.request(method, endpoint, **{ "headers": headers, "params": params }) except Exception as e: raise error.APIConnectionError(message=e)
def import_detector(self, name, **options): """ Note: certain combination of parameters can be supplied: file_detector, file_proto + file_label (+ file_label_ind), or file_proto + labels (+ label_inds). Parentheses part can be optionally supplied for object detection. """ (endpoint, method) = self.endpoints["import_detector"] data = { "name": name, } def get_data_info(): data["inputTensor"] = (options.get("inputTensor"), ) data["outputTensor"] = (options.get("outputTensor"), ) data["detectorType"] = (options.get("detectorType"), ) if options.get("fileDetector"): file_paths = {"fileDetector": options.get("fileDetector")} elif options.get("fileProto") and options.get("fileLabel"): file_paths = { "fileProto": options.get("fileProto"), "fileLabel": options.get("fileLabel"), "fileLabelInd": options.get("fileLabelInd"), } get_data_info() elif options.get("fileProto") and options.get("labels"): file_paths = { "fileProto": options.get("fileProto"), } data["labels"] = options.get("labels") data["labelInds"] = options.get("labelInds") get_data_info() else: raise error.InvalidQueryError(message="Invalid parameter combination") file_objs = {} for file_keyword, file_path in file_paths.items(): file_obj = self.filereader.get_file(file_path) file_objs[file_keyword] = file_obj try: headers = {"Authorization": self.token.authorization_header()} return requests.request( method, endpoint, **{ "headers": headers, "files": file_objs, "data": data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e) finally: for file_keyword, file_obj in file_objs.items(): if isinstance(file_obj, io.IOBase): file_obj.close()
def add_feedback(self, detectorId, feedback, file=None, url=None): """ Add feedback to a detector using a local file or image URL """ (endpoint, method) = self.endpoints["add_feedback"] endpoint = endpoint.replace(":detector_id", detectorId) if not url and not file: raise error.InvalidQueryError( message="Missing required parameter: file or URL") if url and file: raise error.InvalidQueryError( message="You may only specify a file or a URL, not both") data = {"feedback": format_feedback(feedback)} image_file = None files = None try: if url: data["url"] = url else: image_file = self.filereader.get_file(file) files = {"file": image_file} headers = {"Authorization": self.token.authorization_header()} return requests.request( method, endpoint, **{ "headers": headers, "files": files, "data": data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e) finally: if isinstance(image_file, io.IOBase): image_file.close()
def check_file_size(file): # pylint: disable = no-value-for-parameter file_size = os.fstat(file.fileno()).st_size if file_size > MAX_LOCAL_IMAGE_SIZE: raise error.InvalidQueryError( message="File %s is larger than the limit of %d megabytes" % (file.name, bytes_to_mb(MAX_LOCAL_IMAGE_SIZE))) return file_size
def query_collection_by_image(self, taskId, url=None, file=None, **options): """ Query against a collection index (CollectionManagerTask) using an image as key. Takes in an image file or url and returns similar media from the collection. """ (endpoint, method) = self.endpoints["query_collection_by_image"] endpoint = endpoint.replace(":key", taskId) if not file and not url: raise error.InvalidQueryError( message="Missing required parameter: file or url") try: file_to_upload = None headers = {"Authorization": self.token.authorization_header()} data = { "boundingBox": json.dumps(options.get("boundingBox")), "numResults": options.get("num_results"), } if file: file_to_upload = self.filereader.get_file(file) files = {"file": file_to_upload} return requests.request( method, endpoint, **{ "headers": headers, "files": files, "data": data }) else: data["url"] = url return requests.request(method, endpoint, **{ "headers": headers, "data": data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e) finally: if file_to_upload: file_to_upload.close()
def classify_image(self, detectorId, file=None, url=None, **options): """ Classify an image with a detector detectorId: a unique id for the detector file: path to local image file to classify url: internet URL for the image to classify """ (endpoint, method) = self.endpoints["classify_image"] if not url and not file: raise error.InvalidQueryError( message="Missing required parameter: file or url") endpoint = endpoint.replace(":key", detectorId) try: headers = {"Authorization": self.token.authorization_header()} data = {"detectorId": detectorId} data.update(options) if url: data["url"] = url if file: if not isinstance(file, list): file = [file] return batch_file_request(file, method, endpoint, headers, data) else: return requests.request(method, endpoint, **{ "headers": headers, "data": data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e)
def localize_image(self, localizer, localizerLabel, **options): """ Note: this API is very similar to Images/Classify; however, it can be used to update bounding boxes of existing training images by supplying update=true, labelId, and one of imageId or imageIds, and it has access to the internal face localizer (localizer="DEFAULT_FACE" and localizerLabel="face"). """ (endpoint, method) = self.endpoints["localize_image"] data = { "localizer": localizer, "localizerLabel": localizerLabel, } update = options.get("update") if update: image_id = options.get("imageId") image_ids = options.get("imageIds") if not image_id and not image_ids: raise error.InvalidQueryError( message= "Missing required parameter for update: imageId or imageIds") if image_id: data["imageId"] = image_id else: data["imageIds"] = image_ids else: files = options.get("file") urls = options.get("url") if not files and not urls: raise error.InvalidQueryError( message="Missing required parameter: files or urls") data.update({ "files": files, "urls": urls, }) try: headers = {"Authorization": self.token.authorization_header()} data.update({ "confidence": options.get("confidence"), "update": "true" if update else "", "maxFaces": options.get("maxFaces"), "labelId": options.get("labelId"), }) if update: return requests.request(method, endpoint, **{ "headers": headers, "data": data }) if files: if not isinstance(files, list): files = [files] return batch_file_request(files, method, endpoint, headers, data) else: if isinstance(urls, list): data["urls"] = urls else: data["url"] = urls return requests.request(method, endpoint, **{ "headers": headers, "data": data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e)
def classify_image(self, detector_id, image_file=None, image_url=None): """ Classify an image with a detector detector_id: a unique id for the detector image_file: path to local image file to classify image_url: internet URL for the image to classify """ MAX_LOCAL_IMAGE_SIZE = 50 * 1024 * 1024 MAX_LOCAL_IMAGE_BATCH_SIZE = 50 * 1024 * 1024 def batch_file_classify(image_file): try: files = [] total_batch_size = 0 for file in image_file: file_obj = self.filereader.get_file(file) file_size = os.fstat(file_obj.fileno()).st_size if file_size > MAX_LOCAL_IMAGE_SIZE: raise error.InvalidQueryError( message= 'File %s is larger than the limit of %d megabytes' % (file_obj.name, self.bytes_to_mb(MAX_LOCAL_IMAGE_BATCH_SIZE))) files.append(('file', file_obj)) total_batch_size += file_size if total_batch_size > MAX_LOCAL_IMAGE_BATCH_SIZE: raise error.InvalidQueryError( message='Max batch upload size is %d megabytes.' % (self.bytes_to_mb(MAX_LOCAL_IMAGE_BATCH_SIZE))) return requests.request( method, endpoint, **{ 'headers': headers, 'files': files, 'data': data }) finally: for file_tuple in files: (key, file) = file_tuple file.close() (endpoint, method) = self.endpoints['classify_image'] if not image_url and not image_file: raise error.InvalidQueryError( message='Missing required parameter: image_file or image_url') endpoint = endpoint.replace(':key', detector_id) try: headers = {'Authorization': self.token.authorization_header()} data = {'detector_id': detector_id} if image_url: data['url'] = image_url if image_file: if isinstance(image_file, list): return batch_file_classify(image_file) else: with self.filereader.get_file( image_file) as file_to_upload: files = {'file': file_to_upload} file_size = os.fstat(file_to_upload.fileno()).st_size if file_size > MAX_LOCAL_IMAGE_SIZE: raise error.InvalidQueryError( message= 'File %s is larger than the limit of %d megabytes' % (file_to_upload.name, self.bytes_to_mb(MAX_LOCAL_IMAGE_SIZE))) return requests.request( method, endpoint, **{ 'headers': headers, 'files': files, 'data': data }) else: return requests.request(method, endpoint, **{ 'headers': headers, 'data': data }) except IOError as e: raise e except error.InvalidQueryError as e: raise e except Exception as e: raise error.APIConnectionError(message=e)