Skip to content

Commit f72dd7e

Browse files
Merge pull request #4 from Infuzu/dev
Dev
2 parents 059e7cc + 287c80f commit f72dd7e

5 files changed

Lines changed: 119 additions & 95 deletions

File tree

main.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
from src.infuzu import (create_chat_completion, ChatCompletionsHandlerRequestMessage, ChatCompletionsObject)
1+
from src.infuzu import (
2+
create_chat_completion, ChatCompletionsHandlerRequestMessage, ChatCompletionsObject
3+
)
24
from dotenv import load_dotenv
35

46

5-
load_dotenv()
7+
if __name__ == "__main__":
8+
load_dotenv()
69

10+
messages: list[ChatCompletionsHandlerRequestMessage] = [
11+
ChatCompletionsHandlerRequestMessage(role="system", content="You are a helpful assistant."),
12+
ChatCompletionsHandlerRequestMessage(role="user", content="What is the capital of France?"),
13+
]
714

8-
messages: list[ChatCompletionsHandlerRequestMessage] = [
9-
ChatCompletionsHandlerRequestMessage(role="system", content="You are a helpful assistant."),
10-
ChatCompletionsHandlerRequestMessage(role="user", content="What is the capital of France?"),
11-
]
12-
13-
14-
try:
15-
response: ChatCompletionsObject = create_chat_completion(messages=messages)
16-
print(response)
17-
except Exception as e:
18-
print(f"Error: {e}")
15+
try:
16+
response: ChatCompletionsObject = create_chat_completion(messages=messages)
17+
print(response)
18+
except Exception as e:
19+
print(f"Error: {e}")

src/infuzu/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
ChatCompletionsObject,
1818
)
1919
from .errors import (InfuzuAPIError, APIWarning, APIError)
20+
from .utils import get_version
2021

2122

2223
__all__: list[str] = [
@@ -40,4 +41,6 @@
4041
"InfuzuAPIError",
4142
"APIWarning",
4243
"APIError",
44+
45+
"get_version",
4346
]

src/infuzu/api_client.py

Lines changed: 64 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,155 @@
1+
import platform
12
import time
23
import uuid
34
import httpx
45
import os
56
from typing import (Optional, Dict, Union, List)
6-
from pydantic import (BaseModel, validator, Field)
7+
from pydantic import (BaseModel, Field, ConfigDict, model_validator)
8+
from .utils import get_version
79
from .errors import InfuzuAPIError
810

911

1012
class ModelWeights(BaseModel):
13+
model_config = ConfigDict(extra="allow")
14+
1115
price: Optional[float] = None
1216
error: Optional[float] = None
1317
start_latency: Optional[float] = None
1418
end_latency: Optional[float] = None
1519

16-
class Config:
17-
extra: str = "allow"
18-
1920

2021
class InfuzuModelParams(BaseModel):
22+
model_config = ConfigDict(extra="allow")
23+
2124
llms: Optional[List[str]] = None
2225
exclude_llms: Optional[List[str]] = None
2326
weights: Optional[ModelWeights] = None
2427
imsn: Optional[int] = None
2528
max_input_cost: Optional[float] = None
2629
max_output_cost: Optional[float] = None
2730

28-
class Config:
29-
extra: str = "allow"
30-
3131

3232
class ChatCompletionsRequestContentPart(BaseModel):
33+
model_config = ConfigDict(extra="allow")
34+
3335
type: str
3436
text: Optional[str] = None
3537
image_url: Optional[str] = None
3638
input_audio: Optional[str] = None
3739

38-
class Config:
39-
extra: str = "allow"
40-
41-
@validator("text", always=True)
42-
def check_content_fields(cls, value, values):
43-
if "type" in values:
44-
content_type = values["type"]
45-
if content_type == "text" and value is None:
46-
raise ValueError("Text must be provided when type is 'text'")
47-
if content_type != "text" and value is not None:
48-
raise ValueError("Text cannot be provided when type is not 'text'")
49-
return value
40+
@model_validator(mode='after')
41+
def check_content_fields(self) -> 'ChatCompletionsRequestContentPart':
42+
if self.type == "text" and self.text is None:
43+
raise ValueError("Text must be provided when type is 'text'")
44+
if self.type != "text" and self.text is not None:
45+
raise ValueError("Text cannot be provided when type is not 'text'")
46+
return self
5047

5148

5249
class ChatCompletionsHandlerRequestMessage(BaseModel):
50+
model_config = ConfigDict(extra="allow")
51+
5352
content: Union[str, List[ChatCompletionsRequestContentPart]]
5453
role: str
5554
name: Optional[str] = None
5655

