edsl 0.1.38__py3-none-any.whl → 0.1.38.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.
- edsl/Base.py +34 -63
- edsl/BaseDiff.py +7 -7
- edsl/__init__.py +1 -2
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +11 -23
- edsl/agents/AgentList.py +23 -86
- edsl/agents/Invigilator.py +7 -18
- edsl/agents/InvigilatorBase.py +19 -0
- edsl/agents/PromptConstructor.py +4 -5
- edsl/auto/SurveyCreatorPipeline.py +1 -1
- edsl/auto/utilities.py +1 -1
- edsl/base/Base.py +13 -3
- edsl/config.py +0 -8
- edsl/conjure/AgentConstructionMixin.py +160 -0
- edsl/conjure/Conjure.py +62 -0
- edsl/conjure/InputData.py +659 -0
- edsl/conjure/InputDataCSV.py +48 -0
- edsl/conjure/InputDataMixinQuestionStats.py +182 -0
- edsl/conjure/InputDataPyRead.py +91 -0
- edsl/conjure/InputDataSPSS.py +8 -0
- edsl/conjure/InputDataStata.py +8 -0
- edsl/conjure/QuestionOptionMixin.py +76 -0
- edsl/conjure/QuestionTypeMixin.py +23 -0
- edsl/conjure/RawQuestion.py +65 -0
- edsl/conjure/SurveyResponses.py +7 -0
- edsl/conjure/__init__.py +9 -0
- edsl/conjure/examples/placeholder.txt +0 -0
- edsl/{utilities → conjure}/naming_utilities.py +1 -1
- edsl/conjure/utilities.py +201 -0
- edsl/coop/coop.py +7 -77
- edsl/data/Cache.py +17 -45
- edsl/data/CacheEntry.py +3 -8
- edsl/data/RemoteCacheSync.py +19 -0
- edsl/enums.py +0 -2
- edsl/exceptions/agents.py +0 -4
- edsl/inference_services/GoogleService.py +15 -7
- edsl/inference_services/registry.py +0 -2
- edsl/jobs/Jobs.py +559 -110
- edsl/jobs/buckets/TokenBucket.py +0 -3
- edsl/jobs/interviews/Interview.py +7 -7
- edsl/jobs/runners/JobsRunnerAsyncio.py +28 -156
- edsl/jobs/runners/JobsRunnerStatus.py +196 -194
- edsl/jobs/tasks/TaskHistory.py +19 -27
- edsl/language_models/LanguageModel.py +90 -52
- edsl/language_models/ModelList.py +14 -67
- edsl/language_models/registry.py +4 -57
- edsl/notebooks/Notebook.py +8 -7
- edsl/prompts/Prompt.py +3 -8
- edsl/questions/QuestionBase.py +30 -38
- edsl/questions/QuestionBaseGenMixin.py +1 -1
- edsl/questions/QuestionBasePromptsMixin.py +17 -0
- edsl/questions/QuestionExtract.py +4 -3
- edsl/questions/QuestionFunctional.py +3 -10
- edsl/questions/derived/QuestionTopK.py +0 -2
- edsl/questions/question_registry.py +6 -36
- edsl/results/Dataset.py +15 -146
- edsl/results/DatasetExportMixin.py +217 -231
- edsl/results/DatasetTree.py +4 -134
- edsl/results/Result.py +16 -31
- edsl/results/Results.py +65 -159
- edsl/scenarios/FileStore.py +13 -187
- edsl/scenarios/Scenario.py +18 -73
- edsl/scenarios/ScenarioList.py +76 -251
- edsl/surveys/MemoryPlan.py +1 -1
- edsl/surveys/Rule.py +5 -1
- edsl/surveys/RuleCollection.py +1 -1
- edsl/surveys/Survey.py +19 -25
- edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
- edsl/surveys/instructions/ChangeInstruction.py +7 -9
- edsl/surveys/instructions/Instruction.py +7 -21
- edsl/templates/error_reporting/interview_details.html +3 -3
- edsl/templates/error_reporting/interviews.html +9 -18
- edsl/utilities/utilities.py +0 -15
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/METADATA +1 -2
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/RECORD +77 -71
- edsl/exceptions/cache.py +0 -5
- edsl/inference_services/PerplexityService.py +0 -163
- edsl/jobs/JobsChecks.py +0 -147
- edsl/jobs/JobsPrompts.py +0 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +0 -239
- edsl/results/CSSParameterizer.py +0 -108
- edsl/results/TableDisplay.py +0 -198
- edsl/results/table_display.css +0 -78
- edsl/scenarios/ScenarioJoin.py +0 -127
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/LICENSE +0 -0
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/WHEEL +0 -0
@@ -1,21 +1,33 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import os
|
4
3
|
import time
|
5
|
-
import
|
6
|
-
|
7
|
-
from
|
8
|
-
from
|
9
|
-
|
10
|
-
from
|
11
|
-
from
|
12
|
-
from
|
13
|
-
|
4
|
+
from dataclasses import dataclass, asdict
|
5
|
+
|
6
|
+
from typing import List, DefaultDict, Optional, Type, Literal
|
7
|
+
from collections import UserDict, defaultdict
|
8
|
+
|
9
|
+
from rich.text import Text
|
10
|
+
from rich.box import SIMPLE
|
11
|
+
from rich.table import Table
|
12
|
+
from rich.live import Live
|
13
|
+
from rich.panel import Panel
|
14
|
+
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn
|
15
|
+
from rich.layout import Layout
|
16
|
+
from rich.console import Group
|
17
|
+
from rich import box
|
18
|
+
|
19
|
+
from edsl.jobs.interviews.InterviewStatusDictionary import InterviewStatusDictionary
|
14
20
|
from edsl.jobs.tokens.InterviewTokenUsage import InterviewTokenUsage
|
21
|
+
from edsl.jobs.tokens.TokenUsage import TokenUsage
|
22
|
+
from edsl.enums import get_token_pricing
|
23
|
+
from edsl.jobs.tasks.task_status_enum import TaskStatus
|
15
24
|
|
16
25
|
InterviewTokenUsageMapping = DefaultDict[str, InterviewTokenUsage]
|
17
26
|
|
18
27
|
from edsl.jobs.interviews.InterviewStatistic import InterviewStatistic
|
28
|
+
from edsl.jobs.interviews.InterviewStatisticsCollection import (
|
29
|
+
InterviewStatisticsCollection,
|
30
|
+
)
|
19
31
|
from edsl.jobs.tokens.InterviewTokenUsage import InterviewTokenUsage
|
20
32
|
|
21
33
|
|
@@ -35,23 +47,16 @@ class ModelTokenUsageStats:
|
|
35
47
|
cost: str
|
36
48
|
|
37
49
|
|
38
|
-
class
|
50
|
+
class Stats:
|
51
|
+
def elapsed_time(self):
|
52
|
+
InterviewStatistic("elapsed_time", value=elapsed_time, digits=1, units="sec.")
|
53
|
+
|
54
|
+
|
55
|
+
class JobsRunnerStatus:
|
39
56
|
def __init__(
|
40
|
-
self,
|
41
|
-
jobs_runner: "JobsRunnerAsyncio",
|
42
|
-
n: int,
|
43
|
-
refresh_rate: float = 1,
|
44
|
-
endpoint_url: Optional[str] = "http://localhost:8000",
|
45
|
-
job_uuid: Optional[UUID] = None,
|
46
|
-
api_key: str = None,
|
57
|
+
self, jobs_runner: "JobsRunnerAsyncio", n: int, refresh_rate: float = 0.25
|
47
58
|
):
|
48
59
|
self.jobs_runner = jobs_runner
|
49
|
-
|
50
|
-
# The uuid of the job on Coop
|
51
|
-
self.job_uuid = job_uuid
|
52
|
-
|
53
|
-
self.base_url = f"{endpoint_url}"
|
54
|
-
|
55
60
|
self.start_time = time.time()
|
56
61
|
self.completed_interviews = []
|
57
62
|
self.refresh_rate = refresh_rate
|
@@ -75,99 +80,6 @@ class JobsRunnerStatusBase(ABC):
|
|
75
80
|
|
76
81
|
self.completed_interview_by_model = defaultdict(list)
|
77
82
|
|
78
|
-
self.api_key = api_key or os.getenv("EXPECTED_PARROT_API_KEY")
|
79
|
-
|
80
|
-
@abstractmethod
|
81
|
-
def has_ep_api_key(self):
|
82
|
-
"""
|
83
|
-
Checks if the user has an Expected Parrot API key.
|
84
|
-
"""
|
85
|
-
pass
|
86
|
-
|
87
|
-
def get_status_dict(self) -> Dict[str, Any]:
|
88
|
-
"""
|
89
|
-
Converts current status into a JSON-serializable dictionary.
|
90
|
-
"""
|
91
|
-
# Get all statistics
|
92
|
-
stats = {}
|
93
|
-
for stat_name in self.statistics:
|
94
|
-
stat = self._compute_statistic(stat_name)
|
95
|
-
name, value = list(stat.items())[0]
|
96
|
-
stats[name] = value
|
97
|
-
|
98
|
-
# Calculate overall progress
|
99
|
-
total_interviews = len(self.jobs_runner.total_interviews)
|
100
|
-
completed = len(self.completed_interviews)
|
101
|
-
|
102
|
-
# Get model-specific progress
|
103
|
-
model_progress = {}
|
104
|
-
for model in self.distinct_models:
|
105
|
-
completed_for_model = len(self.completed_interview_by_model[model])
|
106
|
-
target_for_model = int(
|
107
|
-
self.num_total_interviews / len(self.distinct_models)
|
108
|
-
)
|
109
|
-
model_progress[model] = {
|
110
|
-
"completed": completed_for_model,
|
111
|
-
"total": target_for_model,
|
112
|
-
"percent": (
|
113
|
-
(completed_for_model / target_for_model * 100)
|
114
|
-
if target_for_model > 0
|
115
|
-
else 0
|
116
|
-
),
|
117
|
-
}
|
118
|
-
|
119
|
-
status_dict = {
|
120
|
-
"overall_progress": {
|
121
|
-
"completed": completed,
|
122
|
-
"total": total_interviews,
|
123
|
-
"percent": (
|
124
|
-
(completed / total_interviews * 100) if total_interviews > 0 else 0
|
125
|
-
),
|
126
|
-
},
|
127
|
-
"language_model_progress": model_progress,
|
128
|
-
"statistics": stats,
|
129
|
-
"status": "completed" if completed >= total_interviews else "running",
|
130
|
-
}
|
131
|
-
|
132
|
-
model_queues = {}
|
133
|
-
for model, bucket in self.jobs_runner.bucket_collection.items():
|
134
|
-
model_name = model.model
|
135
|
-
model_queues[model_name] = {
|
136
|
-
"language_model_name": model_name,
|
137
|
-
"requests_bucket": {
|
138
|
-
"completed": bucket.requests_bucket.num_released,
|
139
|
-
"requested": bucket.requests_bucket.num_requests,
|
140
|
-
"tokens_returned": bucket.requests_bucket.tokens_returned,
|
141
|
-
"target_rate": round(bucket.requests_bucket.target_rate, 1),
|
142
|
-
"current_rate": round(bucket.requests_bucket.get_throughput(), 1),
|
143
|
-
},
|
144
|
-
"tokens_bucket": {
|
145
|
-
"completed": bucket.tokens_bucket.num_released,
|
146
|
-
"requested": bucket.tokens_bucket.num_requests,
|
147
|
-
"tokens_returned": bucket.tokens_bucket.tokens_returned,
|
148
|
-
"target_rate": round(bucket.tokens_bucket.target_rate, 1),
|
149
|
-
"current_rate": round(bucket.tokens_bucket.get_throughput(), 1),
|
150
|
-
},
|
151
|
-
}
|
152
|
-
status_dict["language_model_queues"] = model_queues
|
153
|
-
return status_dict
|
154
|
-
|
155
|
-
@abstractmethod
|
156
|
-
def setup(self):
|
157
|
-
"""
|
158
|
-
Conducts any setup that needs to happen prior to sending status updates.
|
159
|
-
|
160
|
-
Ex. For a local job, creates a job in the Coop database.
|
161
|
-
"""
|
162
|
-
pass
|
163
|
-
|
164
|
-
@abstractmethod
|
165
|
-
def send_status_update(self):
|
166
|
-
"""
|
167
|
-
Updates the current status of the job.
|
168
|
-
"""
|
169
|
-
pass
|
170
|
-
|
171
83
|
def add_completed_interview(self, result):
|
172
84
|
self.completed_interviews.append(result.interview_hash)
|
173
85
|
|
@@ -238,90 +150,180 @@ class JobsRunnerStatusBase(ABC):
|
|
238
150
|
}
|
239
151
|
return stat_definitions[stat_name]()
|
240
152
|
|
241
|
-
def
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
class JobsRunnerStatus(JobsRunnerStatusBase):
|
250
|
-
@property
|
251
|
-
def create_url(self) -> str:
|
252
|
-
return f"{self.base_url}/api/v0/local-job"
|
153
|
+
def create_progress_bar(self):
|
154
|
+
return Progress(
|
155
|
+
TextColumn("[progress.description]{task.description}"),
|
156
|
+
BarColumn(),
|
157
|
+
TaskProgressColumn(),
|
158
|
+
TextColumn("{task.completed}/{task.total}"),
|
159
|
+
)
|
253
160
|
|
254
|
-
|
255
|
-
|
256
|
-
|
161
|
+
def generate_model_queues_table(self):
|
162
|
+
table = Table(show_header=False, box=box.SIMPLE)
|
163
|
+
table.add_column("Info", style="cyan")
|
164
|
+
table.add_column("Value", style="magenta")
|
165
|
+
# table.add_row("Bucket collection", str(self.jobs_runner.bucket_collection))
|
166
|
+
for model, bucket in self.jobs_runner.bucket_collection.items():
|
167
|
+
table.add_row(Text(model.model, style="bold blue"), "")
|
168
|
+
bucket_types = ["requests_bucket", "tokens_bucket"]
|
169
|
+
for bucket_type in bucket_types:
|
170
|
+
table.add_row(Text(" " + bucket_type, style="green"), "")
|
171
|
+
# table.add_row(
|
172
|
+
# f" Current level (capacity = {round(getattr(bucket, bucket_type).capacity, 3)})",
|
173
|
+
# str(round(getattr(bucket, bucket_type).tokens, 3)),
|
174
|
+
# )
|
175
|
+
num_requests = getattr(bucket, bucket_type).num_requests
|
176
|
+
num_released = getattr(bucket, bucket_type).num_released
|
177
|
+
tokens_returned = getattr(bucket, bucket_type).tokens_returned
|
178
|
+
# table.add_row(
|
179
|
+
# f" Requested",
|
180
|
+
# str(num_requests),
|
181
|
+
# )
|
182
|
+
# table.add_row(
|
183
|
+
# f" Completed",
|
184
|
+
# str(num_released),
|
185
|
+
# )
|
186
|
+
table.add_row(
|
187
|
+
" Completed vs. Requested", f"{num_released} vs. {num_requests}"
|
188
|
+
)
|
189
|
+
table.add_row(
|
190
|
+
" Added tokens (from cache)",
|
191
|
+
str(tokens_returned),
|
192
|
+
)
|
193
|
+
if bucket_type == "tokens_bucket":
|
194
|
+
rate_name = "TPM"
|
195
|
+
else:
|
196
|
+
rate_name = "RPM"
|
197
|
+
target_rate = round(getattr(bucket, bucket_type).target_rate, 1)
|
198
|
+
table.add_row(
|
199
|
+
f" Empirical {rate_name} (target = {target_rate})",
|
200
|
+
str(round(getattr(bucket, bucket_type).get_throughput(), 0)),
|
201
|
+
)
|
202
|
+
|
203
|
+
return table
|
204
|
+
|
205
|
+
def generate_layout(self):
|
206
|
+
progress = self.create_progress_bar()
|
207
|
+
task_ids = []
|
208
|
+
for model in self.distinct_models:
|
209
|
+
task_id = progress.add_task(
|
210
|
+
f"[cyan]{model}...",
|
211
|
+
total=int(self.num_total_interviews / len(self.distinct_models)),
|
212
|
+
)
|
213
|
+
task_ids.append((model, task_id))
|
214
|
+
|
215
|
+
progress_height = min(5, 2 + len(self.distinct_models))
|
216
|
+
layout = Layout()
|
217
|
+
|
218
|
+
# Create the top row with only the progress panel
|
219
|
+
layout.split_column(
|
220
|
+
Layout(
|
221
|
+
Panel(
|
222
|
+
progress,
|
223
|
+
title="Interview Progress",
|
224
|
+
border_style="cyan",
|
225
|
+
box=box.ROUNDED,
|
226
|
+
),
|
227
|
+
name="progress",
|
228
|
+
size=progress_height, # Adjusted size
|
229
|
+
),
|
230
|
+
Layout(name="bottom_row"), # Adjusted size
|
231
|
+
)
|
257
232
|
|
258
|
-
|
259
|
-
|
260
|
-
|
233
|
+
# Split the bottom row into two columns for metrics and model queues
|
234
|
+
layout["bottom_row"].split_row(
|
235
|
+
Layout(
|
236
|
+
Panel(
|
237
|
+
self.generate_metrics_table(),
|
238
|
+
title="Metrics",
|
239
|
+
border_style="magenta",
|
240
|
+
box=box.ROUNDED,
|
241
|
+
),
|
242
|
+
name="metrics",
|
243
|
+
),
|
244
|
+
Layout(
|
245
|
+
Panel(
|
246
|
+
self.generate_model_queues_table(),
|
247
|
+
title="Model Queues",
|
248
|
+
border_style="yellow",
|
249
|
+
box=box.ROUNDED,
|
250
|
+
),
|
251
|
+
name="model_queues",
|
252
|
+
),
|
253
|
+
)
|
261
254
|
|
262
|
-
|
263
|
-
"""
|
264
|
-
Creates a local job on Coop if one does not already exist.
|
265
|
-
"""
|
255
|
+
return layout, progress, task_ids
|
266
256
|
|
267
|
-
|
257
|
+
def generate_metrics_table(self):
|
258
|
+
table = Table(show_header=True, header_style="bold magenta", box=box.SIMPLE)
|
259
|
+
table.add_column("Metric", style="cyan", no_wrap=True)
|
260
|
+
table.add_column("Value", justify="right")
|
268
261
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
262
|
+
for stat_name in self.statistics:
|
263
|
+
pretty_name, value = list(self._compute_statistic(stat_name).items())[0]
|
264
|
+
# breakpoint()
|
265
|
+
table.add_row(pretty_name, value)
|
266
|
+
return table
|
273
267
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
268
|
+
def update_progress(self, stop_event):
|
269
|
+
layout, progress, task_ids = self.generate_layout()
|
270
|
+
|
271
|
+
with Live(
|
272
|
+
layout, refresh_per_second=int(1 / self.refresh_rate), transient=True
|
273
|
+
) as live:
|
274
|
+
while (
|
275
|
+
len(self.completed_interviews) < len(self.jobs_runner.total_interviews)
|
276
|
+
and not stop_event.is_set()
|
277
|
+
):
|
278
|
+
completed_tasks = len(self.completed_interviews)
|
279
|
+
total_tasks = len(self.jobs_runner.total_interviews)
|
280
|
+
|
281
|
+
for model, task_id in task_ids:
|
282
|
+
completed_tasks = len(self.completed_interview_by_model[model])
|
283
|
+
progress.update(
|
284
|
+
task_id,
|
285
|
+
completed=completed_tasks,
|
286
|
+
description=f"[cyan]Conducting interviews for {model}...",
|
287
|
+
)
|
288
|
+
|
289
|
+
layout["metrics"].update(
|
290
|
+
Panel(
|
291
|
+
self.generate_metrics_table(),
|
292
|
+
title="Metrics",
|
293
|
+
border_style="magenta",
|
294
|
+
box=box.ROUNDED,
|
295
|
+
)
|
296
|
+
)
|
297
|
+
layout["model_queues"].update(
|
298
|
+
Panel(
|
299
|
+
self.generate_model_queues_table(),
|
300
|
+
title="Final Model Queues",
|
301
|
+
border_style="yellow",
|
302
|
+
box=box.ROUNDED,
|
303
|
+
)
|
304
|
+
)
|
305
|
+
|
306
|
+
time.sleep(self.refresh_rate)
|
307
|
+
|
308
|
+
# Final update
|
309
|
+
for model, task_id in task_ids:
|
310
|
+
completed_tasks = len(self.completed_interview_by_model[model])
|
311
|
+
progress.update(
|
312
|
+
task_id,
|
313
|
+
completed=completed_tasks,
|
314
|
+
description=f"[cyan]Conducting interviews for {model}...",
|
315
|
+
)
|
316
|
+
|
317
|
+
layout["metrics"].update(
|
318
|
+
Panel(
|
319
|
+
self.generate_metrics_table(),
|
320
|
+
title="Final Metrics",
|
321
|
+
border_style="magenta",
|
322
|
+
box=box.ROUNDED,
|
323
|
+
)
|
311
324
|
)
|
312
|
-
|
313
|
-
|
314
|
-
print(f"Failed to send status update for job {self.job_uuid}: {e}")
|
315
|
-
|
316
|
-
def has_ep_api_key(self) -> bool:
|
317
|
-
"""
|
318
|
-
Returns True if the user has an Expected Parrot API key. Otherwise, returns False.
|
319
|
-
"""
|
320
|
-
|
321
|
-
if self.api_key is not None:
|
322
|
-
return True
|
323
|
-
else:
|
324
|
-
return False
|
325
|
+
live.update(layout)
|
326
|
+
time.sleep(1) # Show final state for 1 second
|
325
327
|
|
326
328
|
|
327
329
|
if __name__ == "__main__":
|
edsl/jobs/tasks/TaskHistory.py
CHANGED
@@ -8,12 +8,7 @@ from edsl.jobs.tasks.task_status_enum import TaskStatus
|
|
8
8
|
|
9
9
|
|
10
10
|
class TaskHistory:
|
11
|
-
def __init__(
|
12
|
-
self,
|
13
|
-
interviews: List["Interview"],
|
14
|
-
include_traceback: bool = False,
|
15
|
-
max_interviews: int = 10,
|
16
|
-
):
|
11
|
+
def __init__(self, interviews: List["Interview"], include_traceback: bool = False):
|
17
12
|
"""
|
18
13
|
The structure of a TaskHistory exception
|
19
14
|
|
@@ -27,7 +22,6 @@ class TaskHistory:
|
|
27
22
|
self.include_traceback = include_traceback
|
28
23
|
|
29
24
|
self._interviews = {index: i for index, i in enumerate(self.total_interviews)}
|
30
|
-
self.max_interviews = max_interviews
|
31
25
|
|
32
26
|
@classmethod
|
33
27
|
def example(cls):
|
@@ -79,21 +73,19 @@ class TaskHistory:
|
|
79
73
|
"""Return a string representation of the TaskHistory."""
|
80
74
|
return f"TaskHistory(interviews={self.total_interviews})."
|
81
75
|
|
82
|
-
def to_dict(self
|
76
|
+
def to_dict(self):
|
83
77
|
"""Return the TaskHistory as a dictionary."""
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
# return {
|
79
|
+
# "exceptions": [
|
80
|
+
# e.to_dict(include_traceback=self.include_traceback)
|
81
|
+
# for e in self.exceptions
|
82
|
+
# ],
|
83
|
+
# "indices": self.indices,
|
84
|
+
# }
|
85
|
+
return {
|
86
|
+
"interviews": [i._to_dict() for i in self.total_interviews],
|
89
87
|
"include_traceback": self.include_traceback,
|
90
88
|
}
|
91
|
-
if add_edsl_version:
|
92
|
-
from edsl import __version__
|
93
|
-
|
94
|
-
d["edsl_version"] = __version__
|
95
|
-
d["edsl_class_name"] = "TaskHistory"
|
96
|
-
return d
|
97
89
|
|
98
90
|
@classmethod
|
99
91
|
def from_dict(cls, data: dict):
|
@@ -123,11 +115,10 @@ class TaskHistory:
|
|
123
115
|
|
124
116
|
def _repr_html_(self):
|
125
117
|
"""Return an HTML representation of the TaskHistory."""
|
126
|
-
|
127
|
-
data = [[k, v] for k, v in d.items()]
|
128
|
-
from tabulate import tabulate
|
118
|
+
from edsl.utilities.utilities import data_to_html
|
129
119
|
|
130
|
-
|
120
|
+
newdata = self.to_dict()["exceptions"]
|
121
|
+
return data_to_html(newdata, replace_new_lines=True)
|
131
122
|
|
132
123
|
def show_exceptions(self, tracebacks=False):
|
133
124
|
"""Print the exceptions."""
|
@@ -257,6 +248,8 @@ class TaskHistory:
|
|
257
248
|
for question_name, exceptions in interview.exceptions.items():
|
258
249
|
for exception in exceptions:
|
259
250
|
exception_type = exception.exception.__class__.__name__
|
251
|
+
# exception_type = exception["exception"]
|
252
|
+
# breakpoint()
|
260
253
|
if exception_type in exceptions_by_type:
|
261
254
|
exceptions_by_type[exception_type] += 1
|
262
255
|
else:
|
@@ -343,9 +336,9 @@ class TaskHistory:
|
|
343
336
|
|
344
337
|
env = Environment(loader=TemplateLoader("edsl", "templates/error_reporting"))
|
345
338
|
|
346
|
-
#
|
347
|
-
|
339
|
+
# Load and render a template
|
348
340
|
template = env.get_template("base.html")
|
341
|
+
# rendered_template = template.render(your_data=your_data)
|
349
342
|
|
350
343
|
# Render the template with data
|
351
344
|
output = template.render(
|
@@ -359,7 +352,6 @@ class TaskHistory:
|
|
359
352
|
exceptions_by_model=self.exceptions_by_model,
|
360
353
|
exceptions_by_service=self.exceptions_by_service,
|
361
354
|
models_used=models_used,
|
362
|
-
max_interviews=self.max_interviews,
|
363
355
|
)
|
364
356
|
return output
|
365
357
|
|
@@ -369,7 +361,7 @@ class TaskHistory:
|
|
369
361
|
return_link=False,
|
370
362
|
css=None,
|
371
363
|
cta="Open Report in New Tab",
|
372
|
-
open_in_browser=
|
364
|
+
open_in_browser=True,
|
373
365
|
):
|
374
366
|
"""Return an HTML report."""
|
375
367
|
|