edsl 0.1.33__py3-none-any.whl → 0.1.33.dev1__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 (180) hide show
  1. edsl/Base.py +3 -9
  2. edsl/__init__.py +3 -8
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +8 -40
  5. edsl/agents/AgentList.py +0 -43
  6. edsl/agents/Invigilator.py +219 -135
  7. edsl/agents/InvigilatorBase.py +59 -148
  8. edsl/agents/{PromptConstructor.py → PromptConstructionMixin.py} +89 -138
  9. edsl/agents/__init__.py +0 -1
  10. edsl/config.py +56 -47
  11. edsl/coop/coop.py +7 -50
  12. edsl/data/Cache.py +1 -35
  13. edsl/data_transfer_models.py +38 -73
  14. edsl/enums.py +0 -4
  15. edsl/exceptions/language_models.py +1 -25
  16. edsl/exceptions/questions.py +5 -62
  17. edsl/exceptions/results.py +0 -4
  18. edsl/inference_services/AnthropicService.py +11 -13
  19. edsl/inference_services/AwsBedrock.py +17 -19
  20. edsl/inference_services/AzureAI.py +20 -37
  21. edsl/inference_services/GoogleService.py +12 -16
  22. edsl/inference_services/GroqService.py +0 -2
  23. edsl/inference_services/InferenceServiceABC.py +3 -58
  24. edsl/inference_services/OpenAIService.py +54 -48
  25. edsl/inference_services/models_available_cache.py +6 -0
  26. edsl/inference_services/registry.py +0 -6
  27. edsl/jobs/Answers.py +12 -10
  28. edsl/jobs/Jobs.py +21 -36
  29. edsl/jobs/buckets/BucketCollection.py +15 -24
  30. edsl/jobs/buckets/TokenBucket.py +14 -93
  31. edsl/jobs/interviews/Interview.py +78 -366
  32. edsl/jobs/interviews/InterviewExceptionEntry.py +19 -85
  33. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +286 -0
  34. edsl/jobs/interviews/{InterviewExceptionCollection.py → interview_exception_tracking.py} +68 -14
  35. edsl/jobs/interviews/retry_management.py +37 -0
  36. edsl/jobs/runners/JobsRunnerAsyncio.py +175 -146
  37. edsl/jobs/runners/JobsRunnerStatusMixin.py +333 -0
  38. edsl/jobs/tasks/QuestionTaskCreator.py +23 -30
  39. edsl/jobs/tasks/TaskHistory.py +213 -148
  40. edsl/language_models/LanguageModel.py +156 -261
  41. edsl/language_models/ModelList.py +2 -2
  42. edsl/language_models/RegisterLanguageModelsMeta.py +29 -14
  43. edsl/language_models/registry.py +6 -23
  44. edsl/language_models/repair.py +19 -0
  45. edsl/prompts/Prompt.py +2 -52
  46. edsl/questions/AnswerValidatorMixin.py +26 -23
  47. edsl/questions/QuestionBase.py +249 -329
  48. edsl/questions/QuestionBudget.py +41 -99
  49. edsl/questions/QuestionCheckBox.py +35 -227
  50. edsl/questions/QuestionExtract.py +27 -98
  51. edsl/questions/QuestionFreeText.py +29 -52
  52. edsl/questions/QuestionFunctional.py +0 -7
  53. edsl/questions/QuestionList.py +22 -141
  54. edsl/questions/QuestionMultipleChoice.py +65 -159
  55. edsl/questions/QuestionNumerical.py +46 -88
  56. edsl/questions/QuestionRank.py +24 -182
  57. edsl/questions/RegisterQuestionsMeta.py +12 -31
  58. edsl/questions/__init__.py +4 -3
  59. edsl/questions/derived/QuestionLikertFive.py +5 -10
  60. edsl/questions/derived/QuestionLinearScale.py +2 -15
  61. edsl/questions/derived/QuestionTopK.py +1 -10
  62. edsl/questions/derived/QuestionYesNo.py +3 -24
  63. edsl/questions/descriptors.py +7 -43
  64. edsl/questions/question_registry.py +2 -6
  65. edsl/results/Dataset.py +0 -20
  66. edsl/results/DatasetExportMixin.py +48 -46
  67. edsl/results/Result.py +5 -32
  68. edsl/results/Results.py +46 -135
  69. edsl/results/ResultsDBMixin.py +3 -3
  70. edsl/scenarios/FileStore.py +10 -71
  71. edsl/scenarios/Scenario.py +25 -96
  72. edsl/scenarios/ScenarioImageMixin.py +2 -2
  73. edsl/scenarios/ScenarioList.py +39 -361
  74. edsl/scenarios/ScenarioListExportMixin.py +0 -9
  75. edsl/scenarios/ScenarioListPdfMixin.py +4 -150
  76. edsl/study/SnapShot.py +1 -8
  77. edsl/study/Study.py +0 -32
  78. edsl/surveys/Rule.py +1 -10
  79. edsl/surveys/RuleCollection.py +5 -21
  80. edsl/surveys/Survey.py +310 -636
  81. edsl/surveys/SurveyExportMixin.py +9 -71
  82. edsl/surveys/SurveyFlowVisualizationMixin.py +1 -2
  83. edsl/surveys/SurveyQualtricsImport.py +4 -75
  84. edsl/utilities/gcp_bucket/simple_example.py +9 -0
  85. edsl/utilities/utilities.py +1 -9
  86. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/METADATA +2 -5
  87. edsl-0.1.33.dev1.dist-info/RECORD +209 -0
  88. edsl/TemplateLoader.py +0 -24
  89. edsl/auto/AutoStudy.py +0 -117
  90. edsl/auto/StageBase.py +0 -230
  91. edsl/auto/StageGenerateSurvey.py +0 -178
  92. edsl/auto/StageLabelQuestions.py +0 -125
  93. edsl/auto/StagePersona.py +0 -61
  94. edsl/auto/StagePersonaDimensionValueRanges.py +0 -88
  95. edsl/auto/StagePersonaDimensionValues.py +0 -74
  96. edsl/auto/StagePersonaDimensions.py +0 -69
  97. edsl/auto/StageQuestions.py +0 -73
  98. edsl/auto/SurveyCreatorPipeline.py +0 -21
  99. edsl/auto/utilities.py +0 -224
  100. edsl/coop/PriceFetcher.py +0 -58
  101. edsl/inference_services/MistralAIService.py +0 -120
  102. edsl/inference_services/TestService.py +0 -80
  103. edsl/inference_services/TogetherAIService.py +0 -170
  104. edsl/jobs/FailedQuestion.py +0 -78
  105. edsl/jobs/runners/JobsRunnerStatus.py +0 -331
  106. edsl/language_models/fake_openai_call.py +0 -15
  107. edsl/language_models/fake_openai_service.py +0 -61
  108. edsl/language_models/utilities.py +0 -61
  109. edsl/questions/QuestionBaseGenMixin.py +0 -133
  110. edsl/questions/QuestionBasePromptsMixin.py +0 -266
  111. edsl/questions/Quick.py +0 -41
  112. edsl/questions/ResponseValidatorABC.py +0 -170
  113. edsl/questions/decorators.py +0 -21
  114. edsl/questions/prompt_templates/question_budget.jinja +0 -13
  115. edsl/questions/prompt_templates/question_checkbox.jinja +0 -32
  116. edsl/questions/prompt_templates/question_extract.jinja +0 -11
  117. edsl/questions/prompt_templates/question_free_text.jinja +0 -3
  118. edsl/questions/prompt_templates/question_linear_scale.jinja +0 -11
  119. edsl/questions/prompt_templates/question_list.jinja +0 -17
  120. edsl/questions/prompt_templates/question_multiple_choice.jinja +0 -33
  121. edsl/questions/prompt_templates/question_numerical.jinja +0 -37
  122. edsl/questions/templates/__init__.py +0 -0
  123. edsl/questions/templates/budget/__init__.py +0 -0
  124. edsl/questions/templates/budget/answering_instructions.jinja +0 -7
  125. edsl/questions/templates/budget/question_presentation.jinja +0 -7
  126. edsl/questions/templates/checkbox/__init__.py +0 -0
  127. edsl/questions/templates/checkbox/answering_instructions.jinja +0 -10
  128. edsl/questions/templates/checkbox/question_presentation.jinja +0 -22
  129. edsl/questions/templates/extract/__init__.py +0 -0
  130. edsl/questions/templates/extract/answering_instructions.jinja +0 -7
  131. edsl/questions/templates/extract/question_presentation.jinja +0 -1
  132. edsl/questions/templates/free_text/__init__.py +0 -0
  133. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  134. edsl/questions/templates/free_text/question_presentation.jinja +0 -1
  135. edsl/questions/templates/likert_five/__init__.py +0 -0
  136. edsl/questions/templates/likert_five/answering_instructions.jinja +0 -10
  137. edsl/questions/templates/likert_five/question_presentation.jinja +0 -12
  138. edsl/questions/templates/linear_scale/__init__.py +0 -0
  139. edsl/questions/templates/linear_scale/answering_instructions.jinja +0 -5
  140. edsl/questions/templates/linear_scale/question_presentation.jinja +0 -5
  141. edsl/questions/templates/list/__init__.py +0 -0
  142. edsl/questions/templates/list/answering_instructions.jinja +0 -4
  143. edsl/questions/templates/list/question_presentation.jinja +0 -5
  144. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  145. edsl/questions/templates/multiple_choice/answering_instructions.jinja +0 -9
  146. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  147. edsl/questions/templates/multiple_choice/question_presentation.jinja +0 -12
  148. edsl/questions/templates/numerical/__init__.py +0 -0
  149. edsl/questions/templates/numerical/answering_instructions.jinja +0 -8
  150. edsl/questions/templates/numerical/question_presentation.jinja +0 -7
  151. edsl/questions/templates/rank/__init__.py +0 -0
  152. edsl/questions/templates/rank/answering_instructions.jinja +0 -11
  153. edsl/questions/templates/rank/question_presentation.jinja +0 -15
  154. edsl/questions/templates/top_k/__init__.py +0 -0
  155. edsl/questions/templates/top_k/answering_instructions.jinja +0 -8
  156. edsl/questions/templates/top_k/question_presentation.jinja +0 -22
  157. edsl/questions/templates/yes_no/__init__.py +0 -0
  158. edsl/questions/templates/yes_no/answering_instructions.jinja +0 -6
  159. edsl/questions/templates/yes_no/question_presentation.jinja +0 -12
  160. edsl/results/DatasetTree.py +0 -145
  161. edsl/results/Selector.py +0 -118
  162. edsl/results/tree_explore.py +0 -115
  163. edsl/surveys/instructions/ChangeInstruction.py +0 -47
  164. edsl/surveys/instructions/Instruction.py +0 -34
  165. edsl/surveys/instructions/InstructionCollection.py +0 -77
  166. edsl/surveys/instructions/__init__.py +0 -0
  167. edsl/templates/error_reporting/base.html +0 -24
  168. edsl/templates/error_reporting/exceptions_by_model.html +0 -35
  169. edsl/templates/error_reporting/exceptions_by_question_name.html +0 -17
  170. edsl/templates/error_reporting/exceptions_by_type.html +0 -17
  171. edsl/templates/error_reporting/interview_details.html +0 -116
  172. edsl/templates/error_reporting/interviews.html +0 -10
  173. edsl/templates/error_reporting/overview.html +0 -5
  174. edsl/templates/error_reporting/performance_plot.html +0 -2
  175. edsl/templates/error_reporting/report.css +0 -74
  176. edsl/templates/error_reporting/report.html +0 -118
  177. edsl/templates/error_reporting/report.js +0 -25
  178. edsl-0.1.33.dist-info/RECORD +0 -295
  179. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/LICENSE +0 -0
  180. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/WHEEL +0 -0
