edsl 0.1.27.dev2__py3-none-any.whl โ†’ 0.1.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. edsl/Base.py +107 -30
  2. edsl/BaseDiff.py +260 -0
  3. edsl/__init__.py +25 -21
  4. edsl/__version__.py +1 -1
  5. edsl/agents/Agent.py +103 -46
  6. edsl/agents/AgentList.py +97 -13
  7. edsl/agents/Invigilator.py +23 -10
  8. edsl/agents/InvigilatorBase.py +19 -14
  9. edsl/agents/PromptConstructionMixin.py +342 -100
  10. edsl/agents/descriptors.py +5 -2
  11. edsl/base/Base.py +289 -0
  12. edsl/config.py +2 -1
  13. edsl/conjure/AgentConstructionMixin.py +152 -0
  14. edsl/conjure/Conjure.py +56 -0
  15. edsl/conjure/InputData.py +659 -0
  16. edsl/conjure/InputDataCSV.py +48 -0
  17. edsl/conjure/InputDataMixinQuestionStats.py +182 -0
  18. edsl/conjure/InputDataPyRead.py +91 -0
  19. edsl/conjure/InputDataSPSS.py +8 -0
  20. edsl/conjure/InputDataStata.py +8 -0
  21. edsl/conjure/QuestionOptionMixin.py +76 -0
  22. edsl/conjure/QuestionTypeMixin.py +23 -0
  23. edsl/conjure/RawQuestion.py +65 -0
  24. edsl/conjure/SurveyResponses.py +7 -0
  25. edsl/conjure/__init__.py +9 -4
  26. edsl/conjure/examples/placeholder.txt +0 -0
  27. edsl/conjure/naming_utilities.py +263 -0
  28. edsl/conjure/utilities.py +165 -28
  29. edsl/conversation/Conversation.py +238 -0
  30. edsl/conversation/car_buying.py +58 -0
  31. edsl/conversation/mug_negotiation.py +81 -0
  32. edsl/conversation/next_speaker_utilities.py +93 -0
  33. edsl/coop/coop.py +337 -121
  34. edsl/coop/utils.py +56 -70
  35. edsl/data/Cache.py +74 -22
  36. edsl/data/CacheHandler.py +10 -9
  37. edsl/data/SQLiteDict.py +11 -3
  38. edsl/inference_services/AnthropicService.py +1 -0
  39. edsl/inference_services/DeepInfraService.py +20 -13
  40. edsl/inference_services/GoogleService.py +7 -1
  41. edsl/inference_services/InferenceServicesCollection.py +33 -7
  42. edsl/inference_services/OpenAIService.py +17 -10
  43. edsl/inference_services/models_available_cache.py +69 -0
  44. edsl/inference_services/rate_limits_cache.py +25 -0
  45. edsl/inference_services/write_available.py +10 -0
  46. edsl/jobs/Answers.py +15 -1
  47. edsl/jobs/Jobs.py +322 -73
  48. edsl/jobs/buckets/BucketCollection.py +9 -3
  49. edsl/jobs/buckets/ModelBuckets.py +4 -2
  50. edsl/jobs/buckets/TokenBucket.py +1 -2
  51. edsl/jobs/interviews/Interview.py +7 -10
  52. edsl/jobs/interviews/InterviewStatusMixin.py +3 -3
  53. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +39 -20
  54. edsl/jobs/interviews/retry_management.py +4 -4
  55. edsl/jobs/runners/JobsRunnerAsyncio.py +103 -65
  56. edsl/jobs/runners/JobsRunnerStatusData.py +3 -3
  57. edsl/jobs/tasks/QuestionTaskCreator.py +4 -2
  58. edsl/jobs/tasks/TaskHistory.py +4 -3
  59. edsl/language_models/LanguageModel.py +42 -55
  60. edsl/language_models/ModelList.py +96 -0
  61. edsl/language_models/registry.py +14 -0
  62. edsl/language_models/repair.py +97 -25
  63. edsl/notebooks/Notebook.py +157 -32
  64. edsl/prompts/Prompt.py +31 -19
  65. edsl/questions/QuestionBase.py +145 -23
  66. edsl/questions/QuestionBudget.py +5 -6
  67. edsl/questions/QuestionCheckBox.py +7 -3
  68. edsl/questions/QuestionExtract.py +5 -3
  69. edsl/questions/QuestionFreeText.py +3 -3
  70. edsl/questions/QuestionFunctional.py +0 -3
  71. edsl/questions/QuestionList.py +3 -4
  72. edsl/questions/QuestionMultipleChoice.py +16 -8
  73. edsl/questions/QuestionNumerical.py +4 -3
  74. edsl/questions/QuestionRank.py +5 -3
  75. edsl/questions/__init__.py +4 -3
  76. edsl/questions/descriptors.py +9 -4
  77. edsl/questions/question_registry.py +27 -31
  78. edsl/questions/settings.py +1 -1
  79. edsl/results/Dataset.py +31 -0
  80. edsl/results/DatasetExportMixin.py +493 -0
  81. edsl/results/Result.py +42 -82
  82. edsl/results/Results.py +178 -66
  83. edsl/results/ResultsDBMixin.py +10 -9
  84. edsl/results/ResultsExportMixin.py +23 -507
  85. edsl/results/ResultsGGMixin.py +3 -3
  86. edsl/results/ResultsToolsMixin.py +9 -9
  87. edsl/scenarios/FileStore.py +140 -0
  88. edsl/scenarios/Scenario.py +59 -6
  89. edsl/scenarios/ScenarioList.py +138 -52
  90. edsl/scenarios/ScenarioListExportMixin.py +32 -0
  91. edsl/scenarios/ScenarioListPdfMixin.py +2 -1
  92. edsl/scenarios/__init__.py +1 -0
  93. edsl/study/ObjectEntry.py +173 -0
  94. edsl/study/ProofOfWork.py +113 -0
  95. edsl/study/SnapShot.py +73 -0
  96. edsl/study/Study.py +498 -0
  97. edsl/study/__init__.py +4 -0
  98. edsl/surveys/MemoryPlan.py +11 -4
  99. edsl/surveys/Survey.py +124 -37
  100. edsl/surveys/SurveyExportMixin.py +25 -5
  101. edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
  102. edsl/tools/plotting.py +4 -2
  103. edsl/utilities/__init__.py +21 -20
  104. edsl/utilities/gcp_bucket/__init__.py +0 -0
  105. edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
  106. edsl/utilities/gcp_bucket/simple_example.py +9 -0
  107. edsl/utilities/interface.py +90 -73
  108. edsl/utilities/repair_functions.py +28 -0
  109. edsl/utilities/utilities.py +59 -6
  110. {edsl-0.1.27.dev2.dist-info โ†’ edsl-0.1.29.dist-info}/METADATA +42 -15
  111. edsl-0.1.29.dist-info/RECORD +203 -0
  112. edsl/conjure/RawResponseColumn.py +0 -327
  113. edsl/conjure/SurveyBuilder.py +0 -308
  114. edsl/conjure/SurveyBuilderCSV.py +0 -78
  115. edsl/conjure/SurveyBuilderSPSS.py +0 -118
  116. edsl/data/RemoteDict.py +0 -103
  117. edsl-0.1.27.dev2.dist-info/RECORD +0 -172
  118. {edsl-0.1.27.dev2.dist-info โ†’ edsl-0.1.29.dist-info}/LICENSE +0 -0
  119. {edsl-0.1.27.dev2.dist-info โ†’ edsl-0.1.29.dist-info}/WHEEL +0 -0
