GPTRouter 0.0.2__tar.gz → 0.2.5__tar.gz

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.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: GPTRouter
3
- Version: 0.0.2
3
+ Version: 0.2.5
4
4
  Summary: A Python package for working with GPTRouter APIs
5
- Author-email: sirjanpreet.ext@writesonic.com
5
+ Author-email: sirjanpreet@writesonic.com
6
6
  Classifier: Development Status :: 3 - Alpha
7
7
  Classifier: Intended Audience :: Developers
8
8
  Classifier: Programming Language :: Python :: 3
@@ -11,4 +11,5 @@ gpt_router/__init__.py
11
11
  gpt_router/client.py
12
12
  gpt_router/constants.py
13
13
  gpt_router/enums.py
14
+ gpt_router/exceptions.py
14
15
  gpt_router/models.py
@@ -0,0 +1,3 @@
1
+ httpx>=0.23.3
2
+ pydantic>=1.10.13
3
+ pyhumps>=3.8.0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: GPTRouter
3
- Version: 0.0.2
3
+ Version: 0.2.5
4
4
  Summary: A Python package for working with GPTRouter APIs
5
- Author-email: sirjanpreet.ext@writesonic.com
5
+ Author-email: sirjanpreet@writesonic.com
6
6
  Classifier: Development Status :: 3 - Alpha
7
7
  Classifier: Intended Audience :: Developers
8
8
  Classifier: Programming Language :: Python :: 3
@@ -1,15 +1,41 @@
1
1
  from __future__ import annotations
2
-
2
+ from pydantic import parse_obj_as
3
3
  import logging
4
4
  import json
5
5
  import httpx
6
- from typing import Generator, List, Union
6
+ from typing import Generator, List, Optional, Union
7
7
 
8
- from gpt_router.models import ModelGenerationRequest, GenerationResponse, ChunkedGenerationResponse
8
+ from gpt_router.models import (
9
+ ImageGenerationRequest,
10
+ ImageGenerationResponse,
11
+ ModelGenerationRequest,
12
+ GenerationResponse,
13
+ ChunkedGenerationResponse,
14
+ )
15
+ from gpt_router.exceptions import (
16
+ GPTRouterApiTimeoutError,
17
+ GPTRouterBadRequestError,
18
+ GPTRouterStreamingError,
19
+ GPTRouterForbiddenError,
20
+ GPTRouterInternalServerError,
21
+ GPTRouterNotAvailableError,
22
+ GPTRouterTooManyRequestsError,
23
+ GPTRouterUnauthorizedError,
24
+ )
9
25
  from gpt_router.constants import DEFAULT_REQUEST_TIMEOUT
10
26
 
11
27
  logger = logging.getLogger(__name__)
12
28
 
29
+ STATUS_CODE_EXCEPTION_MAPPING = {
30
+ 400: GPTRouterBadRequestError,
31
+ 406: GPTRouterNotAvailableError,
32
+ 401: GPTRouterUnauthorizedError,
33
+ 403: GPTRouterForbiddenError,
34
+ 429: GPTRouterTooManyRequestsError,
35
+ 500: GPTRouterInternalServerError,
36
+ 503: GPTRouterNotAvailableError,
37
+ }
38
+
13
39
 
14
40
  class GPTRouterClient:
15
41
  models = None
@@ -35,17 +61,17 @@ class GPTRouterClient:
35
61
  )
36
62
  if response.status_code == 200:
37
63
  return response.json()
38
- elif (
39
- response.status_code == 202
40
- or response.status_code == 204
41
- ):
64
+ elif response.status_code == 202 or response.status_code == 204:
42
65
  return None
43
66
  else:
44
- raise Exception(response.json())
67
+ error_class = STATUS_CODE_EXCEPTION_MAPPING.get(
68
+ response.status_code, Exception
69
+ )
70
+ raise error_class(response.json())
45
71
  except httpx.TimeoutException as err:
46
72
  logger.error(f"Timeout error: {err}")