@@ -1,10 +1,7 @@
1
+ from edsl.jobs.tasks.task_status_enum import TaskStatus
1
2
  from typing import List, Optional
2
3
  from io import BytesIO
3
- import webbrowser
4
- import os
5
4
  import base64
6
- from importlib import resources
7
- from edsl.jobs.tasks.task_status_enum import TaskStatus
8
5
 
9
6
 
10
7
  class TaskHistory:
@@ -33,12 +30,7 @@ class TaskHistory:
33
30
 
34
31
  from edsl.config import CONFIG
35
32
 
36
- results = j.run(
37
- print_exceptions=False,
38
- skip_retry=True,
39
- cache=False,
40
- raise_validation_errors=True,
41
- )
33
+ results = j.run(print_exceptions=False, skip_retry=True, cache=False)
42
34
 
43
35
  return cls(results.task_history.total_interviews)
44
36
 
@@ -50,18 +42,6 @@ class TaskHistory:
50
42
  """
51
43
  return [i.exceptions for k, i in self._interviews.items() if i.exceptions != {}]
52
44
 
53
- @property
54
- def unfixed_exceptions(self):
55
- """
56
- >>> len(TaskHistory.example().unfixed_exceptions)
57
- 4
58
- """
59
- return [
60
- i.exceptions
61
- for k, i in self._interviews.items()
62
- if i.exceptions.num_unfixed() > 0
63
- ]
64
-
65
45
  @property
66
46
  def indices(self):
67
47
  return [k for k, i in self._interviews.items() if i.exceptions != {}]
@@ -90,11 +70,6 @@ class TaskHistory:
90
70
  """
