edsl 0.1.39.dev2__py3-none-any.whl → 0.1.39.dev3__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 -385
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +49 -57
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +867 -1079
- edsl/agents/AgentList.py +413 -551
- edsl/agents/Invigilator.py +233 -285
- edsl/agents/InvigilatorBase.py +270 -254
- edsl/agents/PromptConstructor.py +354 -252
- edsl/agents/__init__.py +3 -2
- 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 -279
- edsl/config.py +157 -177
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +58 -59
- 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 -1090
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +555 -562
- edsl/data/CacheEntry.py +233 -230
- edsl/data/CacheHandler.py +149 -170
- edsl/data/RemoteCacheSync.py +78 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +4 -5
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +73 -74
- edsl/enums.py +175 -195
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +42 -54
- 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/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +91 -109
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +22 -29
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +87 -84
- edsl/inference_services/AwsBedrock.py +120 -118
- edsl/inference_services/AzureAI.py +217 -215
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +148 -139
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +147 -80
- edsl/inference_services/InferenceServicesCollection.py +97 -122
- edsl/inference_services/MistralAIService.py +123 -120
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +224 -221
- edsl/inference_services/PerplexityService.py +163 -160
- edsl/inference_services/TestService.py +89 -92
- 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 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/Answers.py +56 -43
- edsl/jobs/Jobs.py +898 -757
- edsl/jobs/JobsChecks.py +147 -172
- edsl/jobs/JobsPrompts.py +268 -270
- edsl/jobs/JobsRemoteInferenceHandler.py +239 -287
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/buckets/BucketCollection.py +63 -104
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +251 -283
- edsl/jobs/interviews/Interview.py +661 -358
- 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 -421
- edsl/jobs/runners/JobsRunnerStatus.py +330 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +242 -244
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +450 -449
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +163 -161
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/KeyLookup.py +30 -0
- edsl/language_models/LanguageModel.py +668 -571
- edsl/language_models/ModelList.py +155 -153
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/__init__.py +3 -2
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/registry.py +190 -180
- edsl/language_models/repair.py +156 -156
- edsl/language_models/unused/ReplicateBase.py +83 -0
- edsl/language_models/utilities.py +64 -65
- edsl/notebooks/Notebook.py +258 -263
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +362 -352
- edsl/prompts/__init__.py +2 -2
- edsl/questions/AnswerValidatorMixin.py +289 -334
- edsl/questions/QuestionBase.py +664 -509
- edsl/questions/QuestionBaseGenMixin.py +161 -165
- edsl/questions/QuestionBasePromptsMixin.py +217 -221
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +182 -182
- edsl/questions/QuestionFreeText.py +114 -113
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +231 -229
- edsl/questions/QuestionMultipleChoice.py +286 -330
- edsl/questions/QuestionNumerical.py +153 -151
- edsl/questions/QuestionRank.py +324 -314
- edsl/questions/Quick.py +41 -41
- edsl/questions/RegisterQuestionsMeta.py +71 -71
- edsl/questions/ResponseValidatorABC.py +174 -200
- edsl/questions/SimpleAskMixin.py +73 -74
- edsl/questions/__init__.py +26 -27
- 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 -90
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +413 -427
- 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 -177
- 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 -108
- edsl/results/Dataset.py +424 -587
- edsl/results/DatasetExportMixin.py +731 -653
- edsl/results/DatasetTree.py +275 -295
- edsl/results/Result.py +465 -451
- edsl/results/Results.py +1165 -1172
- edsl/results/ResultsDBMixin.py +238 -0
- edsl/results/ResultsExportMixin.py +43 -45
- edsl/results/ResultsFetchMixin.py +33 -33
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/ResultsToolsMixin.py +98 -98
- edsl/results/Selector.py +135 -145
- edsl/results/TableDisplay.py +198 -125
- edsl/results/__init__.py +2 -2
- edsl/results/table_display.css +77 -77
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/FileStore.py +632 -511
- edsl/scenarios/Scenario.py +601 -498
- edsl/scenarios/ScenarioHtmlMixin.py +64 -65
- edsl/scenarios/ScenarioJoin.py +127 -131
- edsl/scenarios/ScenarioList.py +1287 -1430
- edsl/scenarios/ScenarioListExportMixin.py +52 -45
- edsl/scenarios/ScenarioListPdfMixin.py +261 -239
- edsl/scenarios/__init__.py +4 -3
- 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 -521
- 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 -327
- edsl/surveys/RuleCollection.py +387 -385
- edsl/surveys/Survey.py +1801 -1229
- edsl/surveys/SurveyCSS.py +261 -273
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualization.py → SurveyFlowVisualizationMixin.py} +179 -181
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/__init__.py +3 -5
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +56 -60
- edsl/surveys/instructions/ChangeInstruction.py +49 -48
- edsl/surveys/instructions/Instruction.py +65 -56
- edsl/surveys/instructions/InstructionCollection.py +77 -82
- 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/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/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 -436
- {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/METADATA +10 -12
- edsl-0.1.39.dev3.dist-info/RECORD +277 -0
- edsl/agents/QuestionInstructionPromptBuilder.py +0 -128
- edsl/agents/QuestionOptionProcessor.py +0 -172
- edsl/agents/QuestionTemplateReplacementsBuilder.py +0 -137
- edsl/coop/CoopFunctionsMixin.py +0 -15
- edsl/coop/ExpectedParrotKeyHandler.py +0 -125
- edsl/exceptions/inference_services.py +0 -5
- edsl/inference_services/AvailableModelCacheHandler.py +0 -184
- edsl/inference_services/AvailableModelFetcher.py +0 -209
- edsl/inference_services/ServiceAvailability.py +0 -135
- edsl/inference_services/data_structures.py +0 -62
- edsl/jobs/AnswerQuestionFunctionConstructor.py +0 -188
- edsl/jobs/FetchInvigilator.py +0 -40
- edsl/jobs/InterviewTaskManager.py +0 -98
- edsl/jobs/InterviewsConstructor.py +0 -48
- edsl/jobs/JobsComponentConstructor.py +0 -189
- edsl/jobs/JobsRemoteInferenceLogger.py +0 -239
- edsl/jobs/RequestTokenEstimator.py +0 -30
- edsl/jobs/buckets/TokenBucketAPI.py +0 -211
- edsl/jobs/buckets/TokenBucketClient.py +0 -191
- edsl/jobs/decorators.py +0 -35
- edsl/jobs/jobs_status_enums.py +0 -9
- edsl/jobs/loggers/HTMLTableJobLogger.py +0 -304
- edsl/language_models/ComputeCost.py +0 -63
- edsl/language_models/PriceManager.py +0 -127
- edsl/language_models/RawResponseHandler.py +0 -106
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/key_management/KeyLookup.py +0 -63
- edsl/language_models/key_management/KeyLookupBuilder.py +0 -273
- edsl/language_models/key_management/KeyLookupCollection.py +0 -38
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +0 -131
- edsl/notebooks/NotebookToLaTeX.py +0 -142
- edsl/questions/ExceptionExplainer.py +0 -77
- edsl/questions/HTMLQuestion.py +0 -103
- edsl/questions/LoopProcessor.py +0 -149
- edsl/questions/QuestionMatrix.py +0 -265
- edsl/questions/ResponseValidatorFactory.py +0 -28
- edsl/questions/templates/matrix/__init__.py +0 -1
- edsl/questions/templates/matrix/answering_instructions.jinja +0 -5
- edsl/questions/templates/matrix/question_presentation.jinja +0 -20
- edsl/results/MarkdownToDocx.py +0 -122
- edsl/results/MarkdownToPDF.py +0 -111
- edsl/results/TextEditor.py +0 -50
- edsl/results/smart_objects.py +0 -96
- edsl/results/table_data_class.py +0 -12
- edsl/results/table_renderers.py +0 -118
- edsl/scenarios/ConstructDownloadLink.py +0 -109
- edsl/scenarios/DirectoryScanner.py +0 -96
- edsl/scenarios/DocumentChunker.py +0 -102
- edsl/scenarios/DocxScenario.py +0 -16
- edsl/scenarios/PdfExtractor.py +0 -40
- edsl/scenarios/ScenarioSelector.py +0 -156
- edsl/scenarios/file_methods.py +0 -85
- edsl/scenarios/handlers/__init__.py +0 -13
- edsl/scenarios/handlers/csv.py +0 -38
- edsl/scenarios/handlers/docx.py +0 -76
- edsl/scenarios/handlers/html.py +0 -37
- edsl/scenarios/handlers/json.py +0 -111
- edsl/scenarios/handlers/latex.py +0 -5
- edsl/scenarios/handlers/md.py +0 -51
- edsl/scenarios/handlers/pdf.py +0 -68
- edsl/scenarios/handlers/png.py +0 -39
- edsl/scenarios/handlers/pptx.py +0 -105
- edsl/scenarios/handlers/py.py +0 -294
- edsl/scenarios/handlers/sql.py +0 -313
- edsl/scenarios/handlers/sqlite.py +0 -149
- edsl/scenarios/handlers/txt.py +0 -33
- edsl/surveys/ConstructDAG.py +0 -92
- edsl/surveys/EditSurvey.py +0 -221
- edsl/surveys/InstructionHandler.py +0 -100
- edsl/surveys/MemoryManagement.py +0 -72
- edsl/surveys/RuleManager.py +0 -172
- edsl/surveys/Simulator.py +0 -75
- edsl/surveys/SurveyToApp.py +0 -141
- edsl/utilities/PrettyList.py +0 -56
- edsl/utilities/is_notebook.py +0 -18
- edsl/utilities/is_valid_variable_name.py +0 -11
- edsl/utilities/remove_edsl_version.py +0 -24
- edsl-0.1.39.dev2.dist-info/RECORD +0 -352
- {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/WHEEL +0 -0
@@ -1,304 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
import uuid
|
3
|
-
from datetime import datetime
|
4
|
-
from IPython.display import display, HTML
|
5
|
-
from edsl.jobs.JobsRemoteInferenceLogger import JobLogger
|
6
|
-
from edsl.jobs.jobs_status_enums import JobsStatus
|
7
|
-
|
8
|
-
|
9
|
-
class HTMLTableJobLogger(JobLogger):
|
10
|
-
def __init__(self, verbose=True, theme="auto", **kwargs):
|
11
|
-
super().__init__(verbose=verbose)
|
12
|
-
self.display_handle = display(HTML(""), display_id=True)
|
13
|
-
self.current_message = None
|
14
|
-
self.log_id = str(uuid.uuid4())
|
15
|
-
self.is_expanded = True
|
16
|
-
self.spinner_chars = ["◐", "◓", "◑", "◒"]
|
17
|
-
self.spinner_idx = 0
|
18
|
-
self.theme = theme # Can be "auto", "light", or "dark"
|
19
|
-
|
20
|
-
# Initialize CSS once when the logger is created
|
21
|
-
self._init_css()
|
22
|
-
|
23
|
-
def _init_css(self):
|
24
|
-
"""Initialize the CSS styles with enhanced theme support"""
|
25
|
-
css = """
|
26
|
-
<style>
|
27
|
-
/* Base theme variables */
|
28
|
-
:root {
|
29
|
-
--jl-bg-primary: #ffffff;
|
30
|
-
--jl-bg-secondary: #f5f5f5;
|
31
|
-
--jl-border-color: #e0e0e0;
|
32
|
-
--jl-text-primary: #24292e;
|
33
|
-
--jl-text-secondary: #586069;
|
34
|
-
--jl-link-color: #0366d6;
|
35
|
-
--jl-success-color: #28a745;
|
36
|
-
--jl-error-color: #d73a49;
|
37
|
-
--jl-header-bg: #f1f1f1;
|
38
|
-
}
|
39
|
-
|
40
|
-
/* Dark theme variables */
|
41
|
-
.theme-dark {
|
42
|
-
--jl-bg-primary: #1e1e1e;
|
43
|
-
--jl-bg-secondary: #252526;
|
44
|
-
--jl-border-color: #2d2d2d;
|
45
|
-
--jl-text-primary: #cccccc;
|
46
|
-
--jl-text-secondary: #999999;
|
47
|
-
--jl-link-color: #4e94ce;
|
48
|
-
--jl-success-color: #89d185;
|
49
|
-
--jl-error-color: #f14c4c;
|
50
|
-
--jl-header-bg: #333333;
|
51
|
-
}
|
52
|
-
|
53
|
-
/* High contrast theme variables */
|
54
|
-
.theme-high-contrast {
|
55
|
-
--jl-bg-primary: #000000;
|
56
|
-
--jl-bg-secondary: #1a1a1a;
|
57
|
-
--jl-border-color: #404040;
|
58
|
-
--jl-text-primary: #ffffff;
|
59
|
-
--jl-text-secondary: #cccccc;
|
60
|
-
--jl-link-color: #66b3ff;
|
61
|
-
--jl-success-color: #00ff00;
|
62
|
-
--jl-error-color: #ff0000;
|
63
|
-
--jl-header-bg: #262626;
|
64
|
-
}
|
65
|
-
|
66
|
-
.job-logger {
|
67
|
-
font-family: system-ui, -apple-system, sans-serif;
|
68
|
-
max-width: 800px;
|
69
|
-
margin: 10px 0;
|
70
|
-
color: var(--jl-text-primary);
|
71
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
|
72
|
-
border-radius: 4px;
|
73
|
-
overflow: hidden;
|
74
|
-
}
|
75
|
-
|
76
|
-
.job-logger-header {
|
77
|
-
padding: 12px 16px;
|
78
|
-
background: var(--jl-header-bg);
|
79
|
-
border: none;
|
80
|
-
border-radius: 4px 4px 0 0;
|
81
|
-
cursor: pointer;
|
82
|
-
color: var(--jl-text-primary);
|
83
|
-
user-select: none;
|
84
|
-
font-weight: 500;
|
85
|
-
letter-spacing: 0.3px;
|
86
|
-
display: flex;
|
87
|
-
justify-content: space-between;
|
88
|
-
align-items: center;
|
89
|
-
}
|
90
|
-
|
91
|
-
.theme-select {
|
92
|
-
padding: 4px 8px;
|
93
|
-
border-radius: 4px;
|
94
|
-
border: 1px solid var(--jl-border-color);
|
95
|
-
background: var(--jl-bg-primary);
|
96
|
-
color: var(--jl-text-primary);
|
97
|
-
font-size: 0.9em;
|
98
|
-
}
|
99
|
-
|
100
|
-
.job-logger-table {
|
101
|
-
width: 100%;
|
102
|
-
border-collapse: separate;
|
103
|
-
border-spacing: 0;
|
104
|
-
background: var(--jl-bg-primary);
|
105
|
-
border: 1px solid var(--jl-border-color);
|
106
|
-
margin-top: -1px;
|
107
|
-
}
|
108
|
-
|
109
|
-
.job-logger-cell {
|
110
|
-
padding: 12px 16px;
|
111
|
-
border-bottom: 1px solid var(--jl-border-color);
|
112
|
-
line-height: 1.4;
|
113
|
-
}
|
114
|
-
|
115
|
-
.job-logger-label {
|
116
|
-
font-weight: 500;
|
117
|
-
color: var(--jl-text-primary);
|
118
|
-
width: 25%;
|
119
|
-
background: var(--jl-bg-secondary);
|
120
|
-
}
|
121
|
-
|
122
|
-
.job-logger-value {
|
123
|
-
color: var(--jl-text-secondary);
|
124
|
-
word-break: break-word;
|
125
|
-
}
|
126
|
-
|
127
|
-
.job-logger-status {
|
128
|
-
margin: 0;
|
129
|
-
padding: 12px 16px;
|
130
|
-
background-color: var(--jl-bg-secondary);
|
131
|
-
border: 1px solid var(--jl-border-color);
|
132
|
-
border-top: none;
|
133
|
-
border-radius: 0 0 4px 4px;
|
134
|
-
color: var(--jl-text-primary);
|
135
|
-
font-size: 0.95em;
|
136
|
-
}
|
137
|
-
</style>
|
138
|
-
|
139
|
-
<script>
|
140
|
-
class ThemeManager {
|
141
|
-
constructor(logId, initialTheme = 'auto') {
|
142
|
-
this.logId = logId;
|
143
|
-
this.currentTheme = initialTheme;
|
144
|
-
this.darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
145
|
-
this.init();
|
146
|
-
}
|
147
|
-
|
148
|
-
init() {
|
149
|
-
this.setupThemeSwitcher();
|
150
|
-
this.updateTheme(this.currentTheme);
|
151
|
-
|
152
|
-
this.darkModeMediaQuery.addListener(() => {
|
153
|
-
if (this.currentTheme === 'auto') {
|
154
|
-
this.updateTheme('auto');
|
155
|
-
}
|
156
|
-
});
|
157
|
-
}
|
158
|
-
|
159
|
-
setupThemeSwitcher() {
|
160
|
-
const logger = document.querySelector(`#logger-${this.logId}`);
|
161
|
-
if (!logger) return;
|
162
|
-
|
163
|
-
const switcher = document.createElement('div');
|
164
|
-
switcher.className = 'theme-switcher';
|
165
|
-
switcher.innerHTML = `
|
166
|
-
<select id="theme-select-${this.logId}" class="theme-select">
|
167
|
-
<option value="auto">Auto</option>
|
168
|
-
<option value="light">Light</option>
|
169
|
-
<option value="dark">Dark</option>
|
170
|
-
<option value="high-contrast">High Contrast</option>
|
171
|
-
</select>
|
172
|
-
`;
|
173
|
-
|
174
|
-
const header = logger.querySelector('.job-logger-header');
|
175
|
-
header.appendChild(switcher);
|
176
|
-
|
177
|
-
const select = switcher.querySelector('select');
|
178
|
-
select.value = this.currentTheme;
|
179
|
-
select.addEventListener('change', (e) => {
|
180
|
-
this.updateTheme(e.target.value);
|
181
|
-
});
|
182
|
-
}
|
183
|
-
|
184
|
-
updateTheme(theme) {
|
185
|
-
const logger = document.querySelector(`#logger-${this.logId}`);
|
186
|
-
if (!logger) return;
|
187
|
-
|
188
|
-
this.currentTheme = theme;
|
189
|
-
|
190
|
-
logger.classList.remove('theme-light', 'theme-dark', 'theme-high-contrast');
|
191
|
-
|
192
|
-
if (theme === 'auto') {
|
193
|
-
const isDark = this.darkModeMediaQuery.matches;
|
194
|
-
logger.classList.add(isDark ? 'theme-dark' : 'theme-light');
|
195
|
-
} else {
|
196
|
-
logger.classList.add(`theme-${theme}`);
|
197
|
-
}
|
198
|
-
|
199
|
-
try {
|
200
|
-
localStorage.setItem('jobLoggerTheme', theme);
|
201
|
-
} catch (e) {
|
202
|
-
console.warn('Unable to save theme preference:', e);
|
203
|
-
}
|
204
|
-
}
|
205
|
-
}
|
206
|
-
|
207
|
-
window.initThemeManager = (logId, initialTheme) => {
|
208
|
-
new ThemeManager(logId, initialTheme);
|
209
|
-
};
|
210
|
-
</script>
|
211
|
-
"""
|
212
|
-
|
213
|
-
init_script = f"""
|
214
|
-
<script>
|
215
|
-
document.addEventListener('DOMContentLoaded', () => {{
|
216
|
-
window.initThemeManager('{self.log_id}', '{self.theme}');
|
217
|
-
}});
|
218
|
-
</script>
|
219
|
-
"""
|
220
|
-
|
221
|
-
display(HTML(css + init_script))
|
222
|
-
|
223
|
-
def _get_table_row(self, key: str, value: str) -> str:
|
224
|
-
"""Generate a table row with key-value pair"""
|
225
|
-
return f"""
|
226
|
-
<tr>
|
227
|
-
<td class="job-logger-cell job-logger-label">{key}</td>
|
228
|
-
<td class="job-logger-cell job-logger-value">{value if value else 'None'}</td>
|
229
|
-
</tr>
|
230
|
-
"""
|
231
|
-
|
232
|
-
def _linkify(self, text: str) -> str:
|
233
|
-
"""Convert URLs in text to clickable links"""
|
234
|
-
url_pattern = r'(https?://[^\s<>"]+|www\.[^\s<>"]+)'
|
235
|
-
return re.sub(
|
236
|
-
url_pattern,
|
237
|
-
r'<a href="\1" target="_blank" class="job-logger-link">\1</a>',
|
238
|
-
text,
|
239
|
-
)
|
240
|
-
|
241
|
-
def _get_spinner(self, status: JobsStatus) -> str:
|
242
|
-
"""Get the current spinner frame if status is running"""
|
243
|
-
if status == JobsStatus.RUNNING:
|
244
|
-
spinner = self.spinner_chars[self.spinner_idx]
|
245
|
-
self.spinner_idx = (self.spinner_idx + 1) % len(self.spinner_chars)
|
246
|
-
return f'<span style="margin-right: 8px;">{spinner}</span>'
|
247
|
-
elif status == JobsStatus.COMPLETED:
|
248
|
-
return (
|
249
|
-
'<span style="margin-right: 8px;" class="job-logger-success">✓</span>'
|
250
|
-
)
|
251
|
-
elif status == JobsStatus.FAILED:
|
252
|
-
return '<span style="margin-right: 8px;" class="job-logger-error">✗</span>'
|
253
|
-
return ""
|
254
|
-
|
255
|
-
def _get_html(self, status: JobsStatus = JobsStatus.RUNNING) -> str:
|
256
|
-
"""Generate the complete HTML display with theme support"""
|
257
|
-
info_rows = ""
|
258
|
-
for field, _ in self.jobs_info.__annotations__.items():
|
259
|
-
if field != "pretty_names":
|
260
|
-
value = getattr(self.jobs_info, field)
|
261
|
-
value = self._linkify(str(value)) if value else None
|
262
|
-
pretty_name = self.jobs_info.pretty_names.get(
|
263
|
-
field, field.replace("_", " ").title()
|
264
|
-
)
|
265
|
-
info_rows += self._get_table_row(pretty_name, value)
|
266
|
-
|
267
|
-
message_html = ""
|
268
|
-
if self.current_message:
|
269
|
-
spinner = self._get_spinner(status)
|
270
|
-
message_html = f"""
|
271
|
-
<div class="job-logger-status">
|
272
|
-
{spinner}<strong>Current Status:</strong> {self._linkify(self.current_message)}
|
273
|
-
</div>
|
274
|
-
"""
|
275
|
-
|
276
|
-
display_style = "block" if self.is_expanded else "none"
|
277
|
-
arrow = "▼" if self.is_expanded else "▶"
|
278
|
-
|
279
|
-
return f"""
|
280
|
-
<!-- #region Remove Inference Info -->
|
281
|
-
<div id="logger-{self.log_id}" class="job-logger">
|
282
|
-
<div class="job-logger-header">
|
283
|
-
<span>
|
284
|
-
<span id="arrow-{self.log_id}">{arrow}</span>
|
285
|
-
Job Status ({datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
|
286
|
-
</span>
|
287
|
-
</div>
|
288
|
-
<div id="content-{self.log_id}" style="display: {display_style};">
|
289
|
-
<table class="job-logger-table">
|
290
|
-
{info_rows}
|
291
|
-
</table>
|
292
|
-
{message_html}
|
293
|
-
</div>
|
294
|
-
</div>
|
295
|
-
<!-- # endregion -->
|
296
|
-
"""
|
297
|
-
|
298
|
-
def update(self, message: str, status: JobsStatus = JobsStatus.RUNNING):
|
299
|
-
"""Update the display with new message and current JobsInfo state"""
|
300
|
-
self.current_message = message
|
301
|
-
if self.verbose:
|
302
|
-
self.display_handle.update(HTML(self._get_html(status)))
|
303
|
-
else:
|
304
|
-
return None
|
@@ -1,63 +0,0 @@
|
|
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
|
@@ -1,127 +0,0 @@
|
|
1
|
-
from typing import Dict, Tuple, Optional, Union
|
2
|
-
|
3
|
-
|
4
|
-
class PriceManager:
|
5
|
-
_instance = None
|
6
|
-
_price_lookup: Dict[Tuple[str, str], Dict] = {}
|
7
|
-
_is_initialized = False
|
8
|
-
|
9
|
-
def __new__(cls):
|
10
|
-
if cls._instance is None:
|
11
|
-
cls._instance = super(PriceManager, cls).__new__(cls)
|
12
|
-
return cls._instance
|
13
|
-
|
14
|
-
def __init__(self):
|
15
|
-
# Only initialize once, even if __init__ is called multiple times
|
16
|
-
if not self._is_initialized:
|
17
|
-
self._is_initialized = True
|
18
|
-
self.refresh_prices()
|
19
|
-
|
20
|
-
def refresh_prices(self) -> None:
|
21
|
-
"""
|
22
|
-
Fetch fresh prices from the Coop service and update the internal price lookup.
|
23
|
-
|
24
|
-
"""
|
25
|
-
from edsl.coop import Coop
|
26
|
-
|
27
|
-
c = Coop()
|
28
|
-
try:
|
29
|
-
self._price_lookup = c.fetch_prices()
|
30
|
-
except Exception as e:
|
31
|
-
print(f"Error fetching prices: {str(e)}")
|
32
|
-
|
33
|
-
def get_price(self, inference_service: str, model: str) -> Optional[Dict]:
|
34
|
-
"""
|
35
|
-
Get the price information for a specific service and model combination.
|
36
|
-
|
37
|
-
Args:
|
38
|
-
inference_service (str): The name of the inference service
|
39
|
-
model (str): The model identifier
|
40
|
-
|
41
|
-
Returns:
|
42
|
-
Optional[Dict]: Price information if found, None otherwise
|
43
|
-
"""
|
44
|
-
key = (inference_service, model)
|
45
|
-
return self._price_lookup.get(key)
|
46
|
-
|
47
|
-
def get_all_prices(self) -> Dict[Tuple[str, str], Dict]:
|
48
|
-
"""
|
49
|
-
Get the complete price lookup dictionary.
|
50
|
-
|
51
|
-
Returns:
|
52
|
-
Dict[Tuple[str, str], Dict]: The complete price lookup dictionary
|
53
|
-
"""
|
54
|
-
return self._price_lookup.copy()
|
55
|
-
|
56
|
-
def calculate_cost(
|
57
|
-
self,
|
58
|
-
inference_service: str,
|
59
|
-
model: str,
|
60
|
-
usage: Dict[str, Union[str, int]],
|
61
|
-
input_token_name: str,
|
62
|
-
output_token_name: str,
|
63
|
-
) -> Union[float, str]:
|
64
|
-
"""
|
65
|
-
Calculate the total cost for a model usage based on input and output tokens.
|
66
|
-
|
67
|
-
Args:
|
68
|
-
inference_service (str): The inference service identifier
|
69
|
-
model (str): The model identifier
|
70
|
-
usage (Dict[str, Union[str, int]]): Dictionary containing token usage information
|
71
|
-
input_token_name (str): Key name for input tokens in the usage dict
|
72
|
-
output_token_name (str): Key name for output tokens in the usage dict
|
73
|
-
|
74
|
-
Returns:
|
75
|
-
Union[float, str]: Total cost if calculation successful, error message string if not
|
76
|
-
"""
|
77
|
-
relevant_prices = self.get_price(inference_service, model)
|
78
|
-
if relevant_prices is None:
|
79
|
-
return f"Could not find price for model {model} in the price lookup."
|
80
|
-
|
81
|
-
# Extract token counts
|
82
|
-
try:
|
83
|
-
input_tokens = int(usage[input_token_name])
|
84
|
-
output_tokens = int(usage[output_token_name])
|
85
|
-
except Exception as e:
|
86
|
-
return f"Could not fetch tokens from model response: {e}"
|
87
|
-
|
88
|
-
# Extract price information
|
89
|
-
try:
|
90
|
-
inverse_output_price = relevant_prices["output"]["one_usd_buys"]
|
91
|
-
inverse_input_price = relevant_prices["input"]["one_usd_buys"]
|
92
|
-
except Exception as e:
|
93
|
-
if "output" not in relevant_prices:
|
94
|
-
return f"Could not fetch prices from {relevant_prices} - {e}; Missing 'output' key."
|
95
|
-
if "input" not in relevant_prices:
|
96
|
-
return f"Could not fetch prices from {relevant_prices} - {e}; Missing 'input' key."
|
97
|
-
return f"Could not fetch prices from {relevant_prices} - {e}"
|
98
|
-
|
99
|
-
# Calculate input cost
|
100
|
-
if inverse_input_price == "infinity":
|
101
|
-
input_cost = 0
|
102
|
-
else:
|
103
|
-
try:
|
104
|
-
input_cost = input_tokens / float(inverse_input_price)
|
105
|
-
except Exception as e:
|
106
|
-
return f"Could not compute input price - {e}."
|
107
|
-
|
108
|
-
# Calculate output cost
|
109
|
-
if inverse_output_price == "infinity":
|
110
|
-
output_cost = 0
|
111
|
-
else:
|
112
|
-
try:
|
113
|
-
output_cost = output_tokens / float(inverse_output_price)
|
114
|
-
except Exception as e:
|
115
|
-
return f"Could not compute output price - {e}"
|
116
|
-
|
117
|
-
return input_cost + output_cost
|
118
|
-
|
119
|
-
@property
|
120
|
-
def is_initialized(self) -> bool:
|
121
|
-
"""
|
122
|
-
Check if the PriceManager has been initialized.
|
123
|
-
|
124
|
-
Returns:
|
125
|
-
bool: True if initialized, False otherwise
|
126
|
-
"""
|
127
|
-
return self._is_initialized
|
@@ -1,106 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from typing import Optional, Any, List
|
3
|
-
from edsl.exceptions.language_models import LanguageModelBadResponseError
|
4
|
-
|
5
|
-
from json_repair import repair_json
|
6
|
-
|
7
|
-
|
8
|
-
def _extract_item_from_raw_response(data, sequence):
|
9
|
-
if isinstance(data, str):
|
10
|
-
try:
|
11
|
-
data = json.loads(data)
|
12
|
-
except json.JSONDecodeError as e:
|
13
|
-
return data
|
14
|
-
current_data = data
|
15
|
-
for i, key in enumerate(sequence):
|
16
|
-
try:
|
17
|
-
if isinstance(current_data, (list, tuple)):
|
18
|
-
if not isinstance(key, int):
|
19
|
-
raise TypeError(
|
20
|
-
f"Expected integer index for sequence at position {i}, got {type(key).__name__}"
|
21
|
-
)
|
22
|
-
if key < 0 or key >= len(current_data):
|
23
|
-
raise IndexError(
|
24
|
-
f"Index {key} out of range for sequence of length {len(current_data)} at position {i}"
|
25
|
-
)
|
26
|
-
elif isinstance(current_data, dict):
|
27
|
-
if key not in current_data:
|
28
|
-
raise KeyError(
|
29
|
-
f"Key '{key}' not found in dictionary at position {i}"
|
30
|
-
)
|
31
|
-
else:
|
32
|
-
raise TypeError(
|
33
|
-
f"Cannot index into {type(current_data).__name__} at position {i}. Full response is: {data} of type {type(data)}. Key sequence is: {sequence}"
|
34
|
-
)
|
35
|
-
|
36
|
-
current_data = current_data[key]
|
37
|
-
except Exception as e:
|
38
|
-
path = " -> ".join(map(str, sequence[: i + 1]))
|
39
|
-
if "error" in data:
|
40
|
-
msg = data["error"]
|
41
|
-
else:
|
42
|
-
msg = f"Error accessing path: {path}. {str(e)}. Full response is: '{data}'"
|
43
|
-
raise LanguageModelBadResponseError(message=msg, response_json=data)
|
44
|
-
if isinstance(current_data, str):
|
45
|
-
return current_data.strip()
|
46
|
-
else:
|
47
|
-
return current_data
|
48
|
-
|
49
|
-
|
50
|
-
class RawResponseHandler:
|
51
|
-
"""Class to handle raw responses from language models."""
|
52
|
-
|
53
|
-
def __init__(self, key_sequence: list, usage_sequence: Optional[list] = None):
|
54
|
-
self.key_sequence = key_sequence
|
55
|
-
self.usage_sequence = usage_sequence
|
56
|
-
|
57
|
-
def get_generated_token_string(self, raw_response):
|
58
|
-
return _extract_item_from_raw_response(raw_response, self.key_sequence)
|
59
|
-
|
60
|
-
def get_usage_dict(self, raw_response):
|
61
|
-
if self.usage_sequence is None:
|
62
|
-
return {}
|
63
|
-
return _extract_item_from_raw_response(raw_response, self.usage_sequence)
|
64
|
-
|
65
|
-
def parse_response(self, raw_response: dict[str, Any]) -> "EDSLOutput":
|
66
|
-
"""Parses the API response and returns the response text."""
|
67
|
-
|
68
|
-
from edsl.data_transfer_models import EDSLOutput
|
69
|
-
|
70
|
-
generated_token_string = self.get_generated_token_string(raw_response)
|
71
|
-
last_newline = generated_token_string.rfind("\n")
|
72
|
-
|
73
|
-
if last_newline == -1:
|
74
|
-
# There is no comment
|
75
|
-
edsl_dict = {
|
76
|
-
"answer": self.convert_answer(generated_token_string),
|
77
|
-
"generated_tokens": generated_token_string,
|
78
|
-
"comment": None,
|
79
|
-
}
|
80
|
-
else:
|
81
|
-
edsl_dict = {
|
82
|
-
"answer": self.convert_answer(generated_token_string[:last_newline]),
|
83
|
-
"comment": generated_token_string[last_newline + 1 :].strip(),
|
84
|
-
"generated_tokens": generated_token_string,
|
85
|
-
}
|
86
|
-
return EDSLOutput(**edsl_dict)
|
87
|
-
|
88
|
-
@staticmethod
|
89
|
-
def convert_answer(response_part):
|
90
|
-
import json
|
91
|
-
|
92
|
-
response_part = response_part.strip()
|
93
|
-
|
94
|
-
if response_part == "None":
|
95
|
-
return None
|
96
|
-
|
97
|
-
repaired = repair_json(response_part)
|
98
|
-
if repaired == '""':
|
99
|
-
# it was a literal string
|
100
|
-
return response_part
|
101
|
-
|
102
|
-
try:
|
103
|
-
return json.loads(repaired)
|
104
|
-
except json.JSONDecodeError as j:
|
105
|
-
# last resort
|
106
|
-
return response_part
|
File without changes
|
@@ -1,63 +0,0 @@
|
|
1
|
-
from collections import UserDict
|
2
|
-
from dataclasses import asdict
|
3
|
-
from edsl.enums import service_to_api_keyname
|
4
|
-
|
5
|
-
from edsl.language_models.key_management.models import LanguageModelInput
|
6
|
-
|
7
|
-
|
8
|
-
class KeyLookup(UserDict):
|
9
|
-
"""A class for looking up API keys and related configuration.
|
10
|
-
|
11
|
-
>>> from edsl.language_models.key_management.models import LanguageModelInput
|
12
|
-
>>> lookup = KeyLookup()
|
13
|
-
>>> lm_input = LanguageModelInput.example()
|
14
|
-
>>> lookup['test'] = lm_input
|
15
|
-
>>> lookup.to_dict()['test']['api_token']
|
16
|
-
'sk-abcd123'
|
17
|
-
>>> restored = KeyLookup.from_dict(lookup.to_dict())
|
18
|
-
>>> restored['test'].api_token
|
19
|
-
'sk-abcd123'
|
20
|
-
"""
|
21
|
-
|
22
|
-
def to_dict(self):
|
23
|
-
"""
|
24
|
-
>>> kl = KeyLookup.example()
|
25
|
-
>>> kl2 = KeyLookup.from_dict(kl.to_dict())
|
26
|
-
>>> kl2 == kl
|
27
|
-
True
|
28
|
-
>>> kl2 is kl
|
29
|
-
False
|
30
|
-
"""
|
31
|
-
return {k: asdict(v) for k, v in self.data.items()}
|
32
|
-
|
33
|
-
@classmethod
|
34
|
-
def from_dict(cls, d):
|
35
|
-
return cls({k: LanguageModelInput(**v) for k, v in d.items()})
|
36
|
-
|
37
|
-
@classmethod
|
38
|
-
def example(cls):
|
39
|
-
return cls(
|
40
|
-
{
|
41
|
-
"test": LanguageModelInput.example(),
|
42
|
-
"openai": LanguageModelInput.example(),
|
43
|
-
}
|
44
|
-
)
|
45
|
-
|
46
|
-
def to_dot_env(self):
|
47
|
-
"""Return a string representation of the key lookup collection for a .env file."""
|
48
|
-
lines = []
|
49
|
-
for service, lm_input in self.items():
|
50
|
-
if service != "test":
|
51
|
-
lines.append(f"EDSL_SERVICE_RPM_{service.upper()}={lm_input.rpm}")
|
52
|
-
lines.append(f"EDSL_SERVICE_TPM_{service.upper()}={lm_input.tpm}")
|
53
|
-
key_name = service_to_api_keyname.get(service, service)
|
54
|
-
lines.append(f"{key_name.upper()}={lm_input.api_token}")
|
55
|
-
if lm_input.api_id is not None:
|
56
|
-
lines.append(f"{service.upper()}_API_ID={lm_input.api_id}")
|
57
|
-
return "\n".join([f"{line}" for line in lines])
|
58
|
-
|
59
|
-
|
60
|
-
if __name__ == "__main__":
|
61
|
-
import doctest
|
62
|
-
|
63
|
-
doctest.testmod(optionflags=doctest.ELLIPSIS)
|