edsl 0.1.33.dev1__py3-none-any.whl → 0.1.33.dev2__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.
Files changed (163) hide show
  1. edsl/TemplateLoader.py +24 -0
  2. edsl/__init__.py +8 -4
  3. edsl/agents/Agent.py +46 -14
  4. edsl/agents/AgentList.py +43 -0
  5. edsl/agents/Invigilator.py +125 -212
  6. edsl/agents/InvigilatorBase.py +140 -32
  7. edsl/agents/PromptConstructionMixin.py +43 -66
  8. edsl/agents/__init__.py +1 -0
  9. edsl/auto/AutoStudy.py +117 -0
  10. edsl/auto/StageBase.py +230 -0
  11. edsl/auto/StageGenerateSurvey.py +178 -0
  12. edsl/auto/StageLabelQuestions.py +125 -0
  13. edsl/auto/StagePersona.py +61 -0
  14. edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
  15. edsl/auto/StagePersonaDimensionValues.py +74 -0
  16. edsl/auto/StagePersonaDimensions.py +69 -0
  17. edsl/auto/StageQuestions.py +73 -0
  18. edsl/auto/SurveyCreatorPipeline.py +21 -0
  19. edsl/auto/utilities.py +224 -0
  20. edsl/config.py +38 -39
  21. edsl/coop/PriceFetcher.py +58 -0
  22. edsl/coop/coop.py +39 -5
  23. edsl/data/Cache.py +35 -1
  24. edsl/data_transfer_models.py +120 -38
  25. edsl/enums.py +2 -0
  26. edsl/exceptions/language_models.py +25 -1
  27. edsl/exceptions/questions.py +62 -5
  28. edsl/exceptions/results.py +4 -0
  29. edsl/inference_services/AnthropicService.py +13 -11
  30. edsl/inference_services/AwsBedrock.py +19 -17
  31. edsl/inference_services/AzureAI.py +37 -20
  32. edsl/inference_services/GoogleService.py +16 -12
  33. edsl/inference_services/GroqService.py +2 -0
  34. edsl/inference_services/InferenceServiceABC.py +24 -0
  35. edsl/inference_services/MistralAIService.py +120 -0
  36. edsl/inference_services/OpenAIService.py +41 -50
  37. edsl/inference_services/TestService.py +71 -0
  38. edsl/inference_services/models_available_cache.py +0 -6
  39. edsl/inference_services/registry.py +4 -0
  40. edsl/jobs/Answers.py +10 -12
  41. edsl/jobs/FailedQuestion.py +78 -0
  42. edsl/jobs/Jobs.py +18 -13
  43. edsl/jobs/buckets/TokenBucket.py +39 -14
  44. edsl/jobs/interviews/Interview.py +297 -77
  45. edsl/jobs/interviews/InterviewExceptionEntry.py +83 -19
  46. edsl/jobs/interviews/interview_exception_tracking.py +0 -70
  47. edsl/jobs/interviews/retry_management.py +3 -1
  48. edsl/jobs/runners/JobsRunnerAsyncio.py +116 -70
  49. edsl/jobs/runners/JobsRunnerStatusMixin.py +1 -1
  50. edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
  51. edsl/jobs/tasks/TaskHistory.py +131 -213
  52. edsl/language_models/LanguageModel.py +239 -129
  53. edsl/language_models/ModelList.py +2 -2
  54. edsl/language_models/RegisterLanguageModelsMeta.py +14 -29
  55. edsl/language_models/fake_openai_call.py +15 -0
  56. edsl/language_models/fake_openai_service.py +61 -0
  57. edsl/language_models/registry.py +15 -2
  58. edsl/language_models/repair.py +0 -19
  59. edsl/language_models/utilities.py +61 -0
  60. edsl/prompts/Prompt.py +52 -2
  61. edsl/questions/AnswerValidatorMixin.py +23 -26
  62. edsl/questions/QuestionBase.py +273 -242
  63. edsl/questions/QuestionBaseGenMixin.py +133 -0
  64. edsl/questions/QuestionBasePromptsMixin.py +266 -0
  65. edsl/questions/QuestionBudget.py +6 -0
  66. edsl/questions/QuestionCheckBox.py +227 -35
  67. edsl/questions/QuestionExtract.py +98 -27
  68. edsl/questions/QuestionFreeText.py +46 -29
  69. edsl/questions/QuestionFunctional.py +7 -0
  70. edsl/questions/QuestionList.py +141 -22
  71. edsl/questions/QuestionMultipleChoice.py +173 -64
  72. edsl/questions/QuestionNumerical.py +87 -46
  73. edsl/questions/QuestionRank.py +182 -24
  74. edsl/questions/RegisterQuestionsMeta.py +31 -12
  75. edsl/questions/ResponseValidatorABC.py +169 -0
  76. edsl/questions/__init__.py +3 -4
  77. edsl/questions/decorators.py +21 -0
  78. edsl/questions/derived/QuestionLikertFive.py +10 -5
  79. edsl/questions/derived/QuestionLinearScale.py +11 -1
  80. edsl/questions/derived/QuestionTopK.py +6 -0
  81. edsl/questions/derived/QuestionYesNo.py +16 -1
  82. edsl/questions/descriptors.py +43 -7
  83. edsl/questions/prompt_templates/question_budget.jinja +13 -0
  84. edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
  85. edsl/questions/prompt_templates/question_extract.jinja +11 -0
  86. edsl/questions/prompt_templates/question_free_text.jinja +3 -0
  87. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
  88. edsl/questions/prompt_templates/question_list.jinja +17 -0
  89. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
  90. edsl/questions/prompt_templates/question_numerical.jinja +37 -0
  91. edsl/questions/question_registry.py +6 -2
  92. edsl/questions/templates/__init__.py +0 -0
  93. edsl/questions/templates/checkbox/__init__.py +0 -0
  94. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
  95. edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
  96. edsl/questions/templates/extract/answering_instructions.jinja +7 -0
  97. edsl/questions/templates/extract/question_presentation.jinja +1 -0
  98. edsl/questions/templates/free_text/__init__.py +0 -0
  99. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  100. edsl/questions/templates/free_text/question_presentation.jinja +1 -0
  101. edsl/questions/templates/likert_five/__init__.py +0 -0
  102. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
  103. edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
  104. edsl/questions/templates/linear_scale/__init__.py +0 -0
  105. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
  106. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
  107. edsl/questions/templates/list/__init__.py +0 -0
  108. edsl/questions/templates/list/answering_instructions.jinja +4 -0
  109. edsl/questions/templates/list/question_presentation.jinja +5 -0
  110. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  111. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
  112. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  113. edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
  114. edsl/questions/templates/numerical/__init__.py +0 -0
  115. edsl/questions/templates/numerical/answering_instructions.jinja +8 -0
  116. edsl/questions/templates/numerical/question_presentation.jinja +7 -0
  117. edsl/questions/templates/rank/answering_instructions.jinja +11 -0
  118. edsl/questions/templates/rank/question_presentation.jinja +15 -0
  119. edsl/questions/templates/top_k/__init__.py +0 -0
  120. edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
  121. edsl/questions/templates/top_k/question_presentation.jinja +22 -0
  122. edsl/questions/templates/yes_no/__init__.py +0 -0
  123. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
  124. edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
  125. edsl/results/Dataset.py +20 -0
  126. edsl/results/DatasetExportMixin.py +41 -47
  127. edsl/results/DatasetTree.py +145 -0
  128. edsl/results/Result.py +32 -5
  129. edsl/results/Results.py +131 -45
  130. edsl/results/ResultsDBMixin.py +3 -3
  131. edsl/results/Selector.py +118 -0
  132. edsl/results/tree_explore.py +115 -0
  133. edsl/scenarios/Scenario.py +10 -4
  134. edsl/scenarios/ScenarioList.py +348 -39
  135. edsl/scenarios/ScenarioListExportMixin.py +9 -0
  136. edsl/study/SnapShot.py +8 -1
  137. edsl/surveys/RuleCollection.py +2 -2
  138. edsl/surveys/Survey.py +634 -315
  139. edsl/surveys/SurveyExportMixin.py +71 -9
  140. edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
  141. edsl/surveys/SurveyQualtricsImport.py +75 -4
  142. edsl/surveys/instructions/ChangeInstruction.py +47 -0
  143. edsl/surveys/instructions/Instruction.py +34 -0
  144. edsl/surveys/instructions/InstructionCollection.py +77 -0
  145. edsl/surveys/instructions/__init__.py +0 -0
  146. edsl/templates/error_reporting/base.html +24 -0
  147. edsl/templates/error_reporting/exceptions_by_model.html +35 -0
  148. edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
  149. edsl/templates/error_reporting/exceptions_by_type.html +17 -0
  150. edsl/templates/error_reporting/interview_details.html +111 -0
  151. edsl/templates/error_reporting/interviews.html +10 -0
  152. edsl/templates/error_reporting/overview.html +5 -0
  153. edsl/templates/error_reporting/performance_plot.html +2 -0
  154. edsl/templates/error_reporting/report.css +74 -0
  155. edsl/templates/error_reporting/report.html +118 -0
  156. edsl/templates/error_reporting/report.js +25 -0
  157. {edsl-0.1.33.dev1.dist-info → edsl-0.1.33.dev2.dist-info}/METADATA +4 -2
  158. edsl-0.1.33.dev2.dist-info/RECORD +289 -0
  159. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -286
  160. edsl/utilities/gcp_bucket/simple_example.py +0 -9
  161. edsl-0.1.33.dev1.dist-info/RECORD +0 -209
  162. {edsl-0.1.33.dev1.dist-info → edsl-0.1.33.dev2.dist-info}/LICENSE +0 -0
  163. {edsl-0.1.33.dev1.dist-info → edsl-0.1.33.dev2.dist-info}/WHEEL +0 -0
