rapidata 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. rapidata/__init__.py +0 -0
  2. rapidata/rapidata_client/__init__.py +1 -0
  3. rapidata/rapidata_client/order/__init__.py +0 -0
  4. rapidata/rapidata_client/order/dataset/__init__.py +0 -0
  5. rapidata/rapidata_client/order/dataset/rapidata_dataset.py +26 -0
  6. rapidata/rapidata_client/order/rapidata_order.py +71 -0
  7. rapidata/rapidata_client/order/rapidata_order_builder.py +52 -0
  8. rapidata/rapidata_client/rapidata_client.py +34 -0
  9. rapidata/rapidata_client/workflow/__init__.py +6 -0
  10. rapidata/rapidata_client/workflow/base_workflow.py +35 -0
  11. rapidata/rapidata_client/workflow/classify_workflow.py +19 -0
  12. rapidata/rapidata_client/workflow/compare_workflow.py +30 -0
  13. rapidata/rapidata_client/workflow/country_codes/__init__.py +1 -0
  14. rapidata/rapidata_client/workflow/country_codes/country_codes.py +19 -0
  15. rapidata/rapidata_client/workflow/feature_flags/__init__.py +1 -0
  16. rapidata/rapidata_client/workflow/feature_flags/feature_flags.py +20 -0
  17. rapidata/rapidata_client/workflow/free_text_workflow.py +17 -0
  18. rapidata/rapidata_client/workflow/referee/__init__.py +3 -0
  19. rapidata/rapidata_client/workflow/referee/base_referee.py +14 -0
  20. rapidata/rapidata_client/workflow/referee/classify_early_stopping_referee.py +20 -0
  21. rapidata/rapidata_client/workflow/referee/naive_referee.py +18 -0
  22. rapidata/service/__init__.py +2 -0
  23. rapidata/service/local_file_service.py +25 -0
  24. rapidata/service/rapidata_api_services/__init__.py +0 -0
  25. rapidata/service/rapidata_api_services/base_service.py +76 -0
  26. rapidata/service/rapidata_api_services/dataset_service.py +82 -0
  27. rapidata/service/rapidata_api_services/order_service.py +49 -0
  28. rapidata/service/rapidata_api_services/rapidata_service.py +18 -0
  29. rapidata/utils/__init__.py +0 -0
  30. rapidata/utils/image_utils.py +13 -0
  31. rapidata-0.1.0.dist-info/LICENSE +201 -0
  32. rapidata-0.1.0.dist-info/METADATA +18 -0
  33. rapidata-0.1.0.dist-info/RECORD +34 -0
  34. rapidata-0.1.0.dist-info/WHEEL +4 -0
