socaity 0.0.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.
socaity/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ # includes clientAPIs and simple APIs
2
+ from socaity.api import *
3
+ from socaity.core import Job, ClientAPI, create_client
@@ -0,0 +1,18 @@
1
+ """
2
+ The references to ClientAPIs and SimpleAPIs
3
+
4
+ # CLIENT APIs
5
+ A ClientAPI is a class that contains the logic to pre and post_process a request to an endpoint.
6
+ It is a wrapper around the client and job classes.
7
+ Instead of using clients and jobs directly, you can use the predefined "model" ClientAPI classes to do the work.
8
+
9
+ # SIMPLE APIs
10
+ A SimpleAPI is a wrapper around a ClientAPI.
11
+ It initiates the ClientAPI with the correct endpoint and model name, and provides a simple function to run the job.
12
+
13
+ """
14
+ # Defined ClientAPIs
15
+ from .audio import *
16
+
17
+ # This references to all simple api functions
18
+ from .simple_api import *
@@ -0,0 +1 @@
1
+ from .bark import Bark
@@ -0,0 +1,89 @@
1
+ from typing import Union
2
+
3
+ from socaity.core.job import Job
4
+ from socaity.core.client_api import ClientAPI
5
+ from socaity.globals import ModelType, EndPointType
6
+ from socaity.utils.audio import audio_from_bytes
7
+ from socaity.utils.utils import get_function_parameters_as_dict
8
+
9
+
10
+ class Bark(ClientAPI):
11
+ """
12
+ With Bark (adapted by socAIty) you can:
13
+ - Convert text to natural sounding speech with predefined speakers in 100+ languages.
14
+ - Clone voices by creating embeddings from audio files
15
+ - Convert voice2voice aka voice cloning
16
+
17
+ For available speakers visit:
18
+ - Official page of suno: https://suno-ai.notion.site/8b8e8749ed514b0cbf3f699013548683?v=bc67cff786b04b50b3ceb756fd05f68c
19
+ - For other speakers visit the socaity references.
20
+
21
+ Bark is developed by Suno.ai. With this client you interact with the Bark adaptation of socAIty.
22
+ For the repos visit: https://github.com/SocAIty/BarkVoiceCloneREST
23
+ """
24
+ def __init__(self, endpoint_type: Union[EndPointType, str] = EndPointType.REMOTE):
25
+ super().__init__(
26
+ model_type=ModelType.TEXT2VOICE,
27
+ model_name="bark",
28
+ endpoint_type=endpoint_type
29
+ )
30
+
31
+ def validate_params(
32
+ self,
33
+ text: str | list,
34
+ voice_name_or_embedding_path: str = "en_speaker_3",
35
+ *args, **kwargs) -> (bool, str):
36
+ """
37
+ Method is executed before a job is created.
38
+ Returns True if the parameters are valid, otherwise False.
39
+ """
40
+ return True, None
41
+
42
+ def _pre_process(self, text: str | list, *args, **kwargs):
43
+ # add text again to args
44
+ _kwargs = get_function_parameters_as_dict(self.run, locals(), kwargs)
45
+
46
+ # attempt to make it batched.
47
+ if isinstance(text, str):
48
+ _kwargs["text"] = [text]
49
+
50
+ return _kwargs
51
+
52
+ def _post_process(self, result, *args, **kwargs):
53
+ return audio_from_bytes(result, save_file_path=None)
54
+
55
+ def __call__(
56
+ self,
57
+ text: str | list,
58
+ voice_name_or_embedding_path: str = "en_speaker_3",
59
+ semantic_temp=0.7,
60
+ semantic_top_k=50,
61
+ semantic_top_p=0.95,
62
+ coarse_temp=0.7,
63
+ coarse_top_k=50,
64
+ coarse_top_p=0.95,
65
+ fine_temp=0.5,
66
+ **kwargs
67
+ ):
68
+ # just reuse args to easy pass them to super
69
+ _kwargs = get_function_parameters_as_dict(self.run, locals(), kwargs)
70
+
71
+ return super().__call__(**_kwargs)
72
+
73
+ def run(
74
+ self,
75
+ text: str | list,
76
+ voice_name_or_embedding_path: str = "en_speaker_3",
77
+ semantic_temp=0.7,
78
+ semantic_top_k=50,
79
+ semantic_top_p=0.95,
80
+ coarse_temp=0.7,
81
+ coarse_top_k=50,
82
+ coarse_top_p=0.95,
83
+ fine_temp=0.5,
84
+ **kwargs
85
+ ) -> Job:
86
+ # just reuse args to easy pass them to super
87
+ _kwargs = get_function_parameters_as_dict(self.run, locals(), kwargs)
88
+ return self.__call__(**_kwargs)
89
+
@@ -0,0 +1,13 @@
1
+ from socaity.api.audio import Bark
2
+ from socaity.globals import EndPointType
3
+
4
+
5
+ def text2speech(text, *args, **kwargs) -> (bytes, int):
6
+ bark = Bark(endpoint_type=EndPointType.REMOTE)
7
+ return bark.run(text, *args, **kwargs)
8
+
9
+ def face2face():
10
+ pass
11
+
12
+ def voice2voice():
13
+ pass
@@ -0,0 +1,6 @@
1
+ # references to the __init__.py file in the Client module
2
+ from .client import *
3
+ # others
4
+ from .client_api import ClientAPI
5
+ from .endpoint import EndPoint, LocalEndPoint, RemoteEndPoint, EndPointType
6
+ from .job import Job, JobStatistics
@@ -0,0 +1,4 @@
1
+ from .client import Client
2
+ from .local_client import LocalClient
3
+ from .remote_client import RemoteClient
4
+ from .client_factory import create_client
@@ -0,0 +1,53 @@
1
+ from socaity.core.endpoint import EndPoint
2
+ from socaity.core.job import Job
3
+ import requests
4
+
5
+ class Client:
6
+ """
7
+ A Client handles the requests to an API.
8
+ """
9
+
10
+ def __init__(self, endpoint: EndPoint):
11
+ self.endpoint = endpoint
12
+
13
+ self._job_queue = []
14
+ self._results = []
15
+
16
+ def __call__(self, *args, **kwargs):
17
+ return self.run(*args, **kwargs)
18
+
19
+ def prepare_payload(self, job: Job) -> Job:
20
+ """
21
+ Subclass this method to implement your own payload preparation.
22
+ This is for example needed in web requests to have post, get and file parameters.
23
+ """
24
+ return job
25
+
26
+ def request(self, job: Job):
27
+ """
28
+ The method to make the request to the API.
29
+ Subclass this method.
30
+ """
31
+ raise NotImplementedError("Subclass the request method")
32
+
33
+ def run(self, job: Job, *args, **kwargs) -> Job:
34
+ """
35
+ Run the job.
36
+ """
37
+ # call pre_process function of client api (which is referenced in the job)
38
+ job.pre_process_params()
39
+ # obtain post, get, and files for web request
40
+ self.prepare_payload(job)
41
+ # make the request
42
+ print(f"Requesting {self.endpoint.endpoint_name} with job {job.job_statistics.created}")
43
+ endpoint_result = self.request(job) # result is also stored in the job
44
+ # call post_process function of client api
45
+ job.post_process_result(endpoint_result)
46
+ print(f"Job {job.job_statistics.created} finished in {job.job_statistics.get_execution_time()} seconds.")
47
+ return job
48
+
49
+ def run_async(self):
50
+ pass
51
+
52
+
53
+
@@ -0,0 +1,46 @@
1
+ from typing import Union
2
+
3
+ from socaity.core.client.local_client import LocalClient
4
+ from socaity.core.client.remote_client import RemoteClient
5
+ from socaity.globals import ModelType, EndPointType
6
+ from socaity.registry.registry import get_endpoint, ACTIVE_CLIENT_REGISTRY
7
+
8
+
9
+ def create_client(
10
+ model_type: Union[ModelType, str, None] = None,
11
+ model_name: str = None,
12
+ endpoint_type: Union[EndPointType, str] = EndPointType.REMOTE,
13
+ provider: str = "socaity",
14
+ ) -> Union[LocalClient, RemoteClient]:
15
+ """
16
+ Create a client to interact with an API.
17
+ :param model_type: for example "text2speech"
18
+ :param model_name: for example "bark"
19
+ :param endpoint_type: for example "remote"
20
+ :param provider: for example "socaity"
21
+ :return: a client to interact with the API
22
+ """
23
+ clients = {
24
+ EndPointType.LOCAL: LocalClient,
25
+ EndPointType.REMOTE: RemoteClient
26
+ }
27
+
28
+ endpoint = get_endpoint(model_type=model_type, model_name=model_name, endpoint_type=endpoint_type, provider=provider)
29
+
30
+ # check if the client is already created and return from the registry if it is the case
31
+ client = ACTIVE_CLIENT_REGISTRY.get_client(endpoint, default_return_value=None)
32
+ if client is not None:
33
+ return client
34
+
35
+
36
+ # create a new client
37
+ if endpoint.endpoint_type in clients:
38
+ client = clients[endpoint.endpoint_type](endpoint)
39
+ else:
40
+ print(f"Endpoint type {endpoint_type} not supported. Defaulting to remote.")
41
+ client = RemoteClient(endpoint)
42
+
43
+ # add the client to the registry
44
+ ACTIVE_CLIENT_REGISTRY.add_active_client(client)
45
+
46
+ return client
@@ -0,0 +1,104 @@
1
+ import time
2
+ import os
3
+ from subprocess import Popen, CREATE_NEW_CONSOLE
4
+ from enum import Enum
5
+
6
+ from socaity.core.job import Job
7
+ from socaity.core.client.remote_client import RemoteClient, web_request
8
+ from socaity.core.endpoint import LocalEndPoint
9
+
10
+ class LocalServerStatus(Enum):
11
+ OK = "ok"
12
+ NOT_OK = "not ok"
13
+ TIMEOUT = "timeout"
14
+
15
+
16
+
17
+ class LocalClient(RemoteClient):
18
+ def __init__(self, endpoint: LocalEndPoint,
19
+ start_server_from_bat_file: bool = True,
20
+ server_not_reachable_timeout: int = 60
21
+ ):
22
+ super().__init__(endpoint)
23
+ self.endpoint = endpoint
24
+ self.is_running = False
25
+ self.__start_server_from_bat_file = start_server_from_bat_file
26
+ self.server_not_reachable_timeout = server_not_reachable_timeout
27
+
28
+ def _start_server(self):
29
+ if not self.is_running:
30
+ print("starting server")
31
+
32
+ # make a test request to check if the server is running
33
+ if self.__check_server_status_ok():
34
+ return True
35
+
36
+ if not os.path.isfile(self.endpoint.start_bat_path):
37
+ raise ValueError(
38
+ f"start_server.bat not found in {self.endpoint.start_bat_path}. Is Bark installed?")
39
+
40
+ # start the server in a new console
41
+ print(f"starting server {self.endpoint.start_bat_path}")
42
+ self.process = Popen(self.endpoint.start_bat_path,
43
+ creationflags=CREATE_NEW_CONSOLE,
44
+ cwd=os.path.dirname(self.endpoint.start_bat_path)
45
+ )
46
+
47
+ status = self._wait_for_ok_of_server()
48
+
49
+ return status
50
+
51
+
52
+ def _wait_for_ok_of_server(self):
53
+ # print("wait until bark is ready")
54
+ start_open = time.time()
55
+
56
+ ## not managed to print the console output in pipe don't know why it doesnt work.
57
+ while True:
58
+ status = self.__check_server_status_ok()
59
+ if status:
60
+ print("server is running")
61
+ break
62
+ elif int(time.time() - start_open) >= self.server_not_reachable_timeout:
63
+ self.is_running = False
64
+ status = LocalServerStatus.TIMEOUT
65
+ print("server start timed out")
66
+ break
67
+ else:
68
+ time.sleep(1) # wait one sec
69
+
70
+ return status
71
+
72
+ def stop_server(self):
73
+ if self.process is not None:
74
+ self.process.terminate()
75
+ self.is_running = False
76
+
77
+ def __check_server_status_ok(self) -> LocalServerStatus:
78
+ """
79
+ Check if the server is running and responding with "ok"
80
+ """
81
+ url = self.endpoint.service_url + "/status"
82
+ status, error = web_request(url=url)
83
+ if "ok" in str(status).lower() and not error:
84
+ self.is_running = True
85
+ return LocalServerStatus.OK
86
+ else:
87
+ return LocalServerStatus.NOT_OK
88
+
89
+
90
+ def request(self, job: Job):
91
+ """
92
+ Subclass of RemoteClient.request
93
+ :param job: the job with the payload to send
94
+ """
95
+ # start the server if not running
96
+ if not self.is_running:
97
+ if self.__start_server_from_bat_file:
98
+ self._start_server()
99
+ else:
100
+ raise ValueError("Server is not running. Please start the server first.")
101
+
102
+ # make the request
103
+ result = super().request(job)
104
+ return result
@@ -0,0 +1,104 @@
1
+ from typing import Union,Tuple
2
+ import requests
3
+ from requests import JSONDecodeError
4
+
5
+ from socaity.core.client.client import Client
6
+ from socaity.core.endpoint import RemoteEndPoint
7
+ from socaity.core.job import Job
8
+
9
+
10
+ def web_request(
11
+ url: str,
12
+ get_params: dict = None,
13
+ post_params: dict = None,
14
+ files: dict = None) -> Tuple[object, Union[str, None]]:
15
+ """
16
+ Request an hosted API.
17
+ :param url: The url of the API
18
+ :param get_params: The parameters to be sent in the GET request
19
+ :param post_params: The parameters to be sent in the POST request
20
+ :param files: The files to be sent in the request.
21
+ :return: result, error_msg (or None if nor error occurred)
22
+ """
23
+ # add get parameters to url
24
+ if get_params:
25
+ url += "?"
26
+ for k, v in get_params:
27
+ url += f"{k}={v}&"
28
+ url = url[:-1]
29
+
30
+ # send request
31
+ error = None
32
+ res = None
33
+ try:
34
+ response = requests.post(url, params=post_params, files=files)
35
+ if response.status_code == 500:
36
+ print(f"API {url} call error: {response.content}")
37
+ return response.content
38
+ if response.headers.get("content-type") in ["audio/wav", "image/png", "image/jpg", "octet-stream"]:
39
+ res = response.content
40
+ else:
41
+ res = response.json()
42
+ except JSONDecodeError as e:
43
+ print(f"Response of API {url} is not JSON format. Intended?")
44
+ error = str(e)
45
+ except Exception as e:
46
+ error = str(e)
47
+ print(f"API {url} call error: {str(e)}")
48
+
49
+ return res, error
50
+
51
+ class RemoteClient(Client):
52
+ """
53
+ Used to interact with remote APIs. Implements Authentication and Authorization.
54
+ It creates Jobs which are then run in a thread.
55
+ The jobs have the required logic to pre and postprocess the requests.
56
+
57
+ 1. Get the token
58
+ 2. Make the request
59
+ """
60
+ def __init__(self, endpoint: RemoteEndPoint):
61
+ super().__init__(endpoint)
62
+ self.endpoint = endpoint
63
+
64
+ def prepare_payload(self, job: Job) -> Job:
65
+ """
66
+ Moves params for post, get, and files.
67
+ """
68
+ # get the named parameters
69
+ payload = {
70
+ "post_params": {k: v for k, v in job.raw_payload.items() if k in self.endpoint.post_params},
71
+ "get_params": {k: v for k, v in job.raw_payload.items() if k in self.endpoint.get_params},
72
+ "files": {k: v for k, v in job.raw_payload.items() if k in self.endpoint.files}
73
+ }
74
+
75
+ # add remaining parameters to post
76
+ remaining_params = {
77
+ k: v for k, v in job.raw_payload.items()
78
+ if k not in payload["post_params"]
79
+ and k not in payload["files"]
80
+ and k not in payload["get_params"]
81
+ }
82
+ payload["post_params"].update(remaining_params)
83
+
84
+ job.payload = payload
85
+
86
+ return job
87
+
88
+ def request(self, job: Job) -> Union[dict, bytes, str, object, None]:
89
+ """
90
+ :param job: the job with the payload to send
91
+ :return: the result of the request to the remote API
92
+ """
93
+ url = self.endpoint.service_url
94
+ url = url if self.endpoint.endpoint_name is None else f"{url}/{self.endpoint.endpoint_name}"
95
+
96
+ res, error = web_request(url, job.payload["get_params"], job.payload["post_params"], job.payload["files"])
97
+
98
+ if error:
99
+ raise Exception(f"API {url} call error: {error}")
100
+
101
+ return res
102
+
103
+ def run(self, job: Job, *args, **kwargs) -> Job:
104
+ return super().run(job, *args, **kwargs)
@@ -0,0 +1,66 @@
1
+ from typing import Union
2
+
3
+ from socaity.core.client.client_factory import create_client
4
+ from socaity.globals import ModelType, EndPointType
5
+ from socaity.core.job import Job
6
+
7
+
8
+ class ClientAPI:
9
+ def __init__(self,
10
+ model_type: ModelType,
11
+ model_name: str,
12
+ endpoint_type: Union[EndPointType, str] = EndPointType.REMOTE
13
+ ):
14
+ self.model_type = model_type
15
+ self.model_name = model_name
16
+ self.endpoint_type = endpoint_type
17
+ self.client = create_client(model_type=model_type, model_name=model_name, endpoint_type=endpoint_type)
18
+
19
+ def validate_params(self, *args, **kwargs) -> (bool, str):
20
+ """
21
+ Method is executed before a job is created.
22
+ Validate the parameters passed to the job before job is created.
23
+ :return: validation_success, error_message
24
+ Subclass this method to implement your own validation.
25
+ """
26
+ return True, None
27
+
28
+ def _pre_process(self, *args, **kwargs):
29
+ """
30
+ This method is called before the job is executed.
31
+ Subclass this method if you want to do some preprocessing of the args and kwargs.
32
+ """
33
+ return args, kwargs
34
+
35
+ def _post_process(self, *args, **kwargs):
36
+ """
37
+ This method is called after the job is executed.
38
+ Subclass this method if you want to do some postprocessing.
39
+ """
40
+ pass
41
+
42
+ def __call__(self, **kwargs) -> Union[Job, None]:
43
+ """
44
+ Run the job with the given parameters.
45
+ Subclass this method if you want type hinting. But don't forget to call super().__call__(..)
46
+ :kwargs: The parameters for running the job. Note only named are further passed to the job. Transform args to kwargs
47
+ """
48
+ valid, error = self.validate_params(**kwargs)
49
+ if not valid:
50
+ print(f"Validation of params failed before job execute: {error}. Job will not be created.")
51
+ return None
52
+
53
+ # The parameters for running the job are in *args and **kwargs and then stored in the job itself.
54
+ job = Job(self._pre_process, self._post_process, **kwargs)
55
+ result = self.client.run(job)
56
+ #try:
57
+ # result = self.client.run(job)
58
+ #except Exception as e:
59
+ # print(f"Job execution failed: {e}.")
60
+ # return None
61
+
62
+ return result
63
+
64
+ def run(self, *args, **kwargs):
65
+ """ Please subclass the class to implement type hinting."""
66
+ return self(*args, **kwargs)
@@ -0,0 +1,73 @@
1
+ from socaity.globals import EndPointType, ModelType
2
+
3
+ class EndPoint:
4
+ """
5
+ An endpoint contains the information to connect to a model hosted on a provider (Remote, Local or Decentralized).
6
+ """
7
+ def __init__(
8
+ self,
9
+ model_type: ModelType,
10
+ model_name: str,
11
+ endpoint_type: EndPointType,
12
+ endpoint_name: str = None,
13
+ provider: str = None,
14
+ post_params: list = None,
15
+ get_params: list = None,
16
+ files: list = None,
17
+ *args,
18
+ **kwargs
19
+ ):
20
+ """
21
+ :param model_type: The type of the model (for example ModelType.TEXT2VOICE)
22
+ :param model_name: The name of the model (for example "bark")
23
+ :param endpoint_type: The type of the endpoint (for example EndPointType.REMOTE)
24
+ :
25
+ :param provider: The provider of the model (for example "socaity")
26
+ :param post_params: The parameters to be sent in the POST request
27
+ :param get_params: The parameters to be sent in the GET request
28
+ :param files: The files to be sent in the request.
29
+ All parameters in a request which are not defined in post, get, or files are default as post parameters.
30
+ """
31
+
32
+ self.model_name = model_name
33
+ self.model_type = model_type
34
+ self.endpoint_type = endpoint_type
35
+ self.endpoint_name = endpoint_name
36
+ self.provider = provider
37
+
38
+ # initiating empty lists if not given to avoid errors
39
+ self.post_params = post_params if post_params is not None else []
40
+ self.get_params = get_params if get_params is not None else []
41
+ self.files = files if files is not None else []
42
+
43
+ def __str__(self):
44
+ return f"{self.model_type.value}_{self.model_name}_{self.endpoint_type.value}_{self.provider}"
45
+
46
+
47
+
48
+ class RemoteEndPoint(EndPoint):
49
+ def __init__(self, model_type: ModelType, model_name: str, service_url: str, endpoint_name: str, *args, **kwargs):
50
+ super().__init__(model_type=model_type, model_name=model_name, endpoint_type=EndPointType.REMOTE,
51
+ endpoint_name=endpoint_name,
52
+ *args, **kwargs)
53
+ self.service_url = service_url
54
+ self.endpoint_name = endpoint_name
55
+
56
+
57
+ class LocalEndPoint(EndPoint):
58
+ def __init__(self, service_url: str, endpoint_name: str, start_bat_path: str = "", *args, **kwargs):
59
+ super().__init__(service_url=service_url, endpoint_name=endpoint_name, endpoint_type=EndPointType.LOCAL,
60
+ *args, **kwargs)
61
+ self.service_url = service_url
62
+ self.start_bat_path = start_bat_path
63
+
64
+
65
+ class SocaityEndpoint(RemoteEndPoint):
66
+ """ Helper class with predifined URLS to define the SOCAITY endpoints. """
67
+ def __init__(self, model_type: ModelType, model_name: str, *args, **kwargs):
68
+ self.service_url = f"https://socaity.ai/api/"
69
+ self.endpoint_name = f"{model_type.value}/{model_name}"
70
+ super().__init__(model_type=model_type, model_name=model_name,
71
+ service_url=self.service_url, endpoint_name=self.endpoint_name,
72
+ provider="socaity", *args, **kwargs)
73
+
socaity/core/job.py ADDED
@@ -0,0 +1,85 @@
1
+ import time
2
+
3
+
4
+ class JobStatistics:
5
+ """
6
+ Stores the time when the different stages of the job were executed.
7
+ """
8
+ def __init__(self):
9
+ self.created = time.time()
10
+ self.pre_processing_started = None
11
+ self.pre_processing_ended = None
12
+ self.request_send = None
13
+ self.request_result_received = None
14
+ self.post_processing_started = None
15
+ self.post_processing_ended = None
16
+
17
+ def get_execution_time(self):
18
+ """
19
+ The time it took to execute the job in seconds.
20
+ """
21
+ return self.post_processing_ended - self.pre_processing_started
22
+
23
+
24
+ class Job:
25
+ """
26
+ A job contains the:
27
+ - the payload to handle a request.
28
+ - references to the pre and post processing functions.
29
+ - the result of the request.
30
+ - the statistics and execution times of the job.
31
+ """
32
+ def __init__(self,
33
+ pre_process_func: callable = None,
34
+ post_process_func: callable = None,
35
+ **kwargs):
36
+ """
37
+ :param pre_process_func: A function that pre_processes the request parameters, before sending the request.
38
+ :param post_process_func: A function that post_processes the result of the request, before returning it.
39
+ :param kwargs: The named parameters of the request. (Note: args where transformed to kwargs in the clientAPI.)
40
+
41
+ If parameters are not named in post, get, or files, they are default sent as post parameters.
42
+ """
43
+
44
+ self.preprocess_func = pre_process_func
45
+ self.post_process_func = post_process_func
46
+ self.job_statistics = JobStatistics()
47
+ self.result = None
48
+
49
+ # prepare payload
50
+ self.raw_payload = kwargs # will be modified in job.preprocess_params in client.run
51
+ self.payload = None # will be prepared for post, get, and file params in client before request is sent
52
+
53
+ def get_payload(self):
54
+ return self.payload
55
+
56
+ def pre_process_params(self):
57
+ """
58
+ This function is called before the request is sent.
59
+ Use it to modify the request payload parameters if needed.
60
+ It is better to do it here than in the init function because this method will be called threaded.
61
+ :param kwargs:
62
+ :return:
63
+ """
64
+ if self.preprocess_func is not None:
65
+ self.job_statistics.pre_processing_started = time.time()
66
+ self.raw_payload = self.preprocess_func(**self.raw_payload)
67
+ self.job_statistics.pre_processing_ended = time.time()
68
+
69
+ return self.raw_payload
70
+
71
+ def post_process_result(self, result, *args, **kwargs):
72
+ """
73
+ The result of the request is the raw response from the server.
74
+ Use this method to process the result before returning it.
75
+ :param result:
76
+ :param kwargs:
77
+ :return:
78
+ """
79
+ if self.post_process_func is not None:
80
+ self.job_statistics.post_processing_started = time.time()
81
+ self.result = self.post_process_func(result, *args, **kwargs)
82
+ self.job_statistics.post_processing_ended = time.time()
83
+
84
+ return self
85
+