freeplay 0.3.19__py3-none-any.whl → 0.3.20__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.
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from typing import Protocol, Dict, List, Union, Any
4
4
 
5
5
  from freeplay.errors import FreeplayConfigurationError
6
+ from freeplay.support import MediaType
6
7
 
7
8
 
8
9
  @dataclass
@@ -11,12 +12,16 @@ class TextContent:
11
12
 
12
13
 
13
14
  @dataclass
14
- class ImageContentUrl:
15
+ class MediaContentUrl:
16
+ slot_name: str
17
+ type: MediaType
15
18
  url: str
16
19
 
17
20
 
18
21
  @dataclass
19
- class ImageContentBase64:
22
+ class MediaContentBase64:
23
+ slot_name: str
24
+ type: MediaType
20
25
  content_type: str
21
26
  data: str
22
27
 
@@ -58,24 +63,28 @@ class AnthropicAdapter(LLMAdapter):
58
63
  return anthropic_messages
59
64
 
60
65
  @staticmethod
61
- def __map_content(content: Union[TextContent, ImageContentBase64, ImageContentUrl]) -> Dict[str, Any]:
66
+ def __map_content(content: Union[TextContent, MediaContentBase64, MediaContentUrl]) -> Dict[str, Any]:
62
67
  if isinstance(content, TextContent):
63
68
  return {
64
69
  "type": "text",
65
70
  "text": content.text
66
71
  }
67
- elif isinstance(content, ImageContentBase64):
72
+ if content.type == "audio" or content.type == "video":
73
+ raise ValueError("Anthropic does not support audio or video content")
74
+
75
+ media_type = "image" if content.type == "image" else "document"
76
+ if isinstance(content, MediaContentBase64):
68
77
  return {
69
- "type": "image",
78
+ "type": media_type,
70
79
  "source": {
71
80
  "type": "base64",
72
81
  "media_type": content.content_type,
73
82
  "data": content.data,
74
83
  }
75
84
  }
