edsl 0.1.32__py3-none-any.whl → 0.1.33__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edsl/Base.py +9 -3
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +8 -3
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +40 -8
- edsl/agents/AgentList.py +43 -0
- edsl/agents/Invigilator.py +135 -219
- edsl/agents/InvigilatorBase.py +148 -59
- edsl/agents/{PromptConstructionMixin.py → PromptConstructor.py} +138 -89
- edsl/agents/__init__.py +1 -0
- edsl/auto/AutoStudy.py +117 -0
- edsl/auto/StageBase.py +230 -0
- edsl/auto/StageGenerateSurvey.py +178 -0
- edsl/auto/StageLabelQuestions.py +125 -0
- edsl/auto/StagePersona.py +61 -0
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
- edsl/auto/StagePersonaDimensionValues.py +74 -0
- edsl/auto/StagePersonaDimensions.py +69 -0
- edsl/auto/StageQuestions.py +73 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +224 -0
- edsl/config.py +47 -56
- edsl/coop/PriceFetcher.py +58 -0
- edsl/coop/coop.py +50 -7
- edsl/data/Cache.py +35 -1
- edsl/data_transfer_models.py +73 -38
- edsl/enums.py +4 -0
- edsl/exceptions/language_models.py +25 -1
- edsl/exceptions/questions.py +62 -5
- edsl/exceptions/results.py +4 -0
- edsl/inference_services/AnthropicService.py +13 -11
- edsl/inference_services/AwsBedrock.py +19 -17
- edsl/inference_services/AzureAI.py +37 -20
- edsl/inference_services/GoogleService.py +16 -12
- edsl/inference_services/GroqService.py +2 -0
- edsl/inference_services/InferenceServiceABC.py +58 -3
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OpenAIService.py +48 -54
- edsl/inference_services/TestService.py +80 -0
- edsl/inference_services/TogetherAIService.py +170 -0
- edsl/inference_services/models_available_cache.py +0 -6
- edsl/inference_services/registry.py +6 -0
- edsl/jobs/Answers.py +10 -12
- edsl/jobs/FailedQuestion.py +78 -0
- edsl/jobs/Jobs.py +37 -22
- edsl/jobs/buckets/BucketCollection.py +24 -15
- edsl/jobs/buckets/TokenBucket.py +93 -14
- edsl/jobs/interviews/Interview.py +366 -78
- edsl/jobs/interviews/{interview_exception_tracking.py → InterviewExceptionCollection.py} +14 -68
- edsl/jobs/interviews/InterviewExceptionEntry.py +85 -19
- edsl/jobs/runners/JobsRunnerAsyncio.py +146 -175
- edsl/jobs/runners/JobsRunnerStatus.py +331 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
- edsl/jobs/tasks/TaskHistory.py +148 -213
- edsl/language_models/LanguageModel.py +261 -156
- edsl/language_models/ModelList.py +2 -2
- edsl/language_models/RegisterLanguageModelsMeta.py +14 -29
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- edsl/language_models/registry.py +23 -6
- edsl/language_models/repair.py +0 -19
- edsl/language_models/utilities.py +61 -0
- edsl/notebooks/Notebook.py +20 -2
- edsl/prompts/Prompt.py +52 -2
- edsl/questions/AnswerValidatorMixin.py +23 -26
- edsl/questions/QuestionBase.py +330 -249
- edsl/questions/QuestionBaseGenMixin.py +133 -0
- edsl/questions/QuestionBasePromptsMixin.py +266 -0
- edsl/questions/QuestionBudget.py +99 -41
- edsl/questions/QuestionCheckBox.py +227 -35
- edsl/questions/QuestionExtract.py +98 -27
- edsl/questions/QuestionFreeText.py +52 -29
- edsl/questions/QuestionFunctional.py +7 -0
- edsl/questions/QuestionList.py +141 -22
- edsl/questions/QuestionMultipleChoice.py +159 -65
- edsl/questions/QuestionNumerical.py +88 -46
- edsl/questions/QuestionRank.py +182 -24
- edsl/questions/Quick.py +41 -0
- edsl/questions/RegisterQuestionsMeta.py +31 -12
- edsl/questions/ResponseValidatorABC.py +170 -0
- edsl/questions/__init__.py +3 -4
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +10 -5
- edsl/questions/derived/QuestionLinearScale.py +15 -2
- edsl/questions/derived/QuestionTopK.py +10 -1
- edsl/questions/derived/QuestionYesNo.py +24 -3
- edsl/questions/descriptors.py +43 -7
- edsl/questions/prompt_templates/question_budget.jinja +13 -0
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
- edsl/questions/prompt_templates/question_extract.jinja +11 -0
- edsl/questions/prompt_templates/question_free_text.jinja +3 -0
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
- edsl/questions/prompt_templates/question_list.jinja +17 -0
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
- edsl/questions/prompt_templates/question_numerical.jinja +37 -0
- edsl/questions/question_registry.py +6 -2
- edsl/questions/templates/__init__.py +0 -0
- edsl/questions/templates/budget/__init__.py +0 -0
- edsl/questions/templates/budget/answering_instructions.jinja +7 -0
- edsl/questions/templates/budget/question_presentation.jinja +7 -0
- edsl/questions/templates/checkbox/__init__.py +0 -0
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
- edsl/questions/templates/extract/__init__.py +0 -0
- edsl/questions/templates/extract/answering_instructions.jinja +7 -0
- edsl/questions/templates/extract/question_presentation.jinja +1 -0
- edsl/questions/templates/free_text/__init__.py +0 -0
- edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
- edsl/questions/templates/free_text/question_presentation.jinja +1 -0
- edsl/questions/templates/likert_five/__init__.py +0 -0
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
- edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
- edsl/questions/templates/linear_scale/__init__.py +0 -0
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
- edsl/questions/templates/list/__init__.py +0 -0
- edsl/questions/templates/list/answering_instructions.jinja +4 -0
- edsl/questions/templates/list/question_presentation.jinja +5 -0
- edsl/questions/templates/multiple_choice/__init__.py +0 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
- edsl/questions/templates/multiple_choice/html.jinja +0 -0
- edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
- edsl/questions/templates/numerical/__init__.py +0 -0
- edsl/questions/templates/numerical/answering_instructions.jinja +8 -0
- edsl/questions/templates/numerical/question_presentation.jinja +7 -0
- edsl/questions/templates/rank/__init__.py +0 -0
- edsl/questions/templates/rank/answering_instructions.jinja +11 -0
- edsl/questions/templates/rank/question_presentation.jinja +15 -0
- edsl/questions/templates/top_k/__init__.py +0 -0
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
- edsl/questions/templates/top_k/question_presentation.jinja +22 -0
- edsl/questions/templates/yes_no/__init__.py +0 -0
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
- edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
- edsl/results/Dataset.py +20 -0
- edsl/results/DatasetExportMixin.py +46 -48
- edsl/results/DatasetTree.py +145 -0
- edsl/results/Result.py +32 -5
- edsl/results/Results.py +135 -46
- edsl/results/ResultsDBMixin.py +3 -3
- edsl/results/Selector.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/FileStore.py +71 -10
- edsl/scenarios/Scenario.py +96 -25
- edsl/scenarios/ScenarioImageMixin.py +2 -2
- edsl/scenarios/ScenarioList.py +361 -39
- edsl/scenarios/ScenarioListExportMixin.py +9 -0
- edsl/scenarios/ScenarioListPdfMixin.py +150 -4
- edsl/study/SnapShot.py +8 -1
- edsl/study/Study.py +32 -0
- edsl/surveys/Rule.py +10 -1
- edsl/surveys/RuleCollection.py +21 -5
- edsl/surveys/Survey.py +637 -311
- edsl/surveys/SurveyExportMixin.py +71 -9
- edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
- edsl/surveys/SurveyQualtricsImport.py +75 -4
- edsl/surveys/instructions/ChangeInstruction.py +47 -0
- edsl/surveys/instructions/Instruction.py +34 -0
- edsl/surveys/instructions/InstructionCollection.py +77 -0
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/templates/error_reporting/base.html +24 -0
- edsl/templates/error_reporting/exceptions_by_model.html +35 -0
- edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
- edsl/templates/error_reporting/exceptions_by_type.html +17 -0
- edsl/templates/error_reporting/interview_details.html +116 -0
- edsl/templates/error_reporting/interviews.html +10 -0
- edsl/templates/error_reporting/overview.html +5 -0
- edsl/templates/error_reporting/performance_plot.html +2 -0
- edsl/templates/error_reporting/report.css +74 -0
- edsl/templates/error_reporting/report.html +118 -0
- edsl/templates/error_reporting/report.js +25 -0
- edsl/utilities/utilities.py +9 -1
- {edsl-0.1.32.dist-info → edsl-0.1.33.dist-info}/METADATA +5 -2
- edsl-0.1.33.dist-info/RECORD +295 -0
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -286
- edsl/jobs/interviews/retry_management.py +0 -37
- edsl/jobs/runners/JobsRunnerStatusMixin.py +0 -333
- edsl/utilities/gcp_bucket/simple_example.py +0 -9
- edsl-0.1.32.dist-info/RECORD +0 -209
- {edsl-0.1.32.dist-info → edsl-0.1.33.dist-info}/LICENSE +0 -0
- {edsl-0.1.32.dist-info → edsl-0.1.33.dist-info}/WHEEL +0 -0
edsl/jobs/tasks/TaskHistory.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
from edsl.jobs.tasks.task_status_enum import TaskStatus
|
2
1
|
from typing import List, Optional
|
3
2
|
from io import BytesIO
|
3
|
+
import webbrowser
|
4
|
+
import os
|
4
5
|
import base64
|
6
|
+
from importlib import resources
|
7
|
+
from edsl.jobs.tasks.task_status_enum import TaskStatus
|
5
8
|
|
6
9
|
|
7
10
|
class TaskHistory:
|
@@ -30,7 +33,12 @@ class TaskHistory:
|
|
30
33
|
|
31
34
|
from edsl.config import CONFIG
|
32
35
|
|
33
|
-
results = j.run(
|
36
|
+
results = j.run(
|
37
|
+
print_exceptions=False,
|
38
|
+
skip_retry=True,
|
39
|
+
cache=False,
|
40
|
+
raise_validation_errors=True,
|
41
|
+
)
|
34
42
|
|
35
43
|
return cls(results.task_history.total_interviews)
|
36
44
|
|
@@ -42,6 +50,18 @@ class TaskHistory:
|
|
42
50
|
"""
|
43
51
|
return [i.exceptions for k, i in self._interviews.items() if i.exceptions != {}]
|
44
52
|
|
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
|
+
|
45
65
|
@property
|
46
66
|
def indices(self):
|
47
67
|
return [k for k, i in self._interviews.items() if i.exceptions != {}]
|
@@ -70,6 +90,11 @@ class TaskHistory:
|
|
70
90
|
"""
|
71
91
|
return len(self.exceptions) > 0
|
72
92
|
|
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
|
+
|
73
98
|
def _repr_html_(self):
|
74
99
|
"""Return an HTML representation of the TaskHistory."""
|
75
100
|
from edsl.utilities.utilities import data_to_html
|
@@ -188,58 +213,14 @@ class TaskHistory:
|
|
188
213
|
plt.show()
|
189
214
|
|
190
215
|
def css(self):
|
191
|
-
|
192
|
-
|
193
|
-
|
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
|
-
}
|
216
|
+
env = resources.files("edsl").joinpath("templates/error_reporting")
|
217
|
+
css = env.joinpath("report.css").read_text()
|
218
|
+
return css
|
227
219
|
|
228
|
-
|
229
|
-
|
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
|
-
"""
|
220
|
+
def javascript(self):
|
221
|
+
env = resources.files("edsl").joinpath("templates/error_reporting")
|
222
|
+
js = env.joinpath("report.js").read_text()
|
223
|
+
return js
|
243
224
|
|
244
225
|
@property
|
245
226
|
def exceptions_by_type(self) -> dict:
|
@@ -248,206 +229,136 @@ class TaskHistory:
|
|
248
229
|
for interview in self.total_interviews:
|
249
230
|
for question_name, exceptions in interview.exceptions.items():
|
250
231
|
for exception in exceptions:
|
251
|
-
exception_type = exception
|
232
|
+
exception_type = exception.exception.__class__.__name__
|
233
|
+
# exception_type = exception["exception"]
|
234
|
+
# breakpoint()
|
252
235
|
if exception_type in exceptions_by_type:
|
253
236
|
exceptions_by_type[exception_type] += 1
|
254
237
|
else:
|
255
238
|
exceptions_by_type[exception_type] = 1
|
256
239
|
return exceptions_by_type
|
257
240
|
|
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
|
+
|
258
253
|
@property
|
259
254
|
def exceptions_by_question_name(self) -> dict:
|
260
255
|
"""Return a dictionary of exceptions tallied by question name."""
|
261
256
|
exceptions_by_question_name = {}
|
262
257
|
for interview in self.total_interviews:
|
263
258
|
for question_name, exceptions in interview.exceptions.items():
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
+
)
|
267
268
|
|
268
269
|
for question in self.total_interviews[0].survey.questions:
|
269
|
-
if
|
270
|
-
|
271
|
-
|
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
|
272
287
|
|
273
288
|
@property
|
274
289
|
def exceptions_by_model(self) -> dict:
|
275
290
|
"""Return a dictionary of exceptions tallied by model and question name."""
|
276
291
|
exceptions_by_model = {}
|
277
292
|
for interview in self.total_interviews:
|
278
|
-
model = interview.model
|
279
|
-
|
280
|
-
|
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
|
281
297
|
if interview.exceptions != {}:
|
282
|
-
exceptions_by_model[model
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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
|
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
|
299
308
|
|
309
|
+
def generate_html_report(self, css: Optional[str]):
|
300
310
|
performance_plot_html = self.plot(num_periods=100, get_embedded_html=True)
|
301
311
|
|
302
312
|
if css is None:
|
303
313
|
css = self.css()
|
304
314
|
|
305
|
-
models_used = set([i.model for index, i in self._interviews.items()])
|
315
|
+
models_used = set([i.model.model for index, i in self._interviews.items()])
|
306
316
|
|
307
|
-
|
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() }}
|
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
|
-
)
|
317
|
+
from jinja2 import Environment, FileSystemLoader
|
318
|
+
from edsl.TemplateLoader import TemplateLoader
|
429
319
|
|
430
|
-
|
320
|
+
env = Environment(loader=TemplateLoader("edsl", "templates/error_reporting"))
|
321
|
+
|
322
|
+
# Load and render a template
|
323
|
+
template = env.get_template("base.html")
|
324
|
+
# rendered_template = template.render(your_data=your_data)
|
431
325
|
|
432
326
|
# Render the template with data
|
433
327
|
output = template.render(
|
434
328
|
interviews=self._interviews,
|
435
329
|
css=css,
|
330
|
+
javascript=self.javascript(),
|
436
331
|
num_exceptions=len(self.exceptions),
|
437
332
|
performance_plot_html=performance_plot_html,
|
438
333
|
exceptions_by_type=self.exceptions_by_type,
|
439
334
|
exceptions_by_question_name=self.exceptions_by_question_name,
|
440
335
|
exceptions_by_model=self.exceptions_by_model,
|
336
|
+
exceptions_by_service=self.exceptions_by_service,
|
441
337
|
models_used=models_used,
|
442
338
|
)
|
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)
|
443
357
|
|
444
358
|
# Save the rendered output to a file
|
445
359
|
with open("output.html", "w") as f:
|
446
360
|
f.write(output)
|
447
361
|
|
448
|
-
if css is None:
|
449
|
-
css = self.css()
|
450
|
-
|
451
362
|
if filename is None:
|
452
363
|
current_directory = os.getcwd()
|
453
364
|
filename = tempfile.NamedTemporaryFile(
|
@@ -456,10 +367,7 @@ class TaskHistory:
|
|
456
367
|
|
457
368
|
with open(filename, "w") as f:
|
458
369
|
with open(filename, "w") as f:
|
459
|
-
# f.write(html_header)
|
460
|
-
# f.write(self._repr_html_())
|
461
370
|
f.write(output)
|
462
|
-
# f.write(html_footer)
|
463
371
|
|
464
372
|
if is_notebook():
|
465
373
|
import html
|
@@ -472,17 +380,44 @@ class TaskHistory:
|
|
472
380
|
<iframe srcdoc="{ escaped_output }" style="width: 800px; height: 600px;"></iframe>
|
473
381
|
"""
|
474
382
|
display(HTML(iframe))
|
475
|
-
# display(HTML(output))
|
476
383
|
else:
|
477
384
|
print(f"Exception report saved to {filename}")
|
478
|
-
import webbrowser
|
479
|
-
import os
|
480
385
|
|
386
|
+
if open_in_browser:
|
481
387
|
webbrowser.open(f"file://{os.path.abspath(filename)}")
|
482
388
|
|
483
389
|
if return_link:
|
484
390
|
return filename
|
485
391
|
|
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
|
+
|
486
421
|
|
487
422
|
if __name__ == "__main__":
|
488
423
|
import doctest
|