edsl 0.1.31.dev4__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 +136 -221
- edsl/agents/InvigilatorBase.py +148 -59
- edsl/agents/{PromptConstructionMixin.py → PromptConstructor.py} +154 -85
- 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 +48 -47
- edsl/conjure/Conjure.py +6 -0
- edsl/coop/PriceFetcher.py +58 -0
- edsl/coop/coop.py +50 -7
- edsl/data/Cache.py +35 -1
- edsl/data/CacheHandler.py +3 -4
- edsl/data_transfer_models.py +73 -38
- edsl/enums.py +8 -0
- edsl/exceptions/general.py +10 -8
- 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 +112 -0
- edsl/inference_services/AzureAI.py +214 -0
- edsl/inference_services/DeepInfraService.py +4 -3
- edsl/inference_services/GoogleService.py +16 -12
- edsl/inference_services/GroqService.py +5 -4
- edsl/inference_services/InferenceServiceABC.py +58 -3
- edsl/inference_services/InferenceServicesCollection.py +13 -8
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +55 -56
- edsl/inference_services/TestService.py +80 -0
- edsl/inference_services/TogetherAIService.py +170 -0
- edsl/inference_services/models_available_cache.py +25 -0
- edsl/inference_services/registry.py +19 -1
- edsl/jobs/Answers.py +10 -12
- edsl/jobs/FailedQuestion.py +78 -0
- edsl/jobs/Jobs.py +137 -41
- edsl/jobs/buckets/BucketCollection.py +24 -15
- edsl/jobs/buckets/TokenBucket.py +105 -18
- edsl/jobs/interviews/Interview.py +393 -83
- edsl/jobs/interviews/{interview_exception_tracking.py → InterviewExceptionCollection.py} +22 -18
- edsl/jobs/interviews/InterviewExceptionEntry.py +167 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +152 -160
- edsl/jobs/runners/JobsRunnerStatus.py +331 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
- edsl/jobs/tasks/TaskCreators.py +1 -1
- edsl/jobs/tasks/TaskHistory.py +205 -126
- edsl/language_models/LanguageModel.py +297 -177
- 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 +25 -8
- 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 -42
- edsl/questions/QuestionCheckBox.py +227 -36
- edsl/questions/QuestionExtract.py +98 -28
- edsl/questions/QuestionFreeText.py +47 -31
- edsl/questions/QuestionFunctional.py +7 -0
- edsl/questions/QuestionList.py +141 -23
- edsl/questions/QuestionMultipleChoice.py +159 -66
- edsl/questions/QuestionNumerical.py +88 -47
- edsl/questions/QuestionRank.py +182 -25
- 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 +58 -30
- 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 +109 -24
- edsl/scenarios/ScenarioImageMixin.py +2 -2
- edsl/scenarios/ScenarioList.py +546 -21
- edsl/scenarios/ScenarioListExportMixin.py +24 -4
- edsl/scenarios/ScenarioListPdfMixin.py +153 -4
- edsl/study/SnapShot.py +8 -1
- edsl/study/Study.py +32 -0
- edsl/surveys/Rule.py +15 -3
- edsl/surveys/RuleCollection.py +21 -5
- edsl/surveys/Survey.py +707 -298
- edsl/surveys/SurveyExportMixin.py +71 -9
- edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- 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 +40 -1
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/METADATA +8 -2
- edsl-0.1.33.dist-info/RECORD +295 -0
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -271
- edsl/jobs/interviews/retry_management.py +0 -37
- edsl/jobs/runners/JobsRunnerStatusMixin.py +0 -303
- edsl/utilities/gcp_bucket/simple_example.py +0 -9
- edsl-0.1.31.dev4.dist-info/RECORD +0 -204
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/LICENSE +0 -0
- {edsl-0.1.31.dev4.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:
|
@@ -11,6 +14,8 @@ class TaskHistory:
|
|
11
14
|
|
12
15
|
[Interview.exceptions, Interview.exceptions, Interview.exceptions, ...]
|
13
16
|
|
17
|
+
>>> _ = TaskHistory.example()
|
18
|
+
...
|
14
19
|
"""
|
15
20
|
|
16
21
|
self.total_interviews = interviews
|
@@ -18,10 +23,45 @@ class TaskHistory:
|
|
18
23
|
|
19
24
|
self._interviews = {index: i for index, i in enumerate(self.total_interviews)}
|
20
25
|
|
26
|
+
@classmethod
|
27
|
+
def example(cls):
|
28
|
+
from edsl.jobs.interviews.Interview import Interview
|
29
|
+
|
30
|
+
from edsl.jobs.Jobs import Jobs
|
31
|
+
|
32
|
+
j = Jobs.example(throw_exception_probability=1, test_model=True)
|
33
|
+
|
34
|
+
from edsl.config import CONFIG
|
35
|
+
|
36
|
+
results = j.run(
|
37
|
+
print_exceptions=False,
|
38
|
+
skip_retry=True,
|
39
|
+
cache=False,
|
40
|
+
raise_validation_errors=True,
|
41
|
+
)
|
42
|
+
|
43
|
+
return cls(results.task_history.total_interviews)
|
44
|
+
|
21
45
|
@property
|
22
46
|
def exceptions(self):
|
47
|
+
"""
|
48
|
+
>>> len(TaskHistory.example().exceptions)
|
49
|
+
4
|
50
|
+
"""
|
23
51
|
return [i.exceptions for k, i in self._interviews.items() if i.exceptions != {}]
|
24
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
|
+
|
25
65
|
@property
|
26
66
|
def indices(self):
|
27
67
|
return [k for k, i in self._interviews.items() if i.exceptions != {}]
|
@@ -42,9 +82,19 @@ class TaskHistory:
|
|
42
82
|
|
43
83
|
@property
|
44
84
|
def has_exceptions(self) -> bool:
|
45
|
-
"""Return True if there are any exceptions.
|
85
|
+
"""Return True if there are any exceptions.
|
86
|
+
|
87
|
+
>>> TaskHistory.example().has_exceptions
|
88
|
+
True
|
89
|
+
|
90
|
+
"""
|
46
91
|
return len(self.exceptions) > 0
|
47
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
|
+
|
48
98
|
def _repr_html_(self):
|
49
99
|
"""Return an HTML representation of the TaskHistory."""
|
50
100
|
from edsl.utilities.utilities import data_to_html
|
@@ -163,58 +213,130 @@ class TaskHistory:
|
|
163
213
|
plt.show()
|
164
214
|
|
165
215
|
def css(self):
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
line-height: 1.6;
|
170
|
-
background-color: #f9f9f9;
|
171
|
-
color: #333;
|
172
|
-
margin: 20px;
|
173
|
-
}
|
216
|
+
env = resources.files("edsl").joinpath("templates/error_reporting")
|
217
|
+
css = env.joinpath("report.css").read_text()
|
218
|
+
return css
|
174
219
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
background-color: #e3f2fd;
|
180
|
-
border-left: 5px solid #2196f3;
|
181
|
-
}
|
220
|
+
def javascript(self):
|
221
|
+
env = resources.files("edsl").joinpath("templates/error_reporting")
|
222
|
+
js = env.joinpath("report.js").read_text()
|
223
|
+
return js
|
182
224
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
225
|
+
@property
|
226
|
+
def exceptions_by_type(self) -> dict:
|
227
|
+
"""Return a dictionary of exceptions by type."""
|
228
|
+
exceptions_by_type = {}
|
229
|
+
for interview in self.total_interviews:
|
230
|
+
for question_name, exceptions in interview.exceptions.items():
|
231
|
+
for exception in exceptions:
|
232
|
+
exception_type = exception.exception.__class__.__name__
|
233
|
+
# exception_type = exception["exception"]
|
234
|
+
# breakpoint()
|
235
|
+
if exception_type in exceptions_by_type:
|
236
|
+
exceptions_by_type[exception_type] += 1
|
237
|
+
else:
|
238
|
+
exceptions_by_type[exception_type] = 1
|
239
|
+
return exceptions_by_type
|
190
240
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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
|
197
252
|
|
198
|
-
|
199
|
-
|
200
|
-
|
253
|
+
@property
|
254
|
+
def exceptions_by_question_name(self) -> dict:
|
255
|
+
"""Return a dictionary of exceptions tallied by question name."""
|
256
|
+
exceptions_by_question_name = {}
|
257
|
+
for interview in self.total_interviews:
|
258
|
+
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
|
+
)
|
268
|
+
|
269
|
+
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
|
+
)
|
201
285
|
}
|
286
|
+
return sorted_exceptions_by_question_name
|
202
287
|
|
203
|
-
|
204
|
-
|
288
|
+
@property
|
289
|
+
def exceptions_by_model(self) -> dict:
|
290
|
+
"""Return a dictionary of exceptions tallied by model and question name."""
|
291
|
+
exceptions_by_model = {}
|
292
|
+
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
|
297
|
+
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
|
+
)
|
205
306
|
}
|
307
|
+
return sorted_exceptions_by_model
|
206
308
|
|
207
|
-
|
208
|
-
|
209
|
-
color: #d32f2f;
|
210
|
-
}
|
309
|
+
def generate_html_report(self, css: Optional[str]):
|
310
|
+
performance_plot_html = self.plot(num_periods=100, get_embedded_html=True)
|
211
311
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
312
|
+
if css is None:
|
313
|
+
css = self.css()
|
314
|
+
|
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
|
319
|
+
|
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)
|
325
|
+
|
326
|
+
# Render the template with data
|
327
|
+
output = template.render(
|
328
|
+
interviews=self._interviews,
|
329
|
+
css=css,
|
330
|
+
javascript=self.javascript(),
|
331
|
+
num_exceptions=len(self.exceptions),
|
332
|
+
performance_plot_html=performance_plot_html,
|
333
|
+
exceptions_by_type=self.exceptions_by_type,
|
334
|
+
exceptions_by_question_name=self.exceptions_by_question_name,
|
335
|
+
exceptions_by_model=self.exceptions_by_model,
|
336
|
+
exceptions_by_service=self.exceptions_by_service,
|
337
|
+
models_used=models_used,
|
338
|
+
)
|
339
|
+
return output
|
218
340
|
|
219
341
|
def html(
|
220
342
|
self,
|
@@ -222,6 +344,7 @@ class TaskHistory:
|
|
222
344
|
return_link=False,
|
223
345
|
css=None,
|
224
346
|
cta="Open Report in New Tab",
|
347
|
+
open_in_browser=True,
|
225
348
|
):
|
226
349
|
"""Return an HTML report."""
|
227
350
|
|
@@ -229,87 +352,13 @@ class TaskHistory:
|
|
229
352
|
import tempfile
|
230
353
|
import os
|
231
354
|
from edsl.utilities.utilities import is_notebook
|
232
|
-
from jinja2 import Template
|
233
355
|
|
234
|
-
|
235
|
-
|
236
|
-
if css is None:
|
237
|
-
css = self.css()
|
238
|
-
|
239
|
-
template = Template(
|
240
|
-
"""
|
241
|
-
<!DOCTYPE html>
|
242
|
-
<html lang="en">
|
243
|
-
<head>
|
244
|
-
<meta charset="UTF-8">
|
245
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
246
|
-
<title>Exception Details</title>
|
247
|
-
<style>
|
248
|
-
{{ css }}
|
249
|
-
</style>
|
250
|
-
</head>
|
251
|
-
<body>
|
252
|
-
{% for index, interview in interviews.items() %}
|
253
|
-
{% if interview.exceptions != {} %}
|
254
|
-
<div class="interview">Interview: {{ index }} </div>
|
255
|
-
<h1>Failing questions</h1>
|
256
|
-
{% endif %}
|
257
|
-
{% for question, exceptions in interview.exceptions.items() %}
|
258
|
-
<div class="question">question_name: {{ question }}</div>
|
259
|
-
|
260
|
-
<h2>Question</h2>
|
261
|
-
<div class="question-detail">
|
262
|
-
{{ interview.survey.get_question(question).html() }}
|
263
|
-
</div>
|
264
|
-
|
265
|
-
<h2>Scenario</h2>
|
266
|
-
<div class="scenario">
|
267
|
-
{{ interview.scenario._repr_html_() }}
|
268
|
-
</div>
|
269
|
-
|
270
|
-
<h2>Agent</h2>
|
271
|
-
<div class="agent">
|
272
|
-
{{ interview.agent._repr_html_() }}
|
273
|
-
</div>
|
274
|
-
|
275
|
-
<h2>Model</h2>
|
276
|
-
<div class="model">
|
277
|
-
{{ interview.model._repr_html_() }}
|
278
|
-
</div>
|
279
|
-
|
280
|
-
<h2>Exception details</h2>
|
281
|
-
|
282
|
-
{% for exception_message in exceptions %}
|
283
|
-
<div class="exception-detail">
|
284
|
-
<div class="exception-exception">Exception: {{ exception_message.exception }}</div>
|
285
|
-
<div class="exception-time">Time: {{ exception_message.time }}</div>
|
286
|
-
<div class="exception-traceback">Traceback: <pre>{{ exception_message.traceback }} </pre></div>
|
287
|
-
</div>
|
288
|
-
{% endfor %}
|
289
|
-
{% endfor %}
|
290
|
-
{% endfor %}
|
291
|
-
|
292
|
-
<h1>Performance Plot</h1>
|
293
|
-
{{ performance_plot_html }}
|
294
|
-
</body>
|
295
|
-
</html>
|
296
|
-
"""
|
297
|
-
)
|
298
|
-
|
299
|
-
# Render the template with data
|
300
|
-
output = template.render(
|
301
|
-
interviews=self._interviews,
|
302
|
-
css=css,
|
303
|
-
performance_plot_html=performance_plot_html,
|
304
|
-
)
|
356
|
+
output = self.generate_html_report(css)
|
305
357
|
|
306
358
|
# Save the rendered output to a file
|
307
359
|
with open("output.html", "w") as f:
|
308
360
|
f.write(output)
|
309
361
|
|
310
|
-
if css is None:
|
311
|
-
css = self.css()
|
312
|
-
|
313
362
|
if filename is None:
|
314
363
|
current_directory = os.getcwd()
|
315
364
|
filename = tempfile.NamedTemporaryFile(
|
@@ -318,10 +367,7 @@ class TaskHistory:
|
|
318
367
|
|
319
368
|
with open(filename, "w") as f:
|
320
369
|
with open(filename, "w") as f:
|
321
|
-
# f.write(html_header)
|
322
|
-
# f.write(self._repr_html_())
|
323
370
|
f.write(output)
|
324
|
-
# f.write(html_footer)
|
325
371
|
|
326
372
|
if is_notebook():
|
327
373
|
import html
|
@@ -334,13 +380,46 @@ class TaskHistory:
|
|
334
380
|
<iframe srcdoc="{ escaped_output }" style="width: 800px; height: 600px;"></iframe>
|
335
381
|
"""
|
336
382
|
display(HTML(iframe))
|
337
|
-
# display(HTML(output))
|
338
383
|
else:
|
339
384
|
print(f"Exception report saved to {filename}")
|
340
|
-
import webbrowser
|
341
|
-
import os
|
342
385
|
|
386
|
+
if open_in_browser:
|
343
387
|
webbrowser.open(f"file://{os.path.abspath(filename)}")
|
344
388
|
|
345
389
|
if return_link:
|
346
390
|
return filename
|
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
|
+
|
421
|
+
|
422
|
+
if __name__ == "__main__":
|
423
|
+
import doctest
|
424
|
+
|
425
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|