91
71
  return len(self.exceptions) > 0
92
72
 
93
- @property
94
- def has_unfixed_exceptions(self) -> bool:
95
- """Return True if there are any exceptions."""
96
- return len(self.unfixed_exceptions) > 0
97
-
98
73
  def _repr_html_(self):
99
74
  """Return an HTML representation of the TaskHistory."""
100
75
  from edsl.utilities.utilities import data_to_html
@@ -213,14 +188,58 @@ class TaskHistory:
213
188
  plt.show()
214
189
 
215
190
  def css(self):
216
- env = resources.files("edsl").joinpath("templates/error_reporting")
217
- css = env.joinpath("report.css").read_text()
218
- return css
191
+ return """
192
+ body {
193
+ font-family: Arial, sans-serif;
194
+ line-height: 1.6;
195
+ background-color: #f9f9f9;
196
+ color: #333;
197
+ margin: 20px;
198
+ }
199
+
200
+ .interview {
201
+ font-size: 1.5em;
202
+ margin-bottom: 10px;
203
+ padding: 10px;
204
+ background-color: #e3f2fd;
205
+ border-left: 5px solid #2196f3;
206
+ }
207
+
208
+ .question {
209
+ font-size: 1.2em;
210
+ margin-bottom: 10px;
211
+ padding: 10px;
212
+ background-color: #fff9c4;
213
+ border-left: 5px solid #ffeb3b;
214
+ }
215
+
216
+ .exception-detail {
217
+ margin-bottom: 10px;
218
+ padding: 10px;
219
+ background-color: #ffebee;
220
+ border-left: 5px solid #f44336;
221
+ }
222
+
223
+ .question-detail {
224
+ border: 3px solid black; /* Adjust the thickness by changing the number */
225
+ padding: 10px; /* Optional: Adds some padding inside the border */
226
+ }
219
227
 
220
- def javascript(self):
221
- env = resources.files("edsl").joinpath("templates/error_reporting")
222
- js = env.joinpath("report.js").read_text()
223
- return js
228
+ .exception-detail div {
229
+ margin-bottom: 5px;
230
+ }
231
+
232
+ .exception-exception {
233
+ font-weight: bold;
234
+ color: #d32f2f;
235
+ }
236
+
237
+ .exception-time,
238
+ .exception-traceback {
239
+ font-style: italic;
240
+ color: #555;
241
+ }
242
+ """
224
243
 