@@ -1,12 +1,45 @@
1
1
  """A module for displaying data in various formats."""
2
2
 
3
3
  from html import escape
4
- from IPython.display import HTML
5
- from IPython.display import display as ipython_diplay
6
4
 
7
- # from PIL import Image, ImageDraw, ImageFont
8
- from rich.console import Console
9
- from rich.table import Table
5
+
6
+ def create_image(console, image_filename):
7
+ """Create an image from the console output."""
8
+ font_size = 15
9
+ from PIL import Image, ImageDraw, ImageFont
10
+
11
+ text = console.export_text() # Get the console output as text.
12
+
13
+ # Create an image from the text
14
+ font_size = 15
15
+ font = ImageFont.load_default() # Use the default font to avoid file path issues.
16
+ # text_width, text_height = ImageDraw.Draw(
17
+ # Image.new("RGB", (100, 100))
18
+ # ).multiline_textsize(text, font=font)
19
+ text_width, text_height = get_multiline_textsize(text, font)
20
+ image = Image.new(
21
+ "RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
22
+ ) # Add some padding
23
+ d = ImageDraw.Draw(image)
24
+
25
+ # Draw text to image
26
+ d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
27
+ # Save the image
28
+ image.save(image_filename)
29
+
30
+
31
+ def display_table(console, table, filename):
32
+ # from rich.console import Console
33
+ # from rich.table import Table
34
+ """Display the table using the rich library and save it to a file if a filename is provided."""
35
+ if filename is not None:
36
+ with open(filename, "w") as f:
37
+ with console.capture() as capture:
38
+ console.print(table)
39
+ f.write(capture.get())
40
+ create_image(console, filename + ".png")
41
+ else:
42
+ console.print(table)
10
43
 