edsl/coop/coop.py CHANGED
@@ -53,6 +53,7 @@ class Coop:
53
53
  method: str,
54
54
  payload: Optional[dict[str, Any]] = None,
55
55
  params: Optional[dict[str, Any]] = None,
56
+ timeout: Optional[float] = 5,
56
57
  ) -> requests.Response:
57
58
  """
58
59
  Send a request to the server and return the response.
@@ -62,11 +63,16 @@ class Coop:
62
63
  method = method.upper()
63
64
  if method in ["GET", "DELETE"]:
64
65
  response = requests.request(
65
- method, url, params=params, headers=self.headers
66
+ method, url, params=params, headers=self.headers, timeout=timeout
66
67
  )
67
68
  elif method in ["POST", "PATCH"]:
68
69
  response = requests.request(
69
- method, url, params=params, json=payload, headers=self.headers
70
+ method,
71
+ url,
72
+ params=params,
73
+ json=payload,
74
+ headers=self.headers,
75
+ timeout=timeout,
70
76
  )
71
77
  else:
72
78
  raise Exception(f"Invalid {method=}.")
@@ -110,10 +116,18 @@ class Coop:
110
116
  def edsl_settings(self) -> dict:
111
117
  """
112
118
  Retrieve and return the EDSL settings stored on Coop.
