freeplay 0.2.14__py3-none-any.whl → 0.2.15__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.
- freeplay/errors.py +12 -0
- freeplay/flavors.py +62 -12
- freeplay/llm_parameters.py +3 -0
- freeplay/provider_config.py +37 -3
- {freeplay-0.2.14.dist-info → freeplay-0.2.15.dist-info}/METADATA +1 -1
- freeplay-0.2.15.dist-info/RECORD +12 -0
- freeplay-0.2.14.dist-info/RECORD +0 -12
- {freeplay-0.2.14.dist-info → freeplay-0.2.15.dist-info}/WHEEL +0 -0
freeplay/errors.py
CHANGED
@@ -2,6 +2,18 @@ class FreeplayError(Exception):
|
|
2
2
|
pass
|
3
3
|
|
4
4
|
|
5
|
+
class APITypeMissingError(Exception):
|
6
|
+
pass
|
7
|
+
|
8
|
+
|
9
|
+
class APIVersionMissingError(Exception):
|
10
|
+
pass
|
11
|
+
|
12
|
+
|
13
|
+
class APIEngineMissingError(Exception):
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
5
17
|
class APIKeyMissingError(Exception):
|
6
18
|
pass
|
7
19
|
|
freeplay/flavors.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import json
|
2
2
|
from abc import abstractmethod, ABC
|
3
3
|
from copy import copy
|
4
|
-
from typing import Optional, Generator, Any
|
4
|
+
from typing import Optional, Generator, Any, Union
|
5
|
+
from dataclasses import dataclass, asdict
|
5
6
|
|
6
7
|
import anthropic # type: ignore
|
7
8
|
import openai
|
@@ -24,6 +25,8 @@ class Flavor(ABC):
|
|
24
25
|
return OpenAIChat()
|
25
26
|
case AnthropicClaudeText.record_format_type:
|
26
27
|
return AnthropicClaudeText()
|
28
|
+
case AzureOpenAIChat.record_format_type:
|
29
|
+
return AzureOpenAIChat()
|
27
30
|
case _:
|
28
31
|
raise FreeplayError(
|
29
32
|
'Configured flavor not found in SDK. Please update your SDK version or configure a different model in the Freeplay UI.')
|
@@ -89,15 +92,28 @@ class ChatFlavor(Flavor, ABC):
|
|
89
92
|
|
90
93
|
|
91
94
|
class OpenAI(Flavor, ABC):
|
92
|
-
def configure_openai(self,
|
95
|
+
def configure_openai(self,
|
96
|
+
openai_config: Optional[OpenAIConfig],
|
97
|
+
api_base: Optional[str] = None,
|
98
|
+
api_version: Optional[str] = None,
|
99
|
+
api_type: Optional[str] = None,
|
100
|
+
) -> None:
|
93
101
|
super().__init__()
|
94
102
|
if not openai_config:
|
95
103
|
raise APIKeyMissingError(
|
96
104
|
"Missing OpenAI key. Use a ProviderConfig to specify keys prior to getting completion.")
|
97
105
|
|
98
|
-
if
|
106
|
+
if api_base:
|
107
|
+
openai.api_base = api_base
|
108
|
+
elif openai_config.api_base:
|
99
109
|
openai.api_base = openai_config.api_base
|
100
110
|
|
111
|
+
if api_type:
|
112
|
+
openai.api_type = api_type
|
113
|
+
|
114
|
+
if api_version:
|
115
|
+
openai.api_version = api_version
|
116
|
+
|
101
117
|
if not openai_config.api_key or not openai_config.api_key.strip():
|
102
118
|
raise APIKeyMissingError("OpenAI API key is not set. It must be set to make calls to the service.")
|
103
119
|
|
@@ -123,7 +139,7 @@ class OpenAIText(OpenAI):
|
|
123
139
|
provider_config: ProviderConfig,
|
124
140
|
llm_parameters: LLMParameters
|
125
141
|
) -> CompletionResponse:
|
126
|
-
completion = self.
|
142
|
+
completion = self._call_openai(formatted_prompt, provider_config, llm_parameters, stream=False)
|
127
143
|
return CompletionResponse(
|
128
144
|
content=completion.choices[0].text,
|
129
145
|
is_complete=completion.choices[0].finish_reason == "stop"
|
@@ -135,7 +151,7 @@ class OpenAIText(OpenAI):
|
|
135
151
|
provider_config: ProviderConfig,
|
136
152
|
llm_parameters: LLMParameters
|
137
153
|
) -> Generator[CompletionChunk, None, None]:
|
138
|
-
completion = self.
|
154
|
+
completion = self._call_openai(formatted_prompt, provider_config, llm_parameters, stream=True)
|
139
155
|
|
140
156
|
for chunk in completion:
|
141
157
|
yield CompletionChunk(
|
@@ -143,7 +159,7 @@ class OpenAIText(OpenAI):
|
|
143
159
|
is_complete=chunk.choices[0].finish_reason == "stop"
|
144
160
|
)
|
145
161
|
|
146
|
-
def
|
162
|
+
def _call_openai(
|
147
163
|
self,
|
148
164
|
prompt: str,
|
149
165
|
provider_config: ProviderConfig,
|
@@ -181,7 +197,7 @@ class OpenAIChat(OpenAI, ChatFlavor):
|
|
181
197
|
llm_parameters: LLMParameters
|
182
198
|
) -> CompletionResponse:
|
183
199
|
messages = json.loads(formatted_prompt)
|
184
|
-
completion = self.
|
200
|
+
completion = self._call_openai(messages, provider_config, llm_parameters, stream=False)
|
185
201
|
return CompletionResponse(
|
186
202
|
content=completion.choices[0].message.content or '',
|
187
203
|
is_complete=completion.choices[0].finish_reason == 'stop',
|
@@ -195,7 +211,7 @@ class OpenAIChat(OpenAI, ChatFlavor):
|
|
195
211
|
llm_parameters: LLMParameters
|
196
212
|
) -> Generator[CompletionChunk, None, None]:
|
197
213
|
messages = json.loads(formatted_prompt)
|
198
|
-
completion_stream = self.
|
214
|
+
completion_stream = self._call_openai(messages, provider_config, llm_parameters, stream=True)
|
199
215
|
for chunk in completion_stream:
|
200
216
|
yield CompletionChunk(
|
201
217
|
text=chunk.choices[0].delta.get('content') or '',
|
@@ -209,7 +225,7 @@ class OpenAIChat(OpenAI, ChatFlavor):
|
|
209
225
|
provider_config: ProviderConfig,
|
210
226
|
llm_parameters: LLMParameters
|
211
227
|
) -> ChatCompletionResponse:
|
212
|
-
completion = self.
|
228
|
+
completion = self._call_openai(messages, provider_config, llm_parameters, stream=False)
|
213
229
|
|
214
230
|
message_history = copy(messages)
|
215
231
|
message_history.append(completion.choices[0].message.to_dict())
|
@@ -225,14 +241,14 @@ class OpenAIChat(OpenAI, ChatFlavor):
|
|
225
241
|
provider_config: ProviderConfig,
|
226
242
|
llm_parameters: LLMParameters
|
227
243
|
) -> Generator[CompletionChunk, None, None]:
|
228
|
-
completion_stream = self.
|
244
|
+
completion_stream = self._call_openai(messages, provider_config, llm_parameters, stream=True)
|
229
245
|
for chunk in completion_stream:
|
230
246
|
yield CompletionChunk(
|
231
247
|
text=chunk.choices[0].delta.get('content', ''),
|
232
248
|
is_complete=chunk.choices[0].finish_reason == "stop"
|
233
249
|
)
|
234
250
|
|
235
|
-
def
|
251
|
+
def _call_openai(
|
236
252
|
self,
|
237
253
|
messages: list[ChatMessage],
|
238
254
|
provider_config: ProviderConfig,
|
@@ -240,13 +256,47 @@ class OpenAIChat(OpenAI, ChatFlavor):
|
|
240
256
|
stream: bool
|
241
257
|
) -> Any:
|
242
258
|
self.configure_openai(provider_config.openai)
|
259
|
+
llm_parameters.pop('endpoint')
|
243
260
|
return openai.ChatCompletion.create(
|
244
261
|
messages=messages,
|
245
262
|
**self.get_model_params(llm_parameters),
|
246
|
-
stream=stream
|
263
|
+
stream=stream,
|
247
264
|
) # type: ignore
|
248
265
|
|
249
266
|
|
267
|
+
class AzureOpenAIChat(OpenAIChat):
|
268
|
+
record_format_type = "azure_openai_chat"
|
269
|
+
|
270
|
+
def _call_openai(
|
271
|
+
self,
|
272
|
+
messages: list[ChatMessage],
|
273
|
+
provider_config: ProviderConfig,
|
274
|
+
llm_parameters: LLMParameters,
|
275
|
+
stream: bool
|
276
|
+
) -> Any:
|
277
|
+
api_version = llm_parameters.get('api_version')
|
278
|
+
deployment_id = llm_parameters.get('deployment_id')
|
279
|
+
resource_name = llm_parameters.get('resource_name')
|
280
|
+
endpoint = f'https://{resource_name}.openai.azure.com'
|
281
|
+
self.configure_openai(
|
282
|
+
provider_config.azure,
|
283
|
+
api_base=endpoint,
|
284
|
+
api_type='azure',
|
285
|
+
api_version=api_version
|
286
|
+
)
|
287
|
+
llm_parameters.pop('resource_name')
|
288
|
+
return openai.ChatCompletion.create(
|
289
|
+
messages=messages,
|
290
|
+
**self.get_model_params(llm_parameters),
|
291
|
+
engine=deployment_id,
|
292
|
+
stream=stream,
|
293
|
+
) # type: ignore
|
294
|
+
|
295
|
+
@property
|
296
|
+
def provider(self) -> str:
|
297
|
+
return "azure"
|
298
|
+
|
299
|
+
|
250
300
|
class AnthropicClaudeText(Flavor):
|
251
301
|
record_format_type = "anthropic_text"
|
252
302
|
_model_params_with_defaults = LLMParameters({
|
freeplay/llm_parameters.py
CHANGED
freeplay/provider_config.py
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
2
|
from typing import Optional
|
3
3
|
|
4
|
-
from .errors import
|
4
|
+
from .errors import (
|
5
|
+
APIEngineMissingError,
|
6
|
+
APIKeyMissingError,
|
7
|
+
APITypeMissingError,
|
8
|
+
APIVersionMissingError,
|
9
|
+
)
|
5
10
|
|
6
11
|
|
7
12
|
@dataclass
|
@@ -9,7 +14,10 @@ class OpenAIConfig:
|
|
9
14
|
api_key: str
|
10
15
|
api_base: Optional[str]
|
11
16
|
|
12
|
-
def __init__(self,
|
17
|
+
def __init__(self,
|
18
|
+
api_key: str,
|
19
|
+
api_base: Optional[str] = None,
|
20
|
+
) -> None:
|
13
21
|
self.api_key = api_key
|
14
22
|
self.api_base = api_base
|
15
23
|
|
@@ -17,6 +25,31 @@ class OpenAIConfig:
|
|
17
25
|
if not self.api_key or not self.api_key.strip():
|
18
26
|
raise APIKeyMissingError("OpenAI API key not set. It must be set to make calls to the service.")
|
19
27
|
|
28
|
+
@dataclass
|
29
|
+
class AzureConfig(OpenAIConfig):
|
30
|
+
engine: Optional[str]
|
31
|
+
api_version: Optional[str]
|
32
|
+
|
33
|
+
def __init__(self,
|
34
|
+
api_key: str,
|
35
|
+
api_base: Optional[str] = None,
|
36
|
+
engine: Optional[str] = None,
|
37
|
+
api_version: Optional[str] = None
|
38
|
+
):
|
39
|
+
super().__init__(api_key, api_base)
|
40
|
+
self.api_version = api_version
|
41
|
+
self.engine = engine
|
42
|
+
|
43
|
+
def validate(self) -> None:
|
44
|
+
super().validate()
|
45
|
+
|
46
|
+
if self.api_version is None:
|
47
|
+
raise APIVersionMissingError(
|
48
|
+
"OpenAI API version not set. It must be set to make calls to the service.")
|
49
|
+
|
50
|
+
if self.engine is None:
|
51
|
+
raise APIEngineMissingError("Azure engine is not set. It must be set to make calls to the service.")
|
52
|
+
|
20
53
|
|
21
54
|
@dataclass
|
22
55
|
class AnthropicConfig:
|
@@ -27,10 +60,11 @@ class AnthropicConfig:
|
|
27
60
|
class ProviderConfig:
|
28
61
|
anthropic: Optional[AnthropicConfig] = None
|
29
62
|
openai: Optional[OpenAIConfig] = None
|
63
|
+
azure: Optional[AzureConfig] = None
|
30
64
|
|
31
65
|
def validate(self) -> None:
|
32
66
|
if self.anthropic is None and self.openai is None:
|
33
67
|
APIKeyMissingError("At least one provider key must be set in ProviderConfig.")
|
68
|
+
|
34
69
|
if self.openai is not None:
|
35
70
|
self.openai.validate()
|
36
|
-
|
@@ -0,0 +1,12 @@
|
|
1
|
+
freeplay/__init__.py,sha256=74A9S9hmLq9BNHsdx0-37yDxlSukudNl9bJ0TE60Z30,61
|
2
|
+
freeplay/api_support.py,sha256=mWauXzpZx9DwIzuqlnfEAXX2LsILE3an4G_6OVMHopI,1834
|
3
|
+
freeplay/completions.py,sha256=M1vlziRTIfmO-TGdqNI_eHHq4zYpMj0n8dzH-boz7bY,992
|
4
|
+
freeplay/errors.py,sha256=RFJtcgVvNsrVOeojnnh4TGvj3wYKglVshLEFpUHzafM,340
|
5
|
+
freeplay/flavors.py,sha256=nxnZnRAv4P_RBzvikg50KKlT4XN-B1V8GgT1XBqwQ5Q,13261
|
6
|
+
freeplay/freeplay.py,sha256=Rkv2V1ED4dyqgNnr5Pi5sxQL1WHz__sDkuyuzvKIYDY,27763
|
7
|
+
freeplay/llm_parameters.py,sha256=ANlau8qbFc5OTtvcnYzItZOicyiejS3VHfh8wnJYSmU,937
|
8
|
+
freeplay/provider_config.py,sha256=EkRHDV4zehqS0Vo5ZQHZHRgqdiw63PRN7rLwvm3Wiig,1871
|
9
|
+
freeplay/utils.py,sha256=n7iZGvgSJcDYL31QpYxpJyPzRpYhhqEi_r7g6t6L04I,369
|
10
|
+
freeplay-0.2.15.dist-info/METADATA,sha256=Nfk3PHXrcJyRUzSZiTUoe5w-fUU6PKbT1SsJlVdsIYc,680
|
11
|
+
freeplay-0.2.15.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
12
|
+
freeplay-0.2.15.dist-info/RECORD,,
|
freeplay-0.2.14.dist-info/RECORD
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
freeplay/__init__.py,sha256=74A9S9hmLq9BNHsdx0-37yDxlSukudNl9bJ0TE60Z30,61
|
2
|
-
freeplay/api_support.py,sha256=mWauXzpZx9DwIzuqlnfEAXX2LsILE3an4G_6OVMHopI,1834
|
3
|
-
freeplay/completions.py,sha256=M1vlziRTIfmO-TGdqNI_eHHq4zYpMj0n8dzH-boz7bY,992
|
4
|
-
freeplay/errors.py,sha256=SEkQ72gamIRMyJt2g_YHqk3mqVJAxl-SF84ODHN6vdw,188
|
5
|
-
freeplay/flavors.py,sha256=bq4wNOyCzOgsS7o2ofGImDMbAMCVmhmXFSQno7mssoE,11724
|
6
|
-
freeplay/freeplay.py,sha256=Rkv2V1ED4dyqgNnr5Pi5sxQL1WHz__sDkuyuzvKIYDY,27763
|
7
|
-
freeplay/llm_parameters.py,sha256=ODAVTVj6dGsMlAux8NSQPPqeVREMo7-IEP2VIjihR54,828
|
8
|
-
freeplay/provider_config.py,sha256=tsMmhV3BAJCfX1I0BmGgDjZjWHT8fJ78l1-BV2LEtmM,955
|
9
|
-
freeplay/utils.py,sha256=n7iZGvgSJcDYL31QpYxpJyPzRpYhhqEi_r7g6t6L04I,369
|
10
|
-
freeplay-0.2.14.dist-info/METADATA,sha256=lRBXXQGYY12KuOGtTwo0fJuTvq67ha1Msba_6nvSNWQ,680
|
11
|
-
freeplay-0.2.14.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
12
|
-
freeplay-0.2.14.dist-info/RECORD,,
|
File without changes
|