11
44
 
12
45
  def gen_html_sandwich(html_inner, interactive=False):
@@ -133,43 +166,10 @@ def get_multiline_textsize(text, font):
133
166
  return max_width, total_height
134
167
 
135
168
 
136
- # def create_image(console, image_filename):
137
- # """Create an image from the console output."""
138
- # font_size = 15
139
-
140
- # text = console.export_text() # Get the console output as text.
141
-
142
- # # Create an image from the text
143
- # font_size = 15
144
- # font = ImageFont.load_default() # Use the default font to avoid file path issues.
145
- # # text_width, text_height = ImageDraw.Draw(
146
- # # Image.new("RGB", (100, 100))
147
- # # ).multiline_textsize(text, font=font)
148
- # text_width, text_height = get_multiline_textsize(text, font)
149
- # image = Image.new(
150
- # "RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
151
- # ) # Add some padding
152
- # d = ImageDraw.Draw(image)
153
-
154
- # # Draw text to image
155
- # d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
156
- # # Save the image
157
- # image.save(image_filename)
158
-
159
-
160
- def display(console, table, filename):
161
- """Display the table using the rich library and save it to a file if a filename is provided."""
162
- if filename is not None:
163
- with open(filename, "w") as f:
164
- with console.capture() as capture:
165
- console.print(table)
166
- f.write(capture.get())
167
- create_image(console, filename + ".png")
168
- else:
169
- console.print(table)
170
-
171
-
172
169
  def print_results_long(results, max_rows=None):
170
+ from rich.console import Console
171
+ from rich.table import Table
172
+
173
173
  console = Console(record=True)
174
174
  table = Table(show_header=True, header_style="bold magenta")
175
175
  table.add_column("Result index", style="dim")
@@ -199,6 +199,9 @@ def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
199
199
  โ”‚ c โ”‚ 3 โ”‚
200
200
  โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
201
201
  """
202
+ from rich.console import Console
203
+ from rich.table import Table
204
+
202
205
  console = Console(record=True)
203
206
  table = Table(show_header=True, header_style="bold magenta")
204
207
  table.add_column(key_name, style="dim")
@@ -206,7 +209,7 @@ def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
206
209
  for key, value in d.items():
207
210
  table.add_row(key, str(value))
208
211
  console.print(table)
209
- # display(console, table, filename)
212
+ # display_table(console, table, filename)
210
213
 
211
214
 
212
215
  def print_dict_as_html_table(
@@ -251,6 +254,9 @@ def print_dict_as_html_table(
251
254
 
252
255
 
253
256
  def print_scenario_list(data):
257
+ from rich.console import Console
258
+ from rich.table import Table
259
+
254
260
  new_data = []
255
261
  for obs in data:
256
262
  try:
@@ -300,6 +306,9 @@ def print_dataset_with_rich(data, filename=None, split_at_dot=True):
300
306
  โ”‚ 3 โ”‚ 6 โ”‚
301
307
  โ””โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜
302
308
  """