119
+ If no response is received within 5 seconds, return an empty dict.
113
120
  """
114
- response = self._send_server_request(uri="api/v0/edsl-settings", method="GET")
115
- self._resolve_server_response(response)
116
- return response.json()
121
+ from requests.exceptions import Timeout
122
+
123
+ try:
124
+ response = self._send_server_request(
125
+ uri="api/v0/edsl-settings", method="GET", timeout=5
126
+ )
127
+ self._resolve_server_response(response)
128
+ return response.json()
129
+ except Timeout:
130
+ return {}
117
131
 
118
132
  ################
119
133
  # Objects
@@ -625,6 +639,26 @@ class Coop:
625
639
 
626
640
  return response_json
627
641
 
642
+ def fetch_prices(self) -> dict:
643
+ from edsl.coop.PriceFetcher import PriceFetcher
644
+
645
+ from edsl.config import CONFIG
646
+
647
+ if bool(CONFIG.get("EDSL_FETCH_TOKEN_PRICES")):
648
+ price_fetcher = PriceFetcher()
649
+ return price_fetcher.fetch_prices()
650
+ else:
651
+ return {}
652
+
653
+
654
+ if __name__ == "__main__":
655
+ sheet_data = fetch_sheet_data()
656
+ if sheet_data:
657
+ print(f"Successfully fetched {len(sheet_data)} rows of data.")
658
+ print("First row:", sheet_data[0])
659
+ else:
660
+ print("Failed to fetch sheet data.")
661
+
628
662
 
629
663
  def main():
630
664
  """
edsl/data/Cache.py CHANGED
@@ -6,6 +6,7 @@ from __future__ import annotations
6
6
  import json
7
7
  import os
8
8
  import warnings
9
+ import copy
9
10
  from typing import Optional, Union
10
11
  from edsl.Base import Base
11
12
  from edsl.data.CacheEntry import CacheEntry