57-
class Config:
58-
extra: str = "allow"
59-
60-
@validator('role')
61-
def role_must_be_valid(cls, v):
62-
if v not in ('system', 'user', 'assistant'):
56+
@model_validator(mode='after')
57+
def role_must_be_valid(self) -> 'ChatCompletionsHandlerRequestMessage':
58+
if self.role not in ('system', 'user', 'assistant'):
6359
raise ValueError('Role must be one of: system, user, assistant')
64-
return v
60+
return self
6561

6662

6763
class ChatCompletionsChoiceMessageAudioObject(BaseModel):
64+
model_config = ConfigDict(extra="allow")
65+
6866
id: Optional[str] = None
6967
expired_at: Optional[int] = None
7068
data: Optional[str] = None
7169
transcript: Optional[str] = None
7270

73-
class Config:
74-
extra: str = "allow"
75-
7671

7772
class ChatCompletionsChoiceMessageFunctionCallObject(BaseModel):
73+
model_config = ConfigDict(extra="allow")
74+
7875
name: Optional[str] = None
7976
arguments: Optional[str] = None
8077

81-
class Config:
82-
extra: str = "allow"
83-
8478

8579
class ChatCompletionsChoiceMessageToolCallFunctionObject(BaseModel):
80+
model_config = ConfigDict(extra="allow")
81+
8682
name: Optional[str] = None
8783
arguments: Optional[str] = None
8884

89-
class Config:
90-
extra: str = "allow"
91-
9285

9386
class chatCompletionsChoiceMessageToolCallObject(BaseModel):
87+
model_config = ConfigDict(extra="allow")
88+
9489
id: Optional[str] = None
9590
type: Optional[str] = None
9691
function: Optional[ChatCompletionsChoiceMessageToolCallFunctionObject] = None
9792

98-
class Config:
99-
extra: str = "allow"
100-
10193

10294
class ChatCompletionsChoiceMessageObject(BaseModel):
95+
model_config = ConfigDict(extra="allow")
96+
10397
content: Optional[str] = None
10498
refusal: Optional[str] = None
10599
tool_calls: Optional[List[chatCompletionsChoiceMessageToolCallObject]] = None
106100
role: Optional[str] = None
107101
function_call: Optional[ChatCompletionsChoiceMessageFunctionCallObject] = None
108102
audio: Optional[ChatCompletionsChoiceMessageAudioObject] = None
109103

110-
class Config:
111-
extra: str = "allow"
112-
113104

114105
class ChatCompletionsChoiceLogprobsItemTopLogprobObject(BaseModel):
106+
model_config = ConfigDict(extra="allow")
107+
115108
token: Optional[str] = None
116109
logprob: Optional[int] = None
117110
bytes: Optional[List[int]] = None
118111

119-
class Config:
120-
extra: str = "allow"
121-
122112

123113
class ChatCompletionsLogprobsItemObject(BaseModel):
114+
model_config = ConfigDict(extra="allow")
115+
124116
token: Optional[str] = None
125117
logprob: Optional[int] = None
126118
bytes: Optional[List[int]] = None
127119
content: Optional[List[ChatCompletionsChoiceLogprobsItemTopLogprobObject]] = None
128120

129-
class Config:
130-
extra: str = "allow"
131-
132121

133122
class ChatCompletionsChoiceLogprobsObject(BaseModel):
123+
model_config = ConfigDict(extra="allow")
124+
134125
content: Optional[List[ChatCompletionsLogprobsItemObject]] = None
135126
refusal: Optional[List[ChatCompletionsLogprobsItemObject]] = None
136127

137-
class Config:
138-
extra: str = "allow"
139-
140128

141129
class ChatCompletionsChoiceModelObject(BaseModel):
130+
model_config = ConfigDict(extra="allow")
131+
142132
ref: Optional[str] = None
143133
rank: Optional[int] = None
144134

145-
class Config:
146-
extra: str = "allow"
147-
148135

149136
class ChatCompletionsChoiceErrorObject(BaseModel):
137+
model_config = ConfigDict(extra="allow")
138+
150139
message: Optional[str] = None
151140
code: Optional[str] = None
152141

153-
class Config:
154-
extra: str = "allow"
155-
156142

157143
class ChatCompletionsChoiceLatencyObject(BaseModel):
144+
model_config = ConfigDict(extra="allow")
145+
158146
start: Optional[int] = Field(None, alias='start_latency')
159147
end: Optional[int] = Field(None, alias='end_latency')
160148

161-
class Config:
162-
extra: str = "allow"
163-
164149

