edsl 0.1.38__py3-none-any.whl → 0.1.38.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.
- edsl/Base.py +31 -60
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +9 -18
- edsl/agents/AgentList.py +8 -59
- edsl/agents/Invigilator.py +7 -18
- edsl/agents/InvigilatorBase.py +19 -0
- edsl/agents/PromptConstructor.py +4 -5
- edsl/config.py +0 -8
- edsl/coop/coop.py +7 -74
- edsl/data/Cache.py +2 -27
- edsl/data/CacheEntry.py +3 -8
- edsl/data/RemoteCacheSync.py +19 -0
- edsl/enums.py +0 -2
- edsl/inference_services/GoogleService.py +15 -7
- edsl/inference_services/registry.py +0 -2
- edsl/jobs/Jobs.py +548 -88
- edsl/jobs/interviews/Interview.py +11 -11
- edsl/jobs/runners/JobsRunnerAsyncio.py +35 -140
- edsl/jobs/runners/JobsRunnerStatus.py +2 -0
- edsl/jobs/tasks/TaskHistory.py +16 -15
- edsl/language_models/LanguageModel.py +84 -44
- edsl/language_models/ModelList.py +1 -47
- edsl/language_models/registry.py +4 -57
- edsl/prompts/Prompt.py +3 -8
- edsl/questions/QuestionBase.py +16 -20
- edsl/questions/QuestionExtract.py +4 -3
- 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 +9 -18
- edsl/results/Results.py +51 -145
- edsl/scenarios/FileStore.py +13 -187
- edsl/scenarios/Scenario.py +4 -61
- edsl/scenarios/ScenarioList.py +62 -237
- edsl/surveys/Survey.py +2 -16
- edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
- edsl/surveys/instructions/Instruction.py +0 -12
- 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.dev2.dist-info}/METADATA +1 -2
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.dist-info}/RECORD +45 -53
- 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.dev2.dist-info}/LICENSE +0 -0
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.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,7 +604,10 @@ class LanguageModel(
|
|
583
604
|
|
584
605
|
return input_cost + output_cost
|
585
606
|
|
586
|
-
|
607
|
+
#######################
|
608
|
+
# SERIALIZATION METHODS
|
609
|
+
#######################
|
610
|
+
def to_dict(self, add_edsl_version=True) -> dict[str, Any]:
|
587
611
|
"""Convert instance to a dictionary
|
588
612
|
|
589
613
|
>>> m = LanguageModel.example()
|
@@ -605,8 +629,18 @@ class LanguageModel(
|
|
605
629
|
from edsl.language_models.registry import get_model_class
|
606
630
|
|
607
631
|
model_class = get_model_class(data["model"])
|
632
|
+
# data["use_cache"] = True
|
608
633
|
return model_class(**data)
|
609
634
|
|
635
|
+
#######################
|
636
|
+
# DUNDER METHODS
|
637
|
+
#######################
|
638
|
+
def print(self):
|
639
|
+
from rich import print_json
|
640
|
+
import json
|
641
|
+
|
642
|
+
print_json(json.dumps(self.to_dict()))
|
643
|
+
|
610
644
|
def __repr__(self) -> str:
|
611
645
|
"""Return a string representation of the object."""
|
612
646
|
param_string = ", ".join(
|
@@ -620,21 +654,33 @@ class LanguageModel(
|
|
620
654
|
|
621
655
|
def __add__(self, other_model: Type[LanguageModel]) -> Type[LanguageModel]:
|
622
656
|
"""Combine two models into a single model (other_model takes precedence over self)."""
|
623
|
-
|
624
|
-
|
625
|
-
warnings.warn(
|
657
|
+
print(
|
626
658
|
f"""Warning: one model is replacing another. If you want to run both models, use a single `by` e.g.,
|
627
659
|
by(m1, m2, m3) not by(m1).by(m2).by(m3)."""
|
628
660
|
)
|
629
661
|
return other_model or self
|
630
662
|
|
663
|
+
def rich_print(self):
|
664
|
+
"""Display an object as a table."""
|
665
|
+
from rich.table import Table
|
666
|
+
|
667
|
+
table = Table(title="Language Model")
|
668
|
+
table.add_column("Attribute", style="bold")
|
669
|
+
table.add_column("Value")
|
670
|
+
|
671
|
+
to_display = self.__dict__.copy()
|
672
|
+
for attr_name, attr_value in to_display.items():
|
673
|
+
table.add_row(attr_name, repr(attr_value))
|
674
|
+
|
675
|
+
return table
|
676
|
+
|
631
677
|
@classmethod
|
632
678
|
def example(
|
633
679
|
cls,
|
634
680
|
test_model: bool = False,
|
635
681
|
canned_response: str = "Hello world",
|
636
682
|
throw_exception: bool = False,
|
637
|
-
)
|
683
|
+
):
|
638
684
|
"""Return a default instance of the class.
|
639
685
|
|
640
686
|
>>> from edsl.language_models import LanguageModel
|
@@ -645,17 +691,11 @@ class LanguageModel(
|
|
645
691
|
>>> q = QuestionFreeText(question_text = "What is your name?", question_name = 'example')
|
646
692
|
>>> q.by(m).run(cache = False, disable_remote_cache = True, disable_remote_inference = True).select('example').first()
|
647
693
|
'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
694
|
"""
|
653
695
|
from edsl import Model
|
654
696
|
|
655
697
|
if test_model:
|
656
|
-
m = Model(
|
657
|
-
"test", canned_response=canned_response, throw_exception=throw_exception
|
658
|
-
)
|
698
|
+
m = Model("test", canned_response=canned_response)
|
659
699
|
return m
|
660
700
|
else:
|
661
701
|
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
|
|
@@ -53,42 +48,6 @@ class ModelList(Base, UserList):
|
|
53
48
|
|
54
49
|
return dict_hash(self.to_dict(sort=True, add_edsl_version=False))
|
55
50
|
|
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
|
-
)
|
88
|
-
|
89
|
-
def to_list(self):
|
90
|
-
return self.to_scenario_list().to_list()
|
91
|
-
|
92
51
|
def to_dict(self, sort=False, add_edsl_version=True):
|
93
52
|
if sort:
|
94
53
|
model_list = sorted([model for model in self], key=lambda x: hash(x))
|
@@ -112,11 +71,6 @@ class ModelList(Base, UserList):
|
|
112
71
|
|
113
72
|
return d
|
114
73
|
|
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
|
-
|
120
74
|
@classmethod
|
121
75
|
def from_names(self, *args, **kwargs):
|
122
76
|
"""A a model list from a list of names"""
|
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/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
@@ -82,8 +82,7 @@ class QuestionBase(
|
|
82
82
|
if not hasattr(self, "_fake_data_factory"):
|
83
83
|
from polyfactory.factories.pydantic_factory import ModelFactory
|
84
84
|
|
85
|
-
class FakeData(ModelFactory[self.response_model]):
|
86
|
-
...
|
85
|
+
class FakeData(ModelFactory[self.response_model]): ...
|
87
86
|
|
88
87
|
self._fake_data_factory = FakeData
|
89
88
|
return self._fake_data_factory
|
@@ -264,9 +263,12 @@ class QuestionBase(
|
|
264
263
|
>>> m.execute_model_call("", "")
|
265
264
|
{'message': [{'text': "Yo, what's up?"}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
|
266
265
|
>>> Q.run_example(show_answer = True, model = m, disable_remote_cache = True, disable_remote_inference = True)
|
267
|
-
|
268
|
-
|
269
|
-
|
266
|
+
┏━━━━━━━━━━━━━━━━┓
|
267
|
+
┃ answer ┃
|
268
|
+
┃ .how_are_you ┃
|
269
|
+
┡━━━━━━━━━━━━━━━━┩
|
270
|
+
│ Yo, what's up? │
|
271
|
+
└────────────────┘
|
270
272
|
"""
|
271
273
|
if model is None:
|
272
274
|
from edsl import Model
|
@@ -282,7 +284,7 @@ class QuestionBase(
|
|
282
284
|
)
|
283
285
|
)
|
284
286
|
if show_answer:
|
285
|
-
|
287
|
+
results.select("answer.*").print()
|
286
288
|
else:
|
287
289
|
return results
|
288
290
|
|
@@ -360,22 +362,16 @@ class QuestionBase(
|
|
360
362
|
|
361
363
|
# region: Magic methods
|
362
364
|
def _repr_html_(self):
|
363
|
-
|
365
|
+
from edsl.utilities.utilities import data_to_html
|
364
366
|
|
365
|
-
data = self.to_dict(
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
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.")
|
367
|
+
data = self.to_dict()
|
368
|
+
try:
|
369
|
+
_ = data.pop("edsl_version")
|
370
|
+
_ = data.pop("edsl_class_name")
|
371
|
+
except KeyError:
|
372
|
+
print("Serialized question lacks edsl version, but is should have it.")
|
377
373
|
|
378
|
-
|
374
|
+
return data_to_html(data)
|
379
375
|
|
380
376
|
def __getitem__(self, key: str) -> Any:
|
381
377
|
"""Get an attribute of the question so it can be treated like a dictionary.
|
@@ -1,7 +1,4 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
import json
|
3
|
-
import re
|
4
|
-
|
5
2
|
from typing import Any, Optional, Dict
|
6
3
|
from edsl.questions.QuestionBase import QuestionBase
|
7
4
|
from edsl.questions.descriptors import AnswerTemplateDescriptor
|
@@ -14,6 +11,9 @@ from edsl.questions.decorators import inject_exception
|
|
14
11
|
from typing import Dict, Any
|
15
12
|
from pydantic import create_model, Field
|
16
13
|
|
14
|
+
import json
|
15
|
+
import re
|
16
|
+
|
17
17
|
|
18
18
|
def extract_json(text, expected_keys, verbose=False):
|
19
19
|
# Escape special regex characters in keys
|
@@ -112,6 +112,7 @@ class QuestionExtract(QuestionBase):
|
|
112
112
|
|
113
113
|
:param question_name: The name of the question.
|
114
114
|
:param question_text: The text of the question.
|
115
|
+
:param question_options: The options the respondent should select from.
|
115
116
|
:param answer_template: The template for the answer.
|
116
117
|
"""
|
117
118
|
self.question_name = question_name
|
@@ -90,22 +90,6 @@ class Question(metaclass=Meta):
|
|
90
90
|
coop = Coop()
|
91
91
|
return coop.patch(uuid, url, description, value, visibility)
|
92
92
|
|
93
|
-
@classmethod
|
94
|
-
def list_question_types(cls):
|
95
|
-
"""Return a list of available question types.
|
96
|
-
|
97
|
-
>>> from edsl import Question
|
98
|
-
>>> Question.list_question_types()
|
99
|
-
['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
|
100
|
-
"""
|
101
|
-
return [
|
102
|
-
q
|
103
|
-
for q in sorted(
|
104
|
-
list(RegisterQuestionsMeta.question_types_to_classes().keys())
|
105
|
-
)
|
106
|
-
if q not in ["budget"]
|
107
|
-
]
|
108
|
-
|
109
93
|
@classmethod
|
110
94
|
def available(cls, show_class_names: bool = False) -> Union[list, dict]:
|
111
95
|
"""Return a list of available question types.
|
@@ -114,32 +98,18 @@ class Question(metaclass=Meta):
|
|
114
98
|
|
115
99
|
Example usage:
|
116
100
|
|
101
|
+
>>> from edsl import Question
|
102
|
+
>>> Question.available()
|
103
|
+
['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
|
117
104
|
"""
|
118
|
-
from edsl.results.Dataset import Dataset
|
119
|
-
|
120
105
|
exclude = ["budget"]
|
121
106
|
if show_class_names:
|
122
107
|
return RegisterQuestionsMeta.question_types_to_classes()
|
123
108
|
else:
|
124
|
-
question_list =
|
125
|
-
|
126
|
-
for q in sorted(
|
127
|
-
set(RegisterQuestionsMeta.question_types_to_classes().keys())
|
128
|
-
)
|
129
|
-
if q not in exclude
|
130
|
-
]
|
131
|
-
d = RegisterQuestionsMeta.question_types_to_classes()
|
132
|
-
question_classes = [d[q] for q in question_list]
|
133
|
-
example_questions = [repr(q.example()) for q in question_classes]
|
134
|
-
|
135
|
-
return Dataset(
|
136
|
-
[
|
137
|
-
{"question_type": [q for q in question_list]},
|
138
|
-
{"question_class": [q.__name__ for q in question_classes]},
|
139
|
-
{"example_question": example_questions},
|
140
|
-
],
|
141
|
-
print_parameters={"containerHeight": "auto"},
|
109
|
+
question_list = sorted(
|
110
|
+
set(RegisterQuestionsMeta.question_types_to_classes().keys())
|
142
111
|
)
|
112
|
+
return [q for q in question_list if q not in exclude]
|
143
113
|
|
144
114
|
|
145
115
|
def get_question_class(question_type):
|