225
244
  @property
226
245
  def exceptions_by_type(self) -> dict:
@@ -229,136 +248,206 @@ class TaskHistory:
229
248
  for interview in self.total_interviews:
230
249
  for question_name, exceptions in interview.exceptions.items():
231
250
  for exception in exceptions:
232
- exception_type = exception.exception.__class__.__name__
233
- # exception_type = exception["exception"]
234
- # breakpoint()
251
+ exception_type = exception["exception"]
235
252
  if exception_type in exceptions_by_type:
236
253
  exceptions_by_type[exception_type] += 1
237
254
  else:
238
255
  exceptions_by_type[exception_type] = 1
239
256
  return exceptions_by_type
240
257
 
241
- @property
242
- def exceptions_by_service(self) -> dict:
243
- """Return a dictionary of exceptions tallied by service."""
244
- exceptions_by_service = {}
245
- for interview in self.total_interviews:
246
- service = interview.model._inference_service_
247
- if service not in exceptions_by_service:
248
- exceptions_by_service[service] = 0
249
- if interview.exceptions != {}:
250
- exceptions_by_service[service] += len(interview.exceptions)
251
- return exceptions_by_service
252
-
253
258
  @property
254
259
  def exceptions_by_question_name(self) -> dict:
255
260
  """Return a dictionary of exceptions tallied by question name."""