165150
class ChatCompletionsChoiceObject(BaseModel):
151+
model_config = ConfigDict(extra="allow")
152+
166153
finish_reason: Optional[str] = None
167154
index: Optional[int] = None
168155
message: Optional[ChatCompletionsChoiceMessageObject] = None
@@ -171,11 +158,10 @@ class ChatCompletionsChoiceObject(BaseModel):
171158
error: Optional[ChatCompletionsChoiceErrorObject] = None
172159
latency: Optional[ChatCompletionsChoiceLatencyObject] = None
173160

174-
class Config:
175-
extra: str = "allow"
176-
177161

178162
class ChatCompletionsObject(BaseModel):
163+
model_config = ConfigDict(extra="allow")
164+
179165
id: Optional[str] = None
180166
choices: Optional[List[ChatCompletionsChoiceObject]] = None
181167
created: Optional[int] = None
@@ -185,11 +171,8 @@ class ChatCompletionsObject(BaseModel):
185171
object: Optional[str] = None
186172
usage: Optional[Dict[str, int]] = None
187173

188-
class Config:
189-
extra: str = "allow"
190-
191174

192-
API_BASE_URL = "https://chat.infuzu.com/api"
175+
API_BASE_URL: str = "https://chat.infuzu.com/api"
193176

194177

195178
def create_chat_completion(
@@ -204,43 +187,49 @@ def create_chat_completion(
204187
messages: A list of message objects.
205188
api_key: Your Infuzu API key. If not provided, it will be read from the
206189
INFUZU_API_KEY environment variable.
207-
model: The model to use for the chat completion. Can be a string (model name)
190+
model: The model to use for the chat completion. Can be a string (model name)
208191
or a InfuzuModelParams object for more advanced configuration.
209192
210193
Returns:
211-
A dictionary containing the JSON response from the API.
194+
The ChatCompletionsObject Object
212195
213196
Raises:
214197
ValueError: If the API key is not provided and the INFUZU_API_KEY
215198
environment variable is not set.
216-
httpx.HTTPStatusError: If the API request returns an error status code.
199+
InfuzuAPIError: If the API request returns an error status code.
217200
"""
218201

219202
if api_key is None:
220-
api_key = os.environ.get("INFUZU_API_KEY")
203+
api_key: str | None = os.environ.get("INFUZU_API_KEY")
221204
if api_key is None:
222205
raise ValueError(
223206
"API key not provided and INFUZU_API_KEY environment variable not set."
224207
)
225208

226-
headers = {
209+
headers: dict[str, str] = {
227210
"Content-Type": "application/json",
228211
"Infuzu-API-Key": api_key,
212+
"User-Agent": (
213+
f"infuzu-python/{get_version()} "
214+
f"(Python {platform.python_version()}; "
215+
f"httpx/{httpx.__version__}; "
216+
f"{platform.system()} {platform.release()})"
217+
)
229218
}
230219

231-
payload = {
232-
"messages": [message.dict(by_alias=True) for message in messages],
220+
payload: dict[str, any] = {
221+
"messages": [message.model_dump(by_alias=True) for message in messages],
233222
}
234223

235224
if model:
236225
if isinstance(model, str):
237226
payload["model"] = model
238227
else:
239-
payload["model"] = model.dict(by_alias=True)
228+
payload["model"] = model.model_dump(by_alias=True)
240229

241230
try:
242231
with httpx.Client() as client:
243-
response = client.post(
232+
response: httpx.Response = client.post(
244233
f"{API_BASE_URL}/v1/chat/completions",
245234
headers=headers,
246235
json=payload,

src/infuzu/errors.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,25 @@
22
from json import JSONDecodeError
33
from typing import Optional
44
import httpx
5-
from pydantic import BaseModel
5+
from pydantic import (BaseModel, ConfigDict)
66

77

88
logger: logging.Logger = logging.getLogger(__name__)
99

1010

1111
class APIError(BaseModel):
12+
model_config = ConfigDict(extra="allow")
13+
1214
code: Optional[str] = None
1315
message: Optional[str] = None
1416

15-
class Config:
16-
extra: str = "allow"
17-
1817

1918
class APIWarning(BaseModel):
19+
model_config = ConfigDict(extra="allow")
20+
2021
code: Optional[str] = None
2122
message: Optional[str] = None
2223

23-
class Config:
24-
extra: str = "allow"
25-
2624

2725
class InfuzuAPIError(httpx.HTTPStatusError):
2826
def __init__(self, base_error: httpx.HTTPStatusError) -> None:

0 commit comments

Comments
 (0)