47
- raise TimeoutError("Request timed out")
48
-
73
+ raise GPTRouterApiTimeoutError("Api Request timed out")
74
+
49
75
  def _api_call(self, *, path: str, method: str, payload: dict):
50
76
  try:
51
77
  with httpx.Client() as client:
@@ -61,16 +87,16 @@ class GPTRouterClient:
61
87
  )
62
88
  if response.status_code == 200:
63
89
  return response.json()
64
- elif (
65
- response.status_code == 202
66
- or response.status_code == 204
67
- ):
90
+ elif response.status_code == 202 or response.status_code == 204:
68
91
  return None
69
92
  else:
70
- raise Exception(response.json())
93
+ error_class = STATUS_CODE_EXCEPTION_MAPPING.get(
94
+ response.status_code, Exception
95
+ )
96
+ raise error_class(response.json())
71
97
  except httpx.TimeoutException as err:
72
98
  logger.error(f"Timeout error: {err}")
73
- raise TimeoutError("Request timed out")
99
+ raise GPTRouterApiTimeoutError("Api Request timed out")
74
100
 
75
101
  async def astream_events(self, *, path: str, method: str, payload: dict):
76
102
  try:
@@ -79,7 +105,10 @@ class GPTRouterClient:
79
105
  method,
80
106
  url=f"{self.base_url}/api{path}",
81
107
  data=json.dumps(payload),
82
- headers={"Content-type": "application/json", "ws-secret": self.api_key},
108
+ headers={
109
+ "Content-type": "application/json",
110
+ "ws-secret": self.api_key,
111
+ },
83
112
  timeout=self.request_timeout,
84
113
  ) as response:
85
114
  async for line in response.aiter_lines():
@@ -95,22 +124,30 @@ class GPTRouterClient:
95
124
  continue
96
125
 
97
126
  data: dict = json.loads(line_data.strip())
98
-
99
- yield ChunkedGenerationResponse.model_validate(data)
127
+ if data["event"] == "error":
128
+ raise GPTRouterStreamingError(data)
129
+ yield parse_obj_as(ChunkedGenerationResponse, data)
130
+ except GPTRouterStreamingError as e:
131
+ raise e
100
132
  except Exception:
101
133
  continue
102
134
  except httpx.TimeoutException as err:
103
135
  logger.error(f"Timeout error: {err}")
104
136
  raise TimeoutError("Request timed out")
105
137
 
106
- def stream_events(self, *, path: str, method: str, payload: dict) -> Generator[ChunkedGenerationResponse]:
138
+ def stream_events(
139
+ self, *, path: str, method: str, payload: dict
140
+ ) -> Generator[ChunkedGenerationResponse]:
107
141
  try:
108
142
  with httpx.Client() as client:
109
143
  with client.stream(
110
144
  method=method,
111
145
  url=f"{self.base_url}/api{path}",
112
146
  data=json.dumps(payload),
113
- headers={"Content-type": "application/json", "ws-secret": self.api_key},
147
+ headers={
148
+ "Content-type": "application/json",
149
+ "ws-secret": self.api_key,
150
+ },
114
151
  timeout=self.request_timeout,
115
152
  ) as response:
116
153
  for line in response.iter_lines():
@@ -125,19 +162,31 @@ class GPTRouterClient:
125
162
  continue
126
163
 
127
164
  data = json.loads(line_data.strip())
128
- yield ChunkedGenerationResponse.model_validate(data)
165
+ if data["event"].lower() == "error":
166
+ raise GPTRouterStreamingError(data["message"])
167
+ yield parse_obj_as(ChunkedGenerationResponse, data)
168
+ except GPTRouterStreamingError as e:
169
+ raise e
129
170
  except Exception:
130
171
  continue
131
172
  except httpx.TimeoutException as err:
132
173
  logger.error(f"Timeout error: {err}")
133
174
  raise TimeoutError("Request timed out")
134
175
 
