edsl 0.1.52__py3-none-any.whl → 0.1.54__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/__version__.py +1 -1
- edsl/inference_services/services/test_service.py +11 -2
- edsl/interviews/request_token_estimator.py +104 -2
- edsl/invigilators/invigilators.py +6 -1
- edsl/jobs/jobs_pricing_estimation.py +127 -46
- edsl/language_models/language_model.py +16 -6
- edsl/language_models/utilities.py +2 -1
- edsl/questions/question_check_box.py +171 -149
- edsl/questions/question_dict.py +47 -40
- edsl/scenarios/file_store.py +73 -23
- {edsl-0.1.52.dist-info → edsl-0.1.54.dist-info}/METADATA +2 -1
- {edsl-0.1.52.dist-info → edsl-0.1.54.dist-info}/RECORD +15 -15
- {edsl-0.1.52.dist-info → edsl-0.1.54.dist-info}/LICENSE +0 -0
- {edsl-0.1.52.dist-info → edsl-0.1.54.dist-info}/WHEEL +0 -0
- {edsl-0.1.52.dist-info → edsl-0.1.54.dist-info}/entry_points.txt +0 -0
edsl/questions/question_dict.py
CHANGED
@@ -51,7 +51,7 @@ def _parse_type_string(type_str: str) -> Any:
|
|
51
51
|
return List[Any]
|
52
52
|
elif type_str.startswith("list["):
|
53
53
|
# e.g. "list[str]" or "list[int]" etc.
|
54
|
-
inner = type_str[len("list[")
|
54
|
+
inner = type_str[len("list[") : -1].strip()
|
55
55
|
return List[_parse_type_string(inner)]
|
56
56
|
# If none matched, return a very permissive type or raise an error
|
57
57
|
return Any
|
@@ -74,15 +74,16 @@ def create_dict_response(
|
|
74
74
|
# 1) Build the 'answer' submodel fields
|
75
75
|
# Each key is required (using `...`), with the associated type from value_types.
|
76
76
|
field_definitions = {}
|
77
|
+
if len(value_types) == 0:
|
78
|
+
value_types = ["str"] * len(answer_keys) # Default to str if no types provided
|
79
|
+
|
77
80
|
for key, t_str in zip(answer_keys, value_types):
|
78
81
|
python_type = _parse_type_string(t_str)
|
79
82
|
field_definitions[key] = (python_type, Field(...))
|
80
83
|
|
81
84
|
# Use Pydantic's create_model to construct an "AnswerSubModel" with these fields
|
82
85
|
AnswerSubModel = create_model(
|
83
|
-
"AnswerSubModel",
|
84
|
-
__base__=BaseModel,
|
85
|
-
**field_definitions
|
86
|
+
"AnswerSubModel", __base__=BaseModel, **field_definitions
|
86
87
|
)
|
87
88
|
|
88
89
|
# 2) Define the top-level model with `answer` + optional `comment`
|
@@ -102,12 +103,12 @@ def create_dict_response(
|
|
102
103
|
class DictResponseValidator(ResponseValidatorABC):
|
103
104
|
"""
|
104
105
|
Validator for dictionary responses with specific keys and value types.
|
105
|
-
|
106
|
+
|
106
107
|
This validator ensures that:
|
107
108
|
1. All required keys are present in the answer
|
108
109
|
2. Each value has the correct type as specified
|
109
110
|
3. Extra keys are forbidden unless permissive=True
|
110
|
-
|
111
|
+
|
111
112
|
Examples:
|
112
113
|
>>> from edsl.questions import QuestionDict
|
113
114
|
>>> q = QuestionDict(
|
@@ -119,7 +120,7 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
119
120
|
>>> validator = q.response_validator
|
120
121
|
>>> result = validator.validate({
|
121
122
|
... "answer": {
|
122
|
-
... "name": "Pancakes",
|
123
|
+
... "name": "Pancakes",
|
123
124
|
... "ingredients": ["flour", "milk", "eggs"],
|
124
125
|
... "steps": ["Mix", "Cook", "Serve"]
|
125
126
|
... }
|
@@ -127,12 +128,13 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
127
128
|
>>> sorted(result.keys())
|
128
129
|
['answer', 'comment', 'generated_tokens']
|
129
130
|
"""
|
131
|
+
|
130
132
|
required_params = ["answer_keys", "permissive"]
|
131
133
|
|
132
134
|
def fix(self, response, verbose=False):
|
133
135
|
"""
|
134
136
|
Attempt to fix an invalid dictionary response.
|
135
|
-
|
137
|
+
|
136
138
|
Examples:
|
137
139
|
>>> # Set up validator with proper response model
|
138
140
|
>>> from pydantic import BaseModel, create_model, Field
|
@@ -151,7 +153,7 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
151
153
|
... permissive=False
|
152
154
|
... )
|
153
155
|
>>> validator.value_types = ["str", "int"]
|
154
|
-
|
156
|
+
|
155
157
|
# Fix dictionary with comment on same line
|
156
158
|
>>> response = "{'name': 'john', 'age': 23} Here you go."
|
157
159
|
>>> result = validator.fix(response)
|
@@ -159,13 +161,13 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
159
161
|
{'name': 'john', 'age': 23}
|
160
162
|
>>> result['comment']
|
161
163
|
'Here you go.'
|
162
|
-
|
164
|
+
|
163
165
|
# Fix type conversion (string to int)
|
164
166
|
>>> response = {"answer": {"name": "john", "age": "23"}}
|
165
167
|
>>> result = validator.fix(response)
|
166
168
|
>>> dict(result['answer']) # Convert to dict for consistent output
|
167
169
|
{'name': 'john', 'age': 23}
|
168
|
-
|
170
|
+
|
169
171
|
# Fix list from comma-separated string
|
170
172
|
>>> AnswerModel2 = create_model('AnswerModel2', name=(str, ...), hobbies=(List[str], ...))
|
171
173
|
>>> ResponseModel2 = create_model(
|
@@ -184,7 +186,7 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
184
186
|
>>> result = validator.fix(response)
|
185
187
|
>>> dict(result['answer']) # Convert to dict for consistent output
|
186
188
|
{'name': 'john', 'hobbies': ['reading', 'gaming', 'coding']}
|
187
|
-
|
189
|
+
|
188
190
|
# Handle invalid input gracefully
|
189
191
|
>>> response = "not a dictionary"
|
190
192
|
>>> validator.fix(response)
|
@@ -194,14 +196,14 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
194
196
|
if isinstance(response, str):
|
195
197
|
# Try to find where the dictionary ends and comment begins
|
196
198
|
try:
|
197
|
-
dict_match = re.match(r
|
199
|
+
dict_match = re.match(r"(\{.*?\})(.*)", response.strip())
|
198
200
|
if dict_match:
|
199
201
|
dict_str, comment = dict_match.groups()
|
200
202
|
try:
|
201
203
|
answer_dict = ast.literal_eval(dict_str)
|
202
204
|
response = {
|
203
205
|
"answer": answer_dict,
|
204
|
-
"comment": comment.strip() if comment.strip() else None
|
206
|
+
"comment": comment.strip() if comment.strip() else None,
|
205
207
|
}
|
206
208
|
except (ValueError, SyntaxError):
|
207
209
|
pass
|
@@ -213,10 +215,10 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
213
215
|
if verbose:
|
214
216
|
print("Cannot fix response: 'answer' field missing or not a dictionary")
|
215
217
|
return response
|
216
|
-
|
218
|
+
|
217
219
|
answer_dict = response["answer"]
|
218
220
|
fixed_answer = {}
|
219
|
-
|
221
|
+
|
220
222
|
# Try to convert values to expected types
|
221
223
|
for key, type_str in zip(self.answer_keys, getattr(self, "value_types", [])):
|
222
224
|
if key in answer_dict:
|
@@ -226,20 +228,24 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
226
228
|
try:
|
227
229
|
fixed_answer[key] = int(value)
|
228
230
|
if verbose:
|
229
|
-
print(
|
231
|
+
print(
|
232
|
+
f"Converted '{key}' from {type(value).__name__} to int"
|
233
|
+
)
|
230
234
|
continue
|
231
235
|
except (ValueError, TypeError):
|
232
236
|
pass
|
233
|
-
|
237
|
+
|
234
238
|
elif type_str == "float" and not isinstance(value, float):
|
235
239
|
try:
|
236
240
|
fixed_answer[key] = float(value)
|
237
241
|
if verbose:
|
238
|
-
print(
|
242
|
+
print(
|
243
|
+
f"Converted '{key}' from {type(value).__name__} to float"
|
244
|
+
)
|
239
245
|
continue
|
240
246
|
except (ValueError, TypeError):
|
241
247
|
pass
|
242
|
-
|
248
|
+
|
243
249
|
elif type_str.startswith("list[") and not isinstance(value, list):
|
244
250
|
# Try to convert string to list by splitting
|
245
251
|
if isinstance(value, str):
|
@@ -248,22 +254,22 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
248
254
|
if verbose:
|
249
255
|
print(f"Converted '{key}' from string to list: {items}")
|
250
256
|
continue
|
251
|
-
|
257
|
+
|
252
258
|
# If no conversion needed or possible, keep original
|
253
259
|
fixed_answer[key] = value
|
254
|
-
|
260
|
+
|
255
261
|
# Preserve any keys we didn't try to fix
|
256
262
|
for key, value in answer_dict.items():
|
257
263
|
if key not in fixed_answer:
|
258
264
|
fixed_answer[key] = value
|
259
|
-
|
265
|
+
|
260
266
|
# Return fixed response
|
261
267
|
fixed_response = {
|
262
268
|
"answer": fixed_answer,
|
263
269
|
"comment": response.get("comment"),
|
264
|
-
"generated_tokens": response.get("generated_tokens")
|
270
|
+
"generated_tokens": response.get("generated_tokens"),
|
265
271
|
}
|
266
|
-
|
272
|
+
|
267
273
|
try:
|
268
274
|
# Validate the fixed answer
|
269
275
|
self.response_model.model_validate(fixed_response)
|
@@ -281,12 +287,12 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
281
287
|
"answer": {
|
282
288
|
"name": "Hot Chocolate",
|
283
289
|
"num_ingredients": 5,
|
284
|
-
"ingredients": ["milk", "cocoa", "sugar"]
|
290
|
+
"ingredients": ["milk", "cocoa", "sugar"],
|
285
291
|
}
|
286
292
|
},
|
287
293
|
{
|
288
294
|
"answer_keys": ["name", "num_ingredients", "ingredients"],
|
289
|
-
"value_types": ["str", "int", "list[str]"]
|
295
|
+
"value_types": ["str", "int", "list[str]"],
|
290
296
|
},
|
291
297
|
)
|
292
298
|
]
|
@@ -300,7 +306,7 @@ class DictResponseValidator(ResponseValidatorABC):
|
|
300
306
|
{"answer": {"ingredients": "milk"}}, # Should be a list
|
301
307
|
{"answer_keys": ["ingredients"], "value_types": ["list[str]"]},
|
302
308
|
"Key 'ingredients' should be a list, got str",
|
303
|
-
)
|
309
|
+
),
|
304
310
|
]
|
305
311
|
|
306
312
|
|
@@ -373,7 +379,9 @@ class QuestionDict(QuestionBase):
|
|
373
379
|
raise QuestionCreationValidationError(
|
374
380
|
"Length of value_types must match length of answer_keys."
|
375
381
|
)
|
376
|
-
if self.value_descriptions and len(self.value_descriptions) != len(
|
382
|
+
if self.value_descriptions and len(self.value_descriptions) != len(
|
383
|
+
self.answer_keys
|
384
|
+
):
|
377
385
|
raise QuestionCreationValidationError(
|
378
386
|
"Length of value_descriptions must match length of answer_keys."
|
379
387
|
)
|
@@ -386,7 +394,7 @@ class QuestionDict(QuestionBase):
|
|
386
394
|
return create_dict_response(
|
387
395
|
answer_keys=self.answer_keys,
|
388
396
|
value_types=self.value_types or [],
|
389
|
-
permissive=self.permissive
|
397
|
+
permissive=self.permissive,
|
390
398
|
)
|
391
399
|
|
392
400
|
def _get_default_answer(self) -> Dict[str, Any]:
|
@@ -397,7 +405,7 @@ class QuestionDict(QuestionBase):
|
|
397
405
|
"title": "Sample Recipe",
|
398
406
|
"ingredients": ["ingredient1", "ingredient2"],
|
399
407
|
"num_ingredients": 2,
|
400
|
-
"instructions": "Sample instructions"
|
408
|
+
"instructions": "Sample instructions",
|
401
409
|
}
|
402
410
|
|
403
411
|
answer = {}
|
@@ -405,7 +413,7 @@ class QuestionDict(QuestionBase):
|
|
405
413
|
t_str = type_str.lower()
|
406
414
|
if t_str.startswith("list["):
|
407
415
|
# e.g. list[str], list[int], etc.
|
408
|
-
inner = t_str[len("list[")
|
416
|
+
inner = t_str[len("list[") : -1].strip()
|
409
417
|
if inner == "str":
|
410
418
|
answer[key] = ["sample_string"]
|
411
419
|
elif inner == "int":
|
@@ -445,7 +453,9 @@ class QuestionDict(QuestionBase):
|
|
445
453
|
return f"Template {template_name} not found in {template_dir}."
|
446
454
|
|
447
455
|
@staticmethod
|
448
|
-
def _normalize_value_types(
|
456
|
+
def _normalize_value_types(
|
457
|
+
value_types: Optional[List[Union[str, type]]]
|
458
|
+
) -> Optional[List[str]]:
|
449
459
|
"""
|
450
460
|
Convert all value_types to string representations (e.g. "int", "list[str]", etc.).
|
451
461
|
This logic is similar to your original approach but expanded to handle
|
@@ -486,7 +496,7 @@ class QuestionDict(QuestionBase):
|
|
486
496
|
}
|
487
497
|
|
488
498
|
@classmethod
|
489
|
-
def from_dict(cls, data: dict) ->
|
499
|
+
def from_dict(cls, data: dict) -> "QuestionDict":
|
490
500
|
"""Recreate from a dictionary."""
|
491
501
|
return cls(
|
492
502
|
question_name=data["question_name"],
|
@@ -500,7 +510,7 @@ class QuestionDict(QuestionBase):
|
|
500
510
|
|
501
511
|
@classmethod
|
502
512
|
@inject_exception
|
503
|
-
def example(cls) ->
|
513
|
+
def example(cls) -> "QuestionDict":
|
504
514
|
"""Return an example question."""
|
505
515
|
return cls(
|
506
516
|
question_name="example",
|
@@ -511,16 +521,13 @@ class QuestionDict(QuestionBase):
|
|
511
521
|
"The title of the recipe.",
|
512
522
|
"A list of ingredients.",
|
513
523
|
"The number of ingredients.",
|
514
|
-
"The instructions for making the recipe."
|
524
|
+
"The instructions for making the recipe.",
|
515
525
|
],
|
516
526
|
)
|
517
527
|
|
518
528
|
def _simulate_answer(self) -> dict:
|
519
529
|
"""Simulate an answer for the question."""
|
520
|
-
return {
|
521
|
-
"answer": self._get_default_answer(),
|
522
|
-
"comment": None
|
523
|
-
}
|
530
|
+
return {"answer": self._get_default_answer(), "comment": None}
|
524
531
|
|
525
532
|
|
526
533
|
if __name__ == "__main__":
|
edsl/scenarios/file_store.py
CHANGED
@@ -17,25 +17,26 @@ from .file_methods import FileMethods
|
|
17
17
|
if TYPE_CHECKING:
|
18
18
|
from .scenario_list import ScenarioList
|
19
19
|
|
20
|
+
|
20
21
|
class FileStore(Scenario):
|
21
22
|
"""
|
22
23
|
A specialized Scenario subclass for managing file content and metadata.
|
23
|
-
|
24
|
+
|
24
25
|
FileStore provides functionality for working with files in EDSL, handling various
|
25
26
|
file formats with appropriate encoding, storage, and access methods. It extends
|
26
27
|
Scenario to allow files to be included in surveys, questions, and other EDSL components.
|
27
|
-
|
28
|
+
|
28
29
|
FileStore supports multiple file formats including text, PDF, Word documents, images,
|
29
30
|
and more. It can load files from local paths or URLs, and provides methods for
|
30
31
|
accessing file content, extracting text, and managing file operations.
|
31
|
-
|
32
|
+
|
32
33
|
Key features:
|
33
34
|
- Base64 encoding for portability and serialization
|
34
35
|
- Lazy loading through temporary files when needed
|
35
36
|
- Automatic MIME type detection
|
36
37
|
- Text extraction from various file formats
|
37
38
|
- Format-specific operations through specialized handlers
|
38
|
-
|
39
|
+
|
39
40
|
Attributes:
|
40
41
|
_path (str): The original file path.
|
41
42
|
_temp_path (str): Path to any generated temporary file.
|
@@ -45,7 +46,7 @@ class FileStore(Scenario):
|
|
45
46
|
base64_string (str): Base64-encoded file content.
|
46
47
|
external_locations (dict): Dictionary of external locations.
|
47
48
|
extracted_text (str): Text extracted from the file.
|
48
|
-
|
49
|
+
|
49
50
|
Examples:
|
50
51
|
>>> import tempfile
|
51
52
|
>>> # Create a text file
|
@@ -53,13 +54,14 @@ class FileStore(Scenario):
|
|
53
54
|
... _ = f.write("Hello World")
|
54
55
|
... _ = f.flush()
|
55
56
|
... fs = FileStore(f.name)
|
56
|
-
|
57
|
+
|
57
58
|
# The following example works locally but is commented out for CI environments
|
58
59
|
# where dependencies like pandoc may not be available:
|
59
60
|
# >>> # FileStore supports various formats
|
60
61
|
# >>> formats = ["txt", "pdf", "docx", "pptx", "md", "py", "json", "csv", "html", "png", "db"]
|
61
62
|
# >>> _ = [FileStore.example(format) for format in formats]
|
62
63
|
"""
|
64
|
+
|
63
65
|
__documentation__ = "https://docs.expectedparrot.com/en/latest/filestore.html"
|
64
66
|
|
65
67
|
def __init__(
|
@@ -75,11 +77,11 @@ class FileStore(Scenario):
|
|
75
77
|
):
|
76
78
|
"""
|
77
79
|
Initialize a new FileStore object.
|
78
|
-
|
80
|
+
|
79
81
|
This constructor creates a FileStore object from either a file path or a base64-encoded
|
80
82
|
string representation of file content. It handles automatic detection of file properties
|
81
83
|
like MIME type, extracts text content when possible, and manages file encoding.
|
82
|
-
|
84
|
+
|
83
85
|
Args:
|
84
86
|
path: Path to the file to load. Can be a local file path or URL.
|
85
87
|
mime_type: MIME type of the file. If not provided, will be auto-detected.
|
@@ -93,7 +95,7 @@ class FileStore(Scenario):
|
|
93
95
|
text will be extracted automatically if possible.
|
94
96
|
**kwargs: Additional keyword arguments. 'filename' can be used as an
|
95
97
|
alternative to 'path'.
|
96
|
-
|
98
|
+
|
97
99
|
Note:
|
98
100
|
If path is a URL (starts with http:// or https://), the file will be
|
99
101
|
downloaded automatically.
|
@@ -138,15 +140,15 @@ class FileStore(Scenario):
|
|
138
140
|
def path(self) -> str:
|
139
141
|
"""
|
140
142
|
Returns a valid path to the file content, creating a temporary file if needed.
|
141
|
-
|
143
|
+
|
142
144
|
This property ensures that a valid file path is always available for the file
|
143
145
|
content, even if the original file is no longer accessible or if the FileStore
|
144
146
|
was created from a base64 string without a path. If the original path doesn't
|
145
147
|
exist, it automatically generates a temporary file from the base64 content.
|
146
|
-
|
148
|
+
|
147
149
|
Returns:
|
148
150
|
A string containing a valid file path to access the file content.
|
149
|
-
|
151
|
+
|
150
152
|
Examples:
|
151
153
|
>>> import tempfile, os
|
152
154
|
>>> with tempfile.NamedTemporaryFile(suffix=".txt", mode="w") as f:
|
@@ -155,8 +157,8 @@ class FileStore(Scenario):
|
|
155
157
|
... fs = FileStore(f.name)
|
156
158
|
... os.path.isfile(fs.path)
|
157
159
|
True
|
158
|
-
|
159
|
-
|
160
|
+
|
161
|
+
|
160
162
|
Notes:
|
161
163
|
- The path may point to a temporary file that will be cleaned up when the
|
162
164
|
Python process exits
|
@@ -319,9 +321,10 @@ class FileStore(Scenario):
|
|
319
321
|
|
320
322
|
link = ConstructDownloadLink(self).html_create_link(self.path, style=None)
|
321
323
|
return f"{parent_html}<br>{link}"
|
322
|
-
|
324
|
+
|
323
325
|
def download_link(self):
|
324
326
|
from .construct_download_link import ConstructDownloadLink
|
327
|
+
|
325
328
|
return ConstructDownloadLink(self).html_create_link(self.path, style=None)
|
326
329
|
|
327
330
|
def encode_file_to_base64_string(self, file_path: str):
|
@@ -572,6 +575,53 @@ class FileStore(Scenario):
|
|
572
575
|
f"Converting {self.suffix} files to pandas DataFrame is not supported"
|
573
576
|
)
|
574
577
|
|
578
|
+
def is_image(self) -> bool:
|
579
|
+
"""
|
580
|
+
Check if the file is an image by examining its MIME type.
|
581
|
+
|
582
|
+
Returns:
|
583
|
+
bool: True if the file is an image, False otherwise.
|
584
|
+
|
585
|
+
Examples:
|
586
|
+
>>> fs = FileStore.example("png")
|
587
|
+
>>> fs.is_image()
|
588
|
+
True
|
589
|
+
>>> fs = FileStore.example("txt")
|
590
|
+
>>> fs.is_image()
|
591
|
+
False
|
592
|
+
"""
|
593
|
+
# Check if the mime type starts with 'image/'
|
594
|
+
return self.mime_type.startswith("image/")
|
595
|
+
|
596
|
+
def get_image_dimensions(self) -> tuple:
|
597
|
+
"""
|
598
|
+
Get the dimensions (width, height) of an image file.
|
599
|
+
|
600
|
+
Returns:
|
601
|
+
tuple: A tuple containing the width and height of the image.
|
602
|
+
|
603
|
+
Raises:
|
604
|
+
ValueError: If the file is not an image or PIL is not installed.
|
605
|
+
|
606
|
+
Examples:
|
607
|
+
>>> fs = FileStore.example("png")
|
608
|
+
>>> width, height = fs.get_image_dimensions()
|
609
|
+
>>> isinstance(width, int) and isinstance(height, int)
|
610
|
+
True
|
611
|
+
"""
|
612
|
+
if not self.is_image():
|
613
|
+
raise ValueError("This file is not an image")
|
614
|
+
|
615
|
+
try:
|
616
|
+
from PIL import Image
|
617
|
+
except ImportError:
|
618
|
+
raise ImportError(
|
619
|
+
"PIL (Pillow) is required to get image dimensions. Install it with: pip install pillow"
|
620
|
+
)
|
621
|
+
|
622
|
+
with Image.open(self.path) as img:
|
623
|
+
return img.size # Returns (width, height)
|
624
|
+
|
575
625
|
def __getattr__(self, name):
|
576
626
|
"""
|
577
627
|
Delegate pandas DataFrame methods to the underlying DataFrame if this is a CSV file
|
@@ -662,13 +712,13 @@ class FileStore(Scenario):
|
|
662
712
|
# endobj
|
663
713
|
# xref
|
664
714
|
# 0 7
|
665
|
-
# 0000000000 65535 f
|
666
|
-
# 0000000010 00000 n
|
667
|
-
# 0000000053 00000 n
|
668
|
-
# 0000000100 00000 n
|
669
|
-
# 0000000173 00000 n
|
670
|
-
# 0000000232 00000 n
|
671
|
-
# 0000000272 00000 n
|
715
|
+
# 0000000000 65535 f
|
716
|
+
# 0000000010 00000 n
|
717
|
+
# 0000000053 00000 n
|
718
|
+
# 0000000100 00000 n
|
719
|
+
# 0000000173 00000 n
|
720
|
+
# 0000000232 00000 n
|
721
|
+
# 0000000272 00000 n
|
672
722
|
# trailer
|
673
723
|
# << /Size 7 /Root 1 0 R >>
|
674
724
|
# startxref
|
@@ -748,6 +798,7 @@ class FileStore(Scenario):
|
|
748
798
|
|
749
799
|
if __name__ == "__main__":
|
750
800
|
import doctest
|
801
|
+
|
751
802
|
doctest.testmod()
|
752
803
|
|
753
804
|
# formats = FileMethods.supported_file_types()
|
@@ -756,4 +807,3 @@ if __name__ == "__main__":
|
|
756
807
|
# fs = FileStore.example(file_type)
|
757
808
|
# fs.view()
|
758
809
|
# input("Press Enter to continue...")
|
759
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: edsl
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.54
|
4
4
|
Summary: Create and analyze LLM-based surveys
|
5
5
|
Home-page: https://www.expectedparrot.com/
|
6
6
|
License: MIT
|
@@ -83,6 +83,7 @@ results = q.run()
|
|
83
83
|
results.select("example")
|
84
84
|
```
|
85
85
|
|
86
|
+
|
86
87
|
> | answer.example |
|
87
88
|
> |-----------------|
|
88
89
|
> | Good |
|
@@ -1,5 +1,5 @@
|
|
1
1
|
edsl/__init__.py,sha256=SXi_Zm4kf6H2WW_YeTuF6zRNZEWKzpKa7NRXUzn2Ty4,4593
|
2
|
-
edsl/__version__.py,sha256=
|
2
|
+
edsl/__version__.py,sha256=0U9S9zRz7MduvARyiWFUbfYZNKDf9XCo9-1NqTcx3CU,23
|
3
3
|
edsl/agents/__init__.py,sha256=AyhfXjygRHT1Pd9w16lcu5Bu0jnBmMPz86aKP1uRL3Y,93
|
4
4
|
edsl/agents/agent.py,sha256=svTVvvg9eCMUhnb49Bxsf9nAwXragtRaeBkyB6q89EE,54423
|
5
5
|
edsl/agents/agent_list.py,sha256=JA39_6RSmiD2mqJgWr2NWovNxNmu4mhZbYmn5be87NQ,21572
|
@@ -87,7 +87,7 @@ edsl/inference_services/services/mistral_ai_service.py,sha256=Q4eWCAUhsibMaBpq5I
|
|
87
87
|
edsl/inference_services/services/ollama_service.py,sha256=quSKlgD0bHG9mO_s9verGePfqQi_rZWovHEQ6dy-Fe0,303
|
88
88
|
edsl/inference_services/services/open_ai_service.py,sha256=_gK1MVJGla-LF9YvySNuVDY5g-SmSsNhByEfIO7usAI,8481
|
89
89
|
edsl/inference_services/services/perplexity_service.py,sha256=th6Zx3YNBBc4MsgjzmpkAfqMwqrPNFBdAhmUxed-gYM,5793
|
90
|
-
edsl/inference_services/services/test_service.py,sha256=
|
90
|
+
edsl/inference_services/services/test_service.py,sha256=1skcodQ9JN7IsIeaperh7gxeQ_CGEQkO2mamNQTHAx0,3363
|
91
91
|
edsl/inference_services/services/together_ai_service.py,sha256=biUYs07jsrIHp19O81o0nJCwYdSWudMEXdGtmA1-y60,6151
|
92
92
|
edsl/inference_services/services/xai_service.py,sha256=hJbXF26DuFTZdy0lYT1wo3yyuWDcwcXA6EiGYUahK1w,280
|
93
93
|
edsl/inference_services/write_available.py,sha256=9L8chJb8iafHfwRBfqZKjMjkSBRWUa5gEe7F0mxsZu0,261
|
@@ -107,12 +107,12 @@ edsl/interviews/interview_status_dictionary.py,sha256=0ZvXLusfOA8xD_Fco4PjEBGwmR
|
|
107
107
|
edsl/interviews/interview_status_enum.py,sha256=KJ-1yLAHdX-p8TiFnM0M3v1tnBwkq4aMCuBX6-ytrI8,229
|
108
108
|
edsl/interviews/interview_status_log.py,sha256=sRiQ9kIT1WcF-8beETn6E7IsdRRrfbco-yjdAjkXncw,3587
|
109
109
|
edsl/interviews/interview_task_manager.py,sha256=wPi5izhsVK5wI5HfMXMLL5NIoucHNCoGXfRuRzI-wYE,3665
|
110
|
-
edsl/interviews/request_token_estimator.py,sha256=
|
110
|
+
edsl/interviews/request_token_estimator.py,sha256=n_C-alSYOFi27cBcIRhtBX-fvklDcvM2Kowte-EDnzM,4833
|
111
111
|
edsl/interviews/statistics.py,sha256=lZCtq79QrDKG3jXao_OWuBRhnly9VyuhM6IdTJaYqPg,2461
|
112
112
|
edsl/invigilators/__init__.py,sha256=fKbZ7p9-kMelpvET3Ku2Owu-tL_apC-8gi9JychpMBY,1843
|
113
113
|
edsl/invigilators/exceptions.py,sha256=ejoF-Gt-YcnW1yHyfpJ3jZm8AC_zD0GCYafRO2LlAMQ,2767
|
114
114
|
edsl/invigilators/invigilator_base.py,sha256=DgrXTK4AAxXr4wg2pzc0p1aGPPf1UUt01C-JW1UBTvo,20099
|
115
|
-
edsl/invigilators/invigilators.py,sha256=
|
115
|
+
edsl/invigilators/invigilators.py,sha256=hY66Nwl1_Y-f_MAs7iqbU36zRQTKQA4JuW2Zi2Rq4qc,22365
|
116
116
|
edsl/invigilators/prompt_constructor.py,sha256=THHGcZPI-QUOH8Z9cQEzH7bZEoo0V_Nc_Phlhc9AzL0,19115
|
117
117
|
edsl/invigilators/prompt_helpers.py,sha256=LuMZFZkInPY8M7Rw9fG9rpJIcT89tr2_Iq10ZHH_Y4A,5409
|
118
118
|
edsl/invigilators/question_instructions_prompt_builder.py,sha256=E5zpwctpt_5JjONkZRcMwB0MACAzDvvnzUhmuWTnjd0,9684
|
@@ -130,7 +130,7 @@ edsl/jobs/jobs.py,sha256=HI8akFqRbDVEeT8DuIy2i_tyEx6Gnv3oOU7SS0TrmcM,38931
|
|
130
130
|
edsl/jobs/jobs_checks.py,sha256=bfPJ3hQ4qvRBhyte4g-4J8zExJxJr3nlLHmtVmFPJcQ,5390
|
131
131
|
edsl/jobs/jobs_component_constructor.py,sha256=XxnJCQEJVC99QHNXjhR3lCfzSn46Z0JMtkgHRiBUfj8,6907
|
132
132
|
edsl/jobs/jobs_interview_constructor.py,sha256=1XTfQ-XAsabIagYQWWn9jLkdXAWqw_7KffNVLQWCfDs,2001
|
133
|
-
edsl/jobs/jobs_pricing_estimation.py,sha256=
|
133
|
+
edsl/jobs/jobs_pricing_estimation.py,sha256=rb4zr0d8DicLmHy2_0l1qVAdskCyBLrXeqtz5Qa60c8,15433
|
134
134
|
edsl/jobs/jobs_remote_inference_logger.py,sha256=1lOlzsBXg69zwVP40Je-WiI4wcvS-Ov7BBuW6V4Mkes,9185
|
135
135
|
edsl/jobs/jobs_runner_asyncio.py,sha256=wSs_Ts__-2BbPqZ_xQG7BM1mQ1YqZFliPUoq9MFuSUY,11034
|
136
136
|
edsl/jobs/jobs_runner_status.py,sha256=hIHHC_sWkK6clqQwnxz8YXAvwrEoL-VVtwWnHij3vfw,10446
|
@@ -146,7 +146,7 @@ edsl/key_management/models.py,sha256=z9TimNMnz47mnITM5SlJy2m2sk1aKKtt0ybV89rsaiY
|
|
146
146
|
edsl/language_models/__init__.py,sha256=WtefJs6XOCn5RSz22PgoAi3eTEr1NzGtnnBpDIie2mg,240
|
147
147
|
edsl/language_models/compute_cost.py,sha256=noWk0osCANksfKSh0sXFkPrcQegtSV8-jCRBjz_52uQ,2570
|
148
148
|
edsl/language_models/exceptions.py,sha256=P9dMA8XfK_qcuXNJZ-Xsb_Ny-12Ldu3fPC133RB40Ek,13728
|
149
|
-
edsl/language_models/language_model.py,sha256=
|
149
|
+
edsl/language_models/language_model.py,sha256=oYxJtE7lBR-1uPnby5-zQc5je0-3OLU0fw3QbQcsbTI,40279
|
150
150
|
edsl/language_models/model.py,sha256=UhBFV7eSgUBub0hR7vpmnerXvLXTX-4Xda2tA_eNJbU,11616
|
151
151
|
edsl/language_models/model_list.py,sha256=Eb62xQdrlayqWYyJVgYxheMiNi14e1U9b_12qYzy1ws,4522
|
152
152
|
edsl/language_models/price_manager.py,sha256=vLqMmrFecdW6aH4csFoM8w_MtRmMGCmi8pb79oS5_EY,5747
|
@@ -155,7 +155,7 @@ edsl/language_models/registry.py,sha256=HY1fEHKXz92AQF8fIMfkvtA8p-_o9mWwr9rt2VDO
|
|
155
155
|
edsl/language_models/repair.py,sha256=ljm0xc9e1tMdyKc9b-v7ikpYRBh639xJ11SkDzI2vZE,5245
|
156
156
|
edsl/language_models/unused/fake_openai_call.py,sha256=dxbL5e4NLF-eTk9IduPyGwLiVCX_-eGCJDaLYPlQTqc,364
|
157
157
|
edsl/language_models/unused/fake_openai_service.py,sha256=p0slW9cTdhuCjym64-uOcH_eHu4tzq5CHPPjvY8C2Ok,1691
|
158
|
-
edsl/language_models/utilities.py,sha256=
|
158
|
+
edsl/language_models/utilities.py,sha256=WHhSVzBw_ujm226sfxi38uCiAMJn-PC4NarQP7bqUYU,2284
|
159
159
|
edsl/load_plugins.py,sha256=rJJiVHguGoeri4ZT6E3AKftRjibnw-o6JMA9R6Qv3Ng,2480
|
160
160
|
edsl/logger.py,sha256=vnik_w_gHPxdRgF4ctgkuhjBeFwUkDt0c0uVUwWKfy4,4291
|
161
161
|
edsl/notebooks/__init__.py,sha256=5uN54Xgjv4J0f_wdtdLoRnSzSUkHpSNTDtjLE2_jpZg,612
|
@@ -198,8 +198,8 @@ edsl/questions/question_base.py,sha256=WJMah2OLOoKvLo288sS4PfAWw2kBYM7q0FWW-yDBB
|
|
198
198
|
edsl/questions/question_base_gen_mixin.py,sha256=Zb1nd0O6NR1c1rf6ik-Im7WPXAiIQrHkZTqK4PPUXSU,9768
|
199
199
|
edsl/questions/question_base_prompts_mixin.py,sha256=YWWAsI-_fzm8UTDbryfnA0g-1ufiGa1QxeZMb6r0T8A,11916
|
200
200
|
edsl/questions/question_budget.py,sha256=C7TmJVk9XT_1Ado2S_JbLOGr4OtRONeR9mp3BoPbif4,24541
|
201
|
-
edsl/questions/question_check_box.py,sha256=
|
202
|
-
edsl/questions/question_dict.py,sha256=
|
201
|
+
edsl/questions/question_check_box.py,sha256=PNxCae2gAbuSqApGMWOdA2zZ2uhZFv_0O8lm6T8nvhg,33613
|
202
|
+
edsl/questions/question_dict.py,sha256=OcKGuA3KpyXn7UjZbC41wIhiIIGxSJySdfoxOtU3Prc,20793
|
203
203
|
edsl/questions/question_extract.py,sha256=6x5LOqwDko_-DnhJAtZBRAju11JIa4PxTjU-5lg1rE0,20227
|
204
204
|
edsl/questions/question_free_text.py,sha256=Oaw7C5BCclCiaWJlWHQJFEPppKxT7zWBFyIbF03LJh0,12879
|
205
205
|
edsl/questions/question_functional.py,sha256=iwFlJmXBoFDu5D4tZ4Ci_yhfQo8_tB9C3W5I2p7KipA,9524
|
@@ -276,7 +276,7 @@ edsl/scenarios/directory_scanner.py,sha256=gnDXU1jKSjSE3LXEhE7ilfJUL_sxK2HHmsA2L
|
|
276
276
|
edsl/scenarios/document_chunker.py,sha256=EpB0V0oxLzpKntl00Qa3VZNPS7sg9aXdYyqKxhFFzTM,7680
|
277
277
|
edsl/scenarios/exceptions.py,sha256=FeORBm90UthKHDp7cE8I7KJgyA3-pFKNpoivZRr8ifc,10636
|
278
278
|
edsl/scenarios/file_methods.py,sha256=cB_IPVTGz4_yJiRMTdNTvpW4l43lrTbyJOV3Pnm6UPs,2631
|
279
|
-
edsl/scenarios/file_store.py,sha256=
|
279
|
+
edsl/scenarios/file_store.py,sha256=slqSIENW6SP1dhnXTviq4umlvGHeYsDB3SM24t0ll_I,28033
|
280
280
|
edsl/scenarios/handlers/__init__.py,sha256=9r1fDjUviGXso9h4d05wG9RECfqzfps55CQgb-ojCBo,848
|
281
281
|
edsl/scenarios/handlers/csv_file_store.py,sha256=kXOms0ph5JJj6jSbpfQ-SZjuT4vvSRhq5AGpv1L4TPQ,1369
|
282
282
|
edsl/scenarios/handlers/docx_file_store.py,sha256=KSKAAUIWF2K5xr92nx7UGQ9djgtDX4ke-Eyik8QAdlQ,2155
|
@@ -358,8 +358,8 @@ edsl/utilities/repair_functions.py,sha256=EXkXsqnmgPqj9b3dff1cZnJyaZw-qEvGENXCRH
|
|
358
358
|
edsl/utilities/restricted_python.py,sha256=248N2p5EWHDSpcK1G-q7DUoJeWy4sB6aO-RV0-5O7uY,2038
|
359
359
|
edsl/utilities/template_loader.py,sha256=SCAcnTnxNQ67MNSkmfz7F-S_u2peyGn2j1oRIqi1wfg,870
|
360
360
|
edsl/utilities/utilities.py,sha256=irHheAGOnl_6RwI--Hi9StVzvsHcWCqB48PWsWJQYOw,12045
|
361
|
-
edsl-0.1.
|
362
|
-
edsl-0.1.
|
363
|
-
edsl-0.1.
|
364
|
-
edsl-0.1.
|
365
|
-
edsl-0.1.
|
361
|
+
edsl-0.1.54.dist-info/LICENSE,sha256=_qszBDs8KHShVYcYzdMz3HNMtH-fKN_p5zjoVAVumFc,1111
|
362
|
+
edsl-0.1.54.dist-info/METADATA,sha256=NGU-XmzH8XskOALpmyMCfowQaFzeGwHkdvBskv1BBns,12671
|
363
|
+
edsl-0.1.54.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
364
|
+
edsl-0.1.54.dist-info/entry_points.txt,sha256=JnG7xqMtHaQu9BU-yPATxdyCeA48XJpuclnWCqMfIMU,38
|
365
|
+
edsl-0.1.54.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|