edsl 0.1.41__py3-none-any.whl → 0.1.42__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 (38) hide show
  1. edsl/__version__.py +1 -1
  2. edsl/agents/Invigilator.py +3 -2
  3. edsl/agents/InvigilatorBase.py +2 -1
  4. edsl/agents/QuestionTemplateReplacementsBuilder.py +7 -2
  5. edsl/coop/coop.py +32 -0
  6. edsl/enums.py +3 -0
  7. edsl/exceptions/jobs.py +1 -9
  8. edsl/exceptions/language_models.py +8 -4
  9. edsl/exceptions/questions.py +8 -11
  10. edsl/inference_services/DeepSeekService.py +18 -0
  11. edsl/inference_services/registry.py +2 -0
  12. edsl/jobs/Jobs.py +18 -11
  13. edsl/jobs/JobsPrompts.py +11 -1
  14. edsl/jobs/JobsRemoteInferenceHandler.py +1 -0
  15. edsl/jobs/JobsRemoteInferenceLogger.py +1 -1
  16. edsl/jobs/interviews/Interview.py +1 -1
  17. edsl/jobs/loggers/HTMLTableJobLogger.py +6 -1
  18. edsl/jobs/results_exceptions_handler.py +2 -7
  19. edsl/jobs/tasks/TaskHistory.py +49 -17
  20. edsl/language_models/LanguageModel.py +7 -4
  21. edsl/language_models/ModelList.py +1 -1
  22. edsl/language_models/model.py +49 -0
  23. edsl/questions/descriptors.py +5 -5
  24. edsl/results/Result.py +9 -3
  25. edsl/results/Results.py +1 -1
  26. edsl/scenarios/PdfExtractor.py +3 -6
  27. edsl/scenarios/Scenario.py +2 -1
  28. edsl/surveys/Survey.py +1 -1
  29. edsl/templates/error_reporting/base.html +2 -4
  30. edsl/templates/error_reporting/exceptions_table.html +35 -0
  31. edsl/templates/error_reporting/interview_details.html +67 -53
  32. edsl/templates/error_reporting/interviews.html +4 -17
  33. edsl/templates/error_reporting/overview.html +31 -5
  34. edsl/templates/error_reporting/performance_plot.html +1 -1
  35. {edsl-0.1.41.dist-info → edsl-0.1.42.dist-info}/METADATA +2 -2
  36. {edsl-0.1.41.dist-info → edsl-0.1.42.dist-info}/RECORD +38 -36
  37. {edsl-0.1.41.dist-info → edsl-0.1.42.dist-info}/LICENSE +0 -0
  38. {edsl-0.1.41.dist-info → edsl-0.1.42.dist-info}/WHEEL +0 -0
@@ -302,10 +302,10 @@ class QuestionOptionsDescriptor(BaseDescriptor):
302
302
  raise QuestionCreationValidationError(
303
303
  f"Question options must be a list (got {value})."
304
304
  )
305
- if len(value) > Settings.MAX_NUM_OPTIONS:
306
- raise QuestionCreationValidationError(
307
- f"Too many question options (got {value})."
308
- )
305
+ # if len(value) > Settings.MAX_NUM_OPTIONS:
306
+ # raise QuestionCreationValidationError(
307
+ # f"Too many question options (got {value})."
308
+ # )
309
309
  if len(value) < Settings.MIN_NUM_OPTIONS:
310
310
  raise QuestionCreationValidationError(
311
311
  f"Too few question options (got {value})."
@@ -408,7 +408,7 @@ class QuestionTextDescriptor(BaseDescriptor):
408
408
  # Automatically replace single braces with double braces
409
409
  # This is here because if the user is using an f-string, the double brace will get converted to a single brace.
410
410
  # This undoes that.
411
- value = re.sub(r"\{([^\{\}]+)\}", r"{{\1}}", value)
411
+ # value = re.sub(r"\{([^\{\}]+)\}", r"{{\1}}", value)
412
412
  return value
413
413
 
414
414
  # iterate through all doubles braces and check if they are valid python identifiers
edsl/results/Result.py CHANGED
@@ -78,7 +78,6 @@ class Result(Base, UserDict):
78
78
  self.question_to_attributes = (
79
79
  question_to_attributes or self._create_question_to_attributes(survey)
80
80
  )
81
-
82
81
  data = {
83
82
  "agent": agent,
84
83
  "scenario": scenario,
@@ -87,7 +86,7 @@ class Result(Base, UserDict):
87
86
  "answer": answer,
88
87
  "prompt": prompt or {},
89
88
  "raw_model_response": raw_model_response or {},
90
- "question_to_attributes": question_to_attributes,
89
+ "question_to_attributes": self.question_to_attributes,
91
90
  "generated_tokens": generated_tokens or {},
92
91
  "comments_dict": comments_dict or {},
93
92
  "cache_used_dict": cache_used_dict or {},
@@ -154,7 +153,9 @@ class Result(Base, UserDict):
154
153
  @staticmethod
155
154
  def _create_model_sub_dict(model) -> dict:
156
155
  return {
157
- "model": model.parameters | {"model": model.model},
156
+ "model": model.parameters
157
+ | {"model": model.model}
158
+ | {"inference_service": model._inference_service_},
158
159
  }
159
160
 
160
161
  @staticmethod
@@ -365,6 +366,10 @@ class Result(Base, UserDict):
365
366
  else prompt_obj.to_dict()
366
367
  )
367
368
  d[key] = new_prompt_dict
369
+
370
+ if self.indices is not None:
371
+ d["indices"] = self.indices
372
+
368
373
  if add_edsl_version:
369
374
  from edsl import __version__
370
375
 
@@ -414,6 +419,7 @@ class Result(Base, UserDict):
414
419
  comments_dict=json_dict.get("comments_dict", {}),
415
420
  cache_used_dict=json_dict.get("cache_used_dict", {}),
416
421
  cache_keys=json_dict.get("cache_keys", {}),
422
+ indices = json_dict.get("indices", None)
417
423
  )
418
424
  return result
419
425
 
edsl/results/Results.py CHANGED
@@ -647,7 +647,7 @@ class Results(UserList, Mixins, Base):
647
647
 
648
648
  >>> r = Results.example()
649
649
  >>> r.model_keys