135
- def generate(self, *, ordered_generation_requests: List[ModelGenerationRequest], is_stream=False) -> Union[GenerationResponse, Generator[ChunkedGenerationResponse]]:
176
+ def generate(
177
+ self,
178
+ *,
179
+ ordered_generation_requests: List[ModelGenerationRequest],
180
+ is_stream=False,
181
+ ) -> Union[GenerationResponse, Generator[ChunkedGenerationResponse]]:
136
182
  api_path = "/v1/generate"
137
183
  api_method = "POST"
138
184
  api_payload = {
139
185
  "stream": is_stream,
140
- "data": [request.model_dump(exclude_none=True, by_alias=True) for request in ordered_generation_requests],
186
+ "data": [
187
+ request.dict(exclude_none=True, by_alias=True)
188
+ for request in ordered_generation_requests
189
+ ],
141
190
  }
142
191
  if is_stream:
143
192
  return self.stream_events(
@@ -145,18 +194,33 @@ class GPTRouterClient:
145
194
  method=api_method,
146
195
  payload=api_payload,
147
196
  )
148
- return GenerationResponse.model_validate(self._api_call(
197
+ result = self._api_call(
149
198
  path=api_path,
150
199
  method=api_method,
151
200
  payload=api_payload,
152
- ))
153
-
154
- async def agenerate(self, *, ordered_generation_requests: List[ModelGenerationRequest], is_stream=False) -> GenerationResponse:
201
+ )
202
+ return parse_obj_as(GenerationResponse, result)
203
+
204
+ async def agenerate(
205
+ self,
206
+ *,
207
+ ordered_generation_requests: List[ModelGenerationRequest],
208
+ is_stream=False,
209
+ tag: Optional[str] = None,
210
+ user_id: Optional[str] = None,
211
+ history_id: Optional[str] = None,
212
+ ) -> GenerationResponse:
155
213
  api_path = "/v1/generate"
156
214
  api_method = "POST"
157
215
  api_payload = {
158
216
  "stream": is_stream,
159
- "data": [request.model_dump(exclude_none=True, by_alias=True) for request in ordered_generation_requests],
217
+ "data": [
218
+ request.dict(exclude_none=True, by_alias=True)
219
+ for request in ordered_generation_requests
220
+ ],
221
+ "tag": tag,
222
+ "createdByUserId": user_id,
223
+ "historyId": history_id,
160
224
  }
161
225
  if is_stream:
162
226
  return self.astream_events(
@@ -164,8 +228,30 @@ class GPTRouterClient:
164
228
  method=api_method,
165
229
  payload=api_payload,
166
230
  )
