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