edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev4__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 +413 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +57 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +1071 -867
- edsl/agents/AgentList.py +551 -413
- edsl/agents/Invigilator.py +284 -233
- edsl/agents/InvigilatorBase.py +257 -270
- edsl/agents/PromptConstructor.py +272 -354
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +2 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -117
- edsl/auto/StageBase.py +243 -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 +74 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +218 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +177 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +59 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1106 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +573 -555
- edsl/data/CacheEntry.py +230 -233
- edsl/data/CacheHandler.py +168 -149
- edsl/data/RemoteCacheSync.py +186 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +5 -4
- edsl/data/hack.py +10 -0
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +74 -73
- edsl/enums.py +202 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +54 -42
- edsl/exceptions/cache.py +5 -5
- 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/inference_services.py +5 -0
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +109 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +29 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +106 -87
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -120
- edsl/inference_services/AzureAI.py +215 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +143 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +80 -147
- edsl/inference_services/InferenceServicesCollection.py +138 -97
- edsl/inference_services/MistralAIService.py +120 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +236 -224
- edsl/inference_services/PerplexityService.py +160 -163
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -89
- edsl/inference_services/TogetherAIService.py +172 -170
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +43 -56
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +823 -898
- edsl/jobs/JobsChecks.py +172 -147
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +283 -251
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +396 -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/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
- edsl/jobs/runners/JobsRunnerStatus.py +297 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +470 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +161 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +626 -668
- edsl/language_models/ModelList.py +164 -155
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +2 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +156 -156
- edsl/language_models/utilities.py +65 -64
- edsl/notebooks/Notebook.py +263 -258
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +352 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -664
- edsl/questions/QuestionBasePromptsMixin.py +221 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +180 -182
- edsl/questions/QuestionFreeText.py +113 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +223 -231
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +330 -286
- edsl/questions/QuestionNumerical.py +151 -153
- edsl/questions/QuestionRank.py +314 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/SimpleAskMixin.py +74 -73
- edsl/questions/__init__.py +27 -26
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +90 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +427 -413
- edsl/questions/loop_processor.py +149 -0
- 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/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
- edsl/questions/question_registry.py +177 -177
- edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
- edsl/questions/response_validator_factory.py +34 -0
- 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/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- 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 -108
- edsl/results/Dataset.py +587 -424
- edsl/results/DatasetExportMixin.py +594 -731
- edsl/results/DatasetTree.py +295 -275
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +557 -465
- edsl/results/Results.py +1183 -1165
- edsl/results/ResultsExportMixin.py +45 -43
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/TableDisplay.py +125 -198
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +2 -2
- edsl/results/file_exports.py +252 -0
- edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
- edsl/results/{Selector.py → results_selector.py} +145 -135
- edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +77 -77
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +511 -632
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +498 -601
- edsl/scenarios/ScenarioHtmlMixin.py +65 -64
- edsl/scenarios/ScenarioList.py +1458 -1287
- edsl/scenarios/ScenarioListExportMixin.py +45 -52
- edsl/scenarios/ScenarioListPdfMixin.py +239 -261
- edsl/scenarios/__init__.py +3 -4
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +38 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
- edsl/scenarios/scenario_selector.py +156 -0
- 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 +521 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +327 -326
- edsl/surveys/RuleCollection.py +385 -387
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1280 -1801
- edsl/surveys/SurveyCSS.py +273 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +5 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +60 -56
- edsl/surveys/instructions/ChangeInstruction.py +48 -49
- edsl/surveys/instructions/Instruction.py +56 -65
- edsl/surveys/instructions/InstructionCollection.py +82 -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 -19
- 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/test_h +1 -0
- 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/PrettyList.py +56 -0
- 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/gcp_bucket/example.py +50 -0
- edsl/utilities/interface.py +627 -627
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +436 -424
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/METADATA +13 -11
- edsl-0.1.39.dev4.dist-info/RECORD +361 -0
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.39.dev3.dist-info/RECORD +0 -277
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.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,161 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from collections import UserDict
|
3
|
-
import enum
|
4
|
-
import time
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
TaskStatus.
|
52
|
-
TaskStatus.
|
53
|
-
TaskStatus.
|
54
|
-
TaskStatus.
|
55
|
-
TaskStatus.
|
56
|
-
TaskStatus.
|
57
|
-
TaskStatus.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
return
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
import
|
117
|
-
from matplotlib.
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
cbar_labels
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
yticks =
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
+
|
7
|
+
class TaskStatus(enum.Enum):
|
8
|
+
"These are the possible states a task can be in."
|
9
|
+
NOT_STARTED = enum.auto()
|
10
|
+
WAITING_FOR_DEPENDENCIES = enum.auto()
|
11
|
+
CANCELLED = enum.auto()
|
12
|
+
PARENT_FAILED = enum.auto()
|
13
|
+
WAITING_FOR_REQUEST_CAPACITY = enum.auto()
|
14
|
+
WAITING_FOR_TOKEN_CAPACITY = enum.auto()
|
15
|
+
API_CALL_IN_PROGRESS = enum.auto()
|
16
|
+
SUCCESS = enum.auto()
|
17
|
+
FAILED = enum.auto()
|
18
|
+
|
19
|
+
|
20
|
+
class TaskStatusLogEntry(UserDict):
|
21
|
+
def __init__(self, log_time, value):
|
22
|
+
self.data = {"log_time": log_time, "value": value}
|
23
|
+
super().__init__(self.data)
|
24
|
+
|
25
|
+
|
26
|
+
class TaskStatusDescriptor:
|
27
|
+
"The descriptor ensures that the task status is always an instance of the TaskStatus enum."
|
28
|
+
|
29
|
+
def __init__(self):
|
30
|
+
self._task_status = None
|
31
|
+
|
32
|
+
def __get__(self, instance, owner):
|
33
|
+
return self._task_status
|
34
|
+
|
35
|
+
def __set__(self, instance, value):
|
36
|
+
"""Ensure that the value is an instance of TaskStatus."""
|
37
|
+
if not isinstance(value, TaskStatus):
|
38
|
+
raise ValueError("Value must be an instance of TaskStatus enum")
|
39
|
+
t = time.monotonic()
|
40
|
+
if hasattr(instance, "status_log"):
|
41
|
+
instance.status_log.append(TaskStatusLogEntry(t, value))
|
42
|
+
self._task_status = value
|
43
|
+
|
44
|
+
def __delete__(self, instance):
|
45
|
+
self._task_status = None
|
46
|
+
|
47
|
+
|
48
|
+
status_colors = {
|
49
|
+
TaskStatus.NOT_STARTED: "grey",
|
50
|
+
TaskStatus.WAITING_FOR_DEPENDENCIES: "orange",
|
51
|
+
TaskStatus.WAITING_FOR_REQUEST_CAPACITY: "yellow",
|
52
|
+
TaskStatus.WAITING_FOR_TOKEN_CAPACITY: "gold",
|
53
|
+
TaskStatus.CANCELLED: "white",
|
54
|
+
TaskStatus.PARENT_FAILED: "darkred",
|
55
|
+
TaskStatus.FAILED: "red",
|
56
|
+
TaskStatus.API_CALL_IN_PROGRESS: "blue",
|
57
|
+
TaskStatus.SUCCESS: "green",
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
def get_enum_from_string(str_key):
|
62
|
+
"""Parse the string to extract the enum member name."""
|
63
|
+
try:
|
64
|
+
_, member_name = str_key.split(".")
|
65
|
+
enum_member = getattr(TaskStatus, member_name)
|
66
|
+
return enum_member
|
67
|
+
except ValueError:
|
68
|
+
return str_key
|
69
|
+
|
70
|
+
|
71
|
+
class InterviewTaskLogDict(UserDict):
|
72
|
+
"""A dictionary of TaskStatusLog objects.
|
73
|
+
|
74
|
+
The key is the name of the task.
|
75
|
+
"""
|
76
|
+
|
77
|
+
@property
|
78
|
+
def min_time(self):
|
79
|
+
return min([log.min_time for log in self.values()])
|
80
|
+
|
81
|
+
@property
|
82
|
+
def max_time(self):
|
83
|
+
return max([log.max_time for log in self.values()])
|
84
|
+
|
85
|
+
def status_matrix(self, num_periods):
|
86
|
+
"""Return a matrix of status values."""
|
87
|
+
start_time = self.min_time
|
88
|
+
end_time = self.max_time
|
89
|
+
time_increment = (end_time - start_time) / num_periods
|
90
|
+
status_matrix = {}
|
91
|
+
time_periods = [start_time + i * time_increment for i in range(num_periods)]
|
92
|
+
for task_name, log in self.items():
|
93
|
+
status_matrix[task_name] = [log.status_at_time(t) for t in time_periods]
|
94
|
+
return status_matrix
|
95
|
+
|
96
|
+
def numerical_matrix(self, num_periods):
|
97
|
+
"""Return a numerical matrix of status values."""
|
98
|
+
status_dicts = self.status_matrix(num_periods)
|
99
|
+
|
100
|
+
num_cols = num_periods
|
101
|
+
num_rows = len(status_dicts)
|
102
|
+
matrix = [[0 for _ in range(num_cols)] for _ in range(num_rows)]
|
103
|
+
|
104
|
+
for row_index, (task_name, status_list) in enumerate(status_dicts.items()):
|
105
|
+
matrix[row_index] = [
|
106
|
+
list(status_colors.keys()).index(status) for status in status_list
|
107
|
+
]
|
108
|
+
|
109
|
+
index_to_names = {i: name for i, name in enumerate(status_dicts.keys())}
|
110
|
+
return matrix, index_to_names
|
111
|
+
|
112
|
+
def visualize(self, num_periods=10):
|
113
|
+
"""Visualize the status matrix with outlined squares."""
|
114
|
+
import matplotlib.pyplot as plt
|
115
|
+
from matplotlib.colors import ListedColormap
|
116
|
+
import numpy as np
|
117
|
+
from matplotlib.patches import Rectangle
|
118
|
+
|
119
|
+
# Define your custom colormap
|
120
|
+
custom_cmap = ListedColormap(list(status_colors.values()))
|
121
|
+
|
122
|
+
# Generate the matrix
|
123
|
+
matrix, index_to_names = self.numerical_matrix(num_periods)
|
124
|
+
|
125
|
+
# Create the figure and axes
|
126
|
+
plt.figure(figsize=(10, 5))
|
127
|
+
ax = plt.gca()
|
128
|
+
|
129
|
+
# Display the matrix and keep a reference to the imshow object
|
130
|
+
im = ax.imshow(matrix, aspect="auto", cmap=custom_cmap)
|
131
|
+
|
132
|
+
# Adding color bar, now correctly associating it with 'im'
|
133
|
+
cbar = plt.colorbar(im, ticks=range(len(status_colors)), label="Task Status")
|
134
|
+
|
135
|
+
cbar_labels = [status.name for status in status_colors.keys()]
|
136
|
+
# breakpoint()
|
137
|
+
cbar.set_ticklabels(cbar_labels) # Setting the custom labels for the colorbar
|
138
|
+
|
139
|
+
im.set_clim(
|
140
|
+
-0.5, len(status_colors) - 0.5
|
141
|
+
) # Setting color limits directly on the imshow object
|
142
|
+
|
143
|
+
# Outline each cell by drawing rectangles
|
144
|
+
for (j, i), val in np.ndenumerate(matrix):
|
145
|
+
ax.add_patch(
|
146
|
+
Rectangle(
|
147
|
+
(i - 0.5, j - 0.5), 1, 1, fill=False, edgecolor="black", lw=0.5
|
148
|
+
)
|
149
|
+
)
|
150
|
+
|
151
|
+
# Set custom y-axis ticks and labels
|
152
|
+
yticks = list(index_to_names.keys())
|
153
|
+
yticklabels = list(index_to_names.values())
|
154
|
+
plt.yticks(ticks=yticks, labels=yticklabels)
|
155
|
+
|
156
|
+
# Show the plot
|
157
|
+
plt.show()
|
158
|
+
|
159
|
+
|
160
|
+
if __name__ == "__main__":
|
161
|
+
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
|
+
)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
from typing import Any, Union
|
2
|
+
|
3
|
+
|
4
|
+
class ComputeCost:
|
5
|
+
def __init__(self, language_model: "LanguageModel"):
|
6
|
+
self.language_model = language_model
|
7
|
+
self._price_lookup = None
|
8
|
+
|
9
|
+
@property
|
10
|
+
def price_lookup(self):
|
11
|
+
if self._price_lookup is None:
|
12
|
+
from edsl.coop import Coop
|
13
|
+
|
14
|
+
c = Coop()
|
15
|
+
self._price_lookup = c.fetch_prices()
|
16
|
+
return self._price_lookup
|
17
|
+
|
18
|
+
def cost(self, raw_response: dict[str, Any]) -> Union[float, str]:
|
19
|
+
"""Return the dollar cost of a raw response."""
|
20
|
+
|
21
|
+
usage = self.get_usage_dict(raw_response)
|
22
|
+
from edsl.coop import Coop
|
23
|
+
|
24
|
+
c = Coop()
|
25
|
+
price_lookup = c.fetch_prices()
|
26
|
+
key = (self._inference_service_, self.model)
|
27
|
+
if key not in price_lookup:
|
28
|
+
return f"Could not find price for model {self.model} in the price lookup."
|
29
|
+
|
30
|
+
relevant_prices = price_lookup[key]
|
31
|
+
try:
|
32
|
+
input_tokens = int(usage[self.input_token_name])
|
33
|
+
output_tokens = int(usage[self.output_token_name])
|
34
|
+
except Exception as e:
|
35
|
+
return f"Could not fetch tokens from model response: {e}"
|
36
|
+
|
37
|
+
try:
|
38
|
+
inverse_output_price = relevant_prices["output"]["one_usd_buys"]
|
39
|
+
inverse_input_price = relevant_prices["input"]["one_usd_buys"]
|
40
|
+
except Exception as e:
|
41
|
+
if "output" not in relevant_prices:
|
42
|
+
return f"Could not fetch prices from {relevant_prices} - {e}; Missing 'output' key."
|
43
|
+
if "input" not in relevant_prices:
|
44
|
+
return f"Could not fetch prices from {relevant_prices} - {e}; Missing 'input' key."
|
45
|
+
return f"Could not fetch prices from {relevant_prices} - {e}"
|
46
|
+
|
47
|
+
if inverse_input_price == "infinity":
|
48
|
+
input_cost = 0
|
49
|
+
else:
|
50
|
+
try:
|
51
|
+
input_cost = input_tokens / float(inverse_input_price)
|
52
|
+
except Exception as e:
|
53
|
+
return f"Could not compute input price - {e}."
|
54
|
+
|
55
|
+
if inverse_output_price == "infinity":
|
56
|
+
output_cost = 0
|
57
|
+
else:
|
58
|
+
try:
|
59
|
+
output_cost = output_tokens / float(inverse_output_price)
|
60
|
+
except Exception as e:
|
61
|
+
return f"Could not compute output price - {e}"
|
62
|
+
|
63
|
+
return input_cost + output_cost
|