256
261
  exceptions_by_question_name = {}
257
262
  for interview in self.total_interviews:
258
263
  for question_name, exceptions in interview.exceptions.items():
259
- question_type = interview.survey.get_question(
260
- question_name
261
- ).question_type
262
- # breakpoint()
263
- if (question_name, question_type) not in exceptions_by_question_name:
264
- exceptions_by_question_name[(question_name, question_type)] = 0
265
- exceptions_by_question_name[(question_name, question_type)] += len(
266
- exceptions
267
- )
264
+ if question_name not in exceptions_by_question_name:
265
+ exceptions_by_question_name[question_name] = 0
266
+ exceptions_by_question_name[question_name] += len(exceptions)
268
267
 
269
268
  for question in self.total_interviews[0].survey.questions:
270
- if (
271
- question.question_name,
272
- question.question_type,
273
- ) not in exceptions_by_question_name:
274
- exceptions_by_question_name[
275
- (question.question_name, question.question_type)
276
- ] = 0
277
-
278
- sorted_exceptions_by_question_name = {
279
- k: v
280
- for k, v in sorted(
281
- exceptions_by_question_name.items(),
282
- key=lambda item: item[1],
283
- reverse=True,
284
- )
285
- }
286
- return sorted_exceptions_by_question_name
269
+ if question.question_name not in exceptions_by_question_name:
270
+ exceptions_by_question_name[question.question_name] = 0
271
+ return exceptions_by_question_name
287
272
 
288
273
  @property
289
274
  def exceptions_by_model(self) -> dict:
290
275
  """Return a dictionary of exceptions tallied by model and question name."""
291
276
  exceptions_by_model = {}
292
277
  for interview in self.total_interviews:
293
- model = interview.model.model
294
- service = interview.model._inference_service_
295
- if (service, model) not in exceptions_by_model:
296
- exceptions_by_model[(service, model)] = 0
278
+ model = interview.model
279
+ if model not in exceptions_by_model:
280
+ exceptions_by_model[model.model] = 0
297
281
  if interview.exceptions != {}:
298
- exceptions_by_model[(service, model)] += len(interview.exceptions)
299
-
300
- # sort the exceptions by model
301
- sorted_exceptions_by_model = {
302
- k: v
303
- for k, v in sorted(
304
- exceptions_by_model.items(), key=lambda item: item[1], reverse=True
305
- )
306
- }
307
- return sorted_exceptions_by_model
282
+ exceptions_by_model[model.model] += len(interview.exceptions)
283
+ return exceptions_by_model
284
+
285
+ def html(
286
+ self,
287
+ filename: Optional[str] = None,
288
+ return_link=False,
289
+ css=None,
290
+ cta="Open Report in New Tab",
291
+ ):
292
+ """Return an HTML report."""
293
+
294
+ from IPython.display import display, HTML
295
+ import tempfile
296
+ import os
297
+ from edsl.utilities.utilities import is_notebook
298
+ from jinja2 import Template
308
299
 
309
- def generate_html_report(self, css: Optional[str]):
310
300
  performance_plot_html = self.plot(num_periods=100, get_embedded_html=True)
311
301
 
312
302
  if css is None:
313
303
  css = self.css()
314
304
 
