edsl 0.1.39__py3-none-any.whl → 0.1.39.dev1__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 (212) hide show
  1. edsl/Base.py +116 -197
  2. edsl/__init__.py +7 -15
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +147 -351
  5. edsl/agents/AgentList.py +73 -211
  6. edsl/agents/Invigilator.py +50 -101
  7. edsl/agents/InvigilatorBase.py +70 -62
  8. edsl/agents/PromptConstructor.py +225 -143
  9. edsl/agents/__init__.py +1 -0
  10. edsl/agents/prompt_helpers.py +3 -3
  11. edsl/auto/AutoStudy.py +5 -18
  12. edsl/auto/StageBase.py +40 -53
  13. edsl/auto/StageQuestions.py +1 -2
  14. edsl/auto/utilities.py +6 -0
  15. edsl/config.py +2 -22
  16. edsl/conversation/car_buying.py +1 -2
  17. edsl/coop/PriceFetcher.py +1 -1
  18. edsl/coop/coop.py +47 -125
  19. edsl/coop/utils.py +14 -14
  20. edsl/data/Cache.py +27 -45
  21. edsl/data/CacheEntry.py +15 -12
  22. edsl/data/CacheHandler.py +12 -31
  23. edsl/data/RemoteCacheSync.py +46 -154
  24. edsl/data/__init__.py +3 -4
  25. edsl/data_transfer_models.py +1 -2
  26. edsl/enums.py +0 -27
  27. edsl/exceptions/__init__.py +50 -50
  28. edsl/exceptions/agents.py +0 -12
  29. edsl/exceptions/questions.py +6 -24
  30. edsl/exceptions/scenarios.py +0 -7
  31. edsl/inference_services/AnthropicService.py +19 -38
  32. edsl/inference_services/AwsBedrock.py +2 -0
  33. edsl/inference_services/AzureAI.py +2 -0
  34. edsl/inference_services/GoogleService.py +12 -7
  35. edsl/inference_services/InferenceServiceABC.py +85 -18
  36. edsl/inference_services/InferenceServicesCollection.py +79 -120
  37. edsl/inference_services/MistralAIService.py +3 -0
  38. edsl/inference_services/OpenAIService.py +35 -47
  39. edsl/inference_services/PerplexityService.py +3 -0
  40. edsl/inference_services/TestService.py +10 -11
  41. edsl/inference_services/TogetherAIService.py +3 -5
  42. edsl/jobs/Answers.py +14 -1
  43. edsl/jobs/Jobs.py +431 -356
  44. edsl/jobs/JobsChecks.py +10 -35
  45. edsl/jobs/JobsPrompts.py +4 -6
  46. edsl/jobs/JobsRemoteInferenceHandler.py +133 -205
  47. edsl/jobs/buckets/BucketCollection.py +3 -44
  48. edsl/jobs/buckets/TokenBucket.py +21 -53
  49. edsl/jobs/interviews/Interview.py +408 -143
  50. edsl/jobs/runners/JobsRunnerAsyncio.py +403 -88
  51. edsl/jobs/runners/JobsRunnerStatus.py +165 -133
  52. edsl/jobs/tasks/QuestionTaskCreator.py +19 -21
  53. edsl/jobs/tasks/TaskHistory.py +18 -38
  54. edsl/jobs/tasks/task_status_enum.py +2 -0
  55. edsl/language_models/KeyLookup.py +30 -0
  56. edsl/language_models/LanguageModel.py +236 -194
  57. edsl/language_models/ModelList.py +19 -28
  58. edsl/language_models/__init__.py +2 -1
  59. edsl/language_models/registry.py +190 -0
  60. edsl/language_models/repair.py +2 -2
  61. edsl/language_models/unused/ReplicateBase.py +83 -0
  62. edsl/language_models/utilities.py +4 -5
  63. edsl/notebooks/Notebook.py +14 -19
  64. edsl/prompts/Prompt.py +39 -29
  65. edsl/questions/{answer_validator_mixin.py → AnswerValidatorMixin.py} +2 -47
  66. edsl/questions/QuestionBase.py +214 -68
  67. edsl/questions/{question_base_gen_mixin.py → QuestionBaseGenMixin.py} +50 -57
  68. edsl/questions/QuestionBasePromptsMixin.py +3 -7
  69. edsl/questions/QuestionBudget.py +1 -1
  70. edsl/questions/QuestionCheckBox.py +3 -3
  71. edsl/questions/QuestionExtract.py +7 -5
  72. edsl/questions/QuestionFreeText.py +3 -2
  73. edsl/questions/QuestionList.py +18 -10
  74. edsl/questions/QuestionMultipleChoice.py +23 -67
  75. edsl/questions/QuestionNumerical.py +4 -2
  76. edsl/questions/QuestionRank.py +17 -7
  77. edsl/questions/{response_validator_abc.py → ResponseValidatorABC.py} +26 -40
  78. edsl/questions/SimpleAskMixin.py +3 -4
  79. edsl/questions/__init__.py +1 -2
  80. edsl/questions/derived/QuestionLinearScale.py +3 -6
  81. edsl/questions/derived/QuestionTopK.py +1 -1
  82. edsl/questions/descriptors.py +3 -17
  83. edsl/questions/question_registry.py +1 -1
  84. edsl/results/CSSParameterizer.py +1 -1
  85. edsl/results/Dataset.py +7 -170
  86. edsl/results/DatasetExportMixin.py +305 -168
  87. edsl/results/DatasetTree.py +8 -28
  88. edsl/results/Result.py +206 -298
  89. edsl/results/Results.py +131 -149
  90. edsl/results/ResultsDBMixin.py +238 -0
  91. edsl/results/ResultsExportMixin.py +0 -2
  92. edsl/results/{results_selector.py → Selector.py} +13 -23
  93. edsl/results/TableDisplay.py +171 -98
  94. edsl/results/__init__.py +1 -1
  95. edsl/scenarios/FileStore.py +239 -150
  96. edsl/scenarios/Scenario.py +193 -90
  97. edsl/scenarios/ScenarioHtmlMixin.py +3 -4
  98. edsl/scenarios/{scenario_join.py → ScenarioJoin.py} +6 -10
  99. edsl/scenarios/ScenarioList.py +244 -415
  100. edsl/scenarios/ScenarioListExportMixin.py +7 -0
  101. edsl/scenarios/ScenarioListPdfMixin.py +37 -15
  102. edsl/scenarios/__init__.py +2 -1
  103. edsl/study/ObjectEntry.py +1 -1
  104. edsl/study/SnapShot.py +1 -1
  105. edsl/study/Study.py +12 -5
  106. edsl/surveys/Rule.py +4 -5
  107. edsl/surveys/RuleCollection.py +27 -25
  108. edsl/surveys/Survey.py +791 -270
  109. edsl/surveys/SurveyCSS.py +8 -20
  110. edsl/surveys/{SurveyFlowVisualization.py → SurveyFlowVisualizationMixin.py} +9 -11
  111. edsl/surveys/__init__.py +2 -4
  112. edsl/surveys/descriptors.py +2 -6
  113. edsl/surveys/instructions/ChangeInstruction.py +2 -1
  114. edsl/surveys/instructions/Instruction.py +13 -4
  115. edsl/surveys/instructions/InstructionCollection.py +6 -11
  116. edsl/templates/error_reporting/interview_details.html +1 -1
  117. edsl/templates/error_reporting/report.html +1 -1
  118. edsl/tools/plotting.py +1 -1
  119. edsl/utilities/utilities.py +23 -35
  120. {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/METADATA +10 -12
  121. edsl-0.1.39.dev1.dist-info/RECORD +277 -0
  122. {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/WHEEL +1 -1
  123. edsl/agents/QuestionInstructionPromptBuilder.py +0 -128
  124. edsl/agents/QuestionTemplateReplacementsBuilder.py +0 -137
  125. edsl/agents/question_option_processor.py +0 -172
  126. edsl/coop/CoopFunctionsMixin.py +0 -15
  127. edsl/coop/ExpectedParrotKeyHandler.py +0 -125
  128. edsl/exceptions/inference_services.py +0 -5
  129. edsl/inference_services/AvailableModelCacheHandler.py +0 -184
  130. edsl/inference_services/AvailableModelFetcher.py +0 -215
  131. edsl/inference_services/ServiceAvailability.py +0 -135
  132. edsl/inference_services/data_structures.py +0 -134
  133. edsl/jobs/AnswerQuestionFunctionConstructor.py +0 -223
  134. edsl/jobs/FetchInvigilator.py +0 -47
  135. edsl/jobs/InterviewTaskManager.py +0 -98
  136. edsl/jobs/InterviewsConstructor.py +0 -50
  137. edsl/jobs/JobsComponentConstructor.py +0 -189
  138. edsl/jobs/JobsRemoteInferenceLogger.py +0 -239
  139. edsl/jobs/RequestTokenEstimator.py +0 -30
  140. edsl/jobs/async_interview_runner.py +0 -138
  141. edsl/jobs/buckets/TokenBucketAPI.py +0 -211
  142. edsl/jobs/buckets/TokenBucketClient.py +0 -191
  143. edsl/jobs/check_survey_scenario_compatibility.py +0 -85
  144. edsl/jobs/data_structures.py +0 -120
  145. edsl/jobs/decorators.py +0 -35
  146. edsl/jobs/jobs_status_enums.py +0 -9
  147. edsl/jobs/loggers/HTMLTableJobLogger.py +0 -304
  148. edsl/jobs/results_exceptions_handler.py +0 -98
  149. edsl/language_models/ComputeCost.py +0 -63
  150. edsl/language_models/PriceManager.py +0 -127
  151. edsl/language_models/RawResponseHandler.py +0 -106
  152. edsl/language_models/ServiceDataSources.py +0 -0
  153. edsl/language_models/key_management/KeyLookup.py +0 -63
  154. edsl/language_models/key_management/KeyLookupBuilder.py +0 -273
  155. edsl/language_models/key_management/KeyLookupCollection.py +0 -38
  156. edsl/language_models/key_management/__init__.py +0 -0
  157. edsl/language_models/key_management/models.py +0 -131
  158. edsl/language_models/model.py +0 -256
  159. edsl/notebooks/NotebookToLaTeX.py +0 -142
  160. edsl/questions/ExceptionExplainer.py +0 -77
  161. edsl/questions/HTMLQuestion.py +0 -103
  162. edsl/questions/QuestionMatrix.py +0 -265
  163. edsl/questions/data_structures.py +0 -20
  164. edsl/questions/loop_processor.py +0 -149
  165. edsl/questions/response_validator_factory.py +0 -34
  166. edsl/questions/templates/matrix/__init__.py +0 -1
  167. edsl/questions/templates/matrix/answering_instructions.jinja +0 -5
  168. edsl/questions/templates/matrix/question_presentation.jinja +0 -20
  169. edsl/results/MarkdownToDocx.py +0 -122
  170. edsl/results/MarkdownToPDF.py +0 -111
  171. edsl/results/TextEditor.py +0 -50
  172. edsl/results/file_exports.py +0 -252
  173. edsl/results/smart_objects.py +0 -96
  174. edsl/results/table_data_class.py +0 -12
  175. edsl/results/table_renderers.py +0 -118
  176. edsl/scenarios/ConstructDownloadLink.py +0 -109
  177. edsl/scenarios/DocumentChunker.py +0 -102
  178. edsl/scenarios/DocxScenario.py +0 -16
  179. edsl/scenarios/PdfExtractor.py +0 -40
  180. edsl/scenarios/directory_scanner.py +0 -96
  181. edsl/scenarios/file_methods.py +0 -85
  182. edsl/scenarios/handlers/__init__.py +0 -13
  183. edsl/scenarios/handlers/csv.py +0 -49
  184. edsl/scenarios/handlers/docx.py +0 -76
  185. edsl/scenarios/handlers/html.py +0 -37
  186. edsl/scenarios/handlers/json.py +0 -111
  187. edsl/scenarios/handlers/latex.py +0 -5
  188. edsl/scenarios/handlers/md.py +0 -51
  189. edsl/scenarios/handlers/pdf.py +0 -68
  190. edsl/scenarios/handlers/png.py +0 -39
  191. edsl/scenarios/handlers/pptx.py +0 -105
  192. edsl/scenarios/handlers/py.py +0 -294
  193. edsl/scenarios/handlers/sql.py +0 -313
  194. edsl/scenarios/handlers/sqlite.py +0 -149
  195. edsl/scenarios/handlers/txt.py +0 -33
  196. edsl/scenarios/scenario_selector.py +0 -156
  197. edsl/surveys/ConstructDAG.py +0 -92
  198. edsl/surveys/EditSurvey.py +0 -221
  199. edsl/surveys/InstructionHandler.py +0 -100
  200. edsl/surveys/MemoryManagement.py +0 -72
  201. edsl/surveys/RuleManager.py +0 -172
  202. edsl/surveys/Simulator.py +0 -75
  203. edsl/surveys/SurveyToApp.py +0 -141
  204. edsl/utilities/PrettyList.py +0 -56
  205. edsl/utilities/is_notebook.py +0 -18
  206. edsl/utilities/is_valid_variable_name.py +0 -11
  207. edsl/utilities/remove_edsl_version.py +0 -24
  208. edsl-0.1.39.dist-info/RECORD +0 -358
  209. /edsl/questions/{register_questions_meta.py → RegisterQuestionsMeta.py} +0 -0
  210. /edsl/results/{results_fetch_mixin.py → ResultsFetchMixin.py} +0 -0
  211. /edsl/results/{results_tools_mixin.py → ResultsToolsMixin.py} +0 -0
  212. {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/LICENSE +0 -0
@@ -1,22 +1,18 @@
1
- from typing import Optional, List, TYPE_CHECKING
1
+ from typing import Optional, List
2
2
  from collections import UserList
3
+ from edsl import Model
3
4
 
5
+ from edsl.language_models import LanguageModel
4
6
  from edsl.Base import Base
5
- from edsl.language_models.model import Model
6
-
7
- #
8
- from edsl.utilities.remove_edsl_version import remove_edsl_version
9
- from edsl.utilities.is_valid_variable_name import is_valid_variable_name
10
-
11
- if TYPE_CHECKING:
12
- from edsl.inference_services.data_structures import AvailableModels
13
- from edsl.language_models import LanguageModel
7
+ from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
8
+ from edsl.utilities.utilities import is_valid_variable_name
9
+ from edsl.utilities.utilities import dict_hash
14
10
 
15
11
 
16
12
  class ModelList(Base, UserList):
17
13
  __documentation__ = """https://docs.expectedparrot.com/en/latest/language_models.html#module-edsl.language_models.ModelList"""
18
14
 
19
- def __init__(self, data: Optional["LanguageModel"] = None):
15
+ def __init__(self, data: Optional[list] = None):
20
16
  """Initialize the ScenarioList class.
21
17
 
22
18
  >>> from edsl import Model
@@ -37,11 +33,14 @@ class ModelList(Base, UserList):
37
33
  """
38
34
  return set([model.model for model in self])
39
35
 
36
+ def rich_print(self):
37
+ pass
38
+
40
39
  def __repr__(self):
41
40
  return f"ModelList({super().__repr__()})"
42
41
 
43
42
  def _summary(self):
44
- return {"models": len(self)}
43
+ return {"EDSL Class": "ModelList", "Number of Models": len(self)}
45
44
 
46
45
  def __hash__(self):
47
46
  """Return a hash of the ModelList. This is used for comparison of ModelLists.
@@ -55,8 +54,7 @@ class ModelList(Base, UserList):
55
54
  return dict_hash(self.to_dict(sort=True, add_edsl_version=False))
56
55
 
57
56
  def to_scenario_list(self):
58
- from edsl.scenarios.ScenarioList import ScenarioList
59
- from edsl.scenarios.Scenario import Scenario
57
+ from edsl import ScenarioList, Scenario
60
58
 
61
59
  sl = ScenarioList()
62
60
  for model in self:
@@ -75,7 +73,7 @@ class ModelList(Base, UserList):
75
73
  pretty_labels: Optional[dict] = None,
76
74
  ):
77
75
  """
78
- >>> ModelList.example().table('model')
76
+ >>> ModelList.example().table("model")
79
77
  model
80
78
  -------
81
79
  gpt-4o
@@ -88,7 +86,7 @@ class ModelList(Base, UserList):
88
86
  .table(*fields, tablefmt=tablefmt, pretty_labels=pretty_labels)
89
87
  )
90
88
 
91
- def to_list(self) -> list:
89
+ def to_list(self):
92
90
  return self.to_scenario_list().to_list()
93
91
 
94
92
  def to_dict(self, sort=False, add_edsl_version=True):
@@ -114,6 +112,11 @@ class ModelList(Base, UserList):
114
112
 
115
113
  return d
116
114
 
115
+ def _repr_html_(self):
116
+ """Return an HTML representation of the ModelList."""
117
+ footer = f"<a href={self.__documentation__}>(docs)</a>"
118
+ return str(self.summary(format="html")) + footer
119
+
117
120
  @classmethod
118
121
  def from_names(self, *args, **kwargs):
119
122
  """A a model list from a list of names"""
@@ -121,16 +124,6 @@ class ModelList(Base, UserList):
121
124
  args = args[0]
122
125
  return ModelList([Model(model_name, **kwargs) for model_name in args])
123
126
 
124
- @classmethod
125
- def from_available_models(self, available_models_list: "AvailableModels"):
126
- """Create a ModelList from an AvailableModels object"""
127
- return ModelList(
128
- [
129
- Model(model.model_name, service_name=model.service_name)
130
- for model in available_models_list
131
- ]
132
- )
133
-
134
127
  @classmethod
135
128
  @remove_edsl_version
136
129
  def from_dict(cls, data):
@@ -140,8 +133,6 @@ class ModelList(Base, UserList):
140
133
  >>> newm = ModelList.from_dict(ModelList.example().to_dict())
141
134
  >>> assert ModelList.example() == newm
142
135
  """
143
- from edsl.language_models.LanguageModel import LanguageModel
144
-
145
136
  return cls(data=[LanguageModel.from_dict(model) for model in data["models"]])
146
137
 
147
138
  def code(self):
@@ -1,2 +1,3 @@
1
1
  from edsl.language_models.LanguageModel import LanguageModel
2
- from edsl.language_models.model import Model
2
+ from edsl.language_models.registry import Model
3
+ from edsl.language_models.KeyLookup import KeyLookup
@@ -0,0 +1,190 @@
1
+ import textwrap
2
+ from random import random
3
+ from edsl.config import CONFIG
4
+
5
+ # if "EDSL_DEFAULT_MODEL" not in CONFIG:
6
+ # default_model = "test"
7
+ # else:
8
+ # default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
9
+
10
+ from collections import UserList
11
+
12
+
13
+ class PrettyList(UserList):
14
+ def __init__(self, data=None, columns=None):
15
+ super().__init__(data)
16
+ self.columns = columns
17
+
18
+ def _repr_html_(self):
19
+ if isinstance(self[0], list) or isinstance(self[0], tuple):
20
+ num_cols = len(self[0])
21
+ else:
22
+ num_cols = 1
23
+
24
+ if self.columns:
25
+ columns = self.columns
26
+ else:
27
+ columns = list(range(num_cols))
28
+
29
+ if num_cols > 1:
30
+ return (
31
+ "<pre><table>"
32
+ + "".join(["<th>" + str(column) + "</th>" for column in columns])
33
+ + "".join(
34
+ [
35
+ "<tr>"
36
+ + "".join(["<td>" + str(x) + "</td>" for x in row])
37
+ + "</tr>"
38
+ for row in self
39
+ ]
40
+ )
41
+ + "</table></pre>"
42
+ )
43
+ else:
44
+ return (
45
+ "<pre><table>"
46
+ + "".join(["<th>" + str(index) + "</th>" for index in columns])
47
+ + "".join(
48
+ ["<tr>" + "<td>" + str(row) + "</td>" + "</tr>" for row in self]
49
+ )
50
+ + "</table></pre>"
51
+ )
52
+
53
+
54
+ def get_model_class(model_name, registry=None):
55
+ from edsl.inference_services.registry import default
56
+
57
+ registry = registry or default
58
+ factory = registry.create_model_factory(model_name)
59
+ return factory
60
+
61
+
62
+ class Meta(type):
63
+ def __repr__(cls):
64
+ return textwrap.dedent(
65
+ f"""\
66
+ Available models: {cls.available()}
67
+
68
+ To create an instance, you can do:
69
+ >>> m = Model('gpt-4-1106-preview', temperature=0.5, ...)
70
+
71
+ To get the default model, you can leave out the model name.
72
+ To see the available models, you can do:
73
+ >>> Model.available()
74
+ """
75
+ )
76
+
77
+
78
+ class Model(metaclass=Meta):
79
+ default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
80
+
81
+ def __new__(
82
+ cls, model_name=None, registry=None, service_name=None, *args, **kwargs
83
+ ):
84
+ # Map index to the respective subclass
85
+ if model_name is None:
86
+ model_name = (
87
+ cls.default_model
88
+ ) # when model_name is None, use the default model, set in the config file
89
+ from edsl.inference_services.registry import default
90
+
91
+ registry = registry or default
92
+
93
+ if isinstance(model_name, int): # can refer to a model by index
94
+ model_name = cls.available(name_only=True)[model_name]
95
+
96
+ factory = registry.create_model_factory(model_name, service_name=service_name)
97
+ return factory(*args, **kwargs)
98
+
99
+ @classmethod
100
+ def add_model(cls, service_name, model_name):
101
+ from edsl.inference_services.registry import default
102
+
103
+ registry = default
104
+ registry.add_model(service_name, model_name)
105
+
106
+ @classmethod
107
+ def services(cls, registry=None):
108
+ from edsl.inference_services.registry import default
109
+
110
+ registry = registry or default
111
+ return [r._inference_service_ for r in registry.services]
112
+
113
+ @classmethod
114
+ def available(cls, search_term=None, name_only=False, registry=None, service=None):
115
+ from edsl.inference_services.registry import default
116
+
117
+ registry = registry or default
118
+ full_list = registry.available()
119
+
120
+ if service is not None:
121
+ if service not in cls.services(registry=registry):
122
+ raise ValueError(f"Service {service} not found in available services.")
123
+
124
+ full_list = [m for m in full_list if m[1] == service]
125
+
126
+ if search_term is None:
127
+ if name_only:
128
+ return PrettyList(
129
+ [m[0] for m in full_list],
130
+ columns=["Model Name", "Service Name", "Code"],
131
+ )
132
+ else:
133
+ return PrettyList(
134
+ full_list, columns=["Model Name", "Service Name", "Code"]
135
+ )
136
+ else:
137
+ filtered_results = [
138
+ m for m in full_list if search_term in m[0] or search_term in m[1]
139
+ ]
140
+ if name_only:
141
+ return PrettyList(
142
+ [m[0] for m in filtered_results],
143
+ columns=["Model Name", "Service Name", "Code"],
144
+ )
145
+ else:
146
+ return PrettyList(
147
+ filtered_results, columns=["Model Name", "Service Name", "Code"]
148
+ )
149
+
150
+ @classmethod
151
+ def check_models(cls, verbose=False):
152
+ print("Checking all available models...\n")
153
+ for model in cls.available(name_only=True):
154
+ print(f"Now checking: {model}")
155
+ try:
156
+ m = cls(model)
157
+ except Exception as e:
158
+ print(f"Error creating instance of {model}: {e}")
159
+ continue
160
+ try:
161
+ results = m.hello(verbose)
162
+ if verbose:
163
+ print(f"Results from model call: {results}")
164
+ except Exception as e:
165
+ print(f"Error calling 'hello' on {model}: {e}")
166
+ continue
167
+ print("OK!")
168
+ print("\n")
169
+
170
+ @classmethod
171
+ def example(cls, randomize: bool = False) -> "Model":
172
+ """
173
+ Returns an example Model instance.
174
+
175
+ :param randomize: If True, the temperature is set to a random decimal between 0 and 1.
176
+ """
177
+ temperature = 0.5 if not randomize else round(random(), 2)
178
+ model_name = cls.default_model
179
+ return cls(model_name, temperature=temperature)
180
+
181
+
182
+ if __name__ == "__main__":
183
+ import doctest
184
+
185
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
186
+
187
+ available = Model.available()
188
+ m = Model("gpt-4-1106-preview")
189
+ results = m.execute_model_call("Hello world")
190
+ print(results)
@@ -32,11 +32,11 @@ async def async_repair(
32
32
  else:
33
33
  return valid_dict, success
34
34
 
35
- from edsl.language_models.model import Model
35
+ from edsl import Model
36
36
 
37
37
  m = Model()
38
38
 
39
- from edsl.questions.QuestionExtract import QuestionExtract
39
+ from edsl import QuestionExtract
40
40
 
41
41
  with warnings.catch_warnings():
42
42
  warnings.simplefilter("ignore", UserWarning)
@@ -0,0 +1,83 @@
1
+ import asyncio
2
+ import aiohttp
3
+ import json
4
+ from typing import Any
5
+
6
+ from edsl import CONFIG
7
+
8
+ from edsl.language_models.LanguageModel import LanguageModel
9
+
10
+
11
+ def replicate_model_factory(model_name, base_url, api_token):
12
+ class ReplicateLanguageModelBase(LanguageModel):
13
+ _model_ = (
14
+ model_name # Example model name, replace with actual model name if needed
15
+ )
16
+ _parameters_ = {
17
+ "temperature": 0.1,
18
+ "topK": 50,
19
+ "topP": 0.9,
20
+ "max_new_tokens": 500,
21
+ "min_new_tokens": -1,
22
+ "repetition_penalty": 1.15,
23
+ # "version": "5fe0a3d7ac2852264a25279d1dfb798acbc4d49711d126646594e212cb821749",
24
+ "use_cache": True,
25
+ }
26
+ _api_token = api_token
27
+ _base_url = base_url
28
+
29
+ async def async_execute_model_call(
30
+ self, user_prompt: str, system_prompt: str = ""
31
+ ) -> dict[str, Any]:
32
+ self.api_token = self._api_token
33
+ self.headers = {
34
+ "Authorization": f"Token {self.api_token}",
35
+ "Content-Type": "application/json",
36
+ }
37
+ # combined_prompt = f"{system_prompt} {user_prompt}".strip()
38
+ # print(f"Prompt: {combined_prompt}")
39
+ data = {
40
+ # "version": self._parameters_["version"],
41
+ "input": {
42
+ "debug": False,
43
+ "top_k": self._parameters_["topK"],
44
+ "top_p": self._parameters_["topP"],
45
+ "prompt": user_prompt,
46
+ "system_prompt": system_prompt,
47
+ "temperature": self._parameters_["temperature"],
48
+ "max_new_tokens": self._parameters_["max_new_tokens"],
49
+ "min_new_tokens": self._parameters_["min_new_tokens"],
50
+ "prompt_template": "{prompt}",
51
+ "repetition_penalty": self._parameters_["repetition_penalty"],
52
+ },
53
+ }
54
+
55
+ async with aiohttp.ClientSession() as session:
56
+ async with session.post(
57
+ self._base_url, headers=self.headers, data=json.dumps(data)
58
+ ) as response:
59
+ raw_response_text = await response.text()
60
+ data = json.loads(raw_response_text)
61
+ print(f"This was the data returned by the model:{data}")
62
+ prediction_url = data["urls"]["get"]
63
+
64
+ while True:
65
+ async with session.get(
66
+ prediction_url, headers=self.headers
67
+ ) as get_response:
68
+ if get_response.status != 200:
69
+ # Handle non-success status codes appropriately
70
+ return None
71
+
72
+ get_data = await get_response.text()
73
+ get_data = json.loads(get_data)
74
+ if get_data["status"] == "succeeded":
75
+ return get_data
76
+ await asyncio.sleep(1)
77
+
78
+ def parse_response(self, raw_response: dict[str, Any]) -> str:
79
+ data = "".join(raw_response["output"])
80
+ print(f"This is what the model returned: {data}")
81
+ return data
82
+
83
+ return ReplicateLanguageModelBase
@@ -1,12 +1,13 @@
1
1
  import asyncio
2
2
  from typing import Any, Optional, List
3
+ from edsl import Survey
4
+ from edsl.config import CONFIG
3
5
  from edsl.enums import InferenceServiceType
6
+ from edsl.language_models.LanguageModel import LanguageModel
7
+ from edsl.questions import QuestionFreeText
4
8
 
5
9
 
6
10
  def create_survey(num_questions: int, chained: bool = True, take_scenario=False):
7
- from edsl.surveys.Survey import Survey
8
- from edsl.questions.QuestionFreeText import QuestionFreeText
9
-
10
11
  survey = Survey()
11
12
  for i in range(num_questions):
12
13
  if take_scenario:
@@ -27,8 +28,6 @@ def create_survey(num_questions: int, chained: bool = True, take_scenario=False)
27
28
  def create_language_model(
28
29
  exception: Exception, fail_at_number: int, never_ending=False
29
30
  ):
30
- from edsl.language_models.LanguageModel import LanguageModel
31
-
32
31
  class LanguageModelFromUtilities(LanguageModel):
33
32
  _model_ = "test"
34
33
  _parameters_ = {"temperature": 0.5}
@@ -17,8 +17,8 @@ class Notebook(Base):
17
17
 
18
18
  def __init__(
19
19
  self,
20
- path: Optional[str] = None,
21
20
  data: Optional[Dict] = None,
21
+ path: Optional[str] = None,
22
22
  name: Optional[str] = None,
23
23
  ):
24
24
  """
@@ -33,16 +33,12 @@ class Notebook(Base):
33
33
  import nbformat
34
34
 
35
35
  # Load current notebook path as fallback (VS Code only)
36
- current_notebook_path = globals().get("__vsc_ipynb_file__")
37
- if path is not None:
38
- with open(path, mode="r", encoding="utf-8") as f:
39
- data = nbformat.read(f, as_version=4)
40
- self.data = json.loads(json.dumps(data))
41
- elif data is not None:
36
+ path = path or globals().get("__vsc_ipynb_file__")
37
+ if data is not None:
42
38
  nbformat.validate(data)
43
39
  self.data = data
44
- elif current_notebook_path is not None:
45
- with open(current_notebook_path, mode="r", encoding="utf-8") as f:
40
+ elif path is not None:
41
+ with open(path, mode="r", encoding="utf-8") as f:
46
42
  data = nbformat.read(f, as_version=4)
47
43
  self.data = json.loads(json.dumps(data))
48
44
  else:
@@ -134,6 +130,15 @@ class Notebook(Base):
134
130
 
135
131
  nbformat.write(nbformat.from_dict(self.data), fp=path)
136
132
 
133
+ def print(self):
134
+ """
135
+ Print the notebook.
136
+ """
137
+ from rich import print_json
138
+ import json
139
+
140
+ print_json(json.dumps(self.to_dict()))
141
+
137
142
  def __repr__(self):
138
143
  """
139
144
  Return representation of Notebook.
@@ -245,16 +250,6 @@ class Notebook(Base):
245
250
  lines.append(f'nb = Notebook(data={self.data}, name="""{self.name}""")')
246
251
  return lines
247
252
 
248
- def to_latex(self, filename: str):
249
- """
250
- Convert notebook to LaTeX and create a folder with all necessary components.
251
-
252
- :param filename: Name of the output folder and main tex file (without extension)
253
- """
254
- from edsl.notebooks.NotebookToLaTeX import NotebookToLaTeX
255
-
256
- NotebookToLaTeX(self).convert(filename)
257
-
258
253
 
259
254
  if __name__ == "__main__":
260
255
  from edsl import Notebook
edsl/prompts/Prompt.py CHANGED
@@ -1,21 +1,43 @@
1
1
  from __future__ import annotations
2
- from typing import Any, List, Union, Dict, Optional
2
+ from typing import Optional
3
+ from abc import ABC
4
+ from typing import Any, List
5
+
6
+ from jinja2 import Environment, FileSystemLoader
7
+ from typing import Union, Dict
3
8
  from pathlib import Path
4
9
 
5
- # from jinja2 import Undefined
10
+ from rich.table import Table
11
+ from jinja2 import Template, Environment, meta, TemplateSyntaxError, Undefined
12
+
13
+
14
+ class PreserveUndefined(Undefined):
15
+ def __str__(self):
16
+ return "{{ " + str(self._undefined_name) + " }}"
6
17
 
7
18
 
8
19
  from edsl.exceptions.prompts import TemplateRenderError
9
- from edsl.Base import PersistenceMixin, RepresentationMixin
20
+ from edsl.Base import PersistenceMixin, RichPrintingMixin
10
21
 
11
22
  MAX_NESTING = 100
12
23
 
13
24
 
14
- class Prompt(PersistenceMixin, RepresentationMixin):
25
+ class Prompt(PersistenceMixin, RichPrintingMixin):
15
26
  """Class for creating a prompt to be used in a survey."""
16
27
 
17
28
  default_instructions: Optional[str] = "Do good things, friendly LLM!"
18
29
 
30
+ def _repr_html_(self):
31
+ """Return an HTML representation of the Prompt."""
32
+ # from edsl.utilities.utilities import data_to_html
33
+ # return data_to_html(self.to_dict())
34
+ d = self.to_dict()
35
+ data = [[k, v] for k, v in d.items()]
36
+ from tabulate import tabulate
37
+
38
+ table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
39
+ return f"<pre>{table}</pre>"
40
+
19
41
  def __len__(self):
20
42
  """Return the length of the prompt text."""
21
43
  return len(self.text)
@@ -163,12 +185,6 @@ class Prompt(PersistenceMixin, RepresentationMixin):
163
185
  :param template: The template to find the variables in.
164
186
 
165
187
  """
166
- from jinja2 import Environment, meta, Undefined
167
-
168
- class PreserveUndefined(Undefined):
169
- def __str__(self):
170
- return "{{ " + str(self._undefined_name) + " }}"
171
-
172
188
  env = Environment(undefined=PreserveUndefined)
173
189
  ast = env.parse(template)
174
190
  return list(meta.find_undeclared_variables(ast))
@@ -257,12 +273,6 @@ class Prompt(PersistenceMixin, RepresentationMixin):
257
273
  >>> p.render({"name": "John", "age": 44}, codebook=codebook)
258
274
  Prompt(text=\"""You are an agent named John. Age: 44\""")
259
275
  """
260
- from jinja2 import Environment, meta, TemplateSyntaxError, Undefined
261
-
262
- class PreserveUndefined(Undefined):
263
- def __str__(self):
264
- return "{{ " + str(self._undefined_name) + " }}"
265
-
266
276
  env = Environment(undefined=PreserveUndefined)
267
277
  try:
268
278
  previous_text = None
@@ -286,7 +296,7 @@ class Prompt(PersistenceMixin, RepresentationMixin):
286
296
  f"Template syntax error: {e}. Bad template: {text}"
287
297
  )
288
298
 
289
- def to_dict(self, add_edsl_version=False) -> dict[str, Any]:
299
+ def to_dict(self) -> dict[str, Any]:
290
300
  """Return the `Prompt` as a dictionary.
291
301
 
292
302
  Example:
@@ -313,18 +323,18 @@ class Prompt(PersistenceMixin, RepresentationMixin):
313
323
  # class_name = data["class_name"]
314
324
  return Prompt(text=data["text"])
315
325
 
316
- # def rich_print(self):
317
- # """Display an object as a table."""
318
- # table = Table(title="Prompt")
319
- # table.add_column("Attribute", style="bold")
320
- # table.add_column("Value")
321
-
322
- # to_display = self.__dict__.copy()
323
- # for attr_name, attr_value in to_display.items():
324
- # table.add_row(attr_name, repr(attr_value))
325
- # table.add_row("Component type", str(self.component_type))
326
- # table.add_row("Model", str(getattr(self, "model", "Not specified")))
327
- # return table
326
+ def rich_print(self):
327
+ """Display an object as a table."""
328
+ table = Table(title="Prompt")
329
+ table.add_column("Attribute", style="bold")
330
+ table.add_column("Value")
331
+
332
+ to_display = self.__dict__.copy()
333
+ for attr_name, attr_value in to_display.items():
334
+ table.add_row(attr_name, repr(attr_value))
335
+ table.add_row("Component type", str(self.component_type))
336
+ table.add_row("Model", str(getattr(self, "model", "Not specified")))
337
+ return table
328
338
 
329
339
  @classmethod
330
340
  def example(cls):
@@ -2,7 +2,7 @@
2
2
 
3
3
  import re
4
4
  from typing import Any, Type, Union
5
- from edsl.exceptions.questions import (
5
+ from edsl.exceptions import (
6
6
  QuestionAnswerValidationError,
7
7
  )
8
8
 
@@ -213,12 +213,7 @@ class AnswerValidatorMixin:
213
213
  - is not less than `min_value`
214
214
  - is not greater than `max_value`
215
215
  """
216
- try:
217
- value = float(answer.get("answer"))
218
- except ValueError:
219
- raise QuestionAnswerValidationError(
220
- f"Answer must real number or convertible to a real number (got {answer.get('answer')})."
221
- )
216
+ value = float(answer.get("answer"))
222
217
  if self.min_value is not None and value < self.min_value:
223
218
  raise QuestionAnswerValidationError(
224
219
  f"Value {value} is less than {self.min_value}"
@@ -284,46 +279,6 @@ class AnswerValidatorMixin:
284
279
  f"Rank answer {value}, but exactly {self.num_selections} selections required."
285
280
  )
286
281
 
287
- def _validate_answer_matrix(self, answer: dict[str, Any]) -> None:
288
- """Validate QuestionMatrix-specific answer.
289
-
290
- Check that answer["answer"]:
291
- - is a dictionary
292
- - has all required question_items as keys
293
- - has values that are valid options from question_options
294
- - has the correct number of responses (one per item)
295
- """
296
- value = answer.get("answer")
297
-
298
- # Check that answer is a dictionary
299
- if not isinstance(value, dict):
300
- raise QuestionAnswerValidationError(
301
- f"Matrix answer must be a dictionary mapping items to responses (got {value})"
302
- )
303
-
304
- # Check that all required items are present
305
- required_items = set(self.question_items)
306
- provided_items = set(value.keys())
307
-
308
- if missing_items := (required_items - provided_items):
309
- raise QuestionAnswerValidationError(
310
- f"Missing responses for items: {missing_items}"
311
- )
312
-
313
- if extra_items := (provided_items - required_items):
314
- raise QuestionAnswerValidationError(
315
- f"Unexpected responses for items: {extra_items}"
316
- )
317
-
318
- # Check that all responses are valid options
319
- valid_options = set(self.question_options)
320
- for item, response in value.items():
321
- if response not in valid_options:
322
- raise QuestionAnswerValidationError(
323
- f"Invalid response '{response}' for item '{item}'. "
324
- f"Must be one of: {valid_options}"
325
- )
326
-
327
282
 
328
283
  if __name__ == "__main__":
329
284
  pass