76
- elif isinstance(content, ImageContentUrl):
85
+ elif isinstance(content, MediaContentUrl):
77
86
  return {
78
- "type": "image",
87
+ "type": media_type,
79
88
  "source": {
80
89
  "type": "url",
81
90
  "url": content.url,
@@ -101,28 +110,52 @@ class OpenAIAdapter(LLMAdapter):
101
110
  return openai_messages
102
111
 
103
112
  @staticmethod
104
- def __map_content(content: Union[TextContent, ImageContentBase64, ImageContentUrl]) -> Dict[str, Any]:
113
+ def __map_content(content: Union[TextContent, MediaContentBase64, MediaContentUrl]) -> Dict[str, Any]:
105
114
  if isinstance(content, TextContent):
106
115
  return {
107
116
  "type": "text",
108
117
  "text": content.text
109
118
  }
110
- elif isinstance(content, ImageContentBase64):
119
+ elif isinstance(content, MediaContentBase64):
120
+ return OpenAIAdapter.__format_base64_content(content)
121
+ elif isinstance(content, MediaContentUrl):
122
+ if content.type != "image":
123
+ raise ValueError("Message contains a non-image URL, but OpenAI only supports image URLs.")
124
+
111
125
  return {
112
126
  "type": "image_url",
113
127
  "image_url": {
114
- "url": f"data:{content.content_type};base64,{content.data}"
128
+ "url": content.url
129
+ }
130
+ }
131
+ else:
132
+ raise ValueError(f"Unexpected content type {type(content)}")
133
+
134
+ @staticmethod
135
+ def __format_base64_content(content: MediaContentBase64) -> Dict[str, Any]:
136
+ if content.type == "audio":
137
+ return {
138
+ "type": "input_audio",
139
+ "input_audio": {
140
+ "data": content.data,
141
+ "format": content.content_type.split("/")[-1].replace("mpeg", "mp3")
142
+ }
143
+ }
144
+ elif content.type == "file":
145
+ return {
146
+ "type": "file",
147
+ "file": {
148
+ "filename": f"{content.slot_name}.{content.content_type.split('/')[-1]}",
149
+ "file_data": f"data:{content.content_type};base64,{content.data}"
115
150
  }
116
151
  }
117
- elif isinstance(content, ImageContentUrl):
152
+ else:
118
153
  return {
119
154
  "type": "image_url",
120
155
  "image_url": {
121
- "url": content.url
156
+ "url": f"data:{content.content_type};base64,{content.data}"
122
157
  }
123
158
  }
124
- else:
125
- raise ValueError(f"Unexpected content type {type(content)}")
126
159
 
127
160
 
128
161
  class Llama3Adapter(LLMAdapter):
@@ -163,17 +196,17 @@ class GeminiAdapter(LLMAdapter):
163
196
  return gemini_messages
164
197
 
165
198
  @staticmethod
166
- def __map_content(content: Union[TextContent, ImageContentBase64, ImageContentUrl]) -> Dict[str, Any]:
199
+ def __map_content(content: Union[TextContent, MediaContentBase64, MediaContentUrl]) -> Dict[str, Any]:
167
200
  if isinstance(content, TextContent):
168
201
  return {"text": content.text}
169
- elif isinstance(content, ImageContentBase64):
202
+ elif isinstance(content, MediaContentBase64):
170
203
  return {
171
204
  "inline_data": {
172
205
  "data": content.data,
173
206
  "mime_type": content.content_type,
174
207
  }
175
208
  }
176
- elif isinstance(content, ImageContentUrl):
209
+ elif isinstance(content, MediaContentUrl):
177
210
  raise ValueError("Message contains an image URL, but image URLs are not supported by Gemini")
178
211
  else:
179
212
  raise ValueError(f"Unexpected content type {type(content)}")
@@ -25,7 +25,7 @@ from freeplay.errors import (
25
25
  )
26
26
  from freeplay.llm_parameters import LLMParameters
27
27
  from freeplay.model import InputVariables
28
- from freeplay.resources.adapters import MissingFlavorError, adaptor_for_flavor, ImageContentBase64, ImageContentUrl, \
28
+ from freeplay.resources.adapters import MissingFlavorError, adaptor_for_flavor, MediaContentBase64, MediaContentUrl, \
29
29
  TextContent
30
30
  from freeplay.support import (
31
31
  CallSupport,
@@ -212,18 +212,16 @@ MediaInputMap = Dict[str, MediaInput]
212
212
 
213
213
 
214
214
  def extract_media_content(media_inputs: MediaInputMap, media_slots: List[MediaSlot]) -> List[
215
- Union[ImageContentBase64, ImageContentUrl]]:
216
- media_content: List[Union[ImageContentBase64, ImageContentUrl]] = []
215
+ Union[MediaContentBase64, MediaContentUrl]]:
216
+ media_content: List[Union[MediaContentBase64, MediaContentUrl]] = []
217
217
  for slot in media_slots:
218
- if slot.type != "image":
219
- continue
220
218
  file = media_inputs.get(slot.placeholder_name, None)
221
219
  if file is None:
222
220
  continue
223
221
  if isinstance(file, MediaInputUrl):
224
- media_content.append(ImageContentUrl(url=file.url))
222
+ media_content.append(MediaContentUrl(type=slot.type, url=file.url, slot_name=slot.placeholder_name))
225
223
  else:
226
- media_content.append(ImageContentBase64(content_type=file.content_type, data=file.data))
224
+ media_content.append(MediaContentBase64(type=slot.type, content_type=file.content_type, data=file.data, slot_name=slot.placeholder_name))
227
225
 
228
226
  return media_content
229
227
 
freeplay/support.py CHANGED
@@ -29,9 +29,12 @@ class ToolSchema:
29
29
  Role = Literal['system', 'user', 'assistant']
30
30
 
31
31
 
32
+ MediaType = Literal["image", "audio", "video", "file"]
33
+
34
+
32
35
  @dataclass
33
36
  class MediaSlot:
34
- type: Literal["image", "audio", "video", "file"]
37
+ type: MediaType
35
38
  placeholder_name: str
36
39
 
37
40
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: freeplay
3
- Version: 0.3.19
3
+ Version: 0.3.20
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: FreePlay Engineering
@@ -7,17 +7,17 @@ freeplay/llm_parameters.py,sha256=bQbfuC8EICF0XMZQa5pwI3FkQqxmCUVqHO3gYHy3Tg8,89
7
7
  freeplay/model.py,sha256=o0de_RZ2WTJ4m5OJw1ZVfC2xG6zBq_XShBrRt1laEjc,1405
8
8
  freeplay/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  freeplay/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- freeplay/resources/adapters.py,sha256=zq-cDTBgFziFHyAJX18rEM4Fv2NHrLg3PuuxPqmg6Vw,6902
10
+ freeplay/resources/adapters.py,sha256=BFqzLoJhLJeXfUyPOKDnllN_3jlbbBH0z32tXv20R20,8188
11
11
  freeplay/resources/customer_feedback.py,sha256=bw8MfEOKbGgn4FOyvcADrcs9GhcpNXNTgxKjBjIzywE,899
12
- freeplay/resources/prompts.py,sha256=i1Lck6UTF0WhW5miK5CAIJl19BFoI760rSyjFdju6H4,22799
12
+ freeplay/resources/prompts.py,sha256=poLt48UG_3q6qDMvMqk0x6Y4QM66Mt6LyASpfcG0jwo,22843
13
13
  freeplay/resources/recordings.py,sha256=z2ARII1jCnmNh1GU3hGnXZUz5IF_KhyayQum71k-h9c,9213
14
14
  freeplay/resources/sessions.py,sha256=J5A3CjiV2MFqQyxN3TWTvJaa9jmMza58mRFRq2v9iAk,3746
15
15
  freeplay/resources/test_cases.py,sha256=nXL_976RwSJDT6OWDM4GEzbcOzcGkJ9ulvb0XOzCRDM,2240
16
16
  freeplay/resources/test_runs.py,sha256=Tp2N-odInT5XEEWrEsVhdgfnsclOE8n92_C8gTwO2MI,2623
17
- freeplay/support.py,sha256=sj3JLD2syBxDyzWVWthWWwYWCUy4GzLNMSLSHegVvkk,12251
17
+ freeplay/support.py,sha256=kQMItnMGZT5TOdPQsSiKOlBbBqO4AyR91vito6wt4JM,12275
18
18
  freeplay/utils.py,sha256=Xvt4mNLXLL7E6MI2hTuDLV5cl5Y83DgdjCZSyDGMjR0,3187
19
- freeplay-0.3.19.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
- freeplay-0.3.19.dist-info/METADATA,sha256=-RBwb7sFV4g4yNM1bREAO8mCF0cIFcWrnKmcPv9FJTI,1654
21
- freeplay-0.3.19.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
22
- freeplay-0.3.19.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
- freeplay-0.3.19.dist-info/RECORD,,
19
+ freeplay-0.3.20.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
+ freeplay-0.3.20.dist-info/METADATA,sha256=3mkuwNZ5k_CGH3wtcIOCrI5lDPL2meBLE4_fqQW7vOc,1654
21
+ freeplay-0.3.20.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
22
+ freeplay-0.3.20.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
+ freeplay-0.3.20.dist-info/RECORD,,