167
- return GenerationResponse.model_validate(await self._async_api_call(
231
+ result = await self._async_api_call(
232
+ path=api_path,
233
+ method=api_method,
234
+ payload=api_payload,
235
+ )
236
+ return parse_obj_as(GenerationResponse, result)
237
+
238
+ async def agenerate_images(
239
+ self, *, image_generation_request: ImageGenerationRequest
240
+ ) -> List[ImageGenerationResponse]:
241
+ api_path = "/v1/generate/generate-image"
242
+ api_method = "POST"
243
+ api_payload = image_generation_request.dict()
244
+
245
+ api_response = await self._async_api_call(
168
246
  path=api_path,
169
247
  method=api_method,
170
248
  payload=api_payload,
171
- ))
249
+ )
250
+ generated_images = api_response.get("response", [])
251
+ if isinstance(generated_images, dict):
252
+ generated_images = generated_images.get('artifacts', [])
253
+
254
+ return [
255
+ parse_obj_as(ImageGenerationResponse, generated_img)
256
+ for generated_img in generated_images
257
+ ]
@@ -0,0 +1,2 @@
1
+ DEFAULT_API_BASE_URL = 'https://gpt-router-preview.writesonic.com'
2
+ DEFAULT_REQUEST_TIMEOUT = 60
@@ -0,0 +1,162 @@
1
+ from collections import namedtuple
2
+ from enum import Enum
3
+
4
+ class ProvidersEnum(Enum):
5
+ OPENAI = "openai"
6
+ CHAT_OPENAI = "chat_openai"
7
+ ANTHROPIC = "anthropic"
8
+ CHAT_ANTHROPIC = "chat_anthropic"
9
+ AZURE_CHAT_OPENAI = "azure_chat_openai"
10
+ COHERE = "cohere"
11
+ DALLE = "dall-e"
12
+ TOGETHER_AI = "together_ai"
13
+ MISTRAL_AI = "mistral_ai"
14
+ PERPLEXITY = "perplexity"
15
+ STABLE_DIFFUSION = "stable-diffusion"
16
+ DALL_E = "dall-e"
17
+ OPENROUTER = "openrouter"
18
+
19
+ class ModelsEnum(Enum):
20
+ OPENAI_GPT_35_TURBO_16K = "gpt-3.5-turbo-16k"
21
+ AZURE_GPT_35_TURBO_16K = "gpt-35-turbo-16k"
22
+
23
+ OPENAI_GPT_35_TURBO_1106 = "gpt-3.5-turbo-1106"
24
+
25
+ OPENAI_GPT_35_TURBO_0613 = "gpt-3.5-turbo-0613"
26
+
27
+ AZURE_GPT_35_TURBO = "gpt-35-turbo"
28
+
29
+ OPENAI_GPT_4 = "gpt-4"
30
+ AZURE_GPT_4 = "gpt-4"
31
+
32
+ OPENAI_GPT_4_0613 = "gpt-4-0613"
33
+
34
+ OPENAI_GPT_4_32K = "gpt-4-32k"
35
+ AZURE_GPT_4_32K = "gpt-4-32k"
36
+
37
+ OPENAI_GPT_35_TURBO_INSTRUCT = "gpt-3.5-turbo-instruct"
38
+
39
+ CLAUDE_INSTANT_12 = "claude-instant-1.2"
40
+
41
+ DALLE_3 = "dall-e-3"
42
+
43
+ STABLE_DIFFUSION_XL = "stable-diffusion-xl-1024-v1-0"
44
+ STABLE_DIFFUSION_V6 = "stable-diffusion-v1-6"
45
+
46
+ class StreamingEventType(Enum):
47
+ UPDATE = "update"
48
+ META = "meta"
49
+ ERROR = "error"
50
+ GENERATION_SOURCE = "generation_source"
51
+ END = "end"
52
+
53
+
54
+ ModelDetails = namedtuple("ModelDetails", ["provider_name", "model_name"])
55
+
56
+
57
+ class GPTRouterEngines(Enum):
58
+ OPENAI_GPT_35_TURBO = ModelDetails(
59
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-3.5-turbo"
60
+ )
61
+ OPENAI_GPT_35_TURBO_0613 = ModelDetails(
62
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-3.5-turbo-0613"
63
+ )
64
+ OPENAI_GPT_35_TURBO_1106 = ModelDetails(
65
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-3.5-turbo-1106"
66
+ )
67
+ OPENAI_GPT_35_TURBO_16K_0613 = ModelDetails(
68
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-3.5-turbo-16k-0613"
69
+ )
70
+ OPENAI_GPT_35_TURBO_INSTRUCT = ModelDetails(
71
+ ProvidersEnum.OPENAI.value, "gpt-3.5-turbo-instruct"
72
+ )
73
+ OPENAI_GPT_35_TURBO_0125 = ModelDetails(
74
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-3.5-turbo-0125"
75
+ )
76
+
77
+ OPENAI_GPT_4_0613 = ModelDetails(ProvidersEnum.CHAT_OPENAI.value, "gpt-4-0613")
78
+ OPENAI_GPT_4_TURBO = ModelDetails(
79
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-4-1106-preview"
80
+ )
81
+ OPENAI_GPT_4_TURBO_2024_04_09 = ModelDetails(
82
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-4-turbo-2024-04-09"
83
+ )
84
+
85
+ OPENAI_GPT_4_TURBO_0125 = ModelDetails(
86
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-4-0125-preview"
87
+ )
88
+
89
+ AZURE_OPENAI_GPT_4_TURBO_0125 = ModelDetails(
90
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt4-turbo-0125"
91
+ )
92
+
93
+ OPENAI_GPT_4_O = ModelDetails(ProvidersEnum.CHAT_OPENAI.value, "gpt-4o")
94
+
95
+ OPENAI_GPT_4_32K_0613 = ModelDetails(
96
+ ProvidersEnum.CHAT_OPENAI.value, "gpt-4-32k-0613"
97
+ )
98
+
99
+ AZURE_GPT_35_TURBO = ModelDetails(
100
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-35-turbo"
101
+ )
102
+ AZURE_GPT_35_TURBO_16K = ModelDetails(
103
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-35-turbo-16k"
104
+ )
105
+ AZURE_GPT_35_TURBO_1106 = ModelDetails(
106
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-35-turbo-1106"
107
+ )
108
+
109
+ AZURE_GPT_4 = ModelDetails(ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-4")
110
+ AZURE_GPT_4_TURBO = ModelDetails(
111
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-4-turbo"
112
+ )
113
+ AZURE_GPT_4_32K = ModelDetails(
114
+ ProvidersEnum.AZURE_CHAT_OPENAI.value, "gpt-4-32k"
115
+ )
116
+
117
+ CLAUDE_INSTANT_12 = ModelDetails(
118
+ ProvidersEnum.ANTHROPIC.value, "claude-instant-1.2"
119
+ )
120
+ CLAUDE_2 = ModelDetails(ProvidersEnum.ANTHROPIC.value, "claude-2")
121
+ CLAUDE_21 = ModelDetails(ProvidersEnum.ANTHROPIC.value, "claude-2.1")
122
+ CLAUDE_3_OPUS = ModelDetails(
123
+ ProvidersEnum.ANTHROPIC.value, "claude-3-opus-20240229"
124
+ )
125
+
126
+ MISTRAL_7B = ModelDetails(
127
+ ProvidersEnum.TOGETHER_AI.value, "mistralai/Mistral-7B-Instruct-v0.2"
128
+ )
129
+ MIXTRAL_8X7B = ModelDetails(
130
+ ProvidersEnum.TOGETHER_AI.value, "mistralai/Mixtral-8x7B-Instruct-v0.1"
131
+ )
132
+ LLAMA_2_70B = ModelDetails(
133
+ ProvidersEnum.TOGETHER_AI.value, "togethercomputer/llama-2-70b-chat"
134
+ )
135
+
136
+ MISTRAL_MEDIUM = ModelDetails(ProvidersEnum.MISTRAL_AI.value, "mistral-medium")
137
+
138
+ PPTX_70B_ONLINE = ModelDetails(
139
+ ProvidersEnum.PERPLEXITY.value, "pplx-70b-online"
140
+ )
141
+ PPTX_7B_ONLINE = ModelDetails(ProvidersEnum.PERPLEXITY.value, "pplx-7b-online")
142
+
143
+ STABLE_DIFFUSION_XL = ModelDetails(
144
+ ProvidersEnum.STABLE_DIFFUSION.value, "stable-diffusion-xl-1024-v1-0"
145
+ )
146
+ DALLE_3 = ModelDetails(ProvidersEnum.DALL_E.value, "dall-e-3")
147
+
148
+ LLAMA_3_70B_NITRO = ModelDetails(
149
+ ProvidersEnum.OPENROUTER, "meta-llama/llama-3-70b-instruct:nitro"
150
+ )
151
+
152
+ CLAUDE_3_SONNET = ModelDetails(
153
+ ProvidersEnum.CHAT_ANTHROPIC.value, "claude-3-sonnet-20240229"
154
+ )
155
+
156
+ CLAUDE_3_HAIKU = ModelDetails(
157
+ ProvidersEnum.CHAT_ANTHROPIC.value, "claude-3-haiku-20240307"
158
+ )
159
+
160
+ OPENROUTER_CLAUDE_3_HAIKU = ModelDetails(
161
+ ProvidersEnum.OPENROUTER.value, "anthropic/claude-3-haiku"
162
+ )
@@ -0,0 +1,59 @@
1
+ class GPTRouterBadRequestError(Exception):
2
+ """Exception raised for HTTP status code 400: Bad Request within the GPTRouter.
3
+
4
+ This status code indicates that the GPTRouter could not understand the request due to invalid syntax."""
5
+
6
+ pass
7
+
8
+
9
+ class GPTRouterNotAvailableError(Exception):
10
+ """Exception raised when GPTRouter is unavailable"""
11
+
12
+ pass
13
+
14
+
15
+ class GPTRouterUnauthorizedError(Exception):
16
+ """Exception raised for HTTP status code 401: Unauthorized.
17
+
18
+ This status code indicates that the client must authenticate itself with the correct GPTRouter API Token."""
19
+
20
+ pass
21
+
22
+
23
+ class GPTRouterForbiddenError(Exception):
24
+ """Exception raised for HTTP status code 403: Forbidden.
25
+
26
+ This status code indicates that the client does not have privileges to perform an action on GPTRouter."""
27
+
28
+ pass
29
+
30
+
31
+ class GPTRouterInternalServerError(Exception):
32
+ """Exception raised for HTTP status code 500: Internal Server Error within the GPTRouter.
33
+
34
+ This status code indicates a server error at GPTRouter end, as the name suggests."""
35
+
36
+ pass
37
+
38
+
39
+ class GPTRouterTooManyRequestsError(Exception):
40
+ """Exception raised for status code 429: Too Many Requests.
41
+
42
+ This status code indicates that the user has sent too many requests in a given amount of time."""
43
+
44
+ def __init__(self, message="You are being rate limited"):
45
+ self.message = message
46
+ super().__init__(self.message)
47
+
48
+
49
+ class GPTRouterApiTimeoutError(Exception):
50
+ """Exception raised for API request timeout within the GPTRouter.
51
+ Indicates that the request took too long to complete."""
52
+
53
+ pass
54
+
55
+
56
+ class GPTRouterStreamingError(Exception):
57
+ """Exception raised for Errors received during streaming a generation response"""
58
+
59
+ pass
@@ -0,0 +1,98 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from typing import List, Optional, Dict, Any
4
+ from humps import camelize
5
+
6
+
7
+ def to_camel(string):
8
+ return camelize(string)
9
+
10
+
11
+ class GenerationParams(BaseModel):
12
+ messages: Optional[List[Any]] = None
13
+ max_tokens: Optional[int] = None
14
+ temperature: Optional[float] = None
15
+ top_p: Optional[float] = None
16
+ n: Optional[int] = None
17
+ user: Optional[str] = None
18
+ prompt: Optional[str] = None
19
+ frequency_penalty: Optional[float] = None
20
+ presence_penalty: Optional[float] = None
21
+ functions: Optional[List[Any]] = None
22
+ function_call: Optional[dict] = None
23
+ tools: Optional[List[Any]] = None
24
+ response_format: Optional[Dict[str, Any]] = None
25
+
26
+
27
+ class ModelGenerationRequest(BaseModel):
28
+ model_name: str
29
+ provider_name: str
30
+ order: int = Field(int)
31
+ prompt_params: Optional[GenerationParams] = Field(default={})
32
+
33
+ class Config:
34
+ alias_generator = to_camel
35
+ allow_population_by_field_name = True
36
+ protected_namespaces = ()
37
+
38
+
39
+ class Usage(BaseModel):
40
+ completion_tokens: Optional[int] = None
41
+ prompt_tokens: Optional[int] = None
42
+ total_tokens: Optional[int] = None
43
+
44
+
45
+ class Choice(BaseModel):
46
+ index: int
47
+ text: str
48
+ finish_reason: str
49
+ role: Optional[str] = None
50
+ function_call: Optional[Any] = None
51
+
52
+
53
+ class GenerationResponse(BaseModel):
54
+ id: str
55
+ choices: List[Choice]
56
+ model: str
57
+ provider_id: Optional[str] = Field(None, alias="providerId")
58
+ model_id: Optional[str] = Field(None, alias="modelId")
59
+ meta: Optional[Usage]
60
+
61
+ class Config:
62
+ alias_generator = to_camel
63
+ allow_population_by_field_name = True
64
+ protected_namespaces = ()
65
+
66
+
67
+ class ChunkedGenerationResponse(BaseModel):
68
+ event: str
69
+ data: dict
70
+
71
+
72
+ class ImageGenerationRequest(BaseModel):
73
+ model_name: str = Field(alias="model")
74
+ provider_name: str = Field(alias="imageVendor")
75
+ prompt: str
76
+ num_images: int = Field(alias="numImages", default=1)
77
+ width: Optional[int] = Field(None, alias="width")
78
+ height: Optional[int] = Field(None, alias="height")
79
+
80
+ class Config:
81
+ allow_population_by_field_name = True
82
+ protected_namespaces = ()
83
+
84
+ @property
85
+ def size(self) -> Optional[str]:
86
+ return f"{self.width}x{self.height}" if self.width and self.height else None
87
+
88
+ def dict(self, *args, **kwargs):
89
+ base_dict = super().dict(*args, **kwargs, exclude_none=True, by_alias=True)
90
+ if self.size is not None:
91
+ base_dict["size"] = self.size
92
+ return base_dict
93
+
94
+
95
+ class ImageGenerationResponse(BaseModel):
96
+ url: str = None
97
+ base64: str = None
98
+ finish_reason: Optional[str] = Field(default="SUCCESS", alias='finishReason')
@@ -8,7 +8,9 @@ readme = "README.md"
8
8
  [tool.poetry.dependencies]
9
9
  python = "^3.10"
10
10
  httpx = "^0.25.2"
11
- pydantic = "^2.5.2"
11
+ pydantic = "^1.10.14"
12
+ pyhumps = "^3.8.0"
13
+ python-dotenv = "^1.0.0"
12
14
 
13
15
 
14
16
  [build-system]
@@ -0,0 +1,22 @@
1
+ from setuptools import setup
2
+
3
+ with open("README.md", "r") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name="GPTRouter",
8
+ version="0.2.5",
9
+ description="A Python package for working with GPTRouter APIs",
10
+ long_description=long_description,
11
+ long_description_content_type="text/markdown",
12
+ author_email="sirjanpreet@writesonic.com",
13
+ packages=["gpt_router"],
14
+ install_requires=["httpx>=0.23.3", "pydantic>=1.10.13", "pyhumps>=3.8.0"],
15
+ classifiers=[
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ ],
22
+ )
@@ -1,2 +0,0 @@
1
- httpx>=0.25.2
2
- pydantic==2.5.2
@@ -1,2 +0,0 @@
1
- DEFAULT_API_BASE_URL = 'http://alpha-model-router-alb-465937182.us-east-1.elb.amazonaws.com'
2
- DEFAULT_REQUEST_TIMEOUT = 60
@@ -1,38 +0,0 @@
1
- from enum import Enum
2
-
3
- class ProvidersEnum(Enum):
4
- OPENAI = "openai"
5
- CHAT_OPENAI = "chat_openai"
6
- ANTHROPIC = "anthropic"
7
- AZURE_CHAT_OPENAI = "azure_chat_openai"
8
- COHERE = "cohere"
9
-
10
- class ModelsEnum(Enum):
11
- OPENAI_GPT_35_TURBO_16K = "gpt-3.5-turbo-16k"
12
- AZURE_GPT_35_TURBO_16K = "gpt-35-turbo-16k"
13
-
14
- OPENAI_GPT_35_TURBO_1106 = "gpt-3.5-turbo-1106"
15
-
16
- OPENAI_GPT_35_TURBO_0613 = "gpt-3.5-turbo-0613"
17
-
18
- OPENAI_GPT_35_TURBO = "gpt-3.5-turbo"
19
- AZURE_GPT_35_TURBO = "gpt-35-turbo"
20
-
21
- OPENAI_GPT_4 = "gpt-4"
22
- AZURE_GPT_4 = "gpt-4"
23
-
24
- OPENAI_GPT_4_0613 = "gpt-4-0613"
25
-
26
- OPENAI_GPT_4_32K = "gpt-4-32k"
27
- AZURE_GPT_4_32K = "gpt-4-32k"
28
-
29
- OPENAI_GPT_35_TURBO_INSTRUCT = "gpt-3.5-turbo-instruct"
30
-
31
- CLAUDE_INSTANT_12 = "claude-instant-1.2"
32
-
33
- class StreamingEventType(Enum):
34
- UPDATE = "update"
35
- META = "meta"
36
- ERROR = "error"
37
- GENERATION_SOURCE = "generation_source"
38
- END = "end"
@@ -1,53 +0,0 @@
1
- from pydantic import BaseModel, Field
2
-
3
- from typing import List, Optional, Dict, Any
4
-
5
-
6
- class GenerationParams(BaseModel):
7
- messages: Optional[List[Dict[str, str]]] = None
8
- max_tokens: Optional[int] = None
9
- temperature: Optional[float] = 0.7
10
- top_p: Optional[float] = None
11
- n: Optional[int] = None
12
- user: Optional[str] = None
13
- prompt: Optional[str] = None
14
- frequency_penalty: Optional[float] = None
15
- presence_penalty: Optional[float] = None
16
- functions: Optional[List[str]] = []
17
- function_call: Optional[str] = None
18
-
19
-
20
- class ModelGenerationRequest(BaseModel):
21
- model_name: str = Field(alias='modelName')
22
- provider_name: str = Field(alias='providerName')
23
- order: int = Field(int)
24
- prompt_params: Optional[GenerationParams] = Field(default={}, alias="promptParams")
25
-
26
- class Config:
27
- populate_by_name = True
28
-
29
- class Usage(BaseModel):
30
- completion_tokens: Optional[int] = None
31
- prompt_tokens: Optional[int] = None
32
- total_tokens: Optional[int] = None
33
-
34
- class Choice(BaseModel):
35
- index: int
36
- text: str
37
- finish_reason: str
38
- role: Optional[str] = None
39
- function_call: Optional[Any] = None
40
-
41
-
42
- class GenerationResponse(BaseModel):
43
- id: str
44
- choices: List[Choice]
45
- model: str
46
- provider_id: Optional[str] = Field(None, alias='providerId')
47
- model_id: Optional[str] = Field(None, alias='modelId')
48
- meta: Optional[Usage]
49
-
50
-
51
- class ChunkedGenerationResponse(BaseModel):
52
- event: str
53
- data: dict
GPTRouter-0.0.2/setup.py DELETED
@@ -1,25 +0,0 @@
1
- from setuptools import setup
2
-
3
- with open("README.md", "r") as fh:
4
- long_description = fh.read()
5
-
6
- setup(
7
- name='GPTRouter',
8
- version='0.0.2',
9
- description='A Python package for working with GPTRouter APIs',
10
- long_description=long_description,
11
- long_description_content_type="text/markdown",
12
- author_email='sirjanpreet.ext@writesonic.com',
13
- packages=['gpt_router'],
14
- install_requires=[
15
- 'httpx>=0.25.2',
16
- "pydantic==2.5.2"
17
- ],
18
- classifiers=[
19
- 'Development Status :: 3 - Alpha',
20
- 'Intended Audience :: Developers',
21
- 'Programming Language :: Python :: 3',
22
- 'Programming Language :: Python :: 3.10',
23
- 'Programming Language :: Python :: 3.11',
24
- ],
25
- )
File without changes
File without changes
File without changes