650
- ['frequency_penalty', 'logprobs', 'max_tokens', 'model', 'model_index', 'presence_penalty', 'temperature', 'top_logprobs', 'top_p']
650
+ ['frequency_penalty', 'inference_service', 'logprobs', 'max_tokens', 'model', 'model_index', 'presence_penalty', 'temperature', 'top_logprobs', 'top_p']
651
651
  """
652
652
  return sorted(self._data_type_to_keys["model"])
653
653
 
@@ -2,14 +2,11 @@ import os
2
2
 
3
3
 
4
4
  class PdfExtractor:
5
- def __init__(self, pdf_path: str, parent_object: object):
5
+ def __init__(self, pdf_path: str):
6
6
  self.pdf_path = pdf_path
7
- self.constructor = parent_object.__class__
7
+ #self.constructor = parent_object.__class__
8
8
 
9
- def get_object(self) -> object:
10
- return self.constructor(self._get_pdf_dict())
11
-
12
- def _get_pdf_dict(self) -> dict:
9
+ def get_pdf_dict(self) -> dict:
13
10
  # Ensure the file exists
14
11
  import fitz
15
12
 
@@ -358,7 +358,8 @@ class Scenario(Base, UserDict, ScenarioHtmlMixin):
358
358
  def from_pdf(cls, pdf_path: str):
359
359
  from edsl.scenarios.PdfExtractor import PdfExtractor
360
360
 
361
- return PdfExtractor(pdf_path, cls).get_object()
361
+ extractor = PdfExtractor(pdf_path)
362
+ return Scenario(extractor.get_pdf_dict())
362
363
 
363
364
  @classmethod
364
365
  def from_docx(cls, docx_path: str) -> "Scenario":
edsl/surveys/Survey.py CHANGED
@@ -1281,4 +1281,4 @@ if __name__ == "__main__":
1281
1281
  import doctest
1282
1282
 
1283
1283
  # doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.SKIP)
1284
- doctest.testmod(optionflags=doctest.ELLIPSIS)
1284
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Exception Details</title>
6
+ <title>Exceptions Report</title>
7
7
  <style>
8
8
  {{ css }}
9
9
  </style>
@@ -15,9 +15,7 @@
15
15
  </head>
16
16
  <body>
17
17
  {% include 'overview.html' %}
18
- {% include 'exceptions_by_type.html' %}
19
- {% include 'exceptions_by_model.html' %}
20
- {% include 'exceptions_by_question_name.html' %}
18
+ {% include 'exceptions_table.html' %}
21
19
  {% include 'interviews.html' %}
22
20
  {% include 'performance_plot.html' %}
23
21
  </body>
@@ -0,0 +1,35 @@
1
+ <style>
2
+ th, td {
3
+ padding: 0 10px; /* This applies the padding uniformly to all td elements */
4
+ }
5
+ </style>
6
+
7
+ <table border="1">
8
+ <thead>
9
+ <tr>
10
+ <th>Exception Type</th>
11
+ <th>Service</th>
12
+ <th>Model</th>
13
+ <th>Question Name</th>
14
+ <th>Total</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ {% for (exception_type, service, model, question_name), count in exceptions_table.items() %}
19
+ <tr>
20
+ <td>{{ exception_type }}</td>
21
+ <td>{{ service }}</td>
22
+ <td>{{ model }}</td>
23
+ <td>{{ question_name }}</td>
24
+ <td>{{ count }}</td>
25
+ </tr>
26
+ {% endfor %}
27
+ </tbody>
28
+ </table>
29
+ <p>
30
+ <i>Note:</i> You may encounter repeated exceptions where retries were attempted.
31
+ You can modify the maximum number of attempts for failed API calls in `edsl/config.py`.
32
+ </p>
33
+ <p>
34
+ Click to expand the details below for information about each exception, including code for reproducing it.
35
+ </p>
@@ -1,43 +1,67 @@
1
- <div class="question">question_name: {{ question }}</div>
2
-
1
+ <style>
2
+ td {
3
+ padding: 0 10px; /* This applies the padding uniformly to all td elements */
4
+ }
5
+ .toggle-btn {
6
+ background-color: #4CAF50;
7
+ color: white;
8
+ border: none;
9
+ padding: 10px 20px;
10
+ text-align: center;
11
+ text-decoration: none;
12
+ display: inline-block;
13
+ font-size: 16px;
14
+ margin: 4px 2px;
15
+ cursor: pointer;
16
+ border-radius: 8px;
17
+ white-space: nowrap;
18
+ }
19
+ .toggle-btn span.collapse {
20
+ display: none;
21
+ }
22
+ .exception-content {
23
+ max-width: 100%; /* Adjust this value based on your layout */
24
+ overflow-x: auto; /* Enables horizontal scrolling */
25
+ }
26
+ </style>
3
27
 
4
- <h2>Exception details</h2>
28
+ <div class="question">question_name: {{ question }}</div>
5
29
 
6
30
  {% for exception_message in exceptions %}
7
31
  <div class="exception-detail">
8
- <div class="exception-header">
32
+ <div class="exception-header">
9
33
  <span class="exception-exception">Exception: {{ exception_message.name }}</span>
10
- <button class="toggle-btn">▼</button>
11
- </div>
12
- <div class="exception-content">
34
+ <button id="toggleBtn" class="toggle-btn" onclick="toggleButton(this)" aria-expanded="false">
35
+ <span class="expand"> ▼ </span>
36
+ </button>
37
+ </div>
38
+ <div class="exception-content">
13
39
  <table border="1">
14
- <tr>
15
- <th>Key</th>
16
- <th>Value</th>
17
- </tr>
18
40
  <tr>
19
41
  <td>Interview ID (index in results)</td>
20
42
  <td>{{ index }}</td>
21
43
  </tr>
22
44
  <tr>
23
- <td>Question name (question_name)</td>
45
+ <td>Question name</td>
24
46
  <td>{{ question }}</td>
25
47
  </tr>
26
-
27
48
  <tr>
28
- <td>Question type (question_type)</td>
49
+ <td>Question type</td>
29
50
  <td>{{ exception_message.question_type }}</td>
30
51
  </tr>
31
-
32
52
  <tr>
33
53
  <td>Human-readable question</td>
34
54
  <td>{{ interview.survey._get_question_by_name(question).html(
35
55
  scenario = interview.scenario,
36
56
  agent = interview.agent,
37
- answers = exception_message.answers)
38
-
57
+ answers = exception_message.answers
58
+ )
39
59
  }}</td>
40
60
  </tr>
61
+ <tr>
62
+ <td>User Prompt</td>
63
+ <td><pre>{{ exception_message.rendered_prompts['user_prompt'] }}</pre></td>
64
+ </tr>
41
65
  <tr>
42
66
  <td>Scenario</td>
43
67
  <td>{{ interview.scenario.__repr__() }}</td>
@@ -47,24 +71,20 @@
47
71
  <td>{{ interview.agent.__repr__() }}</td>
48
72
  </tr>
49
73
  <tr>
50
- <td>Model name</td>
51
- <td>{{ interview.model.model }}</td>
74
+ <td>System Prompt</td>
75
+ <td><pre>{{ exception_message.rendered_prompts['system_prompt'] }}</pre></td>
52
76
  </tr>
53
77
  <tr>
54
78
  <td>Inference service</td>
55
79
  <td>{{ interview.model._inference_service_ }}</td>
56
80
  </tr>
57
81
  <tr>
58
- <td>Model parameters</td>
59
- <td>{{ interview.model.__repr__() }}</td>
60
- </tr>
61
- <tr>
62
- <td>User Prompt</td>
63
- <td><pre>{{ exception_message.rendered_prompts['user_prompt'] }}</pre></td>
82
+ <td>Model name</td>
83
+ <td>{{ interview.model.model }}</td>
64
84
  </tr>
65
85
  <tr>
66
- <td>System Prompt</td>
67
- <td><pre>{{ exception_message.rendered_prompts['system_prompt'] }}</pre></td>
86
+ <td>Model parameters</td>
87
+ <td>{{ interview.model.__repr__() }}</td>
68
88
  </tr>
69
89
  <tr>
70
90
  <td>Raw model response</td>
@@ -77,7 +97,7 @@
77
97
  </td>
78
98
  </tr>
79
99
  <tr>
80
- <td>Code to (likely) reproduce the error</td>
100
+ <td>Code likely to reproduce the error</td>
81
101
  <td>
82
102
  <textarea id="codeToCopy" rows="10" cols="90">{{ exception_message.code_to_reproduce }}</textarea>
83
103
  <button onclick="copyCode()">Copy</button>
@@ -85,32 +105,26 @@
85
105
  </tr>
86
106
 
87
107
  </table>
88
-
89
-
90
- {% if exception_message.exception.__class__.__name__ == 'QuestionAnswerValidationError' %}
91
- <h3>Answer validation details</h3>
92
- <table border="1">
93
- <tr>
94
- <th>Field</th>
95
- <th>Value</th>
96
- </tr>
97
- {% for field, (explanation, open_tag, close_tag, value) in exception_message.exception.to_html_dict().items() %}
98
-
99
- <tr>
100
- <td>{{ field }}: ({{ explanation }})</td>
101
- <td><{{open_tag}}> {{ value | escape }} <{{close_tag}}></td>
102
- </tr>
103
- {% endfor %}
104
- </table>
105
- {% endif %}
106
-
107
- <div class="exception-time">Time: {{ exception_message.time }}</div>
108
- <div class="exception-traceback">Traceback:
109
- <text>
110
- <pre>{{ exception_message.traceback }}</pre>
111
- </text>
112
- </div>
108
+
109
+ {% if exception_message.exception.__class__.__name__ == 'QuestionAnswerValidationError' %}
110
+ <h3>Answer validation details</h3>
111
+ <table border="1">
112
+ {% for field, (open_tag, close_tag, value) in exception_message.exception.to_html_dict().items() %}
113
+ <tr>
114
+ <td>{{ field }}</td>
115
+ <td><{{ open_tag }}> {{ value | escape }} <{{ close_tag }}></td>
116
+ </tr>
117
+ {% endfor %}
118
+ </table>
119
+ {% endif %}
120
+ <br><br>
121
+ <div class="exception-time">Time: {{ exception_message.time }}</div>
122
+ <div class="exception-traceback">Traceback:
123
+ <text>
124
+ <pre>{{ exception_message.traceback }}</pre>
125
+ </text>
113
126
  </div>
114
127
  </div>
128
+ </div>
115
129
 
116
130
  {% endfor %}
@@ -1,19 +1,6 @@
1
-
2
- {% if interviews|length > max_interviews %}
3
- <h1>Only showing the first {{ max_interviews }} interviews with errors</h1>
4
- {% else %}
5
- <h1>Showing all interviews</h1>
6
- {% endif %}
7
-
1
+ <h2>Exceptions Details</h2>
8
2
  {% for index, interview in interviews.items() %}
9
- {% if index < max_interviews %}
10
- {% if interview.exceptions != {} %}
11
- <div class="interview">Interview: {{ index }} </div>
12
- Model: {{ interview.model.model }}
13
- <h1>Failing questions</h1>
14
- {% endif %}
15
- {% for question, exceptions in interview.exceptions.items() %}
16
- {% include 'interview_details.html' %}
17
- {% endfor %}
18
- {% endif %}
3
+ {% for question, exceptions in interview.exceptions.items() %}
4
+ {% include 'interview_details.html' %}
5
+ {% endfor %}
19
6
  {% endfor %}
@@ -1,5 +1,31 @@
1
- <h1>Overview</h1>
2
- <p>There were {{ interviews|length }} total interview(s). An 'interview' is the result of one survey, taken by one agent, with one model, with one scenario.</p>
3
- The number of interviews with any exceptions was {{ num_exceptions }}.</p>
4
- <p>For advice on dealing with exceptions on Expected Parrot,
5
- see <a href="https://docs.expectedparrot.com/en/latest/exceptions.html">here</a>.</p>
1
+ <style>
2
+ td {
3
+ padding: 0 10px; /* This applies the padding uniformly to all td elements */
4
+ }
5
+ </style>
6
+
7
+ <h1>Exceptions Report</h1>
8
+ <p>
9
+ This report summarizes exceptions encountered in the job that was run.
10
+ </p>
11
+ <p>
12
+ For advice on dealing with exceptions, please see the EDSL <a href="https://docs.expectedparrot.com/en/latest/exceptions.html">documentation</a> page. <br>
13
+ You can also post a question at the Expected Parrot <a href="https://discord.com/invite/mxAYkjfy9m">Discord channel</a>, open an issue on <a href="https://github.com/expectedparrot/edsl">GitHub</a>, or send an email to <a href="mailto:info@expectedparrot.com">info@expectedparrot.com</a>.
14
+ </p>
15
+
16
+ <h2>Overview</h2>
17
+ <table border="1">
18
+ <tbody>
19
+ <tr>
20
+ <td>Total interviews</td>
21
+ <td>{{ interviews|length }}</td>
22
+ </tr>
23
+ <tr>
24
+ <td>Interviews with exceptions</td>
25
+ <td>{{ num_exceptions }}</td>
26
+ </tr>
27
+ </tbody>
28
+ </table>
29
+ <p>
30
+ An "interview" is the result of one survey, taken by one agent, with one model and one scenario (if any).
31
+ </p>
@@ -1,2 +1,2 @@
1
- <h1>Performance Plot</h1>
1
+ <h2>Performance Plot</h2>
2
2
  {{ performance_plot_html }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edsl
3
- Version: 0.1.41
3
+ Version: 0.1.42
4
4
  Summary: Create and analyze LLM-based surveys
5
5
  Home-page: https://www.expectedparrot.com/
6
6
  License: MIT
@@ -107,5 +107,5 @@ See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest
107
107
 
108
108
  ## 💡 Contributions, feature requests & bugs
109
109
  Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
110
- 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).
110
+ 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)..
111
111