freeplay 0.3.24a0__py3-none-any.whl → 0.4.0__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/freeplay_cli.py CHANGED
@@ -50,7 +50,53 @@ def download(project_id: str, environment: str, output_dir: str) -> None:
50
50
  click.echo(f"Found {len(prompts.prompt_templates)} prompt templates")
51
51
 
52
52
  for prompt in prompts.prompt_templates:
53
- __write_single_file(environment, output_dir, project_id, prompt)
53
+ __write_single_file(environment, output_dir, prompt)
54
+ except FreeplayClientError as e:
55
+ print(f"Error downloading templates: {e}.\nIs your project ID correct?", file=sys.stderr)
56
+ exit(1)
57
+ except FreeplayServerError as e:
58
+ print(f"Error on Freeplay's servers downloading templates: {e}.\nTry again after a short wait.",
59
+ file=sys.stderr)
60
+ exit(2)
61
+ except Exception as e:
62
+ print(f"Error downloading templates: {e}", file=sys.stderr)
63
+ exit(3)
64
+
65
+
66
+ @cli.command()
67
+ @click.option("--environment", required=True, help="The environment from which the prompts will be pulled.", default="latest")
68
+ @click.option("--output-dir", required=True, help="The directory where the prompts will be saved.")
69
+ def download_all(environment: str, output_dir: str) -> None:
70
+ if "FREEPLAY_API_KEY" not in os.environ:
71
+ print("FREEPLAY_API_KEY is not set. It is required to run the freeplay command.", file=sys.stderr)
72
+ exit(4)
73
+
74
+ if "FREEPLAY_SUBDOMAIN" not in os.environ:
75
+ print("FREEPLAY_SUBDOMAIN is not set. It is required to run the freeplay command.", file=sys.stderr)
76
+ exit(4)
77
+
78
+ FREEPLAY_API_KEY = os.environ["FREEPLAY_API_KEY"]
79
+ freeplay_api_url = f'https://{os.environ["FREEPLAY_SUBDOMAIN"]}.freeplay.ai/api'
80
+
81
+ if "FREEPLAY_API_URL" in os.environ:
82
+ freeplay_api_url = f'{os.environ["FREEPLAY_API_URL"]}/api'
83
+ click.echo("Using URL override for Freeplay specified in the FREEPLAY_API_URL environment variable")
84
+
85
+ click.echo(
86
+ f"Downloading prompts for environment {environment}, "
87
+ f"to directory {output_dir} from {freeplay_api_url}")
88
+
89
+ fp_client = Freeplay(
90
+ freeplay_api_key=FREEPLAY_API_KEY,
91
+ api_base=freeplay_api_url
92
+ )
93
+
94
+ try:
95
+ prompts: PromptTemplates = fp_client.prompts.get_all_for_environment(environment=environment)
96
+ click.echo(f"Found {len(prompts.prompt_templates)} prompt templates")
97
+
98
+ for prompt in prompts.prompt_templates:
99
+ __write_single_file(environment, output_dir, prompt)
54
100
  except FreeplayClientError as e:
55
101
  print(f"Error downloading templates: {e}.\nIs your project ID correct?", file=sys.stderr)
56
102
  exit(1)
@@ -66,10 +112,9 @@ def download(project_id: str, environment: str, output_dir: str) -> None:
66
112
  def __write_single_file(
67
113
  environment: str,
68
114
  output_dir: str,
69
- project_id: str,
70
115
  prompt: PromptTemplate
71
116
  ) -> None:
72
- directory = __root_dir(environment, output_dir, project_id)
117
+ directory = __root_dir(environment, output_dir, prompt.project_id)
73
118
  basename = f'{prompt.prompt_template_name}'
74
119
  prompt_path = directory / f'{basename}.json'
75
120
  click.echo("Writing prompt file: %s" % prompt_path)
