rapida-python 0.1.0__py3-none-any.whl → 0.1.0a0__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.
rapida/__init__.py CHANGED
@@ -1,13 +1,38 @@
1
- """
2
- author: prashant.srivastav
3
- """
1
+ # Copyright (c) 2024. Rapida
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ #
21
+ # Author: Prashant <prashant@rapida.ai>
4
22
 
5
- from rapida.rapida_client import RapidaClient
23
+
24
+ from rapida.rapida_client import (
25
+ RapidaClient,
26
+ RapidaEndpointClient,
27
+ RapidaAssistantClient,
28
+ RapidaGatewayClient,
29
+ )
6
30
  from rapida.rapida_client_options import (
7
31
  RapidaClientOptions,
8
- RapidaEnvironment,
9
- RapidaRegion,
10
32
  )
33
+ from rapida.rapida_environment import RapidaEnvironment
34
+ from rapida.rapida_region import RapidaRegion
35
+ from rapida.rapida_source import RapidaSource
11
36
  from rapida.exceptions import (
12
37
  RapidaException,
13
38
  RapidaInternalServerException,
@@ -15,9 +40,14 @@ from rapida.exceptions import (
15
40
  RapidaConfigurationException,
16
41
  )
17
42
  from rapida.version import VERSION
43
+ from rapida.client.response_wrapper import Message, Content, ToolDefinition
18
44
 
19
45
  __all__ = [
20
46
  "RapidaClient",
47
+ "ToolDefinition",
48
+ "RapidaEndpointClient",
49
+ "RapidaAssistantClient",
50
+ "RapidaGatewayClient",
21
51
  "RapidaClientOptions",
22
52
  "RapidaException",
23
53
  "RapidaInternalServerException",
@@ -26,4 +56,7 @@ __all__ = [
26
56
  "VERSION",
27
57
  "RapidaEnvironment",
28
58
  "RapidaRegion",
59
+ "RapidaSource",
60
+ "Message",
61
+ "Content",
29
62
  ]
@@ -1,33 +1,56 @@
1
- """
2
- author: prashant.srivastav
1
+ # Copyright (c) 2024. Rapida
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ #
21
+ # Base Bridge class for all RPC and gRPC clients.
22
+ # - Changing this class will impact all RPC and gRPC clients and consumer service which implement and inherit
23
+ # this class.
24
+ # - Considered as core computability layer for all RPC and gRPC clients the CHANGE REQUEST is not allowed.
25
+ # - Mostly response being handled with JSON format.
26
+ #
27
+ #
28
+ # Author: Prashant <prashant@rapida.ai>
3
29
 
4
- Base Bridge class for all RPC and gRPC clients.
5
- - Changing this class will impact all RPC and gRPC clients and consumer service which implement and inherit
6
- this class.
7
- - Considered as core computability layer for all RPC and gRPC clients the CHANGE REQUEST is not allowed.
8
- - Mostly response being handled with JSON format.
9
30
 
10
- """
11
31
  import logging
12
32
  import time
13
33
  from abc import ABC
14
- from typing import Any, Dict
34
+ from typing import Any, AsyncIterator, Dict
15
35
 
16
36
  import grpc
17
37
  from google.protobuf.json_format import MessageToDict
18
- from grpc import aio as grpc_aio
38
+ from grpc import UnaryStreamMultiCallable, aio as grpc_aio
19
39
  from google.protobuf.message import Message
20
40
  from grpc.aio import Metadata
21
41
  from grpc.aio._channel import UnaryUnaryMultiCallable
22
42
 
43
+ from rapida.constants import (
44
+ HEADER_API_KEY,
45
+ HEADER_ENVIRONMENT_KEY,
46
+ HEADER_REGION_KEY,
47
+ HEADER_SOURCE_KEY,
48
+ )
23
49
  from rapida.exceptions.exceptions import RapidaException
24
50
 
25
51
  _log = logging.getLogger("rapida.client.grpc_bridge")
26
52
 
27
53
 
28
- # _log = logging.getLogger("bridges.grpc_bridge")
29
-
30
-
31
54
  class GRPCBridge(ABC):
32
55
  """
33
56
  Base class for all GRPC bridges.
@@ -38,6 +61,7 @@ class GRPCBridge(ABC):
38
61
  rapida_api_key: str
39
62
  rapida_region: str
40
63
  rapida_environment: str
64
+ rapida_source: str
41
65
  rapida_is_secure: bool
42
66
 
43
67
  @classmethod
@@ -47,6 +71,7 @@ class GRPCBridge(ABC):
47
71
  rapida_api_key: str,
48
72
  rapida_region: str,
49
73
  rapida_environment: str,
74
+ rapida_source: str,
50
75
  rapida_is_secure: bool,
51
76
  ):
52
77
  """
@@ -54,11 +79,13 @@ class GRPCBridge(ABC):
54
79
  service_url: a url where the endpoint service is deployed
55
80
  rapida_api_key: a api keys to authenticate and authorize the request made to rapida servers (Please find the docs <a>docs.rapida.ai</a>
56
81
  rapida_region: specify the region to accelerate the request if it's specific as per client need
82
+ rapida_source: source of the request for rapida request later it will become important for routing and parsing the information
57
83
  rapida_environment: a tag to represent the env currently (production and development is supported)
58
84
  """
59
85
  cls.service_url = service_url
60
86
  cls.rapida_api_key = rapida_api_key
61
87
  cls.rapida_region = rapida_region
88
+ cls.rapida_source = rapida_source
62
89
  cls.rapida_environment = rapida_environment
63
90
  cls.rapida_is_secure = rapida_is_secure
64
91
 
@@ -108,9 +135,10 @@ class GRPCBridge(ABC):
108
135
  # metadata for request
109
136
  _metadata: Metadata = Metadata()
110
137
 
111
- _metadata.add("x-api-key", cls.rapida_api_key)
112
- _metadata.add("x-rapida-environment", cls.rapida_environment)
113
- _metadata.add("x-rapida-region", cls.rapida_region)
138
+ _metadata.add(HEADER_API_KEY, cls.rapida_api_key)
139
+ _metadata.add(HEADER_ENVIRONMENT_KEY, cls.rapida_environment)
140
+ _metadata.add(HEADER_REGION_KEY, cls.rapida_region)
141
+ _metadata.add(HEADER_SOURCE_KEY, cls.rapida_source)
114
142
 
115
143
  # request executed with asynchronous invocation of a unary-call RPC.
116
144
  results = await unary_unary(request=message_type, metadata=_metadata)
@@ -126,3 +154,52 @@ class GRPCBridge(ABC):
126
154
  f"{cls.__qualname__} {attr} [status:NOT_OK request:{time.time() - started_request}s]"
127
155
  )
128
156
  raise RapidaException(message=str(ex), code=500, source=__name__)
157
+
158
+ @classmethod
159
+ async def fetch_stream(
160
+ cls,
161
+ stub: Any,
162
+ attr: str,
163
+ message_type: Message, # Unary request
164
+ **unmarshal_options,
165
+ ) -> AsyncIterator[Dict[str, Any]]:
166
+ """
167
+ Generic requestor for unary request with streaming response
168
+ :param stub:
169
+ :param attr:
170
+ :param message_type: Unary request message
171
+ :param unmarshal_options: Options to control unmarshalling of the protobuf result.
172
+ """
173
+ started_request = time.time()
174
+ try:
175
+ _log.debug(f"grpc_bridge: in span of {attr}")
176
+ async with cls.channel() as channel:
177
+ _log.debug(f"grpc_bridge: created secure channel for {cls.service_url}")
178
+
179
+ # Get unary-stream method from the stub (request once, receive a stream)
180
+ unary_stream: UnaryStreamMultiCallable = getattr(stub(channel), attr)
181
+
182
+ # Metadata for the request
183
+ _metadata: Metadata = Metadata()
184
+ _metadata.add(HEADER_API_KEY, cls.rapida_api_key)
185
+ _metadata.add(HEADER_ENVIRONMENT_KEY, cls.rapida_environment)
186
+ _metadata.add(HEADER_REGION_KEY, cls.rapida_region)
187
+ _metadata.add(HEADER_SOURCE_KEY, cls.rapida_source)
188
+
189
+ # Send the unary request and receive a stream of responses
190
+ async for response in unary_stream(
191
+ request=message_type, metadata=_metadata
192
+ ):
193
+ # Unmarshal each result with the given options
194
+ json_result = MessageToDict(response, **unmarshal_options)
195
+ _log.info(
196
+ f"{cls.__qualname__} {attr} [status:OK request:{time.time() - started_request}s]"
197
+ )
198
+ # Yield each response as part of the stream
199
+ yield json_result
200
+ except grpc_aio.AioRpcError as ex:
201
+ # Handle errors from inter-service client communication
202
+ _log.error(
203
+ f"{cls.__qualname__} {attr} [status:NOT_OK request:{time.time() - started_request}s]"
204
+ )
205
+ raise RapidaException(message=str(ex), code=500, source=__name__)
@@ -1,14 +1,36 @@
1
- """
2
- author: prashant.srivastav
3
- """
1
+ # Copyright (c) 2024. Rapida
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ #
21
+ # Author: Prashant <prashant@rapida.ai>
22
+
23
+
4
24
  import logging
5
- from typing import Dict, Optional, Mapping
25
+ from typing import AsyncIterator, Dict, List, Optional, Mapping
6
26
  from google.protobuf.json_format import ParseDict
7
27
  from google.protobuf.any_pb2 import Any
8
-
9
-
28
+ from google.protobuf.struct_pb2 import Struct
10
29
  from rapida.client.response_wrapper import InvokeResponseWrapper
11
30
  from rapida.artifacts.protos import (
31
+ common_pb2,
32
+ integration_api_pb2,
33
+ integration_api_pb2_grpc,
12
34
  invoker_api_pb2,
13
35
  invoker_api_pb2_grpc,
14
36
  )
@@ -24,6 +46,7 @@ class RapidaBridge(GRPCBridge):
24
46
  rapida_api_key: str,
25
47
  rapida_region: str,
26
48
  rapida_environment: str,
49
+ rapida_source: str,
27
50
  rapida_is_secure: bool,
28
51
  ):
29
52
  """
@@ -39,6 +62,7 @@ class RapidaBridge(GRPCBridge):
39
62
  rapida_api_key,
40
63
  rapida_region,
41
64
  rapida_environment,
65
+ rapida_source,
42
66
  rapida_is_secure,
43
67
  )
44
68
 
@@ -96,7 +120,6 @@ class RapidaBridge(GRPCBridge):
96
120
  attr="Probe",
97
121
  message_type=invoker_api_pb2.ProbeRequest(requestId=rapida_audit_id),
98
122
  preserving_proto_field_name=True,
99
- # including_default_value_fields=True,
100
123
  )
101
124
  return ParseDict(
102
125
  response, invoker_api_pb2.ProbeResponse(), ignore_unknown_fields=True
@@ -116,7 +139,7 @@ class RapidaBridge(GRPCBridge):
116
139
  """
117
140
  response = await self.fetch(
118
141
  stub=invoker_api_pb2_grpc.DeploymentStub,
119
- attr="UpdateMetadata",
142
+ attr="Update",
120
143
  message_type=invoker_api_pb2.UpdateRequest(
121
144
  requestId=rapida_audit_id,
122
145
  metadata=rapida_metadata,
@@ -128,3 +151,239 @@ class RapidaBridge(GRPCBridge):
128
151
  return ParseDict(
129
152
  response, invoker_api_pb2.UpdateResponse(), ignore_unknown_fields=True
130
153
  )
154
+
155
+ async def chat(
156
+ self,
157
+ cred: Dict,
158
+ provider: str,
159
+ model: str,
160
+ conversations: List[common_pb2.Message],
161
+ tool_definitions: List[integration_api_pb2.ToolDefinition],
162
+ model_parameters: List[integration_api_pb2.ModelParameter],
163
+ meta: Mapping[str, str] = None,
164
+ ) -> integration_api_pb2.ChatResponse:
165
+ """
166
+ Asynchronously initiates a chat interaction with the Rapida service.
167
+
168
+ This method sends a chat request to the Rapida service and processes the response.
169
+ It utilizes gRPC to communicate with the service, specifically calling the
170
+ 'UpdateMetadata' method of the RapidaServiceStub.
171
+
172
+ The function performs the following steps:
173
+ 1. Sends a chat request to the Rapida service using the 'fetch' method.
174
+ 2. Waits for the asynchronous response from the service.
175
+ 3. Parses the received response into a ChatResponse object.
176
+
177
+ Returns:
178
+ integration_api_pb2.ChatResponse: The processed response from the Rapida service,
179
+ containing the chat interaction results.
180
+
181
+ Note:
182
+ - This method uses the 'fetch' utility to handle the gRPC communication.
183
+ - The 'preserving_proto_field_name' parameter is set to True to maintain
184
+ the original field names in the protocol buffer message.
185
+ - The response is parsed using the 'ParseDict' function, which converts
186
+ the dictionary response into a ChatResponse protocol buffer object.
187
+ - Unknown fields in the response are ignored during parsing.
188
+
189
+ Raises:
190
+ Any exceptions that might occur during the gRPC communication or response parsing.
191
+
192
+ Example usage:
193
+ chat_response = await rapida_bridge_instance.chat()
194
+ # Process the chat_response as needed
195
+ """
196
+
197
+ credentials = Struct()
198
+ for k, v in cred.items():
199
+ credentials.update({k: v})
200
+
201
+ response = await self.fetch(
202
+ stub=integration_api_pb2_grpc.RapidaServiceStub,
203
+ attr="Chat",
204
+ message_type=integration_api_pb2.ChatRequest(
205
+ credential=integration_api_pb2.Credential(value=credentials),
206
+ model=f"{provider}/{model}",
207
+ conversations=conversations,
208
+ toolDefinitions=tool_definitions,
209
+ modelParameters=model_parameters,
210
+ additionalData=meta,
211
+ ),
212
+ preserving_proto_field_name=True,
213
+ )
214
+
215
+ return ParseDict(
216
+ response, integration_api_pb2.ChatResponse(), ignore_unknown_fields=True
217
+ )
218
+
219
+ async def generate(
220
+ self,
221
+ cred: Dict,
222
+ provider: str,
223
+ model: str,
224
+ system_prompt: str,
225
+ prompt: str,
226
+ model_parameters: Mapping[str, str] = None,
227
+ meta: Mapping[str, str] = None,
228
+ ) -> integration_api_pb2.GenerateResponse:
229
+ """
230
+ Prepares and sends a generation request to the Rapida service.
231
+
232
+ This function:
233
+ 1. Converts credentials and model parameters to the required format
234
+ 2. Constructs a GenerateRequest message with the provided inputs
235
+ 3. Sends the request to the Rapida service using gRPC
236
+ 4. Parses and returns the response as a GenerateResponse object
237
+
238
+ Args:
239
+ cred (dict): Credentials for authentication
240
+ system_prompt (str): System prompt for the generation
241
+ prompt (str): User prompt for the generation
242
+ provider (str): The AI provider to use
243
+ model (str): The specific model to use
244
+ model_parameters (dict): Additional parameters for the model
245
+ meta (dict): Any additional metadata
246
+
247
+ Returns:
248
+ integration_api_pb2.GenerateResponse: The parsed response from the service
249
+ """
250
+ credentials = Struct()
251
+ for k, v in cred.items():
252
+ credentials.update({k: v})
253
+
254
+ args: List[integration_api_pb2.ModelParameter] = []
255
+ for k, v in model_parameters.items():
256
+ args.append(
257
+ integration_api_pb2.ModelParameter(
258
+ key=k,
259
+ value=v,
260
+ )
261
+ )
262
+
263
+ response = await self.fetch(
264
+ stub=integration_api_pb2_grpc.RapidaServiceStub,
265
+ attr="Generate",
266
+ message_type=integration_api_pb2.GenerateRequest(
267
+ credential=credentials,
268
+ systemPrompt=system_prompt,
269
+ prompt=prompt,
270
+ model=f"{provider}/{model}",
271
+ modelParameters=args,
272
+ additionalData=meta,
273
+ ),
274
+ preserving_proto_field_name=True,
275
+ )
276
+
277
+ return ParseDict(
278
+ response, integration_api_pb2.GenerateResponse(), ignore_unknown_fields=True
279
+ )
280
+
281
+ async def embedding(
282
+ self,
283
+ cred: Dict,
284
+ provider: str,
285
+ model: str,
286
+ contents: List[str],
287
+ model_parameters: Mapping[str, str] = None,
288
+ meta: Mapping[str, str] = None,
289
+ ) -> integration_api_pb2.EmbeddingResponse:
290
+
291
+ credentials = Struct()
292
+ for k, v in cred.items():
293
+ credentials.update({k: v})
294
+
295
+ args: List[integration_api_pb2.ModelParameter] = []
296
+ for k, v in model_parameters.items():
297
+ args.append(
298
+ integration_api_pb2.ModelParameter(
299
+ key=k,
300
+ value=v,
301
+ )
302
+ )
303
+
304
+ _content: Mapping[int, str] = {}
305
+ for i, val in enumerate(contents):
306
+ _content[i] = val
307
+
308
+ response = await self.fetch(
309
+ stub=integration_api_pb2_grpc.RapidaServiceStub,
310
+ attr="Embedding",
311
+ message_type=integration_api_pb2.EmbeddingRequest(
312
+ credential=credentials,
313
+ model=f"{provider}/{model}",
314
+ modelParameters=args,
315
+ additionalData=meta,
316
+ content=_content,
317
+ ),
318
+ preserving_proto_field_name=True,
319
+ )
320
+
321
+ return ParseDict(
322
+ response,
323
+ integration_api_pb2.EmbeddingResponse(),
324
+ ignore_unknown_fields=True,
325
+ )
326
+
327
+ async def chat_stream(
328
+ self,
329
+ cred: Dict,
330
+ provider: str,
331
+ model: str,
332
+ conversations: List[common_pb2.Message],
333
+ tool_definitions: List[integration_api_pb2.ToolDefinition],
334
+ model_parameters: List[integration_api_pb2.ModelParameter],
335
+ meta: Mapping[str, str] = None,
336
+ ) -> AsyncIterator[integration_api_pb2.ChatResponse]:
337
+ """
338
+ Asynchronously initiates a chat interaction with the Rapida service and streams the responses.
339
+
340
+ This method sends a chat request to the Rapida service and handles streaming responses.
341
+ It utilizes gRPC to communicate with the service, specifically calling the
342
+ 'StreamChat' method of the RapidaServiceStub.
343
+
344
+ The function performs the following steps:
345
+ 1. Sends a chat request to the Rapida service using the 'fetch_stream_response' method.
346
+ 2. Asynchronously iterates over the streaming responses from the service.
347
+ 3. Parses each received response into a ChatResponse object.
348
+
349
+ Returns:
350
+ AsyncIterator[integration_api_pb2.ChatResponse]: The streamed responses from the Rapida service,
351
+ containing the chat interaction results.
352
+
353
+ Note:
354
+ - This method uses the 'fetch_stream' utility to handle the gRPC communication.
355
+ - The 'preserving_proto_field_name' parameter is set to True to maintain
356
+ the original field names in the protocol buffer message.
357
+ - Each response is parsed using the 'ParseDict' function, which converts
358
+ the dictionary response into a ChatResponse protocol buffer object.
359
+ - Unknown fields in the response are ignored during parsing.
360
+
361
+ Raises:
362
+ Any exceptions that might occur during the gRPC communication or response parsing.
363
+
364
+ Example usage:
365
+ async for chat_response in rapida_bridge_instance.chat_stream():
366
+ # Process each chat_response as needed
367
+ """
368
+
369
+ credentials = Struct()
370
+ for k, v in cred.items():
371
+ credentials.update({k: v})
372
+
373
+ # Stream the chat response from the gRPC server
374
+ async for response in self.fetch_stream(
375
+ stub=integration_api_pb2_grpc.RapidaServiceStub,
376
+ attr="StreamChat",
377
+ message_type=integration_api_pb2.ChatRequest(
378
+ credential=integration_api_pb2.Credential(value=credentials),
379
+ model=f"{provider}/{model}",
380
+ conversations=conversations,
381
+ toolDefinitions=tool_definitions,
382
+ modelParameters=model_parameters,
383
+ additionalData=meta,
384
+ ),
385
+ preserving_proto_field_name=True,
386
+ ):
387
+ yield ParseDict(
388
+ response, integration_api_pb2.ChatResponse(), ignore_unknown_fields=True
389
+ )