@@ -88,11 +89,24 @@ class Cache(Base):
88
89
  # raise NotImplementedError("This method is not implemented yet.")
89
90
 
90
91
  def keys(self):
92
+ """
93
+ >>> from edsl import Cache
94
+ >>> Cache.example().keys()
95
+ ['5513286eb6967abc0511211f0402587d']
96
+ """
91
97
  return list(self.data.keys())
92
98
 
93
99
  def values(self):
100
+ """
101
+ >>> from edsl import Cache
102
+ >>> Cache.example().values()
103
+ [CacheEntry(...)]
104
+ """
94
105
  return list(self.data.values())
95
106
 
107
+ def items(self):
108
+ return zip(self.keys(), self.values())
109
+
96
110
  def new_entries_cache(self) -> Cache:
97
111
  """Return a new Cache object with the new entries."""
98
112
  return Cache(data={**self.new_entries, **self.fetched_data})
@@ -160,7 +174,7 @@ class Cache(Base):
160
174
  parameters: str,
161
175
  system_prompt: str,
162
176
  user_prompt: str,
163
- response: str,
177
+ response: dict,
164
178
  iteration: int,
165
179
  ) -> str:
166
180
  """
@@ -174,6 +188,15 @@ class Cache(Base):
174
188
  * The key-value pair is added to `self.new_entries`
175
189
  * If `immediate_write` is True , the key-value pair is added to `self.data`
176
190
  * If `immediate_write` is False, the key-value pair is added to `self.new_entries_to_write_later`
191
+
192
+ >>> from edsl import Cache, Model, Question
193
+ >>> m = Model("test")
194
+ >>> c = Cache()
195
+ >>> len(c)
196
+ 0
197
+ >>> results = Question.example("free_text").by(m).run(cache = c)
198
+ >>> len(c)
199
+ 1
177
200
  """
178
201
 