@@ -87,6 +132,6 @@ def __write_single_file(
87
132
 
88
133
 
89
134
  def __root_dir(environment: str, output_dir: str, project_id: str) -> Path:
90
- directory = Path(output_dir) / "freeplay" / "prompts" / project_id / environment
135
+ directory = Path(output_dir).resolve() / "freeplay" / "prompts" / project_id / environment
91
136
  os.makedirs(directory, exist_ok=True)
92
137
  return directory
@@ -19,8 +19,8 @@ class CustomerFeedback:
19
19
  def __init__(self, call_support: CallSupport) -> None:
20
20
  self.call_support = call_support
21
21
 
22
- def update(self, completion_id: str, feedback: Dict[str, FeedbackValue]) -> CustomerFeedbackResponse:
23
- self.call_support.update_customer_feedback(completion_id, feedback)
22
+ def update(self, project_id: str, completion_id: str, feedback: Dict[str, FeedbackValue]) -> CustomerFeedbackResponse:
23
+ self.call_support.update_customer_feedback(project_id, completion_id, feedback)
24
24
  return CustomerFeedbackResponse()
25
25
 
26
26
  def update_trace(
@@ -557,6 +557,9 @@ class Prompts:
557
557
 
558
558
  return TemplatePrompt(prompt_info, prompt.content, prompt.tool_schema)
559
559
 
560
+ def get_all_for_environment(self, environment: str) -> PromptTemplates:
561
+ return self.call_support.get_prompts_for_environment(environment=environment)
562
+
560
563
  def get_by_version_id(self, project_id: str, template_id: str, version_id: str) -> TemplatePrompt:
561
564
  prompt = self.template_resolver.get_prompt_version_id(project_id, template_id, version_id)
562
565
 
@@ -1,23 +1,34 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, Optional, Dict
2
+ from typing import List, Optional, Dict, Any
3
+ import warnings
3
4
 
4
5
  from freeplay.model import InputVariables, TestRunInfo
5
6
  from freeplay.support import CallSupport, SummaryStatistics
6
7
 
7
-
8
8
  @dataclass
9
- class TestCase:
9
+ class CompletionTestCase:
10
10
  def __init__(
11
11
  self,
12
12
  test_case_id: str,
13
13
  variables: InputVariables,
14
14
  output: Optional[str],
15
- history: Optional[List[Dict[str, str]]]
15
+ history: Optional[List[Dict[str, str]]],
16
+ custom_metadata: Optional[Dict[str, str]]
16
17
  ):
17
18
  self.id = test_case_id
18
19
  self.variables = variables
19
20
  self.output = output
20
21
  self.history = history
22
+ self.custom_metadata = custom_metadata
23
+
24
+ class TestCase(CompletionTestCase):
25
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
26
+ warnings.warn(
27
+ "'TestCase' is deprecated; use 'CompletionTestCase' instead.",
28
+ DeprecationWarning,
29
+ stacklevel=2,
30
+ )
31
+ super().__init__(*args, **kwargs)
21
32
 
22
33
  class TraceTestCase:
23
34
  def __init__(
@@ -25,17 +36,18 @@ class TraceTestCase:
25
36
  test_case_id: str,
26
37
  input: str,
27
38
  output: Optional[str],
39
+ custom_metadata: Optional[Dict[str, str]]
28
40
  ):
29
41
  self.id = test_case_id
30
42
  self.input = input
31
43
  self.output = output
32
-
44
+ self.custom_metadata = custom_metadata
33
45
  @dataclass
34
46
  class TestRun:
35
47
  def __init__(
36
48
  self,
37
49
  test_run_id: str,
38
- test_cases: List[TestCase] = [],
50
+ test_cases: List[CompletionTestCase] = [],
39
51
  trace_test_cases: List[TraceTestCase] = []
40
52
  ):
41
53
  self.test_run_id = test_run_id
@@ -46,7 +58,7 @@ class TestRun:
46
58
  if self.test_cases and len(self.test_cases) > 0 and self.trace_test_cases and len(self.trace_test_cases) > 0:
47
59
  raise ValueError("Test case and trace test case cannot both be present")
48
60
 
49
- def get_test_cases(self) -> List[TestCase]:
61
+ def get_test_cases(self) -> List[CompletionTestCase]:
50
62
  self.__must_not_be_both_trace_and_completion()
51
63
  if len(self.trace_test_cases) > 0:
52
64
  raise ValueError("Completion test cases are not present. Please use get_trace_test_cases() instead.")
@@ -93,16 +105,18 @@ class TestRuns:
93
105
  test_run = self.call_support.create_test_run(
94
106
  project_id, testlist, include_outputs, name, description, flavor_name)
95
107
  test_cases = [
96
- TestCase(test_case_id=test_case.id,
108
+ CompletionTestCase(test_case_id=test_case.id,
97
109
  variables=test_case.variables,
98
110
  output=test_case.output,
99
- history=test_case.history)
111
+ history=test_case.history,
112
+ custom_metadata=test_case.custom_metadata)
100
113
  for test_case in test_run.test_cases
101
114
  ]
102
115
  trace_test_cases = [
103
116
  TraceTestCase(test_case_id=test_case.id,
104
117
  input=test_case.input,
105
- output=test_case.output)
118
+ output=test_case.output,
119
+ custom_metadata=test_case.custom_metadata)
106
120
  for test_case in test_run.trace_test_cases
107
121
  ]
108
122
 
freeplay/support.py CHANGED
@@ -76,6 +76,17 @@ class SummaryStatistics:
76
76
  human_evaluation: Dict[str, Any]
77
77
 
78
78
 
79
+ @dataclass
80
+ class ProjectInfo:
81
+ id: str
82
+ name: str
83
+
84
+
85
+ @dataclass
86
+ class ProjectInfos:
87
+ projects: List[ProjectInfo]
88
+
89
+
79
90
  class PromptTemplateEncoder(JSONEncoder):
80
91
  def default(self, prompt_template: PromptTemplate) -> Dict[str, Any]:
81
92
  return prompt_template.__dict__
@@ -89,6 +100,7 @@ class TestCaseTestRunResponse:
89
100
  self.history: Optional[List[Dict[str, Any]]] = test_case.get('history')
90
101
  self.custom_metadata: Optional[Dict[str, str]] = test_case.get('custom_metadata')
91
102
 
103
+
92
104
  class TraceTestCaseTestRunResponse:
93
105
  def __init__(self, test_case: Dict[str, Any]):
94
106
  self.id: str = test_case['test_case_id']
@@ -96,6 +108,7 @@ class TraceTestCaseTestRunResponse:
96
108
  self.output: Optional[str] = test_case.get('output')
97
109
  self.custom_metadata: Optional[Dict[str, str]] = test_case.get('custom_metadata')
98
110
 
111
+
99
112
  class TestRunResponse:
100
113
  def __init__(
101
114
  self,
@@ -185,6 +198,26 @@ class CallSupport:
185
198
 
186
199
  return maybe_prompts
187
200
 
201
+ def get_prompts_for_environment(self, environment: str) -> PromptTemplates:
202
+ projects_response = api_support.get_raw(
203
+ api_key=self.freeplay_api_key,
204
+ url=f'{self.api_base}/v2/projects/all'
205
+ )
206
+ if projects_response.status_code != 200:
207
+ raise freeplay_response_error("Error getting prompt templates", projects_response)
208
+
209
+ maybe_projects: Optional[ProjectInfos] = try_decode(ProjectInfos, projects_response.content)
210
+ if maybe_projects is None:
211
+ raise FreeplayServerError('Failed to parse list of projects from server')
212
+
213
+ prompt_templates = PromptTemplates([])
214
+ for project in maybe_projects.projects:
215
+ prompt_templates.prompt_templates.extend(
216
+ self.get_prompts(project.id, environment).prompt_templates
217
+ )
218
+
219
+ return prompt_templates
220
+
188
221
  def get_prompt(self, project_id: str, template_name: str, environment: str) -> PromptTemplate:
189
222
  response = api_support.get_raw(
190
223
  api_key=self.freeplay_api_key,
@@ -232,12 +265,13 @@ class CallSupport:
232
265
 
233
266
  def update_customer_feedback(
234
267
  self,
268
+ project_id: str,
235
269
  completion_id: str,
236
270
  feedback: Dict[str, Union[bool, str, int, float]]
237
271
  ) -> None:
238
- response = api_support.put_raw(
272
+ response = api_support.post_raw(
239
273
  self.freeplay_api_key,
240
- f'{self.api_base}/v1/completion_feedback/{completion_id}',
274
+ f'{self.api_base}/v2/projects/{project_id}/completion-feedback/id/{completion_id}',
241
275
  feedback
242
276
  )
243
277
  if response.status_code != 201:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: freeplay
3
- Version: 0.3.24a0
3
+ Version: 0.4.0
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: FreePlay Engineering
@@ -2,22 +2,22 @@ freeplay/__init__.py,sha256=ljXF0vHC3oGgk-vLyJFawr7MZKOj_ExYJJsVdrpqZoM,482
2
2
  freeplay/api_support.py,sha256=Kn2x3g6yloHQl3NwFRjbZE9BnIh7d1sgwGwC0mHuvw4,2483
3
3
  freeplay/errors.py,sha256=vwotUBldxDzREZOmLUeoiDoZjcvDwgH1AMwKBLhLooE,807
4
4
  freeplay/freeplay.py,sha256=J04-erDD6rI2SAje_Nsf3x5Qx-Z6p8gQvGrMRHFWoD4,1602
5
- freeplay/freeplay_cli.py,sha256=lmdsYwzdpWmUKHz_ieCzB-e6j1EnDHlVw3XIEyP_NEk,3460
5
+ freeplay/freeplay_cli.py,sha256=TFkMt4_gjV9BLmxA9iBaPgdl4QK4qYdN-HLxHm1A1-A,5451
6
6
  freeplay/llm_parameters.py,sha256=bQbfuC8EICF0XMZQa5pwI3FkQqxmCUVqHO3gYHy3Tg8,898
7
7
  freeplay/model.py,sha256=GI3qPRouwdrBFOPBrcQFt5O0chtlSNvl8jAstePuYlA,1480
8
8
  freeplay/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  freeplay/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  freeplay/resources/adapters.py,sha256=6ZAPpoLeOkUkV1s9VNQNsYrnupV0-sy11zFfKfctM1Y,9296
11
- freeplay/resources/customer_feedback.py,sha256=bw8MfEOKbGgn4FOyvcADrcs9GhcpNXNTgxKjBjIzywE,899
12
- freeplay/resources/prompts.py,sha256=mnL1VscMGM7D4ulGf3CBGQKdsSj8I5Wf_6nJEYa7mZI,23353
11
+ freeplay/resources/customer_feedback.py,sha256=6AUgHyOcXIpHvrxGAhsQgmDERvRHKutB6J-GkhkGH6s,928
12
+ freeplay/resources/prompts.py,sha256=7hQU0f6GW3qNqEytsiFOnHY6M5c1O6B0w9QDmNk91n0,23516
13
13
  freeplay/resources/recordings.py,sha256=V8KAPWnYAQ2-gqwyAJveD8a_AaBPYT32N_xbPU4S27M,9153
14
14
  freeplay/resources/sessions.py,sha256=dZtd9nq2nH8pmXxQOJitBnN5Jl3kjggDItDcjC69TYo,3883
15
15
  freeplay/resources/test_cases.py,sha256=nXL_976RwSJDT6OWDM4GEzbcOzcGkJ9ulvb0XOzCRDM,2240
16
- freeplay/resources/test_runs.py,sha256=snaNOqgwMiIKTRMw2nIGEficVrBdRX6O_zKuGW94k68,3969
17
- freeplay/support.py,sha256=AcaG6vkmI9r6_eNFoX29eTh4MRjdb4To5wIEm78v7IE,13299
16
+ freeplay/resources/test_runs.py,sha256=u7bBfJ3Ro5DJZQdjCAXj4Xj-3fYmtQIGhy8vJeluJvQ,4668
17
+ freeplay/support.py,sha256=uISvxdPA0OvcmbcL4TF136rqoSCARpi8ciniwffKm24,14352
18
18
  freeplay/utils.py,sha256=Xvt4mNLXLL7E6MI2hTuDLV5cl5Y83DgdjCZSyDGMjR0,3187
19
- freeplay-0.3.24a0.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
- freeplay-0.3.24a0.dist-info/METADATA,sha256=t-Xi5FKYXUv59Wj59dxDar6pXokD8OxFY6EvYbuGSo8,1663
21
- freeplay-0.3.24a0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
22
- freeplay-0.3.24a0.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
- freeplay-0.3.24a0.dist-info/RECORD,,
19
+ freeplay-0.4.0.dist-info/LICENSE,sha256=_jzIw45hB1XHGxiQ8leZ0GH_X7bR_a8qgxaqnHbCUOo,1064
20
+ freeplay-0.4.0.dist-info/METADATA,sha256=ofZVrNtcZhOQaFXcIz3sdyEw0o5FZDimLL1hDFBoHV4,1660
21
+ freeplay-0.4.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
22
+ freeplay-0.4.0.dist-info/entry_points.txt,sha256=32s3rf2UUCqiJT4jnClEXZhdXlvl30uwpcxz-Gsy4UU,54
23
+ freeplay-0.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.2
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any