edsl 0.1.37.dev6__py3-none-any.whl → 0.1.38__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 +332 -303
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +49 -48
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +867 -855
- edsl/agents/AgentList.py +413 -350
- edsl/agents/Invigilator.py +233 -222
- edsl/agents/InvigilatorBase.py +265 -284
- edsl/agents/PromptConstructor.py +354 -353
- edsl/agents/__init__.py +3 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/auto/AutoStudy.py +117 -117
- edsl/auto/StageBase.py +230 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +73 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +224 -224
- edsl/base/Base.py +279 -289
- edsl/config.py +157 -149
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +58 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1028 -958
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +555 -527
- edsl/data/CacheEntry.py +233 -228
- edsl/data/CacheHandler.py +149 -149
- edsl/data/RemoteCacheSync.py +78 -97
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +4 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +73 -73
- edsl/enums.py +175 -173
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +42 -38
- edsl/exceptions/cache.py +5 -0
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +91 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +22 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +87 -87
- edsl/inference_services/AwsBedrock.py +120 -120
- edsl/inference_services/AzureAI.py +217 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +148 -156
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +147 -147
- edsl/inference_services/InferenceServicesCollection.py +97 -97
- edsl/inference_services/MistralAIService.py +123 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +224 -224
- edsl/inference_services/PerplexityService.py +163 -0
- edsl/inference_services/TestService.py +89 -89
- edsl/inference_services/TogetherAIService.py +170 -170
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -39
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/Answers.py +56 -56
- edsl/jobs/Jobs.py +898 -1347
- edsl/jobs/JobsChecks.py +147 -0
- edsl/jobs/JobsPrompts.py +268 -0
- edsl/jobs/JobsRemoteInferenceHandler.py +239 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/buckets/BucketCollection.py +63 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +251 -248
- edsl/jobs/interviews/Interview.py +661 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/runners/JobsRunnerAsyncio.py +466 -338
- edsl/jobs/runners/JobsRunnerStatus.py +330 -332
- edsl/jobs/tasks/QuestionTaskCreator.py +242 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +450 -442
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +163 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/KeyLookup.py +30 -30
- edsl/language_models/LanguageModel.py +668 -706
- edsl/language_models/ModelList.py +155 -102
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/__init__.py +3 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/registry.py +190 -137
- edsl/language_models/repair.py +156 -156
- edsl/language_models/unused/ReplicateBase.py +83 -83
- edsl/language_models/utilities.py +64 -64
- edsl/notebooks/Notebook.py +258 -259
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +362 -357
- edsl/prompts/__init__.py +2 -2
- edsl/questions/AnswerValidatorMixin.py +289 -289
- edsl/questions/QuestionBase.py +664 -656
- edsl/questions/QuestionBaseGenMixin.py +161 -161
- edsl/questions/QuestionBasePromptsMixin.py +217 -234
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +182 -183
- edsl/questions/QuestionFreeText.py +114 -114
- edsl/questions/QuestionFunctional.py +166 -159
- edsl/questions/QuestionList.py +231 -231
- edsl/questions/QuestionMultipleChoice.py +286 -286
- edsl/questions/QuestionNumerical.py +153 -153
- edsl/questions/QuestionRank.py +324 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/RegisterQuestionsMeta.py +71 -71
- edsl/questions/ResponseValidatorABC.py +174 -174
- edsl/questions/SimpleAskMixin.py +73 -73
- edsl/questions/__init__.py +26 -26
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +87 -87
- edsl/questions/derived/QuestionTopK.py +93 -91
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +413 -413
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/question_registry.py +177 -147
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -0
- edsl/results/Dataset.py +424 -293
- edsl/results/DatasetExportMixin.py +731 -717
- edsl/results/DatasetTree.py +275 -145
- edsl/results/Result.py +465 -450
- edsl/results/Results.py +1165 -1071
- edsl/results/ResultsDBMixin.py +238 -238
- edsl/results/ResultsExportMixin.py +43 -43
- edsl/results/ResultsFetchMixin.py +33 -33
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/ResultsToolsMixin.py +98 -98
- edsl/results/Selector.py +135 -135
- edsl/results/TableDisplay.py +198 -0
- edsl/results/__init__.py +2 -2
- edsl/results/table_display.css +78 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/FileStore.py +632 -458
- edsl/scenarios/Scenario.py +601 -546
- edsl/scenarios/ScenarioHtmlMixin.py +64 -64
- edsl/scenarios/ScenarioJoin.py +127 -0
- edsl/scenarios/ScenarioList.py +1287 -1112
- edsl/scenarios/ScenarioListExportMixin.py +52 -52
- edsl/scenarios/ScenarioListPdfMixin.py +261 -261
- edsl/scenarios/__init__.py +4 -4
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +528 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +326 -330
- edsl/surveys/RuleCollection.py +387 -387
- edsl/surveys/Survey.py +1801 -1795
- edsl/surveys/SurveyCSS.py +261 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/SurveyFlowVisualizationMixin.py +179 -121
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/__init__.py +3 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +56 -56
- edsl/surveys/instructions/ChangeInstruction.py +49 -47
- edsl/surveys/instructions/Instruction.py +65 -51
- edsl/surveys/instructions/InstructionCollection.py +77 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -10
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/{conjure → utilities}/naming_utilities.py +263 -263
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +424 -409
- {edsl-0.1.37.dev6.dist-info → edsl-0.1.38.dist-info}/LICENSE +21 -21
- {edsl-0.1.37.dev6.dist-info → edsl-0.1.38.dist-info}/METADATA +2 -1
- edsl-0.1.38.dist-info/RECORD +277 -0
- edsl/conjure/AgentConstructionMixin.py +0 -160
- edsl/conjure/Conjure.py +0 -62
- edsl/conjure/InputData.py +0 -659
- edsl/conjure/InputDataCSV.py +0 -48
- edsl/conjure/InputDataMixinQuestionStats.py +0 -182
- edsl/conjure/InputDataPyRead.py +0 -91
- edsl/conjure/InputDataSPSS.py +0 -8
- edsl/conjure/InputDataStata.py +0 -8
- edsl/conjure/QuestionOptionMixin.py +0 -76
- edsl/conjure/QuestionTypeMixin.py +0 -23
- edsl/conjure/RawQuestion.py +0 -65
- edsl/conjure/SurveyResponses.py +0 -7
- edsl/conjure/__init__.py +0 -9
- edsl/conjure/examples/placeholder.txt +0 -0
- edsl/conjure/utilities.py +0 -201
- edsl-0.1.37.dev6.dist-info/RECORD +0 -283
- {edsl-0.1.37.dev6.dist-info → edsl-0.1.38.dist-info}/WHEEL +0 -0
edsl/jobs/tasks/TaskStatusLog.py
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
from collections import UserList
|
2
|
-
|
3
|
-
|
4
|
-
class TaskStatusLog(UserList):
|
5
|
-
"""A list of TaskStatusEntry objects."""
|
6
|
-
|
7
|
-
@property
|
8
|
-
def min_time(self):
|
9
|
-
return self[0]["log_time"]
|
10
|
-
|
11
|
-
@property
|
12
|
-
def max_time(self):
|
13
|
-
return self[-1]["log_time"]
|
14
|
-
|
15
|
-
def status_at_time(self, t):
|
16
|
-
"""Return the status at time t.
|
17
|
-
|
18
|
-
TODO: Could re-factor with bisect to make this faster.
|
19
|
-
"""
|
20
|
-
for entry in self:
|
21
|
-
if entry["log_time"] > t:
|
22
|
-
return entry["value"]
|
23
|
-
return self[-1]["value"]
|
1
|
+
from collections import UserList
|
2
|
+
|
3
|
+
|
4
|
+
class TaskStatusLog(UserList):
|
5
|
+
"""A list of TaskStatusEntry objects."""
|
6
|
+
|
7
|
+
@property
|
8
|
+
def min_time(self):
|
9
|
+
return self[0]["log_time"]
|
10
|
+
|
11
|
+
@property
|
12
|
+
def max_time(self):
|
13
|
+
return self[-1]["log_time"]
|
14
|
+
|
15
|
+
def status_at_time(self, t):
|
16
|
+
"""Return the status at time t.
|
17
|
+
|
18
|
+
TODO: Could re-factor with bisect to make this faster.
|
19
|
+
"""
|
20
|
+
for entry in self:
|
21
|
+
if entry["log_time"] > t:
|
22
|
+
return entry["value"]
|
23
|
+
return self[-1]["value"]
|
@@ -1,163 +1,163 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from collections import UserDict
|
3
|
-
import enum
|
4
|
-
import time
|
5
|
-
|
6
|
-
# from edsl.jobs.tasks.TaskStatusLogEntry import TaskStatusLogEntry
|
7
|
-
|
8
|
-
|
9
|
-
class TaskStatus(enum.Enum):
|
10
|
-
"These are the possible states a task can be in."
|
11
|
-
NOT_STARTED = enum.auto()
|
12
|
-
WAITING_FOR_DEPENDENCIES = enum.auto()
|
13
|
-
CANCELLED = enum.auto()
|
14
|
-
PARENT_FAILED = enum.auto()
|
15
|
-
WAITING_FOR_REQUEST_CAPACITY = enum.auto()
|
16
|
-
WAITING_FOR_TOKEN_CAPACITY = enum.auto()
|
17
|
-
API_CALL_IN_PROGRESS = enum.auto()
|
18
|
-
SUCCESS = enum.auto()
|
19
|
-
FAILED = enum.auto()
|
20
|
-
|
21
|
-
|
22
|
-
class TaskStatusLogEntry(UserDict):
|
23
|
-
def __init__(self, log_time, value):
|
24
|
-
self.data = {"log_time": log_time, "value": value}
|
25
|
-
super().__init__(self.data)
|
26
|
-
|
27
|
-
|
28
|
-
class TaskStatusDescriptor:
|
29
|
-
"The descriptor ensures that the task status is always an instance of the TaskStatus enum."
|
30
|
-
|
31
|
-
def __init__(self):
|
32
|
-
self._task_status = None
|
33
|
-
|
34
|
-
def __get__(self, instance, owner):
|
35
|
-
return self._task_status
|
36
|
-
|
37
|
-
def __set__(self, instance, value):
|
38
|
-
"""Ensure that the value is an instance of TaskStatus."""
|
39
|
-
if not isinstance(value, TaskStatus):
|
40
|
-
raise ValueError("Value must be an instance of TaskStatus enum")
|
41
|
-
t = time.monotonic()
|
42
|
-
if hasattr(instance, "status_log"):
|
43
|
-
instance.status_log.append(TaskStatusLogEntry(t, value))
|
44
|
-
self._task_status = value
|
45
|
-
|
46
|
-
def __delete__(self, instance):
|
47
|
-
self._task_status = None
|
48
|
-
|
49
|
-
|
50
|
-
status_colors = {
|
51
|
-
TaskStatus.NOT_STARTED: "grey",
|
52
|
-
TaskStatus.WAITING_FOR_DEPENDENCIES: "orange",
|
53
|
-
TaskStatus.WAITING_FOR_REQUEST_CAPACITY: "yellow",
|
54
|
-
TaskStatus.WAITING_FOR_TOKEN_CAPACITY: "gold",
|
55
|
-
TaskStatus.CANCELLED: "white",
|
56
|
-
TaskStatus.PARENT_FAILED: "darkred",
|
57
|
-
TaskStatus.FAILED: "red",
|
58
|
-
TaskStatus.API_CALL_IN_PROGRESS: "blue",
|
59
|
-
TaskStatus.SUCCESS: "green",
|
60
|
-
}
|
61
|
-
|
62
|
-
|
63
|
-
def get_enum_from_string(str_key):
|
64
|
-
"""Parse the string to extract the enum member name."""
|
65
|
-
try:
|
66
|
-
_, member_name = str_key.split(".")
|
67
|
-
enum_member = getattr(TaskStatus, member_name)
|
68
|
-
return enum_member
|
69
|
-
except ValueError:
|
70
|
-
return str_key
|
71
|
-
|
72
|
-
|
73
|
-
class InterviewTaskLogDict(UserDict):
|
74
|
-
"""A dictionary of TaskStatusLog objects.
|
75
|
-
|
76
|
-
The key is the name of the task.
|
77
|
-
"""
|
78
|
-
|
79
|
-
@property
|
80
|
-
def min_time(self):
|
81
|
-
return min([log.min_time for log in self.values()])
|
82
|
-
|
83
|
-
@property
|
84
|
-
def max_time(self):
|
85
|
-
return max([log.max_time for log in self.values()])
|
86
|
-
|
87
|
-
def status_matrix(self, num_periods):
|
88
|
-
"""Return a matrix of status values."""
|
89
|
-
start_time = self.min_time
|
90
|
-
end_time = self.max_time
|
91
|
-
time_increment = (end_time - start_time) / num_periods
|
92
|
-
status_matrix = {}
|
93
|
-
time_periods = [start_time + i * time_increment for i in range(num_periods)]
|
94
|
-
for task_name, log in self.items():
|
95
|
-
status_matrix[task_name] = [log.status_at_time(t) for t in time_periods]
|
96
|
-
return status_matrix
|
97
|
-
|
98
|
-
def numerical_matrix(self, num_periods):
|
99
|
-
"""Return a numerical matrix of status values."""
|
100
|
-
status_dicts = self.status_matrix(num_periods)
|
101
|
-
|
102
|
-
num_cols = num_periods
|
103
|
-
num_rows = len(status_dicts)
|
104
|
-
matrix = [[0 for _ in range(num_cols)] for _ in range(num_rows)]
|
105
|
-
|
106
|
-
for row_index, (task_name, status_list) in enumerate(status_dicts.items()):
|
107
|
-
matrix[row_index] = [
|
108
|
-
list(status_colors.keys()).index(status) for status in status_list
|
109
|
-
]
|
110
|
-
|
111
|
-
index_to_names = {i: name for i, name in enumerate(status_dicts.keys())}
|
112
|
-
return matrix, index_to_names
|
113
|
-
|
114
|
-
def visualize(self, num_periods=10):
|
115
|
-
"""Visualize the status matrix with outlined squares."""
|
116
|
-
import matplotlib.pyplot as plt
|
117
|
-
from matplotlib.colors import ListedColormap
|
118
|
-
import numpy as np
|
119
|
-
from matplotlib.patches import Rectangle
|
120
|
-
|
121
|
-
# Define your custom colormap
|
122
|
-
custom_cmap = ListedColormap(list(status_colors.values()))
|
123
|
-
|
124
|
-
# Generate the matrix
|
125
|
-
matrix, index_to_names = self.numerical_matrix(num_periods)
|
126
|
-
|
127
|
-
# Create the figure and axes
|
128
|
-
plt.figure(figsize=(10, 5))
|
129
|
-
ax = plt.gca()
|
130
|
-
|
131
|
-
# Display the matrix and keep a reference to the imshow object
|
132
|
-
im = ax.imshow(matrix, aspect="auto", cmap=custom_cmap)
|
133
|
-
|
134
|
-
# Adding color bar, now correctly associating it with 'im'
|
135
|
-
cbar = plt.colorbar(im, ticks=range(len(status_colors)), label="Task Status")
|
136
|
-
|
137
|
-
cbar_labels = [status.name for status in status_colors.keys()]
|
138
|
-
# breakpoint()
|
139
|
-
cbar.set_ticklabels(cbar_labels) # Setting the custom labels for the colorbar
|
140
|
-
|
141
|
-
im.set_clim(
|
142
|
-
-0.5, len(status_colors) - 0.5
|
143
|
-
) # Setting color limits directly on the imshow object
|
144
|
-
|
145
|
-
# Outline each cell by drawing rectangles
|
146
|
-
for (j, i), val in np.ndenumerate(matrix):
|
147
|
-
ax.add_patch(
|
148
|
-
Rectangle(
|
149
|
-
(i - 0.5, j - 0.5), 1, 1, fill=False, edgecolor="black", lw=0.5
|
150
|
-
)
|
151
|
-
)
|
152
|
-
|
153
|
-
# Set custom y-axis ticks and labels
|
154
|
-
yticks = list(index_to_names.keys())
|
155
|
-
yticklabels = list(index_to_names.values())
|
156
|
-
plt.yticks(ticks=yticks, labels=yticklabels)
|
157
|
-
|
158
|
-
# Show the plot
|
159
|
-
plt.show()
|
160
|
-
|
161
|
-
|
162
|
-
if __name__ == "__main__":
|
163
|
-
pass
|
1
|
+
from __future__ import annotations
|
2
|
+
from collections import UserDict
|
3
|
+
import enum
|
4
|
+
import time
|
5
|
+
|
6
|
+
# from edsl.jobs.tasks.TaskStatusLogEntry import TaskStatusLogEntry
|
7
|
+
|
8
|
+
|
9
|
+
class TaskStatus(enum.Enum):
|
10
|
+
"These are the possible states a task can be in."
|
11
|
+
NOT_STARTED = enum.auto()
|
12
|
+
WAITING_FOR_DEPENDENCIES = enum.auto()
|
13
|
+
CANCELLED = enum.auto()
|
14
|
+
PARENT_FAILED = enum.auto()
|
15
|
+
WAITING_FOR_REQUEST_CAPACITY = enum.auto()
|
16
|
+
WAITING_FOR_TOKEN_CAPACITY = enum.auto()
|
17
|
+
API_CALL_IN_PROGRESS = enum.auto()
|
18
|
+
SUCCESS = enum.auto()
|
19
|
+
FAILED = enum.auto()
|
20
|
+
|
21
|
+
|
22
|
+
class TaskStatusLogEntry(UserDict):
|
23
|
+
def __init__(self, log_time, value):
|
24
|
+
self.data = {"log_time": log_time, "value": value}
|
25
|
+
super().__init__(self.data)
|
26
|
+
|
27
|
+
|
28
|
+
class TaskStatusDescriptor:
|
29
|
+
"The descriptor ensures that the task status is always an instance of the TaskStatus enum."
|
30
|
+
|
31
|
+
def __init__(self):
|
32
|
+
self._task_status = None
|
33
|
+
|
34
|
+
def __get__(self, instance, owner):
|
35
|
+
return self._task_status
|
36
|
+
|
37
|
+
def __set__(self, instance, value):
|
38
|
+
"""Ensure that the value is an instance of TaskStatus."""
|
39
|
+
if not isinstance(value, TaskStatus):
|
40
|
+
raise ValueError("Value must be an instance of TaskStatus enum")
|
41
|
+
t = time.monotonic()
|
42
|
+
if hasattr(instance, "status_log"):
|
43
|
+
instance.status_log.append(TaskStatusLogEntry(t, value))
|
44
|
+
self._task_status = value
|
45
|
+
|
46
|
+
def __delete__(self, instance):
|
47
|
+
self._task_status = None
|
48
|
+
|
49
|
+
|
50
|
+
status_colors = {
|
51
|
+
TaskStatus.NOT_STARTED: "grey",
|
52
|
+
TaskStatus.WAITING_FOR_DEPENDENCIES: "orange",
|
53
|
+
TaskStatus.WAITING_FOR_REQUEST_CAPACITY: "yellow",
|
54
|
+
TaskStatus.WAITING_FOR_TOKEN_CAPACITY: "gold",
|
55
|
+
TaskStatus.CANCELLED: "white",
|
56
|
+
TaskStatus.PARENT_FAILED: "darkred",
|
57
|
+
TaskStatus.FAILED: "red",
|
58
|
+
TaskStatus.API_CALL_IN_PROGRESS: "blue",
|
59
|
+
TaskStatus.SUCCESS: "green",
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
def get_enum_from_string(str_key):
|
64
|
+
"""Parse the string to extract the enum member name."""
|
65
|
+
try:
|
66
|
+
_, member_name = str_key.split(".")
|
67
|
+
enum_member = getattr(TaskStatus, member_name)
|
68
|
+
return enum_member
|
69
|
+
except ValueError:
|
70
|
+
return str_key
|
71
|
+
|
72
|
+
|
73
|
+
class InterviewTaskLogDict(UserDict):
|
74
|
+
"""A dictionary of TaskStatusLog objects.
|
75
|
+
|
76
|
+
The key is the name of the task.
|
77
|
+
"""
|
78
|
+
|
79
|
+
@property
|
80
|
+
def min_time(self):
|
81
|
+
return min([log.min_time for log in self.values()])
|
82
|
+
|
83
|
+
@property
|
84
|
+
def max_time(self):
|
85
|
+
return max([log.max_time for log in self.values()])
|
86
|
+
|
87
|
+
def status_matrix(self, num_periods):
|
88
|
+
"""Return a matrix of status values."""
|
89
|
+
start_time = self.min_time
|
90
|
+
end_time = self.max_time
|
91
|
+
time_increment = (end_time - start_time) / num_periods
|
92
|
+
status_matrix = {}
|
93
|
+
time_periods = [start_time + i * time_increment for i in range(num_periods)]
|
94
|
+
for task_name, log in self.items():
|
95
|
+
status_matrix[task_name] = [log.status_at_time(t) for t in time_periods]
|
96
|
+
return status_matrix
|
97
|
+
|
98
|
+
def numerical_matrix(self, num_periods):
|
99
|
+
"""Return a numerical matrix of status values."""
|
100
|
+
status_dicts = self.status_matrix(num_periods)
|
101
|
+
|
102
|
+
num_cols = num_periods
|
103
|
+
num_rows = len(status_dicts)
|
104
|
+
matrix = [[0 for _ in range(num_cols)] for _ in range(num_rows)]
|
105
|
+
|
106
|
+
for row_index, (task_name, status_list) in enumerate(status_dicts.items()):
|
107
|
+
matrix[row_index] = [
|
108
|
+
list(status_colors.keys()).index(status) for status in status_list
|
109
|
+
]
|
110
|
+
|
111
|
+
index_to_names = {i: name for i, name in enumerate(status_dicts.keys())}
|
112
|
+
return matrix, index_to_names
|
113
|
+
|
114
|
+
def visualize(self, num_periods=10):
|
115
|
+
"""Visualize the status matrix with outlined squares."""
|
116
|
+
import matplotlib.pyplot as plt
|
117
|
+
from matplotlib.colors import ListedColormap
|
118
|
+
import numpy as np
|
119
|
+
from matplotlib.patches import Rectangle
|
120
|
+
|
121
|
+
# Define your custom colormap
|
122
|
+
custom_cmap = ListedColormap(list(status_colors.values()))
|
123
|
+
|
124
|
+
# Generate the matrix
|
125
|
+
matrix, index_to_names = self.numerical_matrix(num_periods)
|
126
|
+
|
127
|
+
# Create the figure and axes
|
128
|
+
plt.figure(figsize=(10, 5))
|
129
|
+
ax = plt.gca()
|
130
|
+
|
131
|
+
# Display the matrix and keep a reference to the imshow object
|
132
|
+
im = ax.imshow(matrix, aspect="auto", cmap=custom_cmap)
|
133
|
+
|
134
|
+
# Adding color bar, now correctly associating it with 'im'
|
135
|
+
cbar = plt.colorbar(im, ticks=range(len(status_colors)), label="Task Status")
|
136
|
+
|
137
|
+
cbar_labels = [status.name for status in status_colors.keys()]
|
138
|
+
# breakpoint()
|
139
|
+
cbar.set_ticklabels(cbar_labels) # Setting the custom labels for the colorbar
|
140
|
+
|
141
|
+
im.set_clim(
|
142
|
+
-0.5, len(status_colors) - 0.5
|
143
|
+
) # Setting color limits directly on the imshow object
|
144
|
+
|
145
|
+
# Outline each cell by drawing rectangles
|
146
|
+
for (j, i), val in np.ndenumerate(matrix):
|
147
|
+
ax.add_patch(
|
148
|
+
Rectangle(
|
149
|
+
(i - 0.5, j - 0.5), 1, 1, fill=False, edgecolor="black", lw=0.5
|
150
|
+
)
|
151
|
+
)
|
152
|
+
|
153
|
+
# Set custom y-axis ticks and labels
|
154
|
+
yticks = list(index_to_names.keys())
|
155
|
+
yticklabels = list(index_to_names.values())
|
156
|
+
plt.yticks(ticks=yticks, labels=yticklabels)
|
157
|
+
|
158
|
+
# Show the plot
|
159
|
+
plt.show()
|
160
|
+
|
161
|
+
|
162
|
+
if __name__ == "__main__":
|
163
|
+
pass
|
@@ -1,27 +1,27 @@
|
|
1
|
-
from edsl.jobs.tokens.TokenUsage import TokenUsage
|
2
|
-
from edsl.enums import TokenPricing
|
3
|
-
|
4
|
-
|
5
|
-
class InterviewTokenUsage:
|
6
|
-
def __init__(
|
7
|
-
self, new_token_usage: TokenUsage = None, cached_token_usage: TokenUsage = None
|
8
|
-
):
|
9
|
-
self.new_token_usage = new_token_usage or TokenUsage(from_cache=False)
|
10
|
-
self.cached_token_usage = cached_token_usage or TokenUsage(from_cache=True)
|
11
|
-
|
12
|
-
def __add__(self, other):
|
13
|
-
if not isinstance(other, InterviewTokenUsage):
|
14
|
-
raise ValueError(f"Can't add {type(other)} to InterviewTokenSummary")
|
15
|
-
return InterviewTokenUsage(
|
16
|
-
new_token_usage=self.new_token_usage + other.new_token_usage,
|
17
|
-
cached_token_usage=self.cached_token_usage + other.cached_token_usage,
|
18
|
-
)
|
19
|
-
|
20
|
-
def __repr__(self):
|
21
|
-
return f"InterviewTokenUsage(new_token_usage={self.new_token_usage}, cached_token_usage={self.cached_token_usage})"
|
22
|
-
|
23
|
-
def cost(self, prices: TokenPricing):
|
24
|
-
return self.new_token_usage.cost(prices)
|
25
|
-
|
26
|
-
def saved(self, prices: TokenPricing):
|
27
|
-
return self.cached_token_usage.cost(prices)
|
1
|
+
from edsl.jobs.tokens.TokenUsage import TokenUsage
|
2
|
+
from edsl.enums import TokenPricing
|
3
|
+
|
4
|
+
|
5
|
+
class InterviewTokenUsage:
|
6
|
+
def __init__(
|
7
|
+
self, new_token_usage: TokenUsage = None, cached_token_usage: TokenUsage = None
|
8
|
+
):
|
9
|
+
self.new_token_usage = new_token_usage or TokenUsage(from_cache=False)
|
10
|
+
self.cached_token_usage = cached_token_usage or TokenUsage(from_cache=True)
|
11
|
+
|
12
|
+
def __add__(self, other):
|
13
|
+
if not isinstance(other, InterviewTokenUsage):
|
14
|
+
raise ValueError(f"Can't add {type(other)} to InterviewTokenSummary")
|
15
|
+
return InterviewTokenUsage(
|
16
|
+
new_token_usage=self.new_token_usage + other.new_token_usage,
|
17
|
+
cached_token_usage=self.cached_token_usage + other.cached_token_usage,
|
18
|
+
)
|
19
|
+
|
20
|
+
def __repr__(self):
|
21
|
+
return f"InterviewTokenUsage(new_token_usage={self.new_token_usage}, cached_token_usage={self.cached_token_usage})"
|
22
|
+
|
23
|
+
def cost(self, prices: TokenPricing):
|
24
|
+
return self.new_token_usage.cost(prices)
|
25
|
+
|
26
|
+
def saved(self, prices: TokenPricing):
|
27
|
+
return self.cached_token_usage.cost(prices)
|
edsl/jobs/tokens/TokenUsage.py
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
from edsl.enums import TokenPricing
|
2
|
-
|
3
|
-
|
4
|
-
class TokenUsage:
|
5
|
-
def __init__(
|
6
|
-
self, from_cache: bool, prompt_tokens: int = 0, completion_tokens: int = 0
|
7
|
-
):
|
8
|
-
self.from_cache = from_cache
|
9
|
-
self.prompt_tokens = prompt_tokens
|
10
|
-
self.completion_tokens = completion_tokens
|
11
|
-
|
12
|
-
def add_tokens(self, prompt_tokens, completion_tokens):
|
13
|
-
self.prompt_tokens += prompt_tokens
|
14
|
-
self.completion_tokens += completion_tokens
|
15
|
-
|
16
|
-
def __add__(self, other):
|
17
|
-
if not isinstance(other, TokenUsage):
|
18
|
-
raise ValueError(f"Can't add {type(other)} to InterviewTokenUsage")
|
19
|
-
if self.from_cache != other.from_cache:
|
20
|
-
raise ValueError(f"Can't add token usages from different sources")
|
21
|
-
return TokenUsage(
|
22
|
-
from_cache=self.from_cache,
|
23
|
-
prompt_tokens=self.prompt_tokens + other.prompt_tokens,
|
24
|
-
completion_tokens=self.completion_tokens + other.completion_tokens,
|
25
|
-
)
|
26
|
-
|
27
|
-
def __repr__(self):
|
28
|
-
return f"TokenUsage(from_cache={self.from_cache}, prompt_tokens={self.prompt_tokens}, completion_tokens={self.completion_tokens})"
|
29
|
-
|
30
|
-
def cost(self, prices: TokenPricing):
|
31
|
-
return (
|
32
|
-
self.prompt_tokens * prices.prompt_token_price
|
33
|
-
+ self.completion_tokens * prices.completion_token_price
|
34
|
-
)
|
1
|
+
from edsl.enums import TokenPricing
|
2
|
+
|
3
|
+
|
4
|
+
class TokenUsage:
|
5
|
+
def __init__(
|
6
|
+
self, from_cache: bool, prompt_tokens: int = 0, completion_tokens: int = 0
|
7
|
+
):
|
8
|
+
self.from_cache = from_cache
|
9
|
+
self.prompt_tokens = prompt_tokens
|
10
|
+
self.completion_tokens = completion_tokens
|
11
|
+
|
12
|
+
def add_tokens(self, prompt_tokens, completion_tokens):
|
13
|
+
self.prompt_tokens += prompt_tokens
|
14
|
+
self.completion_tokens += completion_tokens
|
15
|
+
|
16
|
+
def __add__(self, other):
|
17
|
+
if not isinstance(other, TokenUsage):
|
18
|
+
raise ValueError(f"Can't add {type(other)} to InterviewTokenUsage")
|
19
|
+
if self.from_cache != other.from_cache:
|
20
|
+
raise ValueError(f"Can't add token usages from different sources")
|
21
|
+
return TokenUsage(
|
22
|
+
from_cache=self.from_cache,
|
23
|
+
prompt_tokens=self.prompt_tokens + other.prompt_tokens,
|
24
|
+
completion_tokens=self.completion_tokens + other.completion_tokens,
|
25
|
+
)
|
26
|
+
|
27
|
+
def __repr__(self):
|
28
|
+
return f"TokenUsage(from_cache={self.from_cache}, prompt_tokens={self.prompt_tokens}, completion_tokens={self.completion_tokens})"
|
29
|
+
|
30
|
+
def cost(self, prices: TokenPricing):
|
31
|
+
return (
|
32
|
+
self.prompt_tokens * prices.prompt_token_price
|
33
|
+
+ self.completion_tokens * prices.completion_token_price
|
34
|
+
)
|
@@ -1,30 +1,30 @@
|
|
1
|
-
import os
|
2
|
-
from collections import UserDict
|
3
|
-
|
4
|
-
from edsl.enums import service_to_api_keyname
|
5
|
-
from edsl.exceptions import MissingAPIKeyError
|
6
|
-
|
7
|
-
|
8
|
-
class KeyLookup(UserDict):
|
9
|
-
@classmethod
|
10
|
-
def from_os_environ(cls):
|
11
|
-
"""Create an instance of KeyLookupAPI with keys from os.environ"""
|
12
|
-
return cls({key: value for key, value in os.environ.items()})
|
13
|
-
|
14
|
-
def get_api_token(self, service: str, remote: bool = False):
|
15
|
-
key_name = service_to_api_keyname.get(service, "NOT FOUND")
|
16
|
-
|
17
|
-
if service == "bedrock":
|
18
|
-
api_token = [self.get(key_name[0]), self.get(key_name[1])]
|
19
|
-
missing_token = any(token is None for token in api_token)
|
20
|
-
else:
|
21
|
-
api_token = self.get(key_name)
|
22
|
-
missing_token = api_token is None
|
23
|
-
|
24
|
-
if missing_token and service != "test" and not remote:
|
25
|
-
raise MissingAPIKeyError(
|
26
|
-
f"""The key for service: `{service}` is not set.
|
27
|
-
Need a key with name {key_name} in your .env file."""
|
28
|
-
)
|
29
|
-
|
30
|
-
return api_token
|
1
|
+
import os
|
2
|
+
from collections import UserDict
|
3
|
+
|
4
|
+
from edsl.enums import service_to_api_keyname
|
5
|
+
from edsl.exceptions import MissingAPIKeyError
|
6
|
+
|
7
|
+
|
8
|
+
class KeyLookup(UserDict):
|
9
|
+
@classmethod
|
10
|
+
def from_os_environ(cls):
|
11
|
+
"""Create an instance of KeyLookupAPI with keys from os.environ"""
|
12
|
+
return cls({key: value for key, value in os.environ.items()})
|
13
|
+
|
14
|
+
def get_api_token(self, service: str, remote: bool = False):
|
15
|
+
key_name = service_to_api_keyname.get(service, "NOT FOUND")
|
16
|
+
|
17
|
+
if service == "bedrock":
|
18
|
+
api_token = [self.get(key_name[0]), self.get(key_name[1])]
|
19
|
+
missing_token = any(token is None for token in api_token)
|
20
|
+
else:
|
21
|
+
api_token = self.get(key_name)
|
22
|
+
missing_token = api_token is None
|
23
|
+
|
24
|
+
if missing_token and service != "test" and not remote:
|
25
|
+
raise MissingAPIKeyError(
|
26
|
+
f"""The key for service: `{service}` is not set.
|
27
|
+
Need a key with name {key_name} in your .env file."""
|
28
|
+
)
|
29
|
+
|
30
|
+
return api_token
|