315
- models_used = set([i.model.model for index, i in self._interviews.items()])
316
-
317
- from jinja2 import Environment, FileSystemLoader
318
- from edsl.TemplateLoader import TemplateLoader
305
+ models_used = set([i.model for index, i in self._interviews.items()])
319
306
 
320
- env = Environment(loader=TemplateLoader("edsl", "templates/error_reporting"))
307
+ template = Template(
308
+ """
309
+ <!DOCTYPE html>
310
+ <html lang="en">
311
+ <head>
312
+ <meta charset="UTF-8">
313
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
314
+ <title>Exception Details</title>
315
+ <style>
316
+ {{ css }}
317
+ </style>
318
+ </head>
319
+ <body>
320
+ <h1>Overview</h1>
321
+ <p>There were {{ interviews|length }} total interviews. The number of interviews with exceptions was {{ num_exceptions }}.</p>
322
+ <p>The models used were: {{ models_used }}.</p>
323
+ <p>For documentation on dealing with exceptions on Expected Parrot,
324
+ see <a href="https://docs.expectedparrot.com/en/latest/exceptions.html">here</a>.</p>
325
+
326
+ <h2>Exceptions by Type</h2>
327
+ <table>
328
+ <thead>
329
+ <tr>
330
+ <th>Exception Type</th>
331
+ <th>Number</th>
332
+ </tr>
333
+ </thead>
334
+ <tbody>
335
+ {% for exception_type, exceptions in exceptions_by_type.items() %}
336
+ <tr>
337
+ <td>{{ exception_type }}</td>
338
+ <td>{{ exceptions }}</td>
339
+ </tr>
340
+ {% endfor %}
341
+ </tbody>
342
+ </table>
343
+
344
+
345
+ <h2>Exceptions by Model</h2>
346
+ <table>
347
+ <thead>
348
+ <tr>
349
+ <th>Model</th>
350
+ <th>Number</th>
351
+ </tr>
352
+ </thead>
353
+ <tbody>
354
+ {% for model, exceptions in exceptions_by_model.items() %}
355
+ <tr>
356
+ <td>{{ model }}</td>
357
+ <td>{{ exceptions }}</td>
358
+ </tr>
359
+ {% endfor %}
360
+ </tbody>
361
+ </table>
362
+
363
+
364
+ <h2>Exceptions by Question Name</h2>
365
+ <table>
366
+ <thead>
367
+ <tr>
368
+ <th>Question Name</th>
369
+ <th>Number of Exceptions</th>
370
+ </tr>
371
+ </thead>
372
+ <tbody>
373
+ {% for question_name, exception_count in exceptions_by_question_name.items() %}
374
+ <tr>
375
+ <td>{{ question_name }}</td>
376
+ <td>{{ exception_count }}</td>
377
+ </tr>
378
+ {% endfor %}
379
+ </tbody>
380
+ </table>
381
+
382
+
383
+ {% for index, interview in interviews.items() %}
384
+ {% if interview.exceptions != {} %}
385
+ <div class="interview">Interview: {{ index }} </div>
386
+ <h1>Failing questions</h1>
387
+ {% endif %}
388
+ {% for question, exceptions in interview.exceptions.items() %}
389
+ <div class="question">question_name: {{ question }}</div>
390
+
391
+ <h2>Question</h2>
392
+ <div class="question-detail">
393
+ {{ interview.survey.get_question(question).html(interview.scenario,interview.agent) }}
394
+ </div>
395
+
396
+ <h2>Scenario</h2>
397
+ <div class="scenario">
398
+ {{ interview.scenario._repr_html_() }}
399
+ </div>
400
+
401
+ <h2>Agent</h2>
402
+ <div class="agent">
403
+ {{ interview.agent._repr_html_() }}
404
+ </div>
405
+
406
+ <h2>Model</h2>
407
+ <div class="model">
408
+ {{ interview.model._repr_html_() }}
409
+ </div>
410
+
411
+ <h2>Exception details</h2>
412
+
413
+ {% for exception_message in exceptions %}
414
+ <div class="exception-detail">
415
+ <div class="exception-exception">Exception: {{ exception_message.exception }}</div>
416
+ <div class="exception-time">Time: {{ exception_message.time }}</div>
417
+ <div class="exception-traceback">Traceback: <pre>{{ exception_message.traceback }} </pre></div>
418
+ </div>
419
+ {% endfor %}
420
+ {% endfor %}
421
+ {% endfor %}
422
+
423
+ <h1>Performance Plot</h1>
424
+ {{ performance_plot_html }}
425
+ </body>
426
+ </html>
427
+ """
428
+ )
321
429
 
