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.
- rapidata/__init__.py +0 -0
- rapidata/rapidata_client/__init__.py +1 -0
- rapidata/rapidata_client/order/__init__.py +0 -0
- rapidata/rapidata_client/order/dataset/__init__.py +0 -0
- rapidata/rapidata_client/order/dataset/rapidata_dataset.py +26 -0
- rapidata/rapidata_client/order/rapidata_order.py +71 -0
- rapidata/rapidata_client/order/rapidata_order_builder.py +52 -0
- rapidata/rapidata_client/rapidata_client.py +34 -0
- rapidata/rapidata_client/workflow/__init__.py +6 -0
- rapidata/rapidata_client/workflow/base_workflow.py +35 -0
- rapidata/rapidata_client/workflow/classify_workflow.py +19 -0
- rapidata/rapidata_client/workflow/compare_workflow.py +30 -0
- rapidata/rapidata_client/workflow/country_codes/__init__.py +1 -0
- rapidata/rapidata_client/workflow/country_codes/country_codes.py +19 -0
- rapidata/rapidata_client/workflow/feature_flags/__init__.py +1 -0
- rapidata/rapidata_client/workflow/feature_flags/feature_flags.py +20 -0
- rapidata/rapidata_client/workflow/free_text_workflow.py +17 -0
- rapidata/rapidata_client/workflow/referee/__init__.py +3 -0
- rapidata/rapidata_client/workflow/referee/base_referee.py +14 -0
- rapidata/rapidata_client/workflow/referee/classify_early_stopping_referee.py +20 -0
- rapidata/rapidata_client/workflow/referee/naive_referee.py +18 -0
- rapidata/service/__init__.py +2 -0
- rapidata/service/local_file_service.py +25 -0
- rapidata/service/rapidata_api_services/__init__.py +0 -0
- rapidata/service/rapidata_api_services/base_service.py +76 -0
- rapidata/service/rapidata_api_services/dataset_service.py +82 -0
- rapidata/service/rapidata_api_services/order_service.py +49 -0
- rapidata/service/rapidata_api_services/rapidata_service.py +18 -0
- rapidata/utils/__init__.py +0 -0
- rapidata/utils/image_utils.py +13 -0
- rapidata-0.1.0.dist-info/LICENSE +201 -0
- rapidata-0.1.0.dist-info/METADATA +18 -0
- rapidata-0.1.0.dist-info/RECORD +34 -0
- 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 @@
|
|
|
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,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,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,,
|