edsl 0.1.38__py3-none-any.whl → 0.1.38.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.
- edsl/Base.py +34 -63
- edsl/BaseDiff.py +7 -7
- edsl/__init__.py +1 -2
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +11 -23
- edsl/agents/AgentList.py +23 -86
- edsl/agents/Invigilator.py +7 -18
- edsl/agents/InvigilatorBase.py +19 -0
- edsl/agents/PromptConstructor.py +4 -5
- edsl/auto/SurveyCreatorPipeline.py +1 -1
- edsl/auto/utilities.py +1 -1
- edsl/base/Base.py +13 -3
- edsl/config.py +0 -8
- edsl/conjure/AgentConstructionMixin.py +160 -0
- edsl/conjure/Conjure.py +62 -0
- edsl/conjure/InputData.py +659 -0
- edsl/conjure/InputDataCSV.py +48 -0
- edsl/conjure/InputDataMixinQuestionStats.py +182 -0
- edsl/conjure/InputDataPyRead.py +91 -0
- edsl/conjure/InputDataSPSS.py +8 -0
- edsl/conjure/InputDataStata.py +8 -0
- edsl/conjure/QuestionOptionMixin.py +76 -0
- edsl/conjure/QuestionTypeMixin.py +23 -0
- edsl/conjure/RawQuestion.py +65 -0
- edsl/conjure/SurveyResponses.py +7 -0
- edsl/conjure/__init__.py +9 -0
- edsl/conjure/examples/placeholder.txt +0 -0
- edsl/{utilities → conjure}/naming_utilities.py +1 -1
- edsl/conjure/utilities.py +201 -0
- edsl/coop/coop.py +7 -77
- edsl/data/Cache.py +17 -45
- edsl/data/CacheEntry.py +3 -8
- edsl/data/RemoteCacheSync.py +19 -0
- edsl/enums.py +0 -2
- edsl/exceptions/agents.py +0 -4
- edsl/inference_services/GoogleService.py +15 -7
- edsl/inference_services/registry.py +0 -2
- edsl/jobs/Jobs.py +559 -110
- edsl/jobs/buckets/TokenBucket.py +0 -3
- edsl/jobs/interviews/Interview.py +7 -7
- edsl/jobs/runners/JobsRunnerAsyncio.py +28 -156
- edsl/jobs/runners/JobsRunnerStatus.py +196 -194
- edsl/jobs/tasks/TaskHistory.py +19 -27
- edsl/language_models/LanguageModel.py +90 -52
- edsl/language_models/ModelList.py +14 -67
- edsl/language_models/registry.py +4 -57
- edsl/notebooks/Notebook.py +8 -7
- edsl/prompts/Prompt.py +3 -8
- edsl/questions/QuestionBase.py +30 -38
- edsl/questions/QuestionBaseGenMixin.py +1 -1
- edsl/questions/QuestionBasePromptsMixin.py +17 -0
- edsl/questions/QuestionExtract.py +4 -3
- edsl/questions/QuestionFunctional.py +3 -10
- edsl/questions/derived/QuestionTopK.py +0 -2
- edsl/questions/question_registry.py +6 -36
- edsl/results/Dataset.py +15 -146
- edsl/results/DatasetExportMixin.py +217 -231
- edsl/results/DatasetTree.py +4 -134
- edsl/results/Result.py +16 -31
- edsl/results/Results.py +65 -159
- edsl/scenarios/FileStore.py +13 -187
- edsl/scenarios/Scenario.py +18 -73
- edsl/scenarios/ScenarioList.py +76 -251
- edsl/surveys/MemoryPlan.py +1 -1
- edsl/surveys/Rule.py +5 -1
- edsl/surveys/RuleCollection.py +1 -1
- edsl/surveys/Survey.py +19 -25
- edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
- edsl/surveys/instructions/ChangeInstruction.py +7 -9
- edsl/surveys/instructions/Instruction.py +7 -21
- edsl/templates/error_reporting/interview_details.html +3 -3
- edsl/templates/error_reporting/interviews.html +9 -18
- edsl/utilities/utilities.py +0 -15
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/METADATA +1 -2
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/RECORD +77 -71
- edsl/exceptions/cache.py +0 -5
- edsl/inference_services/PerplexityService.py +0 -163
- edsl/jobs/JobsChecks.py +0 -147
- edsl/jobs/JobsPrompts.py +0 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +0 -239
- edsl/results/CSSParameterizer.py +0 -108
- edsl/results/TableDisplay.py +0 -198
- edsl/results/table_display.css +0 -78
- edsl/scenarios/ScenarioJoin.py +0 -127
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/LICENSE +0 -0
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/WHEEL +0 -0
@@ -41,20 +41,18 @@ from edsl.data_transfer_models import (
|
|
41
41
|
AgentResponseDict,
|
42
42
|
)
|
43
43
|
|
44
|
-
if TYPE_CHECKING:
|
45
|
-
from edsl.data.Cache import Cache
|
46
|
-
from edsl.scenarios.FileStore import FileStore
|
47
|
-
from edsl.questions.QuestionBase import QuestionBase
|
48
44
|
|
49
45
|
from edsl.config import CONFIG
|
50
46
|
from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
|
51
|
-
from edsl.utilities.decorators import remove_edsl_version
|
52
|
-
|
53
|
-
from edsl.
|
47
|
+
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
48
|
+
from edsl.language_models.repair import repair
|
49
|
+
from edsl.enums import InferenceServiceType
|
50
|
+
from edsl.Base import RichPrintingMixin, PersistenceMixin
|
54
51
|
from edsl.language_models.RegisterLanguageModelsMeta import RegisterLanguageModelsMeta
|
55
|
-
from edsl.language_models.KeyLookup import KeyLookup
|
56
52
|
from edsl.exceptions.language_models import LanguageModelBadResponseError
|
57
53
|
|
54
|
+
from edsl.language_models.KeyLookup import KeyLookup
|
55
|
+
|
58
56
|
TIMEOUT = float(CONFIG.get("EDSL_API_TIMEOUT"))
|
59
57
|
|
60
58
|
|
@@ -118,11 +116,29 @@ def handle_key_error(func):
|
|
118
116
|
|
119
117
|
|
120
118
|
class LanguageModel(
|
121
|
-
PersistenceMixin,
|
122
|
-
ABC,
|
123
|
-
metaclass=RegisterLanguageModelsMeta,
|
119
|
+
RichPrintingMixin, PersistenceMixin, ABC, metaclass=RegisterLanguageModelsMeta
|
124
120
|
):
|
125
|
-
"""ABC for
|
121
|
+
"""ABC for LLM subclasses.
|
122
|
+
|
123
|
+
TODO:
|
124
|
+
|
125
|
+
1) Need better, more descriptive names for functions
|
126
|
+
|
127
|
+
get_model_response_no_cache (currently called async_execute_model_call)
|
128
|
+
|
129
|
+
get_model_response (currently called async_get_raw_response; uses cache & adds tracking info)
|
130
|
+
Calls:
|
131
|
+
- async_execute_model_call
|
132
|
+
- _updated_model_response_with_tracking
|
133
|
+
|
134
|
+
get_answer (currently called async_get_response)
|
135
|
+
This parses out the answer block and does some error-handling.
|
136
|
+
Calls:
|
137
|
+
- async_get_raw_response
|
138
|
+
- parse_response
|
139
|
+
|
140
|
+
|
141
|
+
"""
|
126
142
|
|
127
143
|
_model_ = None
|
128
144
|
key_sequence = (
|
@@ -180,7 +196,7 @@ class LanguageModel(
|
|
180
196
|
system_prompt = "You are a helpful agent pretending to be a human."
|
181
197
|
return self.execute_model_call(user_prompt, system_prompt)
|
182
198
|
|
183
|
-
def set_key_lookup(self, key_lookup: KeyLookup)
|
199
|
+
def set_key_lookup(self, key_lookup: KeyLookup):
|
184
200
|
del self._api_token
|
185
201
|
self.key_lookup = key_lookup
|
186
202
|
|
@@ -195,14 +211,10 @@ class LanguageModel(
|
|
195
211
|
def __getitem__(self, key):
|
196
212
|
return getattr(self, key)
|
197
213
|
|
198
|
-
def _repr_html_(self)
|
199
|
-
|
200
|
-
d.update(self.parameters)
|
201
|
-
data = [[k, v] for k, v in d.items()]
|
202
|
-
from tabulate import tabulate
|
214
|
+
def _repr_html_(self):
|
215
|
+
from edsl.utilities.utilities import data_to_html
|
203
216
|
|
204
|
-
|
205
|
-
return f"<pre>{table}</pre>"
|
217
|
+
return data_to_html(self.to_dict())
|
206
218
|
|
207
219
|
def hello(self, verbose=False):
|
208
220
|
"""Runs a simple test to check if the model is working."""
|
@@ -223,6 +235,7 @@ class LanguageModel(
|
|
223
235
|
This method is used to check if the model has a valid API key.
|
224
236
|
"""
|
225
237
|
from edsl.enums import service_to_api_keyname
|
238
|
+
import os
|
226
239
|
|
227
240
|
if self._model_ == "test":
|
228
241
|
return True
|
@@ -235,9 +248,9 @@ class LanguageModel(
|
|
235
248
|
"""Allow the model to be used as a key in a dictionary."""
|
236
249
|
from edsl.utilities.utilities import dict_hash
|
237
250
|
|
238
|
-
return dict_hash(self.to_dict(
|
251
|
+
return dict_hash(self.to_dict())
|
239
252
|
|
240
|
-
def __eq__(self, other)
|
253
|
+
def __eq__(self, other):
|
241
254
|
"""Check is two models are the same.
|
242
255
|
|
243
256
|
>>> m1 = LanguageModel.example()
|
@@ -265,11 +278,15 @@ class LanguageModel(
|
|
265
278
|
@property
|
266
279
|
def RPM(self):
|
267
280
|
"""Model's requests-per-minute limit."""
|
281
|
+
# self._set_rate_limits()
|
282
|
+
# return self._safety_factor * self.__rate_limits["rpm"]
|
268
283
|
return self._rpm
|
269
284
|
|
270
285
|
@property
|
271
286
|
def TPM(self):
|
272
287
|
"""Model's tokens-per-minute limit."""
|
288
|
+
# self._set_rate_limits()
|
289
|
+
# return self._safety_factor * self.__rate_limits["tpm"]
|
273
290
|
return self._tpm
|
274
291
|
|
275
292
|
@property
|
@@ -297,6 +314,8 @@ class LanguageModel(
|
|
297
314
|
>>> LanguageModel._overide_default_parameters(passed_parameter_dict={"temperature": 0.5}, default_parameter_dict={"temperature":0.9, "max_tokens": 1000})
|
298
315
|
{'temperature': 0.5, 'max_tokens': 1000}
|
299
316
|
"""
|
317
|
+
# parameters = dict({})
|
318
|
+
|
300
319
|
# this is the case when data is loaded from a dict after serialization
|
301
320
|
if "parameters" in passed_parameter_dict:
|
302
321
|
passed_parameter_dict = passed_parameter_dict["parameters"]
|
@@ -410,10 +429,9 @@ class LanguageModel(
|
|
410
429
|
self,
|
411
430
|
user_prompt: str,
|
412
431
|
system_prompt: str,
|
413
|
-
cache: Cache,
|
432
|
+
cache: "Cache",
|
414
433
|
iteration: int = 0,
|
415
|
-
files_list
|
416
|
-
invigilator=None,
|
434
|
+
files_list=None,
|
417
435
|
) -> ModelResponse:
|
418
436
|
"""Handle caching of responses.
|
419
437
|
|
@@ -437,6 +455,7 @@ class LanguageModel(
|
|
437
455
|
|
438
456
|
if files_list:
|
439
457
|
files_hash = "+".join([str(hash(file)) for file in files_list])
|
458
|
+
# print(f"Files hash: {files_hash}")
|
440
459
|
user_prompt_with_hashes = user_prompt + f" {files_hash}"
|
441
460
|
else:
|
442
461
|
user_prompt_with_hashes = user_prompt
|
@@ -462,7 +481,9 @@ class LanguageModel(
|
|
462
481
|
"user_prompt": user_prompt,
|
463
482
|
"system_prompt": system_prompt,
|
464
483
|
"files_list": files_list,
|
484
|
+
# **({"encoded_image": encoded_image} if encoded_image else {}),
|
465
485
|
}
|
486
|
+
# response = await f(**params)
|
466
487
|
response = await asyncio.wait_for(f(**params), timeout=TIMEOUT)
|
467
488
|
new_cache_key = cache.store(
|
468
489
|
**cache_call_params, response=response
|
@@ -483,9 +504,11 @@ class LanguageModel(
|
|
483
504
|
_async_get_intended_model_call_outcome
|
484
505
|
)
|
485
506
|
|
507
|
+
# get_raw_response = sync_wrapper(async_get_raw_response)
|
508
|
+
|
486
509
|
def simple_ask(
|
487
510
|
self,
|
488
|
-
question: QuestionBase,
|
511
|
+
question: "QuestionBase",
|
489
512
|
system_prompt="You are a helpful agent pretending to be a human.",
|
490
513
|
top_logprobs=2,
|
491
514
|
):
|
@@ -500,10 +523,9 @@ class LanguageModel(
|
|
500
523
|
self,
|
501
524
|
user_prompt: str,
|
502
525
|
system_prompt: str,
|
503
|
-
cache: Cache,
|
526
|
+
cache: "Cache",
|
504
527
|
iteration: int = 1,
|
505
|
-
files_list: Optional[List[
|
506
|
-
**kwargs,
|
528
|
+
files_list: Optional[List["File"]] = None,
|
507
529
|
) -> dict:
|
508
530
|
"""Get response, parse, and return as string.
|
509
531
|
|
@@ -521,9 +543,6 @@ class LanguageModel(
|
|
521
543
|
"cache": cache,
|
522
544
|
"files_list": files_list,
|
523
545
|
}
|
524
|
-
if "invigilator" in kwargs:
|
525
|
-
params.update({"invigilator": kwargs["invigilator"]})
|
526
|
-
|
527
546
|
model_inputs = ModelInputs(user_prompt=user_prompt, system_prompt=system_prompt)
|
528
547
|
model_outputs = await self._async_get_intended_model_call_outcome(**params)
|
529
548
|
edsl_dict = self.parse_response(model_outputs.response)
|
@@ -534,6 +553,8 @@ class LanguageModel(
|
|
534
553
|
)
|
535
554
|
return agent_response_dict
|
536
555
|
|
556
|
+
# return await self._async_prepare_response(model_call_outcome, cache=cache)
|
557
|
+
|
537
558
|
get_response = sync_wrapper(async_get_response)
|
538
559
|
|
539
560
|
def cost(self, raw_response: dict[str, Any]) -> Union[float, str]:
|
@@ -583,20 +604,21 @@ class LanguageModel(
|
|
583
604
|
|
584
605
|
return input_cost + output_cost
|
585
606
|
|
586
|
-
|
587
|
-
|
607
|
+
#######################
|
608
|
+
# SERIALIZATION METHODS
|
609
|
+
#######################
|
610
|
+
def _to_dict(self) -> dict[str, Any]:
|
611
|
+
return {"model": self.model, "parameters": self.parameters}
|
612
|
+
|
613
|
+
@add_edsl_version
|
614
|
+
def to_dict(self) -> dict[str, Any]:
|
615
|
+
"""Convert instance to a dictionary.
|
588
616
|
|
589
617
|
>>> m = LanguageModel.example()
|
590
618
|
>>> m.to_dict()
|
591
619
|
{'model': '...', 'parameters': {'temperature': ..., 'max_tokens': ..., 'top_p': ..., 'frequency_penalty': ..., 'presence_penalty': ..., 'logprobs': False, 'top_logprobs': ...}, 'edsl_version': '...', 'edsl_class_name': 'LanguageModel'}
|
592
620
|
"""
|
593
|
-
|
594
|
-
if add_edsl_version:
|
595
|
-
from edsl import __version__
|
596
|
-
|
597
|
-
d["edsl_version"] = __version__
|
598
|
-
d["edsl_class_name"] = self.__class__.__name__
|
599
|
-
return d
|
621
|
+
return self._to_dict()
|
600
622
|
|
601
623
|
@classmethod
|
602
624
|
@remove_edsl_version
|
@@ -605,8 +627,18 @@ class LanguageModel(
|
|
605
627
|
from edsl.language_models.registry import get_model_class
|
606
628
|
|
607
629
|
model_class = get_model_class(data["model"])
|
630
|
+
# data["use_cache"] = True
|
608
631
|
return model_class(**data)
|
609
632
|
|
633
|
+
#######################
|
634
|
+
# DUNDER METHODS
|
635
|
+
#######################
|
636
|
+
def print(self):
|
637
|
+
from rich import print_json
|
638
|
+
import json
|
639
|
+
|
640
|
+
print_json(json.dumps(self.to_dict()))
|
641
|
+
|
610
642
|
def __repr__(self) -> str:
|
611
643
|
"""Return a string representation of the object."""
|
612
644
|
param_string = ", ".join(
|
@@ -620,21 +652,33 @@ class LanguageModel(
|
|
620
652
|
|
621
653
|
def __add__(self, other_model: Type[LanguageModel]) -> Type[LanguageModel]:
|
622
654
|
"""Combine two models into a single model (other_model takes precedence over self)."""
|
623
|
-
|
624
|
-
|
625
|
-
warnings.warn(
|
655
|
+
print(
|
626
656
|
f"""Warning: one model is replacing another. If you want to run both models, use a single `by` e.g.,
|
627
657
|
by(m1, m2, m3) not by(m1).by(m2).by(m3)."""
|
628
658
|
)
|
629
659
|
return other_model or self
|
630
660
|
|
661
|
+
def rich_print(self):
|
662
|
+
"""Display an object as a table."""
|
663
|
+
from rich.table import Table
|
664
|
+
|
665
|
+
table = Table(title="Language Model")
|
666
|
+
table.add_column("Attribute", style="bold")
|
667
|
+
table.add_column("Value")
|
668
|
+
|
669
|
+
to_display = self.__dict__.copy()
|
670
|
+
for attr_name, attr_value in to_display.items():
|
671
|
+
table.add_row(attr_name, repr(attr_value))
|
672
|
+
|
673
|
+
return table
|
674
|
+
|
631
675
|
@classmethod
|
632
676
|
def example(
|
633
677
|
cls,
|
634
678
|
test_model: bool = False,
|
635
679
|
canned_response: str = "Hello world",
|
636
680
|
throw_exception: bool = False,
|
637
|
-
)
|
681
|
+
):
|
638
682
|
"""Return a default instance of the class.
|
639
683
|
|
640
684
|
>>> from edsl.language_models import LanguageModel
|
@@ -645,17 +689,11 @@ class LanguageModel(
|
|
645
689
|
>>> q = QuestionFreeText(question_text = "What is your name?", question_name = 'example')
|
646
690
|
>>> q.by(m).run(cache = False, disable_remote_cache = True, disable_remote_inference = True).select('example').first()
|
647
691
|
'WOWZA!'
|
648
|
-
>>> m = LanguageModel.example(test_model = True, canned_response = "WOWZA!", throw_exception = True)
|
649
|
-
>>> r = q.by(m).run(cache = False, disable_remote_cache = True, disable_remote_inference = True, print_exceptions = True)
|
650
|
-
Exception report saved to ...
|
651
|
-
Also see: ...
|
652
692
|
"""
|
653
693
|
from edsl import Model
|
654
694
|
|
655
695
|
if test_model:
|
656
|
-
m = Model(
|
657
|
-
"test", canned_response=canned_response, throw_exception=throw_exception
|
658
|
-
)
|
696
|
+
m = Model("test", canned_response=canned_response)
|
659
697
|
return m
|
660
698
|
else:
|
661
699
|
return Model(skip_api_key_check=True)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import Optional
|
2
2
|
from collections import UserList
|
3
3
|
from edsl import Model
|
4
4
|
|
@@ -10,8 +10,6 @@ from edsl.utilities.utilities import dict_hash
|
|
10
10
|
|
11
11
|
|
12
12
|
class ModelList(Base, UserList):
|
13
|
-
__documentation__ = """https://docs.expectedparrot.com/en/latest/language_models.html#module-edsl.language_models.ModelList"""
|
14
|
-
|
15
13
|
def __init__(self, data: Optional[list] = None):
|
16
14
|
"""Initialize the ScenarioList class.
|
17
15
|
|
@@ -39,9 +37,6 @@ class ModelList(Base, UserList):
|
|
39
37
|
def __repr__(self):
|
40
38
|
return f"ModelList({super().__repr__()})"
|
41
39
|
|
42
|
-
def _summary(self):
|
43
|
-
return {"EDSL Class": "ModelList", "Number of Models": len(self)}
|
44
|
-
|
45
40
|
def __hash__(self):
|
46
41
|
"""Return a hash of the ModelList. This is used for comparison of ModelLists.
|
47
42
|
|
@@ -51,71 +46,14 @@ class ModelList(Base, UserList):
|
|
51
46
|
"""
|
52
47
|
from edsl.utilities.utilities import dict_hash
|
53
48
|
|
54
|
-
return dict_hash(self.
|
55
|
-
|
56
|
-
def to_scenario_list(self):
|
57
|
-
from edsl import ScenarioList, Scenario
|
58
|
-
|
59
|
-
sl = ScenarioList()
|
60
|
-
for model in self:
|
61
|
-
d = {"model": model.model}
|
62
|
-
d.update(model.parameters)
|
63
|
-
sl.append(Scenario(d))
|
64
|
-
return sl
|
65
|
-
|
66
|
-
def tree(self, node_list: Optional[List[str]] = None):
|
67
|
-
return self.to_scenario_list().tree(node_list)
|
68
|
-
|
69
|
-
def table(
|
70
|
-
self,
|
71
|
-
*fields,
|
72
|
-
tablefmt: Optional[str] = None,
|
73
|
-
pretty_labels: Optional[dict] = None,
|
74
|
-
):
|
75
|
-
"""
|
76
|
-
>>> ModelList.example().table("model")
|
77
|
-
model
|
78
|
-
-------
|
79
|
-
gpt-4o
|
80
|
-
gpt-4o
|
81
|
-
gpt-4o
|
82
|
-
"""
|
83
|
-
return (
|
84
|
-
self.to_scenario_list()
|
85
|
-
.to_dataset()
|
86
|
-
.table(*fields, tablefmt=tablefmt, pretty_labels=pretty_labels)
|
87
|
-
)
|
49
|
+
return dict_hash(self._to_dict(sort=True))
|
88
50
|
|
89
|
-
def
|
90
|
-
return self.to_scenario_list().to_list()
|
91
|
-
|
92
|
-
def to_dict(self, sort=False, add_edsl_version=True):
|
51
|
+
def _to_dict(self, sort=False):
|
93
52
|
if sort:
|
94
53
|
model_list = sorted([model for model in self], key=lambda x: hash(x))
|
95
|
-
|
96
|
-
"models": [
|
97
|
-
model.to_dict(add_edsl_version=add_edsl_version)
|
98
|
-
for model in model_list
|
99
|
-
]
|
100
|
-
}
|
54
|
+
return {"models": [model._to_dict() for model in model_list]}
|
101
55
|
else:
|
102
|
-
|
103
|
-
"models": [
|
104
|
-
model.to_dict(add_edsl_version=add_edsl_version) for model in self
|
105
|
-
]
|
106
|
-
}
|
107
|
-
if add_edsl_version:
|
108
|
-
from edsl import __version__
|
109
|
-
|
110
|
-
d["edsl_version"] = __version__
|
111
|
-
d["edsl_class_name"] = "ModelList"
|
112
|
-
|
113
|
-
return d
|
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
|
56
|
+
return {"models": [model._to_dict() for model in self]}
|
119
57
|
|
120
58
|
@classmethod
|
121
59
|
def from_names(self, *args, **kwargs):
|
@@ -124,6 +62,15 @@ class ModelList(Base, UserList):
|
|
124
62
|
args = args[0]
|
125
63
|
return ModelList([Model(model_name, **kwargs) for model_name in args])
|
126
64
|
|
65
|
+
@add_edsl_version
|
66
|
+
def to_dict(self):
|
67
|
+
"""
|
68
|
+
Convert the ModelList to a dictionary.
|
69
|
+
>>> ModelList.example().to_dict()
|
70
|
+
{'models': [...], 'edsl_version': '...', 'edsl_class_name': 'ModelList'}
|
71
|
+
"""
|
72
|
+
return self._to_dict()
|
73
|
+
|
127
74
|
@classmethod
|
128
75
|
@remove_edsl_version
|
129
76
|
def from_dict(cls, data):
|
edsl/language_models/registry.py
CHANGED
@@ -7,49 +7,6 @@ from edsl.config import CONFIG
|
|
7
7
|
# else:
|
8
8
|
# default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
|
9
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
10
|
|
54
11
|
def get_model_class(model_name, registry=None):
|
55
12
|
from edsl.inference_services.registry import default
|
@@ -125,27 +82,17 @@ class Model(metaclass=Meta):
|
|
125
82
|
|
126
83
|
if search_term is None:
|
127
84
|
if name_only:
|
128
|
-
return
|
129
|
-
[m[0] for m in full_list],
|
130
|
-
columns=["Model Name", "Service Name", "Code"],
|
131
|
-
)
|
85
|
+
return [m[0] for m in full_list]
|
132
86
|
else:
|
133
|
-
return
|
134
|
-
full_list, columns=["Model Name", "Service Name", "Code"]
|
135
|
-
)
|
87
|
+
return full_list
|
136
88
|
else:
|
137
89
|
filtered_results = [
|
138
90
|
m for m in full_list if search_term in m[0] or search_term in m[1]
|
139
91
|
]
|
140
92
|
if name_only:
|
141
|
-
return
|
142
|
-
[m[0] for m in filtered_results],
|
143
|
-
columns=["Model Name", "Service Name", "Code"],
|
144
|
-
)
|
93
|
+
return [m[0] for m in filtered_results]
|
145
94
|
else:
|
146
|
-
return
|
147
|
-
filtered_results, columns=["Model Name", "Service Name", "Code"]
|
148
|
-
)
|
95
|
+
return filtered_results
|
149
96
|
|
150
97
|
@classmethod
|
151
98
|
def check_models(cls, verbose=False):
|
edsl/notebooks/Notebook.py
CHANGED
@@ -102,17 +102,18 @@ class Notebook(Base):
|
|
102
102
|
|
103
103
|
return dict_hash(self.data["cells"])
|
104
104
|
|
105
|
-
def
|
105
|
+
def _to_dict(self) -> dict:
|
106
106
|
"""
|
107
107
|
Serialize to a dictionary.
|
108
108
|
"""
|
109
|
-
|
110
|
-
if add_edsl_version:
|
111
|
-
from edsl import __version__
|
109
|
+
return {"name": self.name, "data": self.data}
|
112
110
|
|
113
|
-
|
114
|
-
|
115
|
-
|
111
|
+
@add_edsl_version
|
112
|
+
def to_dict(self) -> dict:
|
113
|
+
"""
|
114
|
+
Convert a Notebook to a dictionary.
|
115
|
+
"""
|
116
|
+
return self._to_dict()
|
116
117
|
|
117
118
|
@classmethod
|
118
119
|
@remove_edsl_version
|
edsl/prompts/Prompt.py
CHANGED
@@ -29,14 +29,9 @@ class Prompt(PersistenceMixin, RichPrintingMixin):
|
|
29
29
|
|
30
30
|
def _repr_html_(self):
|
31
31
|
"""Return an HTML representation of the Prompt."""
|
32
|
-
|
33
|
-
|
34
|
-
|
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>"
|
32
|
+
from edsl.utilities.utilities import data_to_html
|
33
|
+
|
34
|
+
return data_to_html(self.to_dict())
|
40
35
|
|
41
36
|
def __len__(self):
|
42
37
|
"""Return the length of the prompt text."""
|
edsl/questions/QuestionBase.py
CHANGED
@@ -135,7 +135,7 @@ class QuestionBase(
|
|
135
135
|
"""
|
136
136
|
from edsl.utilities.utilities import dict_hash
|
137
137
|
|
138
|
-
return dict_hash(self.
|
138
|
+
return dict_hash(self._to_dict())
|
139
139
|
|
140
140
|
@property
|
141
141
|
def data(self) -> dict:
|
@@ -147,15 +147,13 @@ class QuestionBase(
|
|
147
147
|
"""
|
148
148
|
exclude_list = [
|
149
149
|
"question_type",
|
150
|
-
|
150
|
+
"_include_comment",
|
151
151
|
"_fake_data_factory",
|
152
|
-
|
152
|
+
"_use_code",
|
153
153
|
"_model_instructions",
|
154
154
|
]
|
155
155
|
only_if_not_na_list = ["_answering_instructions", "_question_presentation"]
|
156
156
|
|
157
|
-
only_if_not_default_list = {"_include_comment": True, "_use_code": False}
|
158
|
-
|
159
157
|
def ok(key, value):
|
160
158
|
if not key.startswith("_"):
|
161
159
|
return False
|
@@ -163,12 +161,6 @@ class QuestionBase(
|
|
163
161
|
return False
|
164
162
|
if key in only_if_not_na_list and value is None:
|
165
163
|
return False
|
166
|
-
if (
|
167
|
-
key in only_if_not_default_list
|
168
|
-
and value == only_if_not_default_list[key]
|
169
|
-
):
|
170
|
-
return False
|
171
|
-
|
172
164
|
return True
|
173
165
|
|
174
166
|
candidate_data = {
|
@@ -183,22 +175,25 @@ class QuestionBase(
|
|
183
175
|
|
184
176
|
return candidate_data
|
185
177
|
|
186
|
-
def
|
178
|
+
def _to_dict(self):
|
187
179
|
"""Convert the question to a dictionary that includes the question type (used in deserialization).
|
188
180
|
|
189
|
-
>>> from edsl import QuestionFreeText as Q; Q.example().
|
181
|
+
>>> from edsl import QuestionFreeText as Q; Q.example()._to_dict()
|
190
182
|
{'question_name': 'how_are_you', 'question_text': 'How are you?', 'question_type': 'free_text'}
|
191
183
|
"""
|
192
184
|
candidate_data = self.data.copy()
|
193
185
|
candidate_data["question_type"] = self.question_type
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
d["edsl_version"] = __version__
|
199
|
-
d["edsl_class_name"] = "QuestionBase"
|
186
|
+
return {
|
187
|
+
key: value for key, value in candidate_data.items() if value is not None
|
188
|
+
}
|
200
189
|
|
201
|
-
|
190
|
+
@add_edsl_version
|
191
|
+
def to_dict(self) -> dict[str, Any]:
|
192
|
+
"""Convert the question to a dictionary that includes the question type (used in deserialization).
|
193
|
+
>>> from edsl import QuestionFreeText as Q; Q.example().to_dict()
|
194
|
+
{'question_name': 'how_are_you', 'question_text': 'How are you?', 'question_type': 'free_text', 'edsl_version': '...'}
|
195
|
+
"""
|
196
|
+
return self._to_dict()
|
202
197
|
|
203
198
|
@classmethod
|
204
199
|
@remove_edsl_version
|
@@ -264,9 +259,12 @@ class QuestionBase(
|
|
264
259
|
>>> m.execute_model_call("", "")
|
265
260
|
{'message': [{'text': "Yo, what's up?"}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
|
266
261
|
>>> Q.run_example(show_answer = True, model = m, disable_remote_cache = True, disable_remote_inference = True)
|
267
|
-
|
268
|
-
|
269
|
-
|
262
|
+
┏━━━━━━━━━━━━━━━━┓
|
263
|
+
┃ answer ┃
|
264
|
+
┃ .how_are_you ┃
|
265
|
+
┡━━━━━━━━━━━━━━━━┩
|
266
|
+
│ Yo, what's up? │
|
267
|
+
└────────────────┘
|
270
268
|
"""
|
271
269
|
if model is None:
|
272
270
|
from edsl import Model
|
@@ -282,7 +280,7 @@ class QuestionBase(
|
|
282
280
|
)
|
283
281
|
)
|
284
282
|
if show_answer:
|
285
|
-
|
283
|
+
results.select("answer.*").print()
|
286
284
|
else:
|
287
285
|
return results
|
288
286
|
|
@@ -360,22 +358,16 @@ class QuestionBase(
|
|
360
358
|
|
361
359
|
# region: Magic methods
|
362
360
|
def _repr_html_(self):
|
363
|
-
|
364
|
-
|
365
|
-
data = self.to_dict(add_edsl_version=False)
|
366
|
-
# keys = list(data.keys())
|
367
|
-
# values = list(data.values())
|
368
|
-
from tabulate import tabulate
|
361
|
+
from edsl.utilities.utilities import data_to_html
|
369
362
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
# print("Serialized question lacks edsl version, but is should have it.")
|
363
|
+
data = self.to_dict()
|
364
|
+
try:
|
365
|
+
_ = data.pop("edsl_version")
|
366
|
+
_ = data.pop("edsl_class_name")
|
367
|
+
except KeyError:
|
368
|
+
print("Serialized question lacks edsl version, but is should have it.")
|
377
369
|
|
378
|
-
|
370
|
+
return data_to_html(data)
|
379
371
|
|
380
372
|
def __getitem__(self, key: str) -> Any:
|
381
373
|
"""Get an attribute of the question so it can be treated like a dictionary.
|