309
+ from rich.console import Console
310
+ from rich.table import Table
311
+
303
312
  console = Console(record=True)
304
313
 
305
314
  # Create a table object
@@ -321,7 +330,7 @@ def print_dataset_with_rich(data, filename=None, split_at_dot=True):
321
330
  table.add_row(*row)
322
331
 
323
332
  console.print(table)
324
- # display(console, table, filename)
333
+ # display_table(console, table, filename)
325
334
 
326
335
 
327
336
  def create_latex_table_from_data(data, filename=None, split_at_dot=True):
@@ -331,15 +340,15 @@ def create_latex_table_from_data(data, filename=None, split_at_dot=True):
331
340
 
332
341
  >>> data = [{"a": [1, 2, 3], "b": [4, 5, 6]}]
333
342
  >>> print(create_latex_table_from_data(data))
334
- \begin{tabular}{|c|c|}
335
- \hline
336
- a & b \\
337
- \hline
338
- 1 & 4 \\
339
- 2 & 5 \\
340
- 3 & 6 \\
341
- \hline
342
- \end{tabular}
343
+ \\begin{tabular}{|c|c|}
344
+ \\hline
345
+ a & b \\\\
346
+ \\hline
347
+ 1 & 4 \\\\
348
+ 2 & 5 \\\\
349
+ 3 & 6 \\\\
350
+ \\hline
351
+ \\end{tabular}
343
352
  """
344
353
 
345
354
  def escape_latex(s):
@@ -379,7 +388,7 @@ def create_latex_table_from_data(data, filename=None, split_at_dot=True):
379
388
  num_rows = len(next(iter(data[0].values())))
380
389
 
381
390
  # Debugging: Print the keys of the dictionaries
382
- print("Keys in data[0]:", list(data[0].keys()))
391
+ # print("Keys in data[0]:", list(data[0].keys()))
383
392
 
384
393
  # Add the data rows
385
394
  for i in range(num_rows):
@@ -410,9 +419,7 @@ def create_latex_table_from_data(data, filename=None, split_at_dot=True):
410
419
  return latex_table_str
411
420
 
412
421
 
413
- def print_list_of_dicts_as_html_table(
414
- data, filename=None, interactive=True, notebook=False
415
- ):
422
+ def print_list_of_dicts_as_html_table(data, interactive=True):
416
423
  """Print a list of dictionaries as an HTML table.
417
424
 
418
425
  :param data: The list of dictionaries to print.
