freeplay 0.4.0__tar.gz → 0.5.0a1__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.
- {freeplay-0.4.0 → freeplay-0.5.0a1}/PKG-INFO +1 -1
- {freeplay-0.4.0 → freeplay-0.5.0a1}/pyproject.toml +1 -1
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/model.py +18 -1
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/prompts.py +5 -21
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/recordings.py +38 -24
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/test_runs.py +46 -26
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/support.py +31 -4
- {freeplay-0.4.0 → freeplay-0.5.0a1}/LICENSE +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/README.md +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/__init__.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/api_support.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/errors.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/freeplay.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/freeplay_cli.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/llm_parameters.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/py.typed +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/__init__.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/adapters.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/customer_feedback.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/sessions.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/resources/test_cases.py +0 -0
- {freeplay-0.4.0 → freeplay-0.5.0a1}/src/freeplay/utils.py +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import
|
2
|
+
from typing import Any, Dict, List, Literal, Mapping, TypedDict, Union
|
3
3
|
|
4
4
|
InputValue = Union[str, int, bool, float, Dict[str, Any], List[Any]]
|
5
5
|
InputVariables = Mapping[str, InputValue]
|
@@ -7,6 +7,23 @@ TestRunInput = Mapping[str, InputValue]
|
|
7
7
|
FeedbackValue = Union[bool, str, int, float]
|
8
8
|
|
9
9
|
|
10
|
+
@dataclass
|
11
|
+
class MediaInputUrl:
|
12
|
+
type: Literal["url"]
|
13
|
+
url: str
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class MediaInputBase64:
|
18
|
+
type: Literal["base64"]
|
19
|
+
data: str
|
20
|
+
content_type: str
|
21
|
+
|
22
|
+
|
23
|
+
MediaInput = Union[MediaInputUrl, MediaInputBase64]
|
24
|
+
MediaInputMap = Dict[str, MediaInput]
|
25
|
+
|
26
|
+
|
10
27
|
@dataclass
|
11
28
|
class TestRun:
|
12
29
|
id: str
|
@@ -24,7 +24,11 @@ from freeplay.errors import (
|
|
24
24
|
log_freeplay_client_warning,
|
25
25
|
)
|
26
26
|
from freeplay.llm_parameters import LLMParameters
|
27
|
-
from freeplay.model import
|
27
|
+
from freeplay.model import (
|
28
|
+
InputVariables,
|
29
|
+
MediaInputMap,
|
30
|
+
MediaInputUrl,
|
31
|
+
)
|
28
32
|
from freeplay.resources.adapters import (
|
29
33
|
MediaContentBase64,
|
30
34
|
MediaContentUrl,
|
@@ -96,8 +100,6 @@ class PromptInfo:
|
|
96
100
|
provider: str
|
97
101
|
model: str
|
98
102
|
flavor_name: str
|
99
|
-
project_id: str
|
100
|
-
|
101
103
|
|
102
104
|
class FormattedPrompt:
|
103
105
|
def __init__(
|
@@ -214,22 +216,6 @@ class BoundPrompt:
|
|
214
216
|
)
|
215
217
|
|
216
218
|
|
217
|
-
@dataclass
|
218
|
-
class MediaInputUrl:
|
219
|
-
type: Literal["url"]
|
220
|
-
url: str
|
221
|
-
|
222
|
-
|
223
|
-
@dataclass
|
224
|
-
class MediaInputBase64:
|
225
|
-
type: Literal["base64"]
|
226
|
-
data: str
|
227
|
-
content_type: str
|
228
|
-
|
229
|
-
|
230
|
-
MediaInput = Union[MediaInputUrl, MediaInputBase64]
|
231
|
-
|
232
|
-
MediaInputMap = Dict[str, MediaInput]
|
233
219
|
|
234
220
|
|
235
221
|
def extract_media_content(media_inputs: MediaInputMap, media_slots: List[MediaSlot]) -> List[
|
@@ -552,7 +538,6 @@ class Prompts:
|
|
552
538
|
model=model,
|
553
539
|
flavor_name=prompt.metadata.flavor,
|
554
540
|
provider_info=prompt.metadata.provider_info,
|
555
|
-
project_id=prompt.project_id
|
556
541
|
)
|
557
542
|
|
558
543
|
return TemplatePrompt(prompt_info, prompt.content, prompt.tool_schema)
|
@@ -588,7 +573,6 @@ class Prompts:
|
|
588
573
|
model=model,
|
589
574
|
flavor_name=prompt.metadata.flavor,
|
590
575
|
provider_info=prompt.metadata.provider_info,
|
591
|
-
project_id=prompt.project_id
|
592
576
|
)
|
593
577
|
|
594
578
|
return TemplatePrompt(prompt_info, prompt.content, prompt.tool_schema)
|
@@ -1,20 +1,28 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import Any, Dict, List, Optional, Union
|
5
|
-
from uuid import UUID
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
5
|
+
from uuid import UUID, uuid4
|
6
6
|
|
7
7
|
from requests import HTTPError
|
8
8
|
|
9
9
|
from freeplay import api_support
|
10
10
|
from freeplay.errors import FreeplayClientError, FreeplayError
|
11
11
|
from freeplay.llm_parameters import LLMParameters
|
12
|
-
from freeplay.model import
|
13
|
-
|
12
|
+
from freeplay.model import (
|
13
|
+
InputVariables,
|
14
|
+
MediaInput,
|
15
|
+
MediaInputMap,
|
16
|
+
MediaInputUrl,
|
17
|
+
OpenAIFunctionCall,
|
18
|
+
TestRunInfo,
|
19
|
+
)
|
20
|
+
from freeplay.resources.prompts import (
|
21
|
+
PromptInfo,
|
22
|
+
)
|
14
23
|
from freeplay.resources.sessions import SessionInfo, TraceInfo
|
15
24
|
from freeplay.support import CallSupport
|
16
25
|
|
17
|
-
|
18
26
|
logger = logging.getLogger(__name__)
|
19
27
|
|
20
28
|
|
@@ -29,11 +37,11 @@ ApiStyle = Union[Literal['batch'], Literal['default']]
|
|
29
37
|
|
30
38
|
@dataclass
|
31
39
|
class CallInfo:
|
32
|
-
provider: str
|
33
|
-
model: str
|
34
|
-
start_time: float
|
35
|
-
end_time: float
|
36
|
-
model_parameters: LLMParameters
|
40
|
+
provider: Optional[str] = None
|
41
|
+
model: Optional[str] = None
|
42
|
+
start_time: Optional[float] = None
|
43
|
+
end_time: Optional[float] = None
|
44
|
+
model_parameters: Optional[LLMParameters] = None
|
37
45
|
provider_info: Optional[Dict[str, Any]] = None
|
38
46
|
usage: Optional[UsageTokens] = None
|
39
47
|
api_style: Optional[ApiStyle] = None
|
@@ -69,12 +77,15 @@ class ResponseInfo:
|
|
69
77
|
|
70
78
|
@dataclass
|
71
79
|
class RecordPayload:
|
80
|
+
project_id: str
|
72
81
|
all_messages: List[Dict[str, Any]]
|
73
|
-
inputs: InputVariables
|
74
82
|
|
75
|
-
session_info: SessionInfo
|
76
|
-
|
77
|
-
|
83
|
+
session_info: SessionInfo = field(
|
84
|
+
default_factory=lambda: SessionInfo(session_id=str(uuid4()), custom_metadata=None)
|
85
|
+
)
|
86
|
+
inputs: Optional[InputVariables] = None
|
87
|
+
prompt_info: Optional[PromptInfo] = None
|
88
|
+
call_info: Optional[CallInfo] = None
|
78
89
|
media_inputs: Optional[MediaInputMap] = None
|
79
90
|
tool_schema: Optional[List[Dict[str, Any]]] = None
|
80
91
|
response_info: Optional[ResponseInfo] = None
|
@@ -124,19 +135,25 @@ class Recordings:
|
|
124
135
|
"inputs": record_payload.inputs,
|
125
136
|
"tool_schema": record_payload.tool_schema,
|
126
137
|
"session_info": {"custom_metadata": record_payload.session_info.custom_metadata},
|
127
|
-
|
138
|
+
|
139
|
+
}
|
140
|
+
|
141
|
+
if record_payload.prompt_info is not None:
|
142
|
+
record_api_payload["prompt_info"] = {
|
128
143
|
"environment": record_payload.prompt_info.environment,
|
129
144
|
"prompt_template_version_id": record_payload.prompt_info.prompt_template_version_id,
|
130
|
-
}
|
131
|
-
|
145
|
+
}
|
146
|
+
|
147
|
+
if record_payload.call_info is not None:
|
148
|
+
record_api_payload["call_info"] = {
|
132
149
|
"start_time": record_payload.call_info.start_time,
|
133
150
|
"end_time": record_payload.call_info.end_time,
|
134
151
|
"model": record_payload.call_info.model,
|
135
152
|
"provider": record_payload.call_info.provider,
|
136
153
|
"provider_info": record_payload.call_info.provider_info,
|
137
154
|
"llm_parameters": record_payload.call_info.model_parameters,
|
155
|
+
"api_style": record_payload.call_info.api_style,
|
138
156
|
}
|
139
|
-
}
|
140
157
|
|
141
158
|
if record_payload.completion_id is not None:
|
142
159
|
record_api_payload['completion_id'] = str(record_payload.completion_id)
|
@@ -167,15 +184,12 @@ class Recordings:
|
|
167
184
|
"trace_id": record_payload.trace_info.trace_id
|
168
185
|
}
|
169
186
|
|
170
|
-
if record_payload.call_info.usage is not None:
|
187
|
+
if record_payload.call_info is not None and record_payload.call_info.usage is not None:
|
171
188
|
record_api_payload['call_info']['usage'] = {
|
172
189
|
"prompt_tokens": record_payload.call_info.usage.prompt_tokens,
|
173
190
|
"completion_tokens": record_payload.call_info.usage.completion_tokens,
|
174
191
|
}
|
175
192
|
|
176
|
-
if record_payload.call_info.api_style is not None:
|
177
|
-
record_api_payload['call_info']['api_style'] = record_payload.call_info.api_style
|
178
|
-
|
179
193
|
if record_payload.media_inputs is not None:
|
180
194
|
record_api_payload['media_inputs'] = {
|
181
195
|
name: media_inputs_to_json(media_input)
|
@@ -185,7 +199,7 @@ class Recordings:
|
|
185
199
|
try:
|
186
200
|
recorded_response = api_support.post_raw(
|
187
201
|
api_key=self.call_support.freeplay_api_key,
|
188
|
-
url=f'{self.call_support.api_base}/v2/projects/{record_payload.
|
202
|
+
url=f'{self.call_support.api_base}/v2/projects/{record_payload.project_id}/sessions/{record_payload.session_info.session_id}/completions',
|
189
203
|
payload=record_api_payload
|
190
204
|
)
|
191
205
|
recorded_response.raise_for_status()
|
@@ -1,25 +1,31 @@
|
|
1
|
-
from dataclasses import dataclass
|
2
|
-
from typing import List, Optional, Dict, Any
|
3
1
|
import warnings
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
4
4
|
|
5
|
-
from freeplay.model import InputVariables, TestRunInfo
|
5
|
+
from freeplay.model import InputVariables, MediaInputBase64, MediaInputUrl, TestRunInfo
|
6
6
|
from freeplay.support import CallSupport, SummaryStatistics
|
7
7
|
|
8
|
+
|
8
9
|
@dataclass
|
9
10
|
class CompletionTestCase:
|
10
11
|
def __init__(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
self,
|
13
|
+
test_case_id: str,
|
14
|
+
variables: InputVariables,
|
15
|
+
output: Optional[str],
|
16
|
+
history: Optional[List[Dict[str, str]]],
|
17
|
+
custom_metadata: Optional[Dict[str, str]],
|
18
|
+
media_variables: Optional[
|
19
|
+
Dict[str, Union[MediaInputBase64, MediaInputUrl]]
|
20
|
+
] = None,
|
17
21
|
):
|
18
22
|
self.id = test_case_id
|
19
23
|
self.variables = variables
|
20
24
|
self.output = output
|
21
25
|
self.history = history
|
22
26
|
self.custom_metadata = custom_metadata
|
27
|
+
self.media_variables = media_variables
|
28
|
+
|
23
29
|
|
24
30
|
class TestCase(CompletionTestCase):
|
25
31
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
@@ -30,44 +36,55 @@ class TestCase(CompletionTestCase):
|
|
30
36
|
)
|
31
37
|
super().__init__(*args, **kwargs)
|
32
38
|
|
39
|
+
|
33
40
|
class TraceTestCase:
|
34
41
|
def __init__(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
self,
|
43
|
+
test_case_id: str,
|
44
|
+
input: str,
|
45
|
+
output: Optional[str],
|
46
|
+
custom_metadata: Optional[Dict[str, str]],
|
40
47
|
):
|
41
48
|
self.id = test_case_id
|
42
49
|
self.input = input
|
43
50
|
self.output = output
|
44
51
|
self.custom_metadata = custom_metadata
|
52
|
+
|
45
53
|
@dataclass
|
46
54
|
class TestRun:
|
47
55
|
def __init__(
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
self,
|
57
|
+
test_run_id: str,
|
58
|
+
test_cases: List[CompletionTestCase] = [],
|
59
|
+
trace_test_cases: List[TraceTestCase] = [],
|
52
60
|
):
|
53
61
|
self.test_run_id = test_run_id
|
54
62
|
self.test_cases = test_cases
|
55
63
|
self.trace_test_cases = trace_test_cases
|
56
64
|
|
57
65
|
def __must_not_be_both_trace_and_completion(self) -> None:
|
58
|
-
if
|
66
|
+
if (
|
67
|
+
self.test_cases
|
68
|
+
and len(self.test_cases) > 0
|
69
|
+
and self.trace_test_cases
|
70
|
+
and len(self.trace_test_cases) > 0
|
71
|
+
):
|
59
72
|
raise ValueError("Test case and trace test case cannot both be present")
|
60
73
|
|
61
74
|
def get_test_cases(self) -> List[CompletionTestCase]:
|
62
75
|
self.__must_not_be_both_trace_and_completion()
|
63
76
|
if len(self.trace_test_cases) > 0:
|
64
|
-
raise ValueError(
|
77
|
+
raise ValueError(
|
78
|
+
"Completion test cases are not present. Please use get_trace_test_cases() instead."
|
79
|
+
)
|
65
80
|
return self.test_cases
|
66
81
|
|
67
82
|
def get_trace_test_cases(self) -> List[TraceTestCase]:
|
68
83
|
self.__must_not_be_both_trace_and_completion()
|
69
84
|
if len(self.test_cases) > 0:
|
70
|
-
raise ValueError(
|
85
|
+
raise ValueError(
|
86
|
+
"Trace test cases are not present. Please use get_test_cases() instead."
|
87
|
+
)
|
71
88
|
return self.trace_test_cases
|
72
89
|
|
73
90
|
def get_test_run_info(self, test_case_id: str) -> TestRunInfo:
|
@@ -105,11 +122,14 @@ class TestRuns:
|
|
105
122
|
test_run = self.call_support.create_test_run(
|
106
123
|
project_id, testlist, include_outputs, name, description, flavor_name)
|
107
124
|
test_cases = [
|
108
|
-
CompletionTestCase(
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
125
|
+
CompletionTestCase(
|
126
|
+
test_case_id=test_case.id,
|
127
|
+
variables=test_case.variables,
|
128
|
+
output=test_case.output,
|
129
|
+
history=test_case.history,
|
130
|
+
custom_metadata=test_case.custom_metadata,
|
131
|
+
media_variables=test_case.media_variables,
|
132
|
+
)
|
113
133
|
for test_case in test_run.test_cases
|
114
134
|
]
|
115
135
|
trace_test_cases = [
|
@@ -1,11 +1,18 @@
|
|
1
|
-
from dataclasses import dataclass, field
|
1
|
+
from dataclasses import asdict, dataclass, field
|
2
2
|
from json import JSONEncoder
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
4
4
|
|
5
5
|
from freeplay import api_support
|
6
6
|
from freeplay.api_support import try_decode
|
7
|
-
from freeplay.errors import
|
8
|
-
from freeplay.model import
|
7
|
+
from freeplay.errors import FreeplayServerError, freeplay_response_error
|
8
|
+
from freeplay.model import (
|
9
|
+
FeedbackValue,
|
10
|
+
InputVariables,
|
11
|
+
MediaInputBase64,
|
12
|
+
MediaInputUrl,
|
13
|
+
NormalizedMessage,
|
14
|
+
TestRunInfo,
|
15
|
+
)
|
9
16
|
|
10
17
|
CustomMetadata = Optional[Dict[str, Union[str, int, float, bool]]]
|
11
18
|
|
@@ -100,6 +107,26 @@ class TestCaseTestRunResponse:
|
|
100
107
|
self.history: Optional[List[Dict[str, Any]]] = test_case.get('history')
|
101
108
|
self.custom_metadata: Optional[Dict[str, str]] = test_case.get('custom_metadata')
|
102
109
|
|
110
|
+
if test_case.get("media_variables", None):
|
111
|
+
self.media_variables: Optional[
|
112
|
+
Dict[str, Union[MediaInputBase64, MediaInputUrl]]
|
113
|
+
] = {}
|
114
|
+
for name, media_data in test_case.get("media_variables", {}).items():
|
115
|
+
media_type = media_data.get("type", "base64")
|
116
|
+
if media_type == "url":
|
117
|
+
self.media_variables[name] = MediaInputUrl(
|
118
|
+
type="url",
|
119
|
+
url=media_data["url"],
|
120
|
+
)
|
121
|
+
else:
|
122
|
+
self.media_variables[name] = MediaInputBase64(
|
123
|
+
type="base64",
|
124
|
+
data=media_data["data"],
|
125
|
+
content_type=media_data["content_type"],
|
126
|
+
)
|
127
|
+
else:
|
128
|
+
self.media_variables = None
|
129
|
+
|
103
130
|
|
104
131
|
class TraceTestCaseTestRunResponse:
|
105
132
|
def __init__(self, test_case: Dict[str, Any]):
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|