322
- # Load and render a template
323
- template = env.get_template("base.html")
324
- # rendered_template = template.render(your_data=your_data)
430
+ # breakpoint()
325
431
 
326
432
  # Render the template with data
327
433
  output = template.render(
328
434
  interviews=self._interviews,
329
435
  css=css,
330
- javascript=self.javascript(),
331
436
  num_exceptions=len(self.exceptions),
332
437
  performance_plot_html=performance_plot_html,
333
438
  exceptions_by_type=self.exceptions_by_type,
334
439
  exceptions_by_question_name=self.exceptions_by_question_name,
335
440
  exceptions_by_model=self.exceptions_by_model,
336
- exceptions_by_service=self.exceptions_by_service,
337
441
  models_used=models_used,
338
442
  )
339
- return output
340
-
341
- def html(
342
- self,
343
- filename: Optional[str] = None,
344
- return_link=False,
345
- css=None,
346
- cta="Open Report in New Tab",
347
- open_in_browser=True,
348
- ):
349
- """Return an HTML report."""
350
-
351
- from IPython.display import display, HTML
352
- import tempfile
353
- import os
354
- from edsl.utilities.utilities import is_notebook
355
-
356
- output = self.generate_html_report(css)
357
443
 
358
444
  # Save the rendered output to a file
359
445
  with open("output.html", "w") as f:
360
446
  f.write(output)
361
447
 
448
+ if css is None:
449
+ css = self.css()
450
+
362
451
  if filename is None:
363
452
  current_directory = os.getcwd()
364
453
  filename = tempfile.NamedTemporaryFile(
@@ -367,7 +456,10 @@ class TaskHistory:
367
456
 
368
457
  with open(filename, "w") as f:
369
458
  with open(filename, "w") as f:
459
+ # f.write(html_header)
460
+ # f.write(self._repr_html_())
370
461
  f.write(output)
462
+ # f.write(html_footer)
371
463
 
372
464
  if is_notebook():
373
465
  import html
@@ -380,44 +472,17 @@ class TaskHistory:
380
472
  <iframe srcdoc="{ escaped_output }" style="width: 800px; height: 600px;"></iframe>
381
473
  """
382
474
  display(HTML(iframe))
475
+ # display(HTML(output))
383
476
  else:
384
477
  print(f"Exception report saved to {filename}")
478
+ import webbrowser
479
+ import os
385
480
 
386
- if open_in_browser:
387
481
  webbrowser.open(f"file://{os.path.abspath(filename)}")
388
482
 
389
483
  if return_link:
390
484
  return filename
391
485
 
392
- def notebook(self):
393
- """Create a notebook with the HTML content embedded in the first cell, then delete the cell content while keeping the output."""
394
- from nbformat import v4 as nbf
395
- from nbconvert.preprocessors import ExecutePreprocessor
396
- import nbformat
397
- import os
398
-
399
- # Use the existing html method to generate the HTML content
400
- output_html = self.generate_html_report(css=None)
401
- nb = nbf.new_notebook()
402
-
403
- # Add a code cell that renders the HTML content
404
- code_cell = nbf.new_code_cell(
405
- f"""
406
- from IPython.display import HTML, display
407
- display(HTML('''{output_html}'''))
408
- """
409
- )
410
- nb.cells.append(code_cell)
411
-
412
- # Execute the notebook
413
- ep = ExecutePreprocessor(timeout=600, kernel_name="python3")
414
- ep.preprocess(nb, {"metadata": {"path": os.getcwd()}})
415
-
416
- # After execution, clear the cell's source code
417
- nb.cells[0].source = ""
418
-
419
- return nb
420
-
421
486
 
422
487
  if __name__ == "__main__":
423
488
  import doctest