edsl 0.1.50__py3-none-any.whl → 0.1.52__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/__init__.py +45 -34
- edsl/__version__.py +1 -1
- edsl/base/base_exception.py +2 -2
- edsl/buckets/bucket_collection.py +1 -1
- edsl/buckets/exceptions.py +32 -0
- edsl/buckets/token_bucket_api.py +26 -10
- edsl/caching/cache.py +5 -2
- edsl/caching/remote_cache_sync.py +5 -5
- edsl/caching/sql_dict.py +12 -11
- edsl/config/__init__.py +1 -1
- edsl/config/config_class.py +4 -2
- edsl/conversation/Conversation.py +9 -5
- edsl/conversation/car_buying.py +1 -3
- edsl/conversation/mug_negotiation.py +2 -6
- edsl/coop/__init__.py +11 -8
- edsl/coop/coop.py +15 -13
- edsl/coop/coop_functions.py +1 -1
- edsl/coop/ep_key_handling.py +1 -1
- edsl/coop/price_fetcher.py +2 -2
- edsl/coop/utils.py +2 -2
- edsl/dataset/dataset.py +144 -63
- edsl/dataset/dataset_operations_mixin.py +14 -6
- edsl/dataset/dataset_tree.py +3 -3
- edsl/dataset/display/table_renderers.py +6 -3
- edsl/dataset/file_exports.py +4 -4
- edsl/dataset/r/ggplot.py +3 -3
- edsl/inference_services/available_model_fetcher.py +2 -2
- edsl/inference_services/data_structures.py +5 -5
- edsl/inference_services/inference_service_abc.py +1 -1
- edsl/inference_services/inference_services_collection.py +1 -1
- edsl/inference_services/service_availability.py +3 -3
- edsl/inference_services/services/azure_ai.py +3 -3
- edsl/inference_services/services/google_service.py +1 -1
- edsl/inference_services/services/test_service.py +1 -1
- edsl/instructions/change_instruction.py +5 -4
- edsl/instructions/instruction.py +1 -0
- edsl/instructions/instruction_collection.py +5 -4
- edsl/instructions/instruction_handler.py +10 -8
- edsl/interviews/answering_function.py +20 -21
- edsl/interviews/exception_tracking.py +3 -2
- edsl/interviews/interview.py +1 -1
- edsl/interviews/interview_status_dictionary.py +1 -1
- edsl/interviews/interview_task_manager.py +7 -4
- edsl/interviews/request_token_estimator.py +3 -2
- edsl/interviews/statistics.py +2 -2
- edsl/invigilators/invigilators.py +34 -6
- edsl/jobs/__init__.py +39 -2
- edsl/jobs/async_interview_runner.py +1 -1
- edsl/jobs/check_survey_scenario_compatibility.py +5 -5
- edsl/jobs/data_structures.py +2 -2
- edsl/jobs/html_table_job_logger.py +494 -257
- edsl/jobs/jobs.py +2 -2
- edsl/jobs/jobs_checks.py +5 -5
- edsl/jobs/jobs_component_constructor.py +2 -2
- edsl/jobs/jobs_pricing_estimation.py +1 -1
- edsl/jobs/jobs_runner_asyncio.py +2 -2
- edsl/jobs/jobs_status_enums.py +1 -0
- edsl/jobs/remote_inference.py +47 -13
- edsl/jobs/results_exceptions_handler.py +2 -2
- edsl/language_models/language_model.py +151 -145
- edsl/notebooks/__init__.py +24 -1
- edsl/notebooks/exceptions.py +82 -0
- edsl/notebooks/notebook.py +7 -3
- edsl/notebooks/notebook_to_latex.py +1 -1
- edsl/prompts/__init__.py +23 -2
- edsl/prompts/prompt.py +1 -1
- edsl/questions/__init__.py +4 -4
- edsl/questions/answer_validator_mixin.py +0 -5
- edsl/questions/compose_questions.py +2 -2
- edsl/questions/descriptors.py +1 -1
- edsl/questions/question_base.py +32 -3
- edsl/questions/question_base_prompts_mixin.py +4 -4
- edsl/questions/question_budget.py +503 -102
- edsl/questions/question_check_box.py +658 -156
- edsl/questions/question_dict.py +176 -2
- edsl/questions/question_extract.py +401 -61
- edsl/questions/question_free_text.py +77 -9
- edsl/questions/question_functional.py +118 -9
- edsl/questions/{derived/question_likert_five.py → question_likert_five.py} +2 -2
- edsl/questions/{derived/question_linear_scale.py → question_linear_scale.py} +3 -4
- edsl/questions/question_list.py +246 -26
- edsl/questions/question_matrix.py +586 -73
- edsl/questions/question_multiple_choice.py +213 -47
- edsl/questions/question_numerical.py +360 -29
- edsl/questions/question_rank.py +401 -124
- edsl/questions/question_registry.py +3 -3
- edsl/questions/{derived/question_top_k.py → question_top_k.py} +3 -3
- edsl/questions/{derived/question_yes_no.py → question_yes_no.py} +3 -4
- edsl/questions/register_questions_meta.py +2 -1
- edsl/questions/response_validator_abc.py +6 -2
- edsl/questions/response_validator_factory.py +10 -12
- edsl/results/report.py +1 -1
- edsl/results/result.py +7 -4
- edsl/results/results.py +500 -271
- edsl/results/results_selector.py +2 -2
- edsl/scenarios/construct_download_link.py +3 -3
- edsl/scenarios/scenario.py +1 -2
- edsl/scenarios/scenario_list.py +41 -23
- edsl/surveys/survey_css.py +3 -3
- edsl/surveys/survey_simulator.py +2 -1
- edsl/tasks/__init__.py +22 -2
- edsl/tasks/exceptions.py +72 -0
- edsl/tasks/task_history.py +48 -11
- edsl/templates/error_reporting/base.html +37 -4
- edsl/templates/error_reporting/exceptions_table.html +105 -33
- edsl/templates/error_reporting/interview_details.html +130 -126
- edsl/templates/error_reporting/overview.html +21 -25
- edsl/templates/error_reporting/report.css +215 -46
- edsl/templates/error_reporting/report.js +122 -20
- edsl/tokens/__init__.py +27 -1
- edsl/tokens/exceptions.py +37 -0
- edsl/tokens/interview_token_usage.py +3 -2
- edsl/tokens/token_usage.py +4 -3
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/METADATA +1 -1
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/RECORD +118 -116
- edsl/questions/derived/__init__.py +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/LICENSE +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/WHEEL +0 -0
- {edsl-0.1.50.dist-info → edsl-0.1.52.dist-info}/entry_points.txt +0 -0
edsl/jobs/jobs.py
CHANGED
@@ -620,7 +620,7 @@ class Jobs(Base):
|
|
620
620
|
if jh.use_remote_inference(self.run_config.parameters.disable_remote_inference):
|
621
621
|
job_info: RemoteJobInfo = self._start_remote_inference_job(jh)
|
622
622
|
if background:
|
623
|
-
from
|
623
|
+
from ..results import Results
|
624
624
|
|
625
625
|
results = Results.from_job_info(job_info)
|
626
626
|
return results, None
|
@@ -881,7 +881,7 @@ class Jobs(Base):
|
|
881
881
|
],
|
882
882
|
}
|
883
883
|
if add_edsl_version:
|
884
|
-
from
|
884
|
+
from .. import __version__
|
885
885
|
|
886
886
|
d["edsl_version"] = __version__
|
887
887
|
d["edsl_class_name"] = "Jobs"
|
edsl/jobs/jobs_checks.py
CHANGED
@@ -3,7 +3,7 @@ Checks a Jobs object for missing API keys and other requirements.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import os
|
6
|
-
from
|
6
|
+
from ..key_management.key_lookup_builder import MissingAPIKeyError
|
7
7
|
|
8
8
|
|
9
9
|
class JobsChecks:
|
@@ -16,7 +16,7 @@ class JobsChecks:
|
|
16
16
|
self.jobs = jobs
|
17
17
|
|
18
18
|
def check_api_keys(self) -> None:
|
19
|
-
from
|
19
|
+
from ..language_models.model import Model
|
20
20
|
|
21
21
|
if len(self.jobs.models) == 0:
|
22
22
|
models = [Model()]
|
@@ -37,7 +37,7 @@ class JobsChecks:
|
|
37
37
|
"""
|
38
38
|
missing_api_keys = set()
|
39
39
|
|
40
|
-
from
|
40
|
+
from ..enums import service_to_api_keyname
|
41
41
|
|
42
42
|
for model in self.jobs.models: # + [Model()]:
|
43
43
|
if not model.has_valid_api_key():
|
@@ -134,8 +134,8 @@ class JobsChecks:
|
|
134
134
|
def key_process(self):
|
135
135
|
import secrets
|
136
136
|
from dotenv import load_dotenv
|
137
|
-
from
|
138
|
-
from
|
137
|
+
from ..coop.coop import Coop
|
138
|
+
from ..utilities.utilities import write_api_key_to_env
|
139
139
|
|
140
140
|
missing_api_keys = self.get_missing_api_keys()
|
141
141
|
|
@@ -140,8 +140,8 @@ class JobsComponentConstructor:
|
|
140
140
|
|
141
141
|
@staticmethod
|
142
142
|
def _get_empty_container_object(object):
|
143
|
-
from
|
144
|
-
from
|
143
|
+
from ..agents import AgentList
|
144
|
+
from ..scenarios import ScenarioList
|
145
145
|
|
146
146
|
return {"Agent": AgentList([]), "Scenario": ScenarioList([])}.get(
|
147
147
|
object.__class__.__name__, []
|
@@ -137,7 +137,7 @@ class JobsPrompts:
|
|
137
137
|
def price_lookup(self) -> dict:
|
138
138
|
"""Fetches the price lookup from Coop if it is not already cached."""
|
139
139
|
if self._price_lookup is None:
|
140
|
-
from
|
140
|
+
from ..coop.coop import Coop
|
141
141
|
|
142
142
|
c = Coop()
|
143
143
|
self._price_lookup = c.fetch_prices()
|
edsl/jobs/jobs_runner_asyncio.py
CHANGED
@@ -186,7 +186,7 @@ class JobsRunnerAsyncio:
|
|
186
186
|
self.start_time = time.monotonic()
|
187
187
|
self.completed = False
|
188
188
|
|
189
|
-
from
|
189
|
+
from ..coop import Coop
|
190
190
|
|
191
191
|
coop = Coop()
|
192
192
|
endpoint_url = coop.get_progress_bar_url()
|
@@ -273,7 +273,7 @@ class JobsRunnerAsyncio:
|
|
273
273
|
# breakpoint()
|
274
274
|
results.bucket_collection = self.environment.bucket_collection
|
275
275
|
|
276
|
-
from
|
276
|
+
from .results_exceptions_handler import ResultsExceptionsHandler
|
277
277
|
|
278
278
|
results_exceptions_handler = ResultsExceptionsHandler(results, parameters)
|
279
279
|
|
edsl/jobs/jobs_status_enums.py
CHANGED
edsl/jobs/remote_inference.py
CHANGED
@@ -43,7 +43,7 @@ class JobsRemoteInferenceHandler:
|
|
43
43
|
self.verbose = verbose
|
44
44
|
self.poll_interval = poll_interval
|
45
45
|
|
46
|
-
from
|
46
|
+
from ..config import CONFIG
|
47
47
|
|
48
48
|
self.expected_parrot_url = CONFIG.get("EXPECTED_PARROT_URL")
|
49
49
|
self.remote_inference_url = f"{self.expected_parrot_url}/home/remote-inference"
|
@@ -113,7 +113,7 @@ class JobsRemoteInferenceHandler:
|
|
113
113
|
logger.add_info("job_uuid", job_uuid)
|
114
114
|
|
115
115
|
logger.update(
|
116
|
-
f"Job details are available at your Coop account {self.remote_inference_url}",
|
116
|
+
f"Job details are available at your Coop account. [Go to Remote Inference page]({self.remote_inference_url})",
|
117
117
|
status=JobsStatus.RUNNING,
|
118
118
|
)
|
119
119
|
progress_bar_url = (
|
@@ -121,7 +121,7 @@ class JobsRemoteInferenceHandler:
|
|
121
121
|
)
|
122
122
|
logger.add_info("progress_bar_url", progress_bar_url)
|
123
123
|
logger.update(
|
124
|
-
f"View job progress here
|
124
|
+
f"View job progress [here]({progress_bar_url})", status=JobsStatus.RUNNING
|
125
125
|
)
|
126
126
|
|
127
127
|
return RemoteJobInfo(
|
@@ -169,7 +169,7 @@ class JobsRemoteInferenceHandler:
|
|
169
169
|
message="Job cancelled by the user.", status=JobsStatus.CANCELLED
|
170
170
|
)
|
171
171
|
job_info.logger.update(
|
172
|
-
f"See {self.expected_parrot_url}/home/remote-inference for more details.",
|
172
|
+
f"See [Remote Inference page]({self.expected_parrot_url}/home/remote-inference) for more details.",
|
173
173
|
status=JobsStatus.CANCELLED,
|
174
174
|
)
|
175
175
|
|
@@ -182,22 +182,45 @@ class JobsRemoteInferenceHandler:
|
|
182
182
|
reason = remote_job_data.get("reason")
|
183
183
|
|
184
184
|
if reason == "insufficient funds":
|
185
|
-
|
186
|
-
|
185
|
+
job_info.logger.update(
|
186
|
+
f"Error: Insufficient balance to start the job. Add funds to your account at the [Credits page]({self.expected_parrot_url}/home/credits)",
|
187
|
+
status=JobsStatus.FAILED,
|
188
|
+
)
|
187
189
|
|
188
190
|
if latest_error_report_url:
|
189
191
|
job_info.logger.add_info("error_report_url", latest_error_report_url)
|
190
192
|
|
191
193
|
job_info.logger.update("Job failed.", status=JobsStatus.FAILED)
|
192
194
|
job_info.logger.update(
|
193
|
-
f"See {self.expected_parrot_url}/home/remote-inference for more details.",
|
195
|
+
f"See [Remote Inference page]({self.expected_parrot_url}/home/remote-inference) for more details.",
|
194
196
|
status=JobsStatus.FAILED,
|
195
197
|
)
|
196
198
|
job_info.logger.update(
|
197
|
-
f"Need support? Visit Discord
|
199
|
+
f"Need support? [Visit Discord]({RemoteJobConstants.DISCORD_URL})",
|
198
200
|
status=JobsStatus.FAILED,
|
199
201
|
)
|
200
202
|
|
203
|
+
def _handle_partially_failed_job(
|
204
|
+
self, job_info: RemoteJobInfo, remote_job_data: RemoteInferenceResponse
|
205
|
+
) -> None:
|
206
|
+
"Handles a partially failed job by logging the error and updating the job status."
|
207
|
+
latest_error_report_url = remote_job_data.get("latest_error_report_url")
|
208
|
+
|
209
|
+
if latest_error_report_url:
|
210
|
+
job_info.logger.add_info("error_report_url", latest_error_report_url)
|
211
|
+
|
212
|
+
job_info.logger.update(
|
213
|
+
"Job completed with partial results.", status=JobsStatus.PARTIALLY_FAILED
|
214
|
+
)
|
215
|
+
job_info.logger.update(
|
216
|
+
f"See [Remote Inference page]({self.expected_parrot_url}/home/remote-inference) for more details.",
|
217
|
+
status=JobsStatus.PARTIALLY_FAILED,
|
218
|
+
)
|
219
|
+
job_info.logger.update(
|
220
|
+
f"Need support? [Visit Discord]({RemoteJobConstants.DISCORD_URL})",
|
221
|
+
status=JobsStatus.PARTIALLY_FAILED,
|
222
|
+
)
|
223
|
+
|
201
224
|
def _sleep_for_a_bit(self, job_info: RemoteJobInfo, status: str) -> None:
|
202
225
|
import time
|
203
226
|
from datetime import datetime
|
@@ -212,6 +235,7 @@ class JobsRemoteInferenceHandler:
|
|
212
235
|
def _fetch_results_and_log(
|
213
236
|
self,
|
214
237
|
job_info: RemoteJobInfo,
|
238
|
+
job_status: Literal["failed", "partial_failed", "completed"],
|
215
239
|
results_uuid: str,
|
216
240
|
remote_job_data: RemoteInferenceResponse,
|
217
241
|
object_fetcher: Callable,
|
@@ -221,10 +245,17 @@ class JobsRemoteInferenceHandler:
|
|
221
245
|
results = object_fetcher(results_uuid, expected_object_type="results")
|
222
246
|
results_url = remote_job_data.get("results_url")
|
223
247
|
job_info.logger.add_info("results_url", results_url)
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
248
|
+
|
249
|
+
if job_status == "completed":
|
250
|
+
job_info.logger.update(
|
251
|
+
f"Job completed and Results stored on Coop. [View Results]({results_url})",
|
252
|
+
status=JobsStatus.COMPLETED,
|
253
|
+
)
|
254
|
+
elif job_status == "partial_failed":
|
255
|
+
job_info.logger.update(
|
256
|
+
f"View partial results [here]({results_url})",
|
257
|
+
status=JobsStatus.PARTIALLY_FAILED,
|
258
|
+
)
|
228
259
|
results.job_uuid = job_info.job_uuid
|
229
260
|
results.results_uuid = results_uuid
|
230
261
|
return results
|
@@ -244,13 +275,16 @@ class JobsRemoteInferenceHandler:
|
|
244
275
|
return None, reason
|
245
276
|
|
246
277
|
elif status == "failed" or status == "completed" or status == "partial_failed":
|
247
|
-
if status == "failed"
|
278
|
+
if status == "failed":
|
248
279
|
self._handle_failed_job(job_info, remote_job_data)
|
280
|
+
elif status == "partial_failed":
|
281
|
+
self._handle_partially_failed_job(job_info, remote_job_data)
|
249
282
|
|
250
283
|
results_uuid = remote_job_data.get("results_uuid")
|
251
284
|
if results_uuid:
|
252
285
|
results = self._fetch_results_and_log(
|
253
286
|
job_info=job_info,
|
287
|
+
job_status=status,
|
254
288
|
results_uuid=results_uuid,
|
255
289
|
remote_job_data=remote_job_data,
|
256
290
|
object_fetcher=object_fetcher,
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import Protocol
|
2
2
|
import sys
|
3
3
|
#from edsl.scenarios.FileStore import HTMLFileStore
|
4
|
-
from
|
5
|
-
from
|
4
|
+
from ..config import CONFIG
|
5
|
+
from ..coop.coop import Coop
|
6
6
|
from ..scenarios import FileStore
|
7
7
|
from .exceptions import JobsErrors
|
8
8
|
|