@@ -459,20 +466,7 @@ def print_list_of_dicts_as_html_table(
459
466
  # Close the table
460
467
  html_table += "</tbody>\n"
461
468
  html_table += "</table>"
462
-
463
- html = gen_html_sandwich(html_table, interactive=interactive)
464
-
465
- # Output or save to file
466
- if filename:
467
- with open(filename, "w") as f:
468
- f.write(html)
469
- else:
470
- # view_html(html)
471
- if notebook:
472
- # ipython_diplay(HTML(html))
473
- return html
474
- else:
475
- print(html)
469
+ return gen_html_sandwich(html_table, interactive=interactive)
476
470
 
477
471
 
478
472
  def print_list_of_dicts_as_markdown_table(data, filename=None):
@@ -486,7 +480,11 @@ def print_list_of_dicts_as_markdown_table(data, filename=None):
486
480
  return
487
481
 
488
482
  # Gather all unique headers
489
- headers = list({key for d in data for key in d.keys()})
483
+ # headers = list({key for d in data for key in d.keys()})
484
+ headers = []
485
+ for column in data:
486
+ headers.append(list(column.keys())[0])
487
+
490
488
  markdown_table = "| " + " | ".join(headers) + " |\n"
491
489
  markdown_table += "|-" + "-|-".join(["" for _ in headers]) + "-|\n"
492
490
 
@@ -506,6 +504,9 @@ def print_list_of_dicts_as_markdown_table(data, filename=None):
506
504
 
507
505
  def print_public_methods_with_doc(obj):
508
506
  """Print the public methods of an object along with their docstrings."""
507
+ from rich.console import Console
508
+ from rich.table import Table
509
+
509
510
  console = Console()
510
511
  public_methods_with_docstrings = [
511
512
  (method, getattr(obj, method).__doc__)
@@ -527,8 +528,19 @@ def print_tally_with_rich(data, filename=None):
527
528
  Example:
528
529
  >>> data = {'a':12, 'b':14, 'c':9}
529
530
  >>> print_tally_with_rich(data)
531
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”“
532
+ โ”ƒ Value โ”ƒ Count โ”ƒ
533
+ โ”กโ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”ฉ
534
+ โ”‚ a โ”‚ 12 โ”‚
535
+ โ”‚ b โ”‚ 14 โ”‚
536
+ โ”‚ c โ”‚ 9 โ”‚
537
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
530
538
  """
531
539
  # Initialize a console object
540
+ from rich.console import Console
541
+ from rich.table import Table
542
+ from IPython.display import display
543
+
532
544
  console = Console(record=True)
533
545
 
534
546
  # Create a new table
@@ -542,7 +554,9 @@ def print_tally_with_rich(data, filename=None):
542
554
  for key, value in data.items():
543
555
  table.add_row(key, str(value))
544
556
 
545
- display(console, table, filename)
557
+ from IPython.display import display
558
+
559
+ display_table(console, table, filename)
546
560
 
547
561
 
548
562
  def print_table_with_rich(data, filename=None):
@@ -565,6 +579,9 @@ def print_table_with_rich(data, filename=None):
565
579
  โ”‚ 2 โ”‚ 9 โ”‚ 8 โ”‚
566
580
  โ””โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜
567
581
  """
582
+ from rich.console import Console
583
+ from rich.table import Table
584
+
568
585
  # Initialize a console object - expects a list of dictionaries
569
586
  console = Console(record=True)
570
587
 
@@ -584,7 +601,7 @@ def print_table_with_rich(data, filename=None):
584
601
  for row in data:
585
602
  table.add_row(*[str(value) for value in row.values()])
586
603
 
587
- display(console, table, filename)
604
+ display_table(console, table, filename)
588
605
 
589
606
 
590
607
  if __name__ == "__main__":
@@ -0,0 +1,28 @@
1
+ import json
2
+ from edsl.utilities.utilities import valid_json
3
+
4
+
5
+ def extract_json_from_string(s):
6
+ """Extract a JSON string from a string."""
7
+ # Find the first occurrence of '{'
8
+ start_idx = s.find("{")
9
+ # Find the last occurrence of '}'
10
+ end_idx = s.rfind("}")
11
+ # If both '{' and '}' are found in the string
12
+ if start_idx != -1 and end_idx != -1 and start_idx < end_idx:
13
+ # Extract the substring from start_idx to end_idx (inclusive)
14
+ json_str = s[start_idx : end_idx + 1]
15
+ try:
16
+ return json.loads(json_str)
17
+ except json.JSONDecodeError:
18
+ raise ValueError("Invalid JSON string")
19
+ else:
20
+ raise ValueError("No JSON object found in string")
21
+
22
+
23
+ if __name__ == "__main__":
24
+ text = (
25
+ 'Sure - here is some JSON { "key": "value", "number": 123, "array": [1, 2, 3] }'
26
+ )
27
+ extracted_json = extract_json_from_string(text)
28
+ d = extracted_json
@@ -1,5 +1,9 @@
1
1
  """Utility functions for working with strings, dictionaries, and files."""
2
2
 
3
+ from functools import wraps
4
+ import types
5
+ import time
6
+
3
7
  import hashlib
4
8
  import json
5
9
  import keyword
@@ -11,13 +15,50 @@ import tempfile
11
15
  import gzip
12
16
  import webbrowser
13
17
  import json
18
+
14
19
  from html import escape
15
20
  from typing import Callable, Union
16
21
 
17
- from pygments import highlight
18
- from pygments.lexers import JsonLexer
19
- from pygments.formatters import HtmlFormatter
20
- from IPython.display import HTML
22
+
23
+ def time_it(func):
24
+ @wraps(func)
25
+ def wrapper(*args, **kwargs):
26
+ start_time = time.time()
27
+ result = func(*args, **kwargs)
28
+ end_time = time.time()
29
+ execution_time = end_time - start_time
30
+ class_name = args[0].__class__.__name__ if args else func.__module__
31
+ print(
32
+ f"Function {class_name}.{func.__name__} took {execution_time:.4f} seconds to execute"
33
+ )
34
+ return result
35
+
36
+ return wrapper
37
+
38
+
39
+ def time_all_functions(module_or_class):
40
+ for name, obj in vars(module_or_class).items():
41
+ if isinstance(obj, types.FunctionType):
42
+ setattr(module_or_class, name, time_it(obj))
43
+
44
+
45
+ def dict_hash(data: dict):
46
+ return hash(
47
+ int(hashlib.md5(json.dumps(data, sort_keys=True).encode()).hexdigest(), 16)
48
+ )
49
+
50
+
51
+ def extract_json_from_string(text):
52
+ pattern = re.compile(r"\{.*?\}")
53
+ match = pattern.search(text)
54
+ if match:
55
+ json_data = match.group(0)
56
+ try:
57
+ json_object = json.loads(json_data)
58
+ return json_object
59
+ except json.JSONDecodeError:
60
+ return None
61
+ return None
21
62
 
22
63
 
23
64
  def clean_json(bad_json_str):
@@ -32,6 +73,7 @@ def clean_json(bad_json_str):
32
73
  ("\t", "\\t"),
33
74
  ("\b", "\\b"),
34
75
  ("\f", "\\f"),
76
+ ("[/INST]", "removed_inst"),
35
77
  ]
36
78
 
37
79
  s = bad_json_str
@@ -46,6 +88,11 @@ def data_to_html(data, replace_new_lines=False):
46
88
  if "edsl_class_name" in data:
47
89
  _ = data.pop("edsl_class_name")
48
90
 
91
+ from pygments import highlight
92
+ from pygments.lexers import JsonLexer
93
+ from pygments.formatters import HtmlFormatter
94
+ from IPython.display import HTML
95
+
49
96
  json_str = json.dumps(data, indent=4)
50
97
  formatted_json = highlight(
51
98
  json_str,
@@ -54,6 +101,7 @@ def data_to_html(data, replace_new_lines=False):
54
101
  )
55
102
  if replace_new_lines:
56
103
  formatted_json = formatted_json.replace("\\n", "<br>")
104
+
57
105
  return HTML(formatted_json).data
58
106
 
59
107
 
@@ -233,9 +281,14 @@ def valid_json(json_string):
233
281
  return False
234
282
 
235
283
 
236
- def is_valid_variable_name(name):
284
+ def is_valid_variable_name(name, allow_name=True):
237
285
  """Check if a string is a valid variable name."""
238
- return name.isidentifier() and not keyword.iskeyword(name)
286
+ if allow_name:
287
+ return name.isidentifier() and not keyword.iskeyword(name)
288
+ else:
289
+ return (
290
+ name.isidentifier() and not keyword.iskeyword(name) and not name == "name"
291
+ )
239
292
 
240
293
 
241
294
  def create_valid_var_name(s, transform_func: Callable = lambda x: x.lower()) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edsl
3
- Version: 0.1.27.dev2
3
+ Version: 0.1.29
4
4
  Summary: Create and analyze LLM-based surveys
5
5
  Home-page: https://www.expectedparrot.com/
6
6
  License: MIT
@@ -30,6 +30,7 @@ Requires-Dist: pandas (>=2.1.4,<3.0.0)
30
30
  Requires-Dist: pydot (>=2.0.0,<3.0.0)
31
31
  Requires-Dist: pygments (>=2.17.2,<3.0.0)
32
32
  Requires-Dist: pymupdf (>=1.24.4,<2.0.0)
33
+ Requires-Dist: pyreadstat (>=1.2.7,<2.0.0)
33
34
  Requires-Dist: python-docx (>=1.1.0,<2.0.0)
34
35
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
35
36
  Requires-Dist: restrictedpython (>=7.1,<8.0)
@@ -45,28 +46,54 @@ Description-Content-Type: text/markdown
45
46
  <img src="https://github.com/expectedparrot/edsl/blob/main/static/logo.png?raw=true" alt="edsl.png" width="100"/>
46
47
  </p>
47
48
 
48
- The Expected Parrot Domain-Specific Language (EDSL) package lets you conduct computational social science and market research with AI. Use it to design surveys and experiments, simulate responses with large language models, and perform data labeling and other research tasks. EDSL comes with built-in methods for analyzing, visualizing and sharing your results.
49
+ The Expected Parrot Domain-Specific Language (EDSL) package lets you conduct computational social science and market research with AI. Use it to design surveys and experiments, simulate responses with large language models, and perform data labeling and other research tasks. Results are formatted as specified datasets and come with built-in methods for analyzing, visualizing, and sharing.
49
50
 
50
51
  ## ๐Ÿ”— Links
51
- - PyPI: https://pypi.org/project/edsl/
52
- - Documentation: https://docs.expectedparrot.com
53
- - Getting started: https://docs.expectedparrot.com/en/latest/starter_tutorial.html
54
- - Discord: https://discord.com/invite/mxAYkjfy9m
52
+ - [PyPI](https://pypi.org/project/edsl/)
53
+ - [Documentation](https://docs.expectedparrot.com)
54
+ - [Getting started](https://docs.expectedparrot.com/en/latest/starter_tutorial.html)
55
+ - [Discord](https://discord.com/invite/mxAYkjfy9m)
56
+ - [Twitter](https://x.com/ExpectedParrot)
57
+ - [LinkedIn](https://www.linkedin.com/company/expectedparrot/)
58
+ - [Blog](https://blog.expectedparrot.com)
55
59
 
60
+ ## ๐ŸŒŽ Hello, World!
61
+ A quick example:
56
62
 
57
- ## ๐Ÿ’ก Contributions, Feature Requests & Bugs
58
- Interested in contributing? Want us to add a new feature? Found a nasty bug that you would like us to squash? Please send us an email at info@expectedparrot.com or message us at our Discord server.
63
+ ```python
64
+ # Import a question type
65
+ from edsl.questions import QuestionMultipleChoice
59
66
 
67
+ # Construct a question using the question type template
68
+ q = QuestionMultipleChoice(
69
+ question_name="example_question",
70
+ question_text="How do you feel today?",
71
+ question_options=["Bad", "OK", "Good"]
72
+ )
60
73
 
61
- ## ๐Ÿ’ป Getting started
62
- EDSL is compatible with Python 3.9 - 3.12.
74
+ # Run it with the default language model
75
+ results = q.run()
76
+
77
+ # Inspect the results in a dataset
78
+ results.select("example_question").print()
63
79
  ```
64
- pip install edsl
80
+
81
+ Output:
82
+ ```python
83
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
84
+ โ”ƒ answer โ”ƒ
85
+ โ”ƒ .example_question โ”ƒ
86
+ โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
87
+ โ”‚ Good โ”‚
88
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
65
89
  ```
66
90
 
67
- - Read the docs at http://docs.expectedparrot.com.
68
- - See https://docs.expectedparrot.com/en/latest/starter_tutorial.html for examples and tutorials.
91
+ ## ๐Ÿ’ป Requirements
92
+ * EDSL is compatible with Python 3.9 - 3.12.
93
+ * API keys for large language models that you want to use, stored in a `.env` file.
94
+ See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
69
95
 
70
- ## ๐Ÿ”ง Dependencies
71
- API keys for LLMs that you want to use, stored in a `.env` file
96
+ ## ๐Ÿ’ก Contributions, feature requests & bugs
97
+ Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
98
+ Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
72
99