179
202
  entry = CacheEntry(
@@ -326,6 +349,17 @@ class Cache(Base):
326
349
  for key, value in self.data.items():
327
350
  f.write(json.dumps({key: value.to_dict()}) + "\n")
328
351
 
352
+ def to_scenario_list(self):
353
+ from edsl import ScenarioList, Scenario
354
+
355
+ scenarios = []
356
+ for key, value in self.data.items():
357
+ new_d = value.to_dict()
358
+ new_d["cache_key"] = key
359
+ s = Scenario(new_d)
360
+ scenarios.append(s)
361
+ return ScenarioList(scenarios)
362
+
329
363
  ####################
330
364
  # REMOTE
331
365
  ####################
@@ -1,38 +1,120 @@
1
- """This module contains the data transfer models for the application."""
2
-
3
- from collections import UserDict
4
-
5
-
6
- class AgentResponseDict(UserDict):
7
- """A dictionary to store the response of the agent to a question."""
8
-
9
- def __init__(
10
- self,
11
- *,
12
- question_name,
13
- answer,
14
- prompts,
15
- usage=None,
16
- comment=None,
17
- cached_response=None,
18
- raw_model_response=None,
19
- simple_model_raw_response=None,
20
- cache_used=None,
21
- cache_key=None,
22
- ):
23
- """Initialize the AgentResponseDict object."""
24
- usage = usage or {"prompt_tokens": 0, "completion_tokens": 0}
25
- super().__init__(
26
- {
27
- "answer": answer,
28
- "comment": comment,
29
- "question_name": question_name,
30
- "prompts": prompts,
31
- "usage": usage,
32
- "cached_response": cached_response,
33
- "raw_model_response": raw_model_response,
34
- "simple_model_raw_response": simple_model_raw_response,
35
- "cache_used": cache_used,
36
- "cache_key": cache_key,
37
- }
38
- )
1
+ from typing import NamedTuple, Dict, List, Optional, Any
2
+
3
+
4
+ class ModelInputs(NamedTuple):
5
+ "This is what was send by the agent to the model"
6
+ user_prompt: str
7
+ system_prompt: str
8
+ encoded_image: Optional[str] = None
9
+
10
+
11
+ class EDSLOutput(NamedTuple):
12
+ "This is the edsl dictionary that is returned by the model"
13
+ answer: Any
14
+ generated_tokens: str
15
+ comment: Optional[str] = None
16
+
17
+
18
+ class ModelResponse(NamedTuple):
19
+ "This is the metadata that is returned by the model and includes info about the cache"
20
+ response: dict
21
+ cache_used: bool
22
+ cache_key: str
23
+ cached_response: Optional[Dict[str, Any]] = None
24
+ cost: Optional[float] = None
25
+
26
+
27
+ class AgentResponseDict(NamedTuple):
28
+ edsl_dict: EDSLOutput
29
+ model_inputs: ModelInputs
30
+ model_outputs: ModelResponse
31
+
32
+
33
+ class EDSLResultObjectInput(NamedTuple):
34
+ generated_tokens: str
35
+ question_name: str
36
+ prompts: dict
37
+ cached_response: str
38
+ raw_model_response: str
39
+ cache_used: bool
40
+ cache_key: str
41
+ answer: Any
42
+ comment: str
43
+ validated: bool = False
44
+ exception_occurred: Exception = None
45
+ cost: Optional[float] = None
46
+
47
+
48
+ # from collections import UserDict
49
+
50
+
51
+ # class AgentResponseDict(UserDict):
52
+ # """A dictionary to store the response of the agent to a question."""
53
+
54
+ # def __init__(
55
+ # self,
56
+ # *,
57
+ # question_name,
58
+ # answer,
59
+ # prompts,
60
+ # generated_tokens: str,
61
+ # usage=None,
62
+ # comment=None,
63
+ # cached_response=None,
64
+ # raw_model_response=None,
65
+ # simple_model_raw_response=None,
66
+ # cache_used=None,
67
+ # cache_key=None,
68
+ # ):
69
+ # """Initialize the AgentResponseDict object."""
70
+ # usage = usage or {"prompt_tokens": 0, "completion_tokens": 0}
71
+ # if generated_tokens is None:
72
+ # raise ValueError("generated_tokens must be provided")
73
+ # self.data = {
74
+ # "answer": answer,
75
+ # "comment": comment,
76
+ # "question_name": question_name,
77
+ # "prompts": prompts,
78
+ # "usage": usage,
79
+ # "cached_response": cached_response,
80
+ # "raw_model_response": raw_model_response,
81
+ # "simple_model_raw_response": simple_model_raw_response,
82
+ # "cache_used": cache_used,
83
+ # "cache_key": cache_key,
84
+ # "generated_tokens": generated_tokens,
85
+ # }
86
+
87
+ # @property
88
+ # def data(self):
89
+ # return self._data
90
+
91
+ # @data.setter
92
+ # def data(self, value):
93
+ # self._data = value
94
+
95
+ # def __getitem__(self, key):
96
+ # return self.data.get(key, None)
97
+
98
+ # def __setitem__(self, key, value):
99
+ # self.data[key] = value
100
+
101
+ # def __delitem__(self, key):
102
+ # del self.data[key]
103
+
104
+ # def __iter__(self):
105
+ # return iter(self.data)
106
+
107
+ # def __len__(self):
108
+ # return len(self.data)
109
+
110
+ # def keys(self):
111
+ # return self.data.keys()
112
+
113
+ # def values(self):
114
+ # return self.data.values()
115
+
116
+ # def items(self):
117
+ # return self.data.items()
118
+
119
+ # def is_this_same_model(self):
120
+ # return True
edsl/enums.py CHANGED
@@ -62,6 +62,7 @@ class InferenceServiceType(EnumWithChecks):
62
62
  GROQ = "groq"
63
63
  AZURE = "azure"
64
64
  OLLAMA = "ollama"
65
+ MISTRAL = "mistral"
65
66
 
66
67
 
67
68
  service_to_api_keyname = {
@@ -74,6 +75,7 @@ service_to_api_keyname = {
74
75
  InferenceServiceType.ANTHROPIC.value: "ANTHROPIC_API_KEY",
75
76
  InferenceServiceType.GROQ.value: "GROQ_API_KEY",
76
77
  InferenceServiceType.BEDROCK.value: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"],
78
+ InferenceServiceType.MISTRAL.value: "MISTRAL_API_KEY",
77
79
  }
78
80
 
79
81
 
@@ -1,8 +1,32 @@
1
1
  from textwrap import dedent
2
+ from typing import Optional
2
3
 
3
4
 
4
5
  class LanguageModelExceptions(Exception):
5
- pass
6
+ explanation = (
7
+ "This is the base class for all exceptions in the LanguageModel class."
8
+ )
9
+
10
+ def __init__(self, message):
11
+ super().__init__(message)
12
+ self.message = message
13
+
14
+
15
+ class LanguageModelNoResponseError(LanguageModelExceptions):
16
+ explanation = (
17
+ """This happens when the LLM API cannot be reached and/or does not respond."""
18
+ )
19
+
20
+ def __init__(self, message):
21
+ super().__init__(message)
22
+
23
+
24
+ class LanguageModelBadResponseError(LanguageModelExceptions):
25
+ explanation = """This happens when the LLM API can be reached and responds, does not return a usable answer."""
26
+
27
+ def __init__(self, message, response_json: Optional[dict] = None):
28
+ super().__init__(message)
29
+ self.response_json = response_json
6
30
 
7
31
 
8
32
  class LanguageModelNotFound(LanguageModelExceptions):
@@ -1,16 +1,73 @@
1
+ from typing import Any, SupportsIndex
2
+ from jinja2 import Template
3
+ import json
4
+
5
+
1
6
  class QuestionErrors(Exception):
2
- pass
7
+ """
8
+ Base exception class for question-related errors.
9
+ """
3
10
 
11
+ def __init__(self, message="An error occurred with the question"):
12
+ self.message = message
13
+ super().__init__(self.message)
4
14
 
5
- class QuestionCreationValidationError(QuestionErrors):
6
- pass
7
15
 
16
+ class QuestionAnswerValidationError(QuestionErrors):
17
+ documentation = "https://docs.expectedparrot.com/en/latest/exceptions.html"
18
+
19
+ explanation = """This when the answer coming from the Language Model does not conform to the expectation for that question type.
20
+ For example, if the question is a multiple choice question, the answer should be drawn from the list of options provided.
21
+ """
22
+
23
+ def __init__(self, message="Invalid answer.", data=None, model=None):
24
+ self.message = message
25
+ self.data = data
26
+ self.model = model
27
+ super().__init__(self.message)
28
+
29
+ def __str__(self):
30
+ return f"""{repr(self)}
31
+ Data being validated: {self.data}
32
+ Pydnantic Model: {self.model}.
33
+ Reported error: {self.message}."""
34
+
35
+ def to_html_dict(self):
36
+ return {
37
+ "error_type": ("Name of the exception", "p", "/p", self.__class__.__name__),
38
+ "explaination": ("Explanation", "p", "/p", self.explanation),
39
+ "edsl answer": (
40
+ "What model returned",
41
+ "pre",
42
+ "/pre",
43
+ json.dumps(self.data, indent=2),
44
+ ),
45
+ "validating_model": (
46
+ "Pydantic model for answers",
47
+ "pre",
48
+ "/pre",
49
+ json.dumps(self.model.model_json_schema(), indent=2),
50
+ ),
51
+ "error_message": (
52
+ "Error message Pydantic returned",
53
+ "p",
54
+ "/p",
55
+ self.message,
56
+ ),
57
+ "documentation_url": (
58
+ "URL to EDSL docs",
59
+ f"a href='{self.documentation}'",
60
+ "/a",
61
+ self.documentation,
62
+ ),
63
+ }
8
64
 
9
- class QuestionResponseValidationError(QuestionErrors):
65
+
66
+ class QuestionCreationValidationError(QuestionErrors):
10
67
  pass
11
68
 
12
69
 
13
- class QuestionAnswerValidationError(QuestionErrors):
70
+ class QuestionResponseValidationError(QuestionErrors):
14
71
  pass
15
72
 
16
73
 
@@ -2,6 +2,10 @@ class ResultsErrors(Exception):
2
2
  pass
3
3
 
4
4
 
5
+ class ResultsDeserializationError(ResultsErrors):
6
+ pass
7
+
8
+
5
9
  class ResultsBadMutationstringError(ResultsErrors):
6
10
  pass
7
11
 
@@ -11,6 +11,11 @@ class AnthropicService(InferenceServiceABC):
11
11
 
12
12
  _inference_service_ = "anthropic"
13
13
  _env_key_name_ = "ANTHROPIC_API_KEY"
14
+ key_sequence = ["content", 0, "text"] # ["content"][0]["text"]
15
+ usage_sequence = ["usage"]
16
+ input_token_name = "input_tokens"
17
+ output_token_name = "output_tokens"
18
+ model_exclude_list = []
14
19
 
15
20
  @classmethod
16
21
  def available(cls):
@@ -34,6 +39,11 @@ class AnthropicService(InferenceServiceABC):
34
39
  Child class of LanguageModel for interacting with OpenAI models
35
40
  """
36
41
 
42
+ key_sequence = cls.key_sequence
43
+ usage_sequence = cls.usage_sequence
44
+ input_token_name = cls.input_token_name
45
+ output_token_name = cls.output_token_name
46
+
37
47
  _inference_service_ = cls._inference_service_
38
48
  _model_ = model_name
39
49
  _parameters_ = {
@@ -46,6 +56,9 @@ class AnthropicService(InferenceServiceABC):
46
56
  "top_logprobs": 3,
47
57
  }
48
58
 
59
+ _tpm = cls.get_tpm(cls)
60
+ _rpm = cls.get_rpm(cls)
61
+
49
62
  async def async_execute_model_call(
50
63
  self, user_prompt: str, system_prompt: str = ""
51
64
  ) -> dict[str, Any]:
@@ -66,17 +79,6 @@ class AnthropicService(InferenceServiceABC):
66
79
  )
67
80
  return response.model_dump()
68
81
 
69
- @staticmethod
70
- def parse_response(raw_response: dict[str, Any]) -> str:
71
- """Parses the API response and returns the response text."""
72
- response = raw_response["content"][0]["text"]
73
- pattern = r"^```json(?:\\n|\n)(.+?)(?:\\n|\n)```$"
74
- match = re.match(pattern, response, re.DOTALL)
75
- if match:
76
- return match.group(1)
77
- else:
78
- return response
79
-
80
82
  LLM.__name__ = model_class_name
81
83
 
82
84
  return LLM
@@ -16,6 +16,18 @@ class AwsBedrockService(InferenceServiceABC):
16
16
  _env_key_name_ = (
17
17
  "AWS_ACCESS_KEY_ID" # or any other environment key for AWS credentials
18
18
  )
19
+ key_sequence = ["output", "message", "content", 0, "text"]
20
+ input_token_name = "inputTokens"
21
+ output_token_name = "outputTokens"
22
+ usage_sequence = ["usage"]
23
+ model_exclude_list = [
24
+ "ai21.j2-grande-instruct",
25
+ "ai21.j2-jumbo-instruct",
26
+ "ai21.j2-mid",
27
+ "ai21.j2-mid-v1",
28
+ "ai21.j2-ultra",
29
+ "ai21.j2-ultra-v1",
30
+ ]
19
31
 
20
32
  @classmethod
21
33
  def available(cls):
@@ -28,7 +40,7 @@ class AwsBedrockService(InferenceServiceABC):
28
40
  else:
29
41
  all_models_ids = cls._models_list_cache
30
42
 
31
- return all_models_ids
43
+ return [m for m in all_models_ids if m not in cls.model_exclude_list]
32
44
 
33
45
  @classmethod
34
46
  def create_model(
@@ -42,6 +54,8 @@ class AwsBedrockService(InferenceServiceABC):
42
54
  Child class of LanguageModel for interacting with AWS Bedrock models.
43
55
  """
44
56
 
57
+ key_sequence = cls.key_sequence
58
+ usage_sequence = cls.usage_sequence
45
59
  _inference_service_ = cls._inference_service_
46
60
  _model_ = model_name
47
61
  _parameters_ = {
@@ -49,6 +63,10 @@ class AwsBedrockService(InferenceServiceABC):
49
63
  "max_tokens": 512,
50
64
  "top_p": 0.9,
51
65
  }
66
+ input_token_name = cls.input_token_name
67
+ output_token_name = cls.output_token_name
68
+ _rpm = cls.get_rpm(cls)
69
+ _tpm = cls.get_tpm(cls)
52
70
 
53
71
  async def async_execute_model_call(
54
72
  self, user_prompt: str, system_prompt: str = ""
@@ -89,22 +107,6 @@ class AwsBedrockService(InferenceServiceABC):
89
107
  print(e)
90
108
  return {"error": str(e)}
91
109
 
92
- @staticmethod
93
- def parse_response(raw_response: dict[str, Any]) -> str:
94
- """Parses the API response and returns the response text."""
95
- if "output" in raw_response and "message" in raw_response["output"]:
96
- response = raw_response["output"]["message"]["content"][0]["text"]
97
- pattern = r"^```json(?:\\n|\n)(.+?)(?:\\n|\n)```$"
98
- match = re.match(pattern, response, re.DOTALL)
99
- if match:
100
- return match.group(1)
101
- else:
102
- out = fix_partial_correct_response(response)
103
- if "error" not in out:
104
- response = out["extracted_json"]
105
- return response
106
- return "Error parsing response"
107
-
108
110
  LLM.__name__ = model_class_name
109
111
 
110
112
  return LLM
@@ -25,11 +25,22 @@ def json_handle_none(value: Any) -> Any:
25
25
  class AzureAIService(InferenceServiceABC):
26
26
  """Azure AI service class."""
27
27
 
28
+ # key_sequence = ["content", 0, "text"] # ["content"][0]["text"]
29
+ key_sequence = ["choices", 0, "message", "content"]
30
+ usage_sequence = ["usage"]
31
+ input_token_name = "prompt_tokens"
32
+ output_token_name = "completion_tokens"
33
+
28
34
  _inference_service_ = "azure"
29
35
  _env_key_name_ = (
30
36
  "AZURE_ENDPOINT_URL_AND_KEY" # Environment variable for Azure API key
31
37
  )
32
38
  _model_id_to_endpoint_and_key = {}
39
+ model_exclude_list = [
40
+ "Cohere-command-r-plus-xncmg",
41
+ "Mistral-Nemo-klfsi",
42
+ "Mistral-large-2407-ojfld",
43
+ ]
33
44
 
34
45
  @classmethod
35
46
  def available(cls):
@@ -82,7 +93,7 @@ class AzureAIService(InferenceServiceABC):
82
93
 
83
94
  except Exception as e:
84
95
  raise e
85
- return out
96
+ return [m for m in out if m not in cls.model_exclude_list]
86
97
 
87
98
  @classmethod
88
99
  def create_model(
@@ -96,6 +107,10 @@ class AzureAIService(InferenceServiceABC):
96
107
  Child class of LanguageModel for interacting with Azure OpenAI models.
97
108
  """
98
109
 
110
+ key_sequence = cls.key_sequence
111
+ usage_sequence = cls.usage_sequence
112
+ input_token_name = cls.input_token_name
113
+ output_token_name = cls.output_token_name
99
114
  _inference_service_ = cls._inference_service_
100
115
  _model_ = model_name
101
116
  _parameters_ = {
@@ -103,6 +118,8 @@ class AzureAIService(InferenceServiceABC):
103
118
  "max_tokens": 512,
104
119
  "top_p": 0.9,
105
120
  }
121
+ _rpm = cls.get_rpm(cls)
122
+ _tpm = cls.get_tpm(cls)
106
123
 
107
124
  async def async_execute_model_call(
108
125
  self, user_prompt: str, system_prompt: str = ""
@@ -172,25 +189,25 @@ class AzureAIService(InferenceServiceABC):
172
189
  )
173
190
  return response.model_dump()
174
191
 
175
- @staticmethod
176
- def parse_response(raw_response: dict[str, Any]) -> str:
177
- """Parses the API response and returns the response text."""
178
- if (
179
- raw_response
180
- and "choices" in raw_response
181
- and raw_response["choices"]
182
- ):
183
- response = raw_response["choices"][0]["message"]["content"]
184
- pattern = r"^```json(?:\\n|\n)(.+?)(?:\\n|\n)```$"
185
- match = re.match(pattern, response, re.DOTALL)
186
- if match:
187
- return match.group(1)
188
- else:
189
- out = fix_partial_correct_response(response)
190
- if "error" not in out:
191
- response = out["extracted_json"]
192
- return response
193
- return "Error parsing response"
192
+ # @staticmethod
193
+ # def parse_response(raw_response: dict[str, Any]) -> str:
194
+ # """Parses the API response and returns the response text."""
195
+ # if (
196
+ # raw_response
197
+ # and "choices" in raw_response
198
+ # and raw_response["choices"]
199
+ # ):
200
+ # response = raw_response["choices"][0]["message"]["content"]
201
+ # pattern = r"^```json(?:\\n|\n)(.+?)(?:\\n|\n)```$"
202
+ # match = re.match(pattern, response, re.DOTALL)
203
+ # if match:
204
+ # return match.group(1)
205
+ # else:
206
+ # out = fix_partial_correct_response(response)
207
+ # if "error" not in out:
208
+ # response = out["extracted_json"]
209
+ # return response
210
+ # return "Error parsing response"
194
211
 
195
212
  LLM.__name__ = model_class_name
196
213