rapidata/__init__.py ADDED
File without changes
@@ -0,0 +1 @@
1
+ from .rapidata_client import RapidataClient as RapidataClient
File without changes
File without changes
@@ -0,0 +1,26 @@
1
+ import os
2
+ from rapidata.service import LocalFileService
3
+ from rapidata.service import RapidataService
4
+
5
+
6
+ class RapidataDataset:
7
+
8
+ def __init__(self, dataset_id: str, rapidata_service: RapidataService):
9
+ self.dataset_id = dataset_id
10
+ self.rapidata_service = rapidata_service
11
+ self.local_file_service = LocalFileService()
12
+
13
+ def add_texts(self, texts: list[str]):
14
+ self.rapidata_service.dataset.upload_text_sources(self.dataset_id, texts)
15
+
16
+ def add_images_from_paths(self, image_paths: list[str]):
17
+ image_names = [os.path.basename(image_path) for image_path in image_paths]
18
+ images = self.local_file_service.load_images(image_paths)
19
+
20
+ self.rapidata_service.dataset.upload_images(self.dataset_id, images, image_names)
21
+
22
+ def add_videos_from_paths(self, video_paths: list[str]):
23
+ video_names = [os.path.basename(video_path) for video_path in video_paths]
24
+ videos = self.local_file_service.load_videos(video_paths)
25
+
26
+ self.rapidata_service.dataset.upload_videos(self.dataset_id, videos, video_names)
@@ -0,0 +1,71 @@
1
+ from rapidata.rapidata_client.order.dataset.rapidata_dataset import RapidataDataset
2
+ from rapidata.rapidata_client.workflow import Workflow
3
+ from rapidata.service import RapidataService
4
+
5
+
6
+ class RapidataOrder:
7
+ """
8
+ Represents a Rapidata order.
9
+
10
+ :param name: The name of the order.
11
+ :type name: str
12
+ :param workflow: The workflow associated with the order.
13
+ :type workflow: Workflow
14
+ :param rapidata_service: The Rapidata service used to create and manage the order.
15
+ :type rapidata_service: RapidataService
16
+ """
17
+
18
+ def __init__(
19
+ self, name: str, workflow: Workflow, rapidata_service: RapidataService
20
+ ):
21
+ self.name = name
22
+ self.workflow = workflow
23
+ self.rapidata_service = rapidata_service
24
+ self.order_id = None
25
+ self._dataset = None
26
+
27
+ def create(self):
28
+ """
29
+ Creates the order using the provided name and workflow.
30
+
31
+ :return: The created RapidataOrder instance.
32
+ :rtype: RapidataOrder
33
+ """
34
+ self.order_id, dataset_id = self.rapidata_service.order.create_order(self.name, self.workflow.to_dict())
35
+ self._dataset = RapidataDataset(dataset_id, self.rapidata_service)
36
+ return self
37
+
38
+ def submit(self):
39
+ """
40
+ Submits the order for processing.
41
+
42
+ :raises ValueError: If the order has not been created.
43
+ """
44
+ if self.order_id is None:
45
+ raise ValueError("You must create the order before submitting it.")
46
+
47
+ self.rapidata_service.order.submit(self.order_id)
48
+
49
+ def approve(self):
50
+ """
51
+ Approves the order for execution.
52
+
53
+ :raises ValueError: If the order has not been created.
54
+ """
55
+ if self.order_id is None:
56
+ raise ValueError("You must create the order before approving it.")
57
+
58
+ self.rapidata_service.order.approve(self.order_id)
59
+
60
+ @property
61
+ def dataset(self):
62
+ """
63
+ The dataset associated with the order.
64
+
65
+ :raises ValueError: If the order has not been submitted.
66
+ :return: The RapidataDataset instance.
67
+ :rtype: RapidataDataset
68
+ """
69
+ if self._dataset is None:
70
+ raise ValueError("You must submit the order before accessing the dataset.")
71
+ return self._dataset
@@ -0,0 +1,52 @@
1
+ from rapidata.rapidata_client.workflow import Workflow
2
+ from rapidata.rapidata_client.order.rapidata_order import RapidataOrder
3
+ from rapidata.service import RapidataService
4
+
5
+
6
+ class RapidataOrderBuilder:
7
+ """
8
+ Builder object for creating Rapidata orders.
9
+
10
+ Use the fluent interface to set the desired configuration. Add a workflow to the order using `.workflow()` and finally call `.create()` to create the order.
11
+
12
+ :param rapidata_service: The RapidataService instance.
13
+ :type rapidata_service: RapidataService
14
+ :param name: The name of the order.
15
+ :type name: str
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ rapidata_service: RapidataService,
21
+ name: str,
22
+ ):
23
+ self._name = name
24
+ self._rapidata_service = rapidata_service
25
+ self._workflow: Workflow | None = None
26
+
27
+ def create(self) -> RapidataOrder:
28
+ """
29
+ Create a RapidataOrder instance based on the configured settings.
30
+
31
+ :return: The created RapidataOrder instance.
32
+ :rtype: RapidataOrder
33
+ :raises ValueError: If no workflow is provided.
34
+ """
35
+ if self._workflow is None:
36
+ raise ValueError("You must provide a blueprint to create an order.")
37
+
38
+ return RapidataOrder(
39
+ name=self._name, workflow=self._workflow, rapidata_service=self._rapidata_service
40
+ ).create()
41
+
42
+ def workflow(self, workflow: Workflow):
43
+ """
44
+ Set the workflow for the order.
45
+
46
+ :param workflow: The workflow to be set.
47
+ :type workflow: Workflow
48
+ :return: The updated RapidataOrderBuilder instance.
49
+ :rtype: RapidataOrderBuilder
50
+ """
51
+ self._workflow = workflow
52
+ return self
@@ -0,0 +1,34 @@
1
+ from rapidata.rapidata_client.order.rapidata_order_builder import RapidataOrderBuilder
2
+ from rapidata.service import RapidataService
3
+
4
+
5
+ class RapidataClient:
6
+ """
7
+ A client for interacting with the Rapidata API.
8
+ """
9
+
10
+ def __init__(
11
+ self,
12
+ client_id: str,
13
+ client_secret: str,
14
+ endpoint: str = "https://api.rapidata.ai",
15
+ ):
16
+ """
17
+ Initialize the RapidataClient.
18
+
19
+ :param client_id: The client ID for authentication.
20
+ :param client_secret: The client secret for authentication.
21
+ :param endpoint: The API endpoint URL. Defaults to "https://api.rapidata.ai".
22
+ """
23
+ self._rapidata_service = RapidataService(
24
+ client_id=client_id, client_secret=client_secret, endpoint=endpoint
25
+ )
26
+
27
+ def new_order(self, name: str) -> RapidataOrderBuilder:
28
+ """
29
+ Create a new order using a RapidataOrderBuilder instance.
30
+
31
+ :param name: The name of the order.
32
+ :return: A RapidataOrderBuilder instance.
33
+ """
34
+ return RapidataOrderBuilder(rapidata_service=self._rapidata_service, name=name)
@@ -0,0 +1,6 @@
1
+ from .base_workflow import Workflow as Workflow
2
+ from .classify_workflow import ClassifyWorkflow as ClassifyWorkflow
3
+ from .compare_workflow import CompareWorkflow as CompareWorkflow
4
+ from .free_text_workflow import FreeTextWorkflow as FreeTextWorkflow
5
+ from .feature_flags import FeatureFlags as FeatureFlags
6
+ from .country_codes import CountryCodes as CountryCodes
@@ -0,0 +1,35 @@
1
+ from abc import ABC
2
+ from typing import Any
3
+
4
+ from rapidata.rapidata_client.workflow.feature_flags import FeatureFlags
5
+ from rapidata.rapidata_client.workflow.referee.base_referee import Referee
6
+ from rapidata.rapidata_client.workflow.referee.naive_referee import NaiveReferee
7
+
8
+
9
+ class Workflow(ABC):
10
+
11
+ def __init__(self, type: str):
12
+ self._type = type
13
+ self._referee = NaiveReferee()
14
+ self._target_country_codes: list[str] = []
15
+ self._feature_flags: FeatureFlags = FeatureFlags()
16
+
17
+ def to_dict(self) -> dict[str, Any]:
18
+ return {
19
+ "_t": self._type,
20
+ "referee": self._referee.to_dict(),
21
+ "targetCountryCodes": self._target_country_codes,
22
+ "featureFlags": self._feature_flags.to_list(),
23
+ }
24
+
25
+ def referee(self, referee: Referee):
26
+ self._referee = referee
27
+ return self
28
+
29
+ def target_country_codes(self, target_country_codes: list[str]):
30
+ self._target_country_codes = target_country_codes
31
+ return self
32
+
33
+ def feature_flags(self, feature_flags: FeatureFlags):
34
+ self._feature_flags = feature_flags
35
+ return self
@@ -0,0 +1,19 @@
1
+ from typing import Any
2
+ from rapidata.rapidata_client.workflow import Workflow
3
+
4
+
5
+ class ClassifyWorkflow(Workflow):
6
+ def __init__(self, question: str, categories: list[str]):
7
+ super().__init__(type="SimpleWorkflowConfig")
8
+ self._question = question
9
+ self._categories = categories
10
+
11
+ def to_dict(self) -> dict[str, Any]:
12
+ return {
13
+ **super().to_dict(),
14
+ "blueprint": {
15
+ "_t": "ClassifyBlueprint",
16
+ "title": self._question,
17
+ "possibleCategories": self._categories,
18
+ }
19
+ }
@@ -0,0 +1,30 @@
1
+ from typing import Any
2
+ from rapidata.rapidata_client.workflow import Workflow
3
+
4
+
5
+ class CompareWorkflow(Workflow):
6
+ def __init__(self, criteria: str):
7
+ super().__init__(type="CompareWorkflowConfig")
8
+ self._criteria = criteria
9
+ self._k_factor = 40
10
+ self._match_size = 2
11
+ self._matches_until_completed = 10
12
+
13
+ def to_dict(self) -> dict[str, Any]:
14
+ return {
15
+ **super().to_dict(),
16
+ "criteria": self._criteria,
17
+ }
18
+
19
+ def k_factor(self, k_factor: int):
20
+ self._k_factor = k_factor
21
+ return self
22
+
23
+ def match_size(self, match_size: int):
24
+ self._match_size = match_size
25
+ return self
26
+
27
+ def matches_until_completed(self, matches_until_completed: int):
28
+ self._matches_until_completed = matches_until_completed
29
+ return self
30
+
@@ -0,0 +1 @@
1
+ from .country_codes import CountryCodes as CountryCodes
@@ -0,0 +1,19 @@
1
+ class CountryCodes:
2
+
3
+ ENGLISH_SPEAKING = [
4
+ "AU",
5
+ "BE",
6
+ "CA",
7
+ "DK",
8
+ "FI",
9
+ "IE",
10
+ "LU",
11
+ "NL",
12
+ "NZ",
13
+ "NO",
14
+ "SG",
15
+ "SE",
16
+ "GB",
17
+ "US",
18
+ ]
19
+ GERMAN_SPEAKING = (["AT", "DE"],)
@@ -0,0 +1 @@
1
+ from .feature_flags import FeatureFlags as FeatureFlags
@@ -0,0 +1,20 @@
1
+ class FeatureFlags:
2
+ def __init__(self):
3
+ self._flags: dict[str, str] = {}
4
+
5
+ def to_list(self) -> list[dict[str, str]]:
6
+ # transform dict of flags to list of flags
7
+ return [{"key": name, "value": value} for name, value in self._flags.items()]
8
+
9
+ def alert_on_fast_response(self, value: int):
10
+ self._flags["alertOnFastResponse"] = str(value)
11
+ return self
12
+
13
+ def disable_translation(self, value: bool):
14
+ self._flags["disableTranslation"] = str(value)
15
+ return self
16
+
17
+ def free_text_minimum_characters(self, value: int):
18
+ self._flags["freeTextMinimumCharacters"] = str(value)
19
+ return self
20
+
@@ -0,0 +1,17 @@
1
+ from typing import Any
2
+ from rapidata.rapidata_client.workflow import Workflow
3
+
4
+
5
+ class FreeTextWorkflow(Workflow):
6
+ def __init__(self, question: str):
7
+ super().__init__(type="SimpleWorkflowConfig")
8
+ self._question = question
9
+
10
+ def to_dict(self) -> dict[str, Any]:
11
+ return {
12
+ **super().to_dict(),
13
+ "blueprint": {
14
+ "_t": "FreeTextBlueprint",
15
+ "question": self._question,
16
+ },
17
+ }
@@ -0,0 +1,3 @@
1
+ from .base_referee import Referee as Referee
2
+ from .naive_referee import NaiveReferee as NaiveReferee
3
+ from .classify_early_stopping_referee import ClassifyEarlyStoppingReferee as ClassifyEarlyStoppingReferee
@@ -0,0 +1,14 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Mapping
3
+
4
+
5
+ class Referee(ABC):
6
+ """
7
+ The referee defines when a rapid is considered complete.
8
+ """
9
+ @abstractmethod
10
+ def to_dict(self) -> Mapping[str, str | int | float]:
11
+ """
12
+ Convert the referee to a referee configuration dict.
13
+ """
14
+ pass
@@ -0,0 +1,20 @@
1
+ from rapidata.rapidata_client.workflow.referee.base_referee import Referee
2
+
3
+
4
+ class ClassifyEarlyStoppingReferee(Referee):
5
+ """
6
+ The referee defines when a task is considered complete.
7
+ The EarlyStoppingReferee stops the task when the confidence in the winning category is above a threshold.
8
+ The threshold behaves logarithmically, i.e. if 0.99 stops too early, try 0.999 or 0.9999.
9
+ """
10
+
11
+ def __init__(self, threshold: float = 0.999, max_vote_count: int = 100):
12
+ self.threshold = threshold
13
+ self.max_vote_count = max_vote_count
14
+
15
+ def to_dict(self):
16
+ return {
17
+ "_t": "ProbabilisticAttachCategoryRefereeConfig",
18
+ "threshold": self.threshold,
19
+ "maxVotes": self.max_vote_count,
20
+ }
@@ -0,0 +1,18 @@
1
+ from rapidata.rapidata_client.workflow.referee.base_referee import Referee
2
+
3
+
4
+ class NaiveReferee(Referee):
5
+ """
6
+ The referee defines when a task is considered complete.
7
+ The SimpleReferee is the simplest referee, requiring a fixed number of guesses.
8
+ """
9
+
10
+ def __init__(self, required_guesses: int = 10):
11
+ super().__init__()
12
+ self.required_guesses = required_guesses
13
+
14
+ def to_dict(self):
15
+ return {
16
+ "_t": "NaiveRefereeConfig",
17
+ "guessesRequired": self.required_guesses,
18
+ }
@@ -0,0 +1,2 @@
1
+ from .rapidata_api_services.rapidata_service import RapidataService as RapidataService
2
+ from .local_file_service import LocalFileService as LocalFileService
@@ -0,0 +1,25 @@
1
+ import os
2
+ from PIL import Image
3
+
4
+ class LocalFileService:
5
+
6
+ def load_image(self, image_path: str) -> Image.Image:
7
+ self.check_file_exists(image_path)
8
+ return Image.open(image_path)
9
+
10
+ def load_images(self, image_paths: list[str]) -> list[Image.Image]:
11
+ return [self.load_image(image_path) for image_path in image_paths]
12
+
13
+ def load_video(self, video_path: str):
14
+ self.check_file_exists(video_path)
15
+ return open(video_path, 'rb')
16
+
17
+ def load_videos(self, video_paths: list[str]):
18
+ return [self.load_video(video_path) for video_path in video_paths]
19
+
20
+ def _file_exists(self, file_path: str) -> bool:
21
+ return os.path.exists(file_path)
22
+
23
+ def check_file_exists(self, file_path: str):
24
+ if not self._file_exists(file_path):
25
+ raise FileNotFoundError(f"File {file_path} not found.")
File without changes
@@ -0,0 +1,76 @@
1
+ from datetime import datetime, timedelta
2
+ from typing import Any
3
+ import jwt
4
+ import requests
5
+
6
+
7
+ class BaseRapidataAPIService:
8
+
9
+ def __init__(self, client_id: str, client_secret: str, endpoint: str):
10
+ self.client_id = client_id
11
+ self.client_secret = client_secret
12
+ self.endpoint = endpoint
13
+ self.auth_header = None
14
+ self.token = self._get_auth_token()
15
+
16
+ def _check_response(self, response: requests.Response):
17
+ if response.status_code != 200:
18
+ raise Exception(f"Error: {response.status_code} - {response.text}")
19
+
20
+ def _get_new_auth_token_if_outdated(self):
21
+ if not self.token or not self._is_token_valid():
22
+ self._get_auth_token()
23
+
24
+ def _is_token_valid(self, expiration_threshold: timedelta = timedelta(minutes=5)):
25
+ try:
26
+ payload = jwt.decode(self.token, options={"verify_signature": False}) # type: ignore
27
+ exp_timestamp = payload.get("exp")
28
+ if exp_timestamp:
29
+ expiration_time = datetime.fromtimestamp(exp_timestamp)
30
+ return datetime.now() + expiration_threshold <= expiration_time
31
+ except jwt.DecodeError:
32
+ return False
33
+ return False
34
+
35
+ def _get_auth_token(self):
36
+ url = f"{self.endpoint}/Identity/GetClientAuthToken"
37
+ params = {
38
+ "clientId": self.client_id,
39
+ }
40
+ headers = {"Authorization": f"Basic {self.client_secret}"}
41
+ response = requests.post(url, params=params, headers=headers)
42
+ self._check_response(response)
43
+ self.token = response.json().get("authToken")
44
+ if not self.token:
45
+ raise Exception("No token received")
46
+ self.auth_header = {"Authorization": f"Bearer {self.token}"}
47
+
48
+ def _post(
49
+ self,
50
+ url: str,
51
+ params: dict[str, Any] | None = None,
52
+ data: dict[str, Any] | None = None,
53
+ json: dict[str, Any] | None = None,
54
+ files: Any | None = None,
55
+ ):
56
+ self._get_new_auth_token_if_outdated()
57
+ response = requests.post(
58
+ url,
59
+ params=params,
60
+ data=data,
61
+ json=json,
62
+ files=files,
63
+ headers=self.auth_header,
64
+ )
65
+ self._check_response(response)
66
+ return response
67
+
68
+ def _get(
69
+ self,
70
+ url: str,
71
+ params: dict[str, Any] | None = None,
72
+ ):
73
+ self._get_new_auth_token_if_outdated()
74
+ response = requests.get(url, params=params, headers=self.auth_header)
75
+ self._check_response(response)
76
+ return response
@@ -0,0 +1,82 @@
1
+ from io import BufferedReader
2
+ from PIL import Image
3
+ from rapidata.service.rapidata_api_services.base_service import BaseRapidataAPIService
4
+ from rapidata.utils.image_utils import ImageUtils
5
+
6
+
7
+ class DatasetService(BaseRapidataAPIService):
8
+ def __init__(self, client_id: str, client_secret: str, endpoint: str):
9
+ super().__init__(
10
+ client_id=client_id, client_secret=client_secret, endpoint=endpoint
11
+ )
12
+
13
+ def upload_text_sources(self, dataset_id: str, text_sources: list[str]):
14
+ url = f"{self.endpoint}/Dataset/UploadTextSourcesToDataset"
15
+ payload = {"datasetId": dataset_id, "textSources": text_sources}
16
+
17
+ response = self._post(url, json=payload)
18
+
19
+ return response
20
+
21
+ def upload_images(
22
+ self, dataset_id: str, images: list[Image.Image], image_names: list[str]
23
+ ):
24
+ url = f"{self.endpoint}/Dataset/UploadImagesToDataset"
25
+
26
+ params = {"datasetId": dataset_id}
27
+
28
+ images_bytes: list[bytes] = [
29
+ ImageUtils.convert_PIL_image_to_bytes(image) for image in images
30
+ ]
31
+
32
+ files = [
33
+ ("files", (image_name, image_bytes))
34
+ for image_name, image_bytes in zip(image_names, images_bytes)
35
+ ]
36
+
37
+ response = self._post(url, params=params, files=files)
38
+
39
+ return response
40
+
41
+ def upload_videos(
42
+ self, dataset_id: str, videos: list[BufferedReader], video_names: list[str]
43
+ ):
44
+ url = f"{self.endpoint}/Dataset/UploadImagesToDataset"
45
+
46
+ params = {"datasetId": dataset_id}
47
+
48
+ files = [
49
+ ("files", (video_name, video_bytes))
50
+ for video_name, video_bytes in zip(video_names, videos)
51
+ ]
52
+
53
+ response = self._post(url, params=params, files=files)
54
+
55
+ return response
56
+
57
+ def upload_images_from_s3(
58
+ self,
59
+ dataset_id: str,
60
+ bucket_name: str,
61
+ region: str,
62
+ source_prefix: str,
63
+ access_key: str,
64
+ secret_key: str,
65
+ clear_dataset: bool = True,
66
+ ):
67
+ url = f"{self.endpoint}/Dataset/UploadFilesFromS3"
68
+
69
+ payload = {
70
+ "datasetId": dataset_id,
71
+ "bucketName": bucket_name,
72
+ "region": region,
73
+ "sourcePrefix": source_prefix,
74
+ "accessKey": access_key,
75
+ "secretKey": secret_key,
76
+ "useCustomAwsCredentials": True,
77
+ "clearDataset": clear_dataset,
78
+ }
79
+
80
+ response = self._post(url, json=payload)
81
+
82
+ return response
@@ -0,0 +1,49 @@
1
+
2
+ from typing import Any
3
+ from rapidata.service.rapidata_api_services.base_service import BaseRapidataAPIService
4
+
5
+
6
+ class OrderService(BaseRapidataAPIService):
7
+ def __init__(self, client_id: str, client_secret: str, endpoint: str):
8
+ super().__init__(
9
+ client_id=client_id, client_secret=client_secret, endpoint=endpoint
10
+ )
11
+
12
+ def create_order(self, name: str, workflow_config: dict[str, Any]) -> tuple[str, str]:
13
+ """
14
+ order_name: name of the order that will be displayed in the Rapidata dashboard.
15
+ question: The question shown to the labeler in the rapid.
16
+ categories: The answer options, between which the labeler can choose.
17
+ target_country_codes: A list of two digit target country codes.
18
+ disable_translation: Per default, the question and categories get translated with DeepL (or Google Translate, if DeepL doesn't support a language). By setting this to `True`, the translation is disabled.
19
+ referee: The referee determines when the task is done. See above for the options.
20
+ """
21
+ url = f"{self.endpoint}/Order/CreateDefaultOrder"
22
+
23
+ payload = {
24
+ "orderName": name,
25
+ "datasetName": f"{name} dataset",
26
+ "isPublic": False,
27
+ "workflowConfig": workflow_config,
28
+ "aggregatorType": "Classification",
29
+ }
30
+
31
+ response = self._post(url, json=payload)
32
+
33
+ return response.json()["orderId"], response.json()["datasetId"]
34
+
35
+ def submit(self, order_id: str):
36
+ url = f"{self.endpoint}/Order/Submit"
37
+ params = {"orderId": order_id}
38
+
39
+ submit_response = self._post(url, params=params)
40
+
41
+ return submit_response
42
+
43
+ def approve(self, order_id: str):
44
+ url = f"{self.endpoint}/Order/Approve"
45
+ params = {"orderId": order_id}
46
+
47
+ approve_response = self._post(url, params=params)
48
+
49
+ return approve_response
@@ -0,0 +1,18 @@
1
+ from rapidata.service.rapidata_api_services.base_service import BaseRapidataAPIService
2
+ from rapidata.service.rapidata_api_services.dataset_service import DatasetService
3
+ from rapidata.service.rapidata_api_services.order_service import OrderService
4
+
5
+
6
+ class RapidataService(BaseRapidataAPIService):
7
+ def __init__(self, client_id: str, client_secret: str, endpoint: str):
8
+ super().__init__(client_id, client_secret, endpoint)
9
+ self._order_service = OrderService(client_id, client_secret, endpoint)
10
+ self._dataset_service = DatasetService(client_id, client_secret, endpoint)
11
+
12
+ @property
13
+ def order(self):
14
+ return self._order_service
15
+
16
+ @property
17
+ def dataset(self):
18
+ return self._dataset_service
File without changes
@@ -0,0 +1,13 @@
1
+ from io import BytesIO
2
+ import PIL.Image as Image
3
+
4
+ class ImageUtils:
5
+
6
+ @staticmethod
7
+ def convert_PIL_image_to_bytes(image: Image.Image):
8
+ """
9
+ Convert a PIL image to bytes with meta data encoded. We can't just use image.tobytes() because this only returns the pixel data.
10
+ """
11
+ buffer = BytesIO()
12
+ image.save(buffer, image.format)
13
+ return buffer.getvalue()
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: rapidata
3
+ Version: 0.1.0
4
+ Summary: Rapidata package containing the Rapidata Python Client to interact with the Rapidata Web API in an easy way.
5
+ License: Apache-2.0
6
+ Author: Marian Kannwischer
7
+ Author-email: marian.kannwischer@t-online.de
8
+ Requires-Python: >=3.12,<4.0
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Requires-Dist: PyJWT (>=2.9.0,<3.0.0)
13
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
14
+ Description-Content-Type: text/markdown
15
+
16
+ # rapidata-python
17
+ Python client to interface with the Rapidata API
18
+
@@ -0,0 +1,34 @@
1
+ rapidata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ rapidata/rapidata_client/__init__.py,sha256=S34OtjhVlHBYmruPZHpJ5C-pVflCHPwj7FHwhMN-YyY,61
3
+ rapidata/rapidata_client/order/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ rapidata/rapidata_client/order/dataset/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ rapidata/rapidata_client/order/dataset/rapidata_dataset.py,sha256=Nk5v0VBHM6j8V_7boh-tUgjxBL4i8OiX5VRyYRCqtaI,1071
6
+ rapidata/rapidata_client/order/rapidata_order.py,sha256=1FV1PtDdkWX2J12_d1Z5M-8-yXC2oXaxCn2un_yxaq8,2269
7
+ rapidata/rapidata_client/order/rapidata_order_builder.py,sha256=DTDGmT0RywkSU8r7wfAfOgkVGPnroROIFkNg4L1_2ls,1699
8
+ rapidata/rapidata_client/rapidata_client.py,sha256=I1s9ZCghxUvU5iZl_m9QBR8HJoNi92XhStXMED7smPc,1119
9
+ rapidata/rapidata_client/workflow/__init__.py,sha256=-xbTGFPdJH7SgTvJsGqHHjB3GFZOQyKH3amfcI4NVmA,362
10
+ rapidata/rapidata_client/workflow/base_workflow.py,sha256=wMAL4WTSvdpgqmcbtVAijzHg7p5okPU_6BePRhIQN6U,1151
11
+ rapidata/rapidata_client/workflow/classify_workflow.py,sha256=jzwhShNmvF_fEmKY82krhKK0ega-NFwrc8gcds90m5c,585
12
+ rapidata/rapidata_client/workflow/compare_workflow.py,sha256=4oB8GfFycJ72WMiYcgJaExLIeGSchU_LMoao3Wko00U,850
13
+ rapidata/rapidata_client/workflow/country_codes/__init__.py,sha256=Y8qeG2IMjvMGvhaPydq0nhwRQHb6dQqilctlEXu0_PE,55
14
+ rapidata/rapidata_client/workflow/country_codes/country_codes.py,sha256=Q0HMX7uHJQDeLCFPP5bq4iYi6pgcDWEcl2ONGhjgoeU,286
15
+ rapidata/rapidata_client/workflow/feature_flags/__init__.py,sha256=BNG_NQ4CrrC61fAWliImr8r581pIvegrkepVVbxcBw8,55
16
+ rapidata/rapidata_client/workflow/feature_flags/feature_flags.py,sha256=BqMwL2p8Da3woa4BjGbzB3tYh3xTDyjkwQip0NE87sk,676
17
+ rapidata/rapidata_client/workflow/free_text_workflow.py,sha256=96Jb4jC-iQtl0AGTyC9BkM64qjsKyzMoKXfMGaydExg,472
18
+ rapidata/rapidata_client/workflow/referee/__init__.py,sha256=x0AxGCsR6TlDjfqQ00lB9V7QVS9EZCJzweNEIzx42PI,207
19
+ rapidata/rapidata_client/workflow/referee/base_referee.py,sha256=JE5EIh7fva3CBMGQ6WcstP-llK1LD9TQLsaycvfZ4-k,338
20
+ rapidata/rapidata_client/workflow/referee/classify_early_stopping_referee.py,sha256=7nvf9gdPmjpR9c_RcC_2G1QFI1Q8TwLNJpJF8KOG_BU,759
21
+ rapidata/rapidata_client/workflow/referee/naive_referee.py,sha256=vLevsNBwKtCklUBABYUf54E7jixPYr1SbNGroCuwAu4,540
22
+ rapidata/service/__init__.py,sha256=2y7otliX28HSkZpHRnIaN_fO8ETUbooevdlZH4AF-YQ,155
23
+ rapidata/service/local_file_service.py,sha256=pgorvlWcx52Uh3cEG6VrdMK_t__7dacQ_5AnfY14BW8,877
24
+ rapidata/service/rapidata_api_services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ rapidata/service/rapidata_api_services/base_service.py,sha256=VwYHv8ted3NQtCrLUZ5_r4v7Vxt_IetRHTvh4ybWS10,2568
26
+ rapidata/service/rapidata_api_services/dataset_service.py,sha256=fT5IV_lD35gPKmRaXTYcOZ71TDv3Koyb5FKtK2fwLLA,2480
27
+ rapidata/service/rapidata_api_services/order_service.py,sha256=gytLUflH7fcOvH616TFJrHYs-hFpoGYn4HpIu8m-qlw,1919
28
+ rapidata/service/rapidata_api_services/rapidata_service.py,sha256=AvYMxjwgZHyQPMeqq_IKpmQX-NH_7yuWUyQjU_cJmAs,740
29
+ rapidata/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ rapidata/utils/image_utils.py,sha256=TldO3eJWG8IhfJjm5MfNGO0mEDm1mQTsRoA0HLU1Uxs,404
31
+ rapidata-0.1.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
32
+ rapidata-0.1.0.dist-info/METADATA,sha256=u4iDZRc_io5u2vkRo3KX__FT0F4X8q22iDBpS0SCJ5k,642
33
+ rapidata-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
34
+ rapidata-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any