edsl 0.1.31.dev4__py3-none-any.whl → 0.1.33__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edsl/Base.py +9 -3
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +8 -3
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +40 -8
- edsl/agents/AgentList.py +43 -0
- edsl/agents/Invigilator.py +136 -221
- edsl/agents/InvigilatorBase.py +148 -59
- edsl/agents/{PromptConstructionMixin.py → PromptConstructor.py} +154 -85
- edsl/agents/__init__.py +1 -0
- edsl/auto/AutoStudy.py +117 -0
- edsl/auto/StageBase.py +230 -0
- edsl/auto/StageGenerateSurvey.py +178 -0
- edsl/auto/StageLabelQuestions.py +125 -0
- edsl/auto/StagePersona.py +61 -0
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
- edsl/auto/StagePersonaDimensionValues.py +74 -0
- edsl/auto/StagePersonaDimensions.py +69 -0
- edsl/auto/StageQuestions.py +73 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +224 -0
- edsl/config.py +48 -47
- edsl/conjure/Conjure.py +6 -0
- edsl/coop/PriceFetcher.py +58 -0
- edsl/coop/coop.py +50 -7
- edsl/data/Cache.py +35 -1
- edsl/data/CacheHandler.py +3 -4
- edsl/data_transfer_models.py +73 -38
- edsl/enums.py +8 -0
- edsl/exceptions/general.py +10 -8
- edsl/exceptions/language_models.py +25 -1
- edsl/exceptions/questions.py +62 -5
- edsl/exceptions/results.py +4 -0
- edsl/inference_services/AnthropicService.py +13 -11
- edsl/inference_services/AwsBedrock.py +112 -0
- edsl/inference_services/AzureAI.py +214 -0
- edsl/inference_services/DeepInfraService.py +4 -3
- edsl/inference_services/GoogleService.py +16 -12
- edsl/inference_services/GroqService.py +5 -4
- edsl/inference_services/InferenceServiceABC.py +58 -3
- edsl/inference_services/InferenceServicesCollection.py +13 -8
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +55 -56
- edsl/inference_services/TestService.py +80 -0
- edsl/inference_services/TogetherAIService.py +170 -0
- edsl/inference_services/models_available_cache.py +25 -0
- edsl/inference_services/registry.py +19 -1
- edsl/jobs/Answers.py +10 -12
- edsl/jobs/FailedQuestion.py +78 -0
- edsl/jobs/Jobs.py +137 -41
- edsl/jobs/buckets/BucketCollection.py +24 -15
- edsl/jobs/buckets/TokenBucket.py +105 -18
- edsl/jobs/interviews/Interview.py +393 -83
- edsl/jobs/interviews/{interview_exception_tracking.py → InterviewExceptionCollection.py} +22 -18
- edsl/jobs/interviews/InterviewExceptionEntry.py +167 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +152 -160
- edsl/jobs/runners/JobsRunnerStatus.py +331 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
- edsl/jobs/tasks/TaskCreators.py +1 -1
- edsl/jobs/tasks/TaskHistory.py +205 -126
- edsl/language_models/LanguageModel.py +297 -177
- edsl/language_models/ModelList.py +2 -2
- edsl/language_models/RegisterLanguageModelsMeta.py +14 -29
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- edsl/language_models/registry.py +25 -8
- edsl/language_models/repair.py +0 -19
- edsl/language_models/utilities.py +61 -0
- edsl/notebooks/Notebook.py +20 -2
- edsl/prompts/Prompt.py +52 -2
- edsl/questions/AnswerValidatorMixin.py +23 -26
- edsl/questions/QuestionBase.py +330 -249
- edsl/questions/QuestionBaseGenMixin.py +133 -0
- edsl/questions/QuestionBasePromptsMixin.py +266 -0
- edsl/questions/QuestionBudget.py +99 -42
- edsl/questions/QuestionCheckBox.py +227 -36
- edsl/questions/QuestionExtract.py +98 -28
- edsl/questions/QuestionFreeText.py +47 -31
- edsl/questions/QuestionFunctional.py +7 -0
- edsl/questions/QuestionList.py +141 -23
- edsl/questions/QuestionMultipleChoice.py +159 -66
- edsl/questions/QuestionNumerical.py +88 -47
- edsl/questions/QuestionRank.py +182 -25
- edsl/questions/Quick.py +41 -0
- edsl/questions/RegisterQuestionsMeta.py +31 -12
- edsl/questions/ResponseValidatorABC.py +170 -0
- edsl/questions/__init__.py +3 -4
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +10 -5
- edsl/questions/derived/QuestionLinearScale.py +15 -2
- edsl/questions/derived/QuestionTopK.py +10 -1
- edsl/questions/derived/QuestionYesNo.py +24 -3
- edsl/questions/descriptors.py +43 -7
- edsl/questions/prompt_templates/question_budget.jinja +13 -0
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
- edsl/questions/prompt_templates/question_extract.jinja +11 -0
- edsl/questions/prompt_templates/question_free_text.jinja +3 -0
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
- edsl/questions/prompt_templates/question_list.jinja +17 -0
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
- edsl/questions/prompt_templates/question_numerical.jinja +37 -0
- edsl/questions/question_registry.py +6 -2
- edsl/questions/templates/__init__.py +0 -0
- edsl/questions/templates/budget/__init__.py +0 -0
- edsl/questions/templates/budget/answering_instructions.jinja +7 -0
- edsl/questions/templates/budget/question_presentation.jinja +7 -0
- edsl/questions/templates/checkbox/__init__.py +0 -0
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
- edsl/questions/templates/extract/__init__.py +0 -0
- edsl/questions/templates/extract/answering_instructions.jinja +7 -0
- edsl/questions/templates/extract/question_presentation.jinja +1 -0
- edsl/questions/templates/free_text/__init__.py +0 -0
- edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
- edsl/questions/templates/free_text/question_presentation.jinja +1 -0
- edsl/questions/templates/likert_five/__init__.py +0 -0
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
- edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
- edsl/questions/templates/linear_scale/__init__.py +0 -0
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
- edsl/questions/templates/list/__init__.py +0 -0
- edsl/questions/templates/list/answering_instructions.jinja +4 -0
- edsl/questions/templates/list/question_presentation.jinja +5 -0
- edsl/questions/templates/multiple_choice/__init__.py +0 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
- edsl/questions/templates/multiple_choice/html.jinja +0 -0
- edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
- edsl/questions/templates/numerical/__init__.py +0 -0
- edsl/questions/templates/numerical/answering_instructions.jinja +8 -0
- edsl/questions/templates/numerical/question_presentation.jinja +7 -0
- edsl/questions/templates/rank/__init__.py +0 -0
- edsl/questions/templates/rank/answering_instructions.jinja +11 -0
- edsl/questions/templates/rank/question_presentation.jinja +15 -0
- edsl/questions/templates/top_k/__init__.py +0 -0
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
- edsl/questions/templates/top_k/question_presentation.jinja +22 -0
- edsl/questions/templates/yes_no/__init__.py +0 -0
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
- edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
- edsl/results/Dataset.py +20 -0
- edsl/results/DatasetExportMixin.py +58 -30
- edsl/results/DatasetTree.py +145 -0
- edsl/results/Result.py +32 -5
- edsl/results/Results.py +135 -46
- edsl/results/ResultsDBMixin.py +3 -3
- edsl/results/Selector.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/FileStore.py +71 -10
- edsl/scenarios/Scenario.py +109 -24
- edsl/scenarios/ScenarioImageMixin.py +2 -2
- edsl/scenarios/ScenarioList.py +546 -21
- edsl/scenarios/ScenarioListExportMixin.py +24 -4
- edsl/scenarios/ScenarioListPdfMixin.py +153 -4
- edsl/study/SnapShot.py +8 -1
- edsl/study/Study.py +32 -0
- edsl/surveys/Rule.py +15 -3
- edsl/surveys/RuleCollection.py +21 -5
- edsl/surveys/Survey.py +707 -298
- edsl/surveys/SurveyExportMixin.py +71 -9
- edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- edsl/surveys/instructions/ChangeInstruction.py +47 -0
- edsl/surveys/instructions/Instruction.py +34 -0
- edsl/surveys/instructions/InstructionCollection.py +77 -0
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/templates/error_reporting/base.html +24 -0
- edsl/templates/error_reporting/exceptions_by_model.html +35 -0
- edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
- edsl/templates/error_reporting/exceptions_by_type.html +17 -0
- edsl/templates/error_reporting/interview_details.html +116 -0
- edsl/templates/error_reporting/interviews.html +10 -0
- edsl/templates/error_reporting/overview.html +5 -0
- edsl/templates/error_reporting/performance_plot.html +2 -0
- edsl/templates/error_reporting/report.css +74 -0
- edsl/templates/error_reporting/report.html +118 -0
- edsl/templates/error_reporting/report.js +25 -0
- edsl/utilities/utilities.py +40 -1
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/METADATA +8 -2
- edsl-0.1.33.dist-info/RECORD +295 -0
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -271
- edsl/jobs/interviews/retry_management.py +0 -37
- edsl/jobs/runners/JobsRunnerStatusMixin.py +0 -303
- edsl/utilities/gcp_bucket/simple_example.py +0 -9
- edsl-0.1.31.dev4.dist-info/RECORD +0 -204
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/LICENSE +0 -0
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/WHEEL +0 -0
edsl/jobs/buckets/TokenBucket.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Union, List, Any
|
1
|
+
from typing import Union, List, Any, Optional
|
2
2
|
import asyncio
|
3
3
|
import time
|
4
4
|
|
@@ -17,6 +17,12 @@ class TokenBucket:
|
|
17
17
|
self.bucket_name = bucket_name
|
18
18
|
self.bucket_type = bucket_type
|
19
19
|
self.capacity = capacity # Maximum number of tokens
|
20
|
+
self.added_tokens = 0
|
21
|
+
|
22
|
+
self.target_rate = (
|
23
|
+
capacity * 60
|
24
|
+
) # set this here because it can change with turbo mode
|
25
|
+
|
20
26
|
self._old_capacity = capacity
|
21
27
|
self.tokens = capacity # Current number of available tokens
|
22
28
|
self.refill_rate = refill_rate # Rate at which tokens are refilled
|
@@ -25,6 +31,12 @@ class TokenBucket:
|
|
25
31
|
self.log: List[Any] = []
|
26
32
|
self.turbo_mode = False
|
27
33
|
|
34
|
+
self.creation_time = time.monotonic()
|
35
|
+
|
36
|
+
self.num_requests = 0
|
37
|
+
self.num_released = 0
|
38
|
+
self.tokens_returned = 0
|
39
|
+
|
28
40
|
def turbo_mode_on(self):
|
29
41
|
"""Set the refill rate to infinity."""
|
30
42
|
if self.turbo_mode:
|
@@ -69,6 +81,7 @@ class TokenBucket:
|
|
69
81
|
>>> bucket.tokens
|
70
82
|
10
|
71
83
|
"""
|
84
|
+
self.tokens_returned += tokens
|
72
85
|
self.tokens = min(self.capacity, self.tokens + tokens)
|
73
86
|
self.log.append((time.monotonic(), self.tokens))
|
74
87
|
|
@@ -82,25 +95,34 @@ class TokenBucket:
|
|
82
95
|
>>> bucket.refill()
|
83
96
|
>>> bucket.tokens > 0
|
84
97
|
True
|
85
|
-
|
86
98
|
"""
|
99
|
+
"""Refill the bucket with new tokens based on elapsed time."""
|
87
100
|
now = time.monotonic()
|
101
|
+
# print(f"Time is now: {now}; Last refill time: {self.last_refill}")
|
88
102
|
elapsed = now - self.last_refill
|
103
|
+
# print("Elapsed time: ", elapsed)
|
89
104
|
refill_amount = elapsed * self.refill_rate
|
90
105
|
self.tokens = min(self.capacity, self.tokens + refill_amount)
|
91
106
|
self.last_refill = now
|
92
107
|
|
108
|
+
if self.tokens < self.capacity:
|
109
|
+
pass
|
110
|
+
# print(f"Refilled. Current tokens: {self.tokens:.4f}")
|
111
|
+
# print(f"Elapsed time: {elapsed:.4f} seconds")
|
112
|
+
# print(f"Refill amount: {refill_amount:.4f}")
|
113
|
+
|
93
114
|
self.log.append((now, self.tokens))
|
94
115
|
|
95
116
|
def wait_time(self, requested_tokens: Union[float, int]) -> float:
|
96
117
|
"""Calculate the time to wait for the requested number of tokens."""
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
118
|
+
# self.refill() # Update the current token count
|
119
|
+
if self.tokens >= requested_tokens:
|
120
|
+
return 0
|
121
|
+
return (requested_tokens - self.tokens) / self.refill_rate
|
122
|
+
|
123
|
+
async def get_tokens(
|
124
|
+
self, amount: Union[int, float] = 1, cheat_bucket_capacity=True
|
125
|
+
) -> None:
|
104
126
|
"""Wait for the specified number of tokens to become available.
|
105
127
|
|
106
128
|
|
@@ -116,21 +138,38 @@ class TokenBucket:
|
|
116
138
|
True
|
117
139
|
|
118
140
|
>>> bucket = TokenBucket(bucket_name="test", bucket_type="test", capacity=10, refill_rate=1)
|
119
|
-
>>> asyncio.run(bucket.get_tokens(11))
|
141
|
+
>>> asyncio.run(bucket.get_tokens(11, cheat_bucket_capacity=False))
|
120
142
|
Traceback (most recent call last):
|
121
143
|
...
|
122
144
|
ValueError: Requested amount exceeds bucket capacity. Bucket capacity: 10, requested amount: 11. As the bucket never overflows, the requested amount will never be available.
|
145
|
+
>>> asyncio.run(bucket.get_tokens(11, cheat_bucket_capacity=True))
|
146
|
+
>>> bucket.capacity
|
147
|
+
12.100000000000001
|
123
148
|
"""
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
149
|
+
self.num_requests += amount
|
150
|
+
if amount >= self.capacity:
|
151
|
+
if not cheat_bucket_capacity:
|
152
|
+
msg = f"Requested amount exceeds bucket capacity. Bucket capacity: {self.capacity}, requested amount: {amount}. As the bucket never overflows, the requested amount will never be available."
|
153
|
+
raise ValueError(msg)
|
154
|
+
else:
|
155
|
+
self.capacity = amount * 1.10
|
156
|
+
self._old_capacity = self.capacity
|
157
|
+
|
158
|
+
start_time = time.monotonic()
|
159
|
+
while True:
|
160
|
+
self.refill() # Refill based on elapsed time
|
161
|
+
if self.tokens >= amount:
|
162
|
+
self.tokens -= amount
|
163
|
+
break
|
164
|
+
|
165
|
+
wait_time = self.wait_time(amount)
|
166
|
+
if wait_time > 0:
|
167
|
+
await asyncio.sleep(wait_time)
|
168
|
+
|
169
|
+
self.num_released += amount
|
132
170
|
now = time.monotonic()
|
133
171
|
self.log.append((now, self.tokens))
|
172
|
+
return None
|
134
173
|
|
135
174
|
def get_log(self) -> list[tuple]:
|
136
175
|
return self.log
|
@@ -154,6 +193,54 @@ class TokenBucket:
|
|
154
193
|
plt.tight_layout()
|
155
194
|
plt.show()
|
156
195
|
|
196
|
+
def get_throughput(self, time_window: Optional[float] = None) -> float:
|
197
|
+
"""
|
198
|
+
Calculate the empirical bucket throughput in tokens per minute for the specified time window.
|
199
|
+
|
200
|
+
:param time_window: The time window in seconds to calculate the throughput for.
|
201
|
+
:return: The throughput in tokens per minute.
|
202
|
+
|
203
|
+
>>> bucket = TokenBucket(bucket_name="test", bucket_type="test", capacity=100, refill_rate=10)
|
204
|
+
>>> asyncio.run(bucket.get_tokens(50))
|
205
|
+
>>> time.sleep(1) # Wait for 1 second
|
206
|
+
>>> asyncio.run(bucket.get_tokens(30))
|
207
|
+
>>> throughput = bucket.get_throughput(1)
|
208
|
+
>>> 4750 < throughput < 4850
|
209
|
+
True
|
210
|
+
"""
|
211
|
+
now = time.monotonic()
|
212
|
+
|
213
|
+
if time_window is None:
|
214
|
+
start_time = self.creation_time
|
215
|
+
else:
|
216
|
+
start_time = now - time_window
|
217
|
+
|
218
|
+
if start_time < self.creation_time:
|
219
|
+
start_time = self.creation_time
|
220
|
+
|
221
|
+
elapsed_time = now - start_time
|
222
|
+
|
223
|
+
return (self.num_released / elapsed_time) * 60
|
224
|
+
|
225
|
+
# # Filter log entries within the time window
|
226
|
+
# relevant_log = [(t, tokens) for t, tokens in self.log if t >= start_time]
|
227
|
+
|
228
|
+
# if len(relevant_log) < 2:
|
229
|
+
# return 0 # Not enough data points to calculate throughput
|
230
|
+
|
231
|
+
# # Calculate total tokens used
|
232
|
+
# initial_tokens = relevant_log[0][1]
|
233
|
+
# final_tokens = relevant_log[-1][1]
|
234
|
+
# tokens_used = self.num_released - (final_tokens - initial_tokens)
|
235
|
+
|
236
|
+
# # Calculate actual time elapsed
|
237
|
+
# actual_time_elapsed = relevant_log[-1][0] - relevant_log[0][0]
|
238
|
+
|
239
|
+
# # Calculate throughput in tokens per minute
|
240
|
+
# throughput = (tokens_used / actual_time_elapsed) * 60
|
241
|
+
|
242
|
+
# return throughput
|
243
|
+
|
157
244
|
|
158
245
|
if __name__ == "__main__":
|
159
246
|
import doctest
|