edsl 0.1.47__py3-none-any.whl → 0.1.49__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 +44 -39
- edsl/__version__.py +1 -1
- edsl/agents/__init__.py +4 -2
- edsl/agents/{Agent.py → agent.py} +442 -152
- edsl/agents/{AgentList.py → agent_list.py} +220 -162
- edsl/agents/descriptors.py +46 -7
- edsl/{exceptions/agents.py → agents/exceptions.py} +3 -12
- edsl/base/__init__.py +75 -0
- edsl/base/base_class.py +1303 -0
- edsl/base/data_transfer_models.py +114 -0
- edsl/base/enums.py +215 -0
- edsl/base.py +8 -0
- edsl/buckets/__init__.py +25 -0
- edsl/buckets/bucket_collection.py +324 -0
- edsl/buckets/model_buckets.py +206 -0
- edsl/buckets/token_bucket.py +502 -0
- edsl/{jobs/buckets/TokenBucketAPI.py → buckets/token_bucket_api.py} +1 -1
- edsl/buckets/token_bucket_client.py +509 -0
- edsl/caching/__init__.py +20 -0
- edsl/caching/cache.py +814 -0
- edsl/caching/cache_entry.py +427 -0
- edsl/{data/CacheHandler.py → caching/cache_handler.py} +14 -15
- edsl/caching/exceptions.py +24 -0
- edsl/caching/orm.py +30 -0
- edsl/{data/RemoteCacheSync.py → caching/remote_cache_sync.py} +3 -3
- edsl/caching/sql_dict.py +441 -0
- edsl/config/__init__.py +8 -0
- edsl/config/config_class.py +177 -0
- edsl/config.py +4 -176
- edsl/conversation/Conversation.py +7 -7
- edsl/conversation/car_buying.py +4 -4
- edsl/conversation/chips.py +6 -6
- edsl/coop/__init__.py +25 -2
- edsl/coop/coop.py +311 -75
- edsl/coop/{ExpectedParrotKeyHandler.py → ep_key_handling.py} +86 -10
- edsl/coop/exceptions.py +62 -0
- edsl/coop/price_fetcher.py +126 -0
- edsl/coop/utils.py +89 -24
- edsl/data_transfer_models.py +5 -72
- edsl/dataset/__init__.py +10 -0
- edsl/{results/Dataset.py → dataset/dataset.py} +116 -36
- edsl/{results/DatasetExportMixin.py → dataset/dataset_operations_mixin.py} +606 -122
- edsl/{results/DatasetTree.py → dataset/dataset_tree.py} +156 -75
- edsl/{results/TableDisplay.py → dataset/display/table_display.py} +18 -7
- edsl/{results → dataset/display}/table_renderers.py +58 -2
- edsl/{results → dataset}/file_exports.py +4 -5
- edsl/{results → dataset}/smart_objects.py +2 -2
- edsl/enums.py +5 -205
- edsl/inference_services/__init__.py +5 -0
- edsl/inference_services/{AvailableModelCacheHandler.py → available_model_cache_handler.py} +2 -3
- edsl/inference_services/{AvailableModelFetcher.py → available_model_fetcher.py} +8 -14
- edsl/inference_services/data_structures.py +3 -2
- edsl/{exceptions/inference_services.py → inference_services/exceptions.py} +1 -1
- edsl/inference_services/{InferenceServiceABC.py → inference_service_abc.py} +1 -1
- edsl/inference_services/{InferenceServicesCollection.py → inference_services_collection.py} +8 -7
- edsl/inference_services/registry.py +4 -41
- edsl/inference_services/{ServiceAvailability.py → service_availability.py} +5 -25
- edsl/inference_services/services/__init__.py +31 -0
- edsl/inference_services/{AnthropicService.py → services/anthropic_service.py} +3 -3
- edsl/inference_services/{AwsBedrock.py → services/aws_bedrock.py} +2 -2
- edsl/inference_services/{AzureAI.py → services/azure_ai.py} +2 -2
- edsl/inference_services/{DeepInfraService.py → services/deep_infra_service.py} +1 -3
- edsl/inference_services/{DeepSeekService.py → services/deep_seek_service.py} +2 -4
- edsl/inference_services/{GoogleService.py → services/google_service.py} +5 -4
- edsl/inference_services/{GroqService.py → services/groq_service.py} +1 -1
- edsl/inference_services/{MistralAIService.py → services/mistral_ai_service.py} +3 -3
- edsl/inference_services/{OllamaService.py → services/ollama_service.py} +1 -7
- edsl/inference_services/{OpenAIService.py → services/open_ai_service.py} +5 -6
- edsl/inference_services/{PerplexityService.py → services/perplexity_service.py} +3 -7
- edsl/inference_services/{TestService.py → services/test_service.py} +7 -6
- edsl/inference_services/{TogetherAIService.py → services/together_ai_service.py} +2 -6
- edsl/inference_services/{XAIService.py → services/xai_service.py} +1 -1
- edsl/inference_services/write_available.py +1 -2
- edsl/instructions/__init__.py +6 -0
- edsl/{surveys/instructions/Instruction.py → instructions/instruction.py} +11 -6
- edsl/{surveys/instructions/InstructionCollection.py → instructions/instruction_collection.py} +10 -5
- edsl/{surveys/InstructionHandler.py → instructions/instruction_handler.py} +3 -3
- edsl/{jobs/interviews → interviews}/ReportErrors.py +2 -2
- edsl/interviews/__init__.py +4 -0
- edsl/{jobs/AnswerQuestionFunctionConstructor.py → interviews/answering_function.py} +45 -18
- edsl/{jobs/interviews/InterviewExceptionEntry.py → interviews/exception_tracking.py} +107 -22
- edsl/interviews/interview.py +638 -0
- edsl/{jobs/interviews/InterviewStatusDictionary.py → interviews/interview_status_dictionary.py} +21 -12
- edsl/{jobs/interviews/InterviewStatusLog.py → interviews/interview_status_log.py} +16 -7
- edsl/{jobs/InterviewTaskManager.py → interviews/interview_task_manager.py} +12 -7
- edsl/{jobs/RequestTokenEstimator.py → interviews/request_token_estimator.py} +8 -3
- edsl/{jobs/interviews/InterviewStatistic.py → interviews/statistics.py} +36 -10
- edsl/invigilators/__init__.py +38 -0
- edsl/invigilators/invigilator_base.py +477 -0
- edsl/{agents/Invigilator.py → invigilators/invigilators.py} +263 -10
- edsl/invigilators/prompt_constructor.py +476 -0
- edsl/{agents → invigilators}/prompt_helpers.py +2 -1
- edsl/{agents/QuestionInstructionPromptBuilder.py → invigilators/question_instructions_prompt_builder.py} +18 -13
- edsl/{agents → invigilators}/question_option_processor.py +96 -21
- edsl/{agents/QuestionTemplateReplacementsBuilder.py → invigilators/question_template_replacements_builder.py} +64 -12
- edsl/jobs/__init__.py +7 -1
- edsl/jobs/async_interview_runner.py +99 -35
- edsl/jobs/check_survey_scenario_compatibility.py +7 -5
- edsl/jobs/data_structures.py +153 -22
- edsl/{exceptions/jobs.py → jobs/exceptions.py} +2 -1
- edsl/jobs/{FetchInvigilator.py → fetch_invigilator.py} +4 -4
- edsl/jobs/{loggers/HTMLTableJobLogger.py → html_table_job_logger.py} +6 -2
- edsl/jobs/{Jobs.py → jobs.py} +313 -167
- edsl/jobs/{JobsChecks.py → jobs_checks.py} +15 -7
- edsl/jobs/{JobsComponentConstructor.py → jobs_component_constructor.py} +19 -17
- edsl/jobs/{InterviewsConstructor.py → jobs_interview_constructor.py} +10 -5
- edsl/jobs/jobs_pricing_estimation.py +347 -0
- edsl/jobs/{JobsRemoteInferenceLogger.py → jobs_remote_inference_logger.py} +4 -3
- edsl/jobs/jobs_runner_asyncio.py +282 -0
- edsl/jobs/{JobsRemoteInferenceHandler.py → remote_inference.py} +19 -22
- edsl/jobs/results_exceptions_handler.py +2 -2
- edsl/key_management/__init__.py +28 -0
- edsl/key_management/key_lookup.py +161 -0
- edsl/{language_models/key_management/KeyLookupBuilder.py → key_management/key_lookup_builder.py} +118 -47
- edsl/key_management/key_lookup_collection.py +82 -0
- edsl/key_management/models.py +218 -0
- edsl/language_models/__init__.py +7 -2
- edsl/language_models/{ComputeCost.py → compute_cost.py} +18 -3
- edsl/{exceptions/language_models.py → language_models/exceptions.py} +2 -1
- edsl/language_models/language_model.py +1080 -0
- edsl/language_models/model.py +10 -25
- edsl/language_models/{ModelList.py → model_list.py} +9 -14
- edsl/language_models/{RawResponseHandler.py → raw_response_handler.py} +1 -1
- edsl/language_models/{RegisterLanguageModelsMeta.py → registry.py} +1 -1
- edsl/language_models/repair.py +4 -4
- edsl/language_models/utilities.py +4 -4
- edsl/notebooks/__init__.py +3 -1
- edsl/notebooks/{Notebook.py → notebook.py} +7 -8
- edsl/prompts/__init__.py +1 -1
- edsl/{exceptions/prompts.py → prompts/exceptions.py} +3 -1
- edsl/prompts/{Prompt.py → prompt.py} +101 -95
- edsl/questions/HTMLQuestion.py +1 -1
- edsl/questions/__init__.py +154 -25
- edsl/questions/answer_validator_mixin.py +1 -1
- edsl/questions/compose_questions.py +4 -3
- edsl/questions/derived/question_likert_five.py +166 -0
- edsl/questions/derived/{QuestionLinearScale.py → question_linear_scale.py} +4 -4
- edsl/questions/derived/{QuestionTopK.py → question_top_k.py} +4 -4
- edsl/questions/derived/{QuestionYesNo.py → question_yes_no.py} +4 -5
- edsl/questions/descriptors.py +24 -30
- edsl/questions/loop_processor.py +65 -19
- edsl/questions/question_base.py +881 -0
- edsl/questions/question_base_gen_mixin.py +15 -16
- edsl/questions/{QuestionBasePromptsMixin.py → question_base_prompts_mixin.py} +2 -2
- edsl/questions/{QuestionBudget.py → question_budget.py} +3 -4
- edsl/questions/{QuestionCheckBox.py → question_check_box.py} +16 -16
- edsl/questions/{QuestionDict.py → question_dict.py} +39 -5
- edsl/questions/{QuestionExtract.py → question_extract.py} +9 -9
- edsl/questions/question_free_text.py +282 -0
- edsl/questions/{QuestionFunctional.py → question_functional.py} +6 -5
- edsl/questions/{QuestionList.py → question_list.py} +6 -7
- edsl/questions/{QuestionMatrix.py → question_matrix.py} +6 -5
- edsl/questions/{QuestionMultipleChoice.py → question_multiple_choice.py} +126 -21
- edsl/questions/{QuestionNumerical.py → question_numerical.py} +5 -5
- edsl/questions/{QuestionRank.py → question_rank.py} +6 -6
- edsl/questions/question_registry.py +4 -9
- edsl/questions/register_questions_meta.py +8 -4
- edsl/questions/response_validator_abc.py +17 -16
- edsl/results/__init__.py +4 -1
- edsl/{exceptions/results.py → results/exceptions.py} +1 -1
- edsl/results/report.py +197 -0
- edsl/results/{Result.py → result.py} +131 -45
- edsl/results/{Results.py → results.py} +365 -220
- edsl/results/results_selector.py +344 -25
- edsl/scenarios/__init__.py +30 -3
- edsl/scenarios/{ConstructDownloadLink.py → construct_download_link.py} +7 -0
- edsl/scenarios/directory_scanner.py +156 -13
- edsl/scenarios/document_chunker.py +186 -0
- edsl/scenarios/exceptions.py +101 -0
- edsl/scenarios/file_methods.py +2 -3
- edsl/scenarios/{FileStore.py → file_store.py} +275 -189
- edsl/scenarios/handlers/__init__.py +14 -14
- edsl/scenarios/handlers/{csv.py → csv_file_store.py} +1 -2
- edsl/scenarios/handlers/{docx.py → docx_file_store.py} +8 -7
- edsl/scenarios/handlers/{html.py → html_file_store.py} +1 -2
- edsl/scenarios/handlers/{jpeg.py → jpeg_file_store.py} +1 -1
- edsl/scenarios/handlers/{json.py → json_file_store.py} +1 -1
- edsl/scenarios/handlers/latex_file_store.py +5 -0
- edsl/scenarios/handlers/{md.py → md_file_store.py} +1 -1
- edsl/scenarios/handlers/{pdf.py → pdf_file_store.py} +2 -2
- edsl/scenarios/handlers/{png.py → png_file_store.py} +1 -1
- edsl/scenarios/handlers/{pptx.py → pptx_file_store.py} +8 -7
- edsl/scenarios/handlers/{py.py → py_file_store.py} +1 -3
- edsl/scenarios/handlers/{sql.py → sql_file_store.py} +2 -1
- edsl/scenarios/handlers/{sqlite.py → sqlite_file_store.py} +2 -3
- edsl/scenarios/handlers/{txt.py → txt_file_store.py} +1 -1
- edsl/scenarios/scenario.py +928 -0
- edsl/scenarios/scenario_join.py +18 -5
- edsl/scenarios/{ScenarioList.py → scenario_list.py} +294 -106
- edsl/scenarios/{ScenarioListPdfMixin.py → scenario_list_pdf_tools.py} +16 -15
- edsl/scenarios/scenario_selector.py +5 -1
- edsl/study/ObjectEntry.py +2 -2
- edsl/study/SnapShot.py +5 -5
- edsl/study/Study.py +18 -19
- edsl/study/__init__.py +6 -4
- edsl/surveys/__init__.py +7 -4
- edsl/surveys/dag/__init__.py +2 -0
- edsl/surveys/{ConstructDAG.py → dag/construct_dag.py} +3 -3
- edsl/surveys/{DAG.py → dag/dag.py} +13 -10
- edsl/surveys/descriptors.py +1 -1
- edsl/surveys/{EditSurvey.py → edit_survey.py} +9 -9
- edsl/{exceptions/surveys.py → surveys/exceptions.py} +1 -2
- edsl/surveys/memory/__init__.py +3 -0
- edsl/surveys/{MemoryPlan.py → memory/memory_plan.py} +10 -9
- edsl/surveys/rules/__init__.py +3 -0
- edsl/surveys/{Rule.py → rules/rule.py} +103 -43
- edsl/surveys/{RuleCollection.py → rules/rule_collection.py} +21 -30
- edsl/surveys/{RuleManager.py → rules/rule_manager.py} +19 -13
- edsl/surveys/survey.py +1743 -0
- edsl/surveys/{SurveyExportMixin.py → survey_export.py} +22 -27
- edsl/surveys/{SurveyFlowVisualization.py → survey_flow_visualization.py} +11 -2
- edsl/surveys/{Simulator.py → survey_simulator.py} +10 -3
- edsl/tasks/__init__.py +32 -0
- edsl/{jobs/tasks/QuestionTaskCreator.py → tasks/question_task_creator.py} +115 -57
- edsl/tasks/task_creators.py +135 -0
- edsl/{jobs/tasks/TaskHistory.py → tasks/task_history.py} +86 -47
- edsl/{jobs/tasks → tasks}/task_status_enum.py +91 -7
- edsl/tasks/task_status_log.py +85 -0
- edsl/tokens/__init__.py +2 -0
- edsl/tokens/interview_token_usage.py +53 -0
- edsl/utilities/PrettyList.py +1 -1
- edsl/utilities/SystemInfo.py +25 -22
- edsl/utilities/__init__.py +29 -21
- edsl/utilities/gcp_bucket/__init__.py +2 -0
- edsl/utilities/gcp_bucket/cloud_storage.py +99 -96
- edsl/utilities/interface.py +44 -536
- edsl/{results/MarkdownToPDF.py → utilities/markdown_to_pdf.py} +13 -5
- edsl/utilities/repair_functions.py +1 -1
- {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/METADATA +1 -1
- edsl-0.1.49.dist-info/RECORD +347 -0
- edsl/Base.py +0 -493
- edsl/BaseDiff.py +0 -260
- edsl/agents/InvigilatorBase.py +0 -260
- edsl/agents/PromptConstructor.py +0 -318
- edsl/coop/PriceFetcher.py +0 -54
- edsl/data/Cache.py +0 -582
- edsl/data/CacheEntry.py +0 -238
- edsl/data/SQLiteDict.py +0 -292
- edsl/data/__init__.py +0 -5
- edsl/data/orm.py +0 -10
- edsl/exceptions/cache.py +0 -5
- edsl/exceptions/coop.py +0 -14
- edsl/exceptions/data.py +0 -14
- edsl/exceptions/scenarios.py +0 -29
- edsl/jobs/Answers.py +0 -43
- edsl/jobs/JobsPrompts.py +0 -354
- edsl/jobs/buckets/BucketCollection.py +0 -134
- edsl/jobs/buckets/ModelBuckets.py +0 -65
- edsl/jobs/buckets/TokenBucket.py +0 -283
- edsl/jobs/buckets/TokenBucketClient.py +0 -191
- edsl/jobs/interviews/Interview.py +0 -395
- edsl/jobs/interviews/InterviewExceptionCollection.py +0 -99
- edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -25
- edsl/jobs/runners/JobsRunnerAsyncio.py +0 -163
- edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
- edsl/jobs/tasks/TaskCreators.py +0 -64
- edsl/jobs/tasks/TaskStatusLog.py +0 -23
- edsl/jobs/tokens/InterviewTokenUsage.py +0 -27
- edsl/language_models/LanguageModel.py +0 -635
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/key_management/KeyLookup.py +0 -63
- edsl/language_models/key_management/KeyLookupCollection.py +0 -38
- edsl/language_models/key_management/models.py +0 -137
- edsl/questions/QuestionBase.py +0 -544
- edsl/questions/QuestionFreeText.py +0 -130
- edsl/questions/derived/QuestionLikertFive.py +0 -76
- edsl/results/ResultsExportMixin.py +0 -45
- edsl/results/TextEditor.py +0 -50
- edsl/results/results_fetch_mixin.py +0 -33
- edsl/results/results_tools_mixin.py +0 -98
- edsl/scenarios/DocumentChunker.py +0 -104
- edsl/scenarios/Scenario.py +0 -548
- edsl/scenarios/ScenarioHtmlMixin.py +0 -65
- edsl/scenarios/ScenarioListExportMixin.py +0 -45
- edsl/scenarios/handlers/latex.py +0 -5
- edsl/shared.py +0 -1
- edsl/surveys/Survey.py +0 -1301
- edsl/surveys/SurveyQualtricsImport.py +0 -284
- edsl/surveys/SurveyToApp.py +0 -141
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/tools/__init__.py +0 -1
- edsl/tools/clusters.py +0 -192
- edsl/tools/embeddings.py +0 -27
- edsl/tools/embeddings_plotting.py +0 -118
- edsl/tools/plotting.py +0 -112
- edsl/tools/summarize.py +0 -18
- edsl/utilities/data/Registry.py +0 -6
- edsl/utilities/data/__init__.py +0 -1
- edsl/utilities/data/scooter_results.json +0 -1
- edsl-0.1.47.dist-info/RECORD +0 -354
- /edsl/coop/{CoopFunctionsMixin.py → coop_functions.py} +0 -0
- /edsl/{results → dataset/display}/CSSParameterizer.py +0 -0
- /edsl/{language_models/key_management → dataset/display}/__init__.py +0 -0
- /edsl/{results → dataset/display}/table_data_class.py +0 -0
- /edsl/{results → dataset/display}/table_display.css +0 -0
- /edsl/{results/ResultsGGMixin.py → dataset/r/ggplot.py} +0 -0
- /edsl/{results → dataset}/tree_explore.py +0 -0
- /edsl/{surveys/instructions/ChangeInstruction.py → instructions/change_instruction.py} +0 -0
- /edsl/{jobs/interviews → interviews}/interview_status_enum.py +0 -0
- /edsl/jobs/{runners/JobsRunnerStatus.py → jobs_runner_status.py} +0 -0
- /edsl/language_models/{PriceManager.py → price_manager.py} +0 -0
- /edsl/language_models/{fake_openai_call.py → unused/fake_openai_call.py} +0 -0
- /edsl/language_models/{fake_openai_service.py → unused/fake_openai_service.py} +0 -0
- /edsl/notebooks/{NotebookToLaTeX.py → notebook_to_latex.py} +0 -0
- /edsl/{exceptions/questions.py → questions/exceptions.py} +0 -0
- /edsl/questions/{SimpleAskMixin.py → simple_ask_mixin.py} +0 -0
- /edsl/surveys/{Memory.py → memory/memory.py} +0 -0
- /edsl/surveys/{MemoryManagement.py → memory/memory_management.py} +0 -0
- /edsl/surveys/{SurveyCSS.py → survey_css.py} +0 -0
- /edsl/{jobs/tokens/TokenUsage.py → tokens/token_usage.py} +0 -0
- /edsl/{results/MarkdownToDocx.py → utilities/markdown_to_docx.py} +0 -0
- /edsl/{TemplateLoader.py → utilities/template_loader.py} +0 -0
- {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/LICENSE +0 -0
- {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/WHEEL +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
"""A
|
1
|
+
"""A class for exporting surveys to different formats."""
|
2
2
|
|
3
3
|
from typing import Union, Optional
|
4
4
|
|
@@ -24,11 +24,15 @@ def open_docx(file_path):
|
|
24
24
|
subprocess.call(("xdg-open", file_path))
|
25
25
|
|
26
26
|
|
27
|
-
class
|
28
|
-
"""A
|
27
|
+
class SurveyExport:
|
28
|
+
"""A class for exporting surveys to different formats."""
|
29
|
+
|
30
|
+
def __init__(self, survey):
|
31
|
+
"""Initialize with a Survey object."""
|
32
|
+
self.survey = survey
|
29
33
|
|
30
34
|
def css(self):
|
31
|
-
from
|
35
|
+
from .survey_css import SurveyCSS
|
32
36
|
|
33
37
|
return SurveyCSS.default_style().generate_css()
|
34
38
|
|
@@ -36,7 +40,7 @@ class SurveyExportMixin:
|
|
36
40
|
"""Return the description of the survey."""
|
37
41
|
from edsl import QuestionFreeText
|
38
42
|
|
39
|
-
question_texts = "\n".join([q.question_text for q in self._questions])
|
43
|
+
question_texts = "\n".join([q.question_text for q in self.survey._questions])
|
40
44
|
q = QuestionFreeText(
|
41
45
|
question_name="description",
|
42
46
|
question_text=f"""A survey was conducted with the following questions:
|
@@ -58,7 +62,7 @@ class SurveyExportMixin:
|
|
58
62
|
doc = Document()
|
59
63
|
doc.add_heading("EDSL Survey")
|
60
64
|
doc.add_paragraph(f"\n")
|
61
|
-
for index, question in enumerate(self._questions):
|
65
|
+
for index, question in enumerate(self.survey._questions):
|
62
66
|
h = doc.add_paragraph() # Add question as a paragraph
|
63
67
|
h.add_run(f"Question {index + 1} ({question.question_name})").bold = True
|
64
68
|
h.add_run(f"; {question.question_type}").italic = True
|
@@ -72,20 +76,13 @@ class SurveyExportMixin:
|
|
72
76
|
for option in getattr(question, "question_options", []):
|
73
77
|
doc.add_paragraph(str(option), style="ListBullet")
|
74
78
|
|
75
|
-
if return_document_object
|
79
|
+
if return_document_object:
|
76
80
|
return doc
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
"
|
81
|
-
|
82
|
-
filename = f.name
|
83
|
-
|
84
|
-
doc.save(filename)
|
85
|
-
print("The survey has been saved to", filename)
|
86
|
-
if open_file:
|
87
|
-
open_docx(filename)
|
88
|
-
return
|
81
|
+
else:
|
82
|
+
doc.save(filename)
|
83
|
+
if open_file:
|
84
|
+
os.system(f"open {filename}")
|
85
|
+
return None
|
89
86
|
|
90
87
|
def show(self):
|
91
88
|
self.to_scenario_list(questions_only=False, rename=True).print(format="rich")
|
@@ -93,14 +90,12 @@ class SurveyExportMixin:
|
|
93
90
|
def to_scenario_list(
|
94
91
|
self, questions_only: bool = True, rename=False
|
95
92
|
) -> "ScenarioList":
|
96
|
-
from
|
97
|
-
|
98
|
-
# from edsl.questions import QuestionBase
|
93
|
+
from ..scenarios import ScenarioList, Scenario
|
99
94
|
|
100
95
|
if questions_only:
|
101
|
-
to_iterate_over = self._questions
|
96
|
+
to_iterate_over = self.survey._questions
|
102
97
|
else:
|
103
|
-
to_iterate_over = self.recombined_questions_and_instructions()
|
98
|
+
to_iterate_over = self.survey.recombined_questions_and_instructions()
|
104
99
|
|
105
100
|
if rename:
|
106
101
|
renaming_dict = {
|
@@ -150,13 +145,13 @@ class SurveyExportMixin:
|
|
150
145
|
header_lines = ["from edsl.surveys.Survey import Survey"]
|
151
146
|
header_lines.append("from edsl import Question")
|
152
147
|
lines = ["\n".join(header_lines)]
|
153
|
-
for question in self._questions:
|
148
|
+
for question in self.survey._questions:
|
154
149
|
question.question_text = question["question_text"].replace("\n", " ")
|
155
150
|
# remove dublicate spaces
|
156
151
|
question.question_text = " ".join(question.question_text.split())
|
157
152
|
lines.append(f"{question.question_name} = " + repr(question))
|
158
153
|
lines.append(
|
159
|
-
f"{survey_var_name} = Survey(questions = [{', '.join(self.question_names)}])"
|
154
|
+
f"{survey_var_name} = Survey(questions = [{', '.join(self.survey.question_names)}])"
|
160
155
|
)
|
161
156
|
# return lines
|
162
157
|
code_string = "\n".join(lines)
|
@@ -216,7 +211,7 @@ class SurveyExportMixin:
|
|
216
211
|
|
217
212
|
with open(filename, "w") as f:
|
218
213
|
f.write(html_header)
|
219
|
-
for question in self._questions:
|
214
|
+
for question in self.survey._questions:
|
220
215
|
f.write(
|
221
216
|
question.html(
|
222
217
|
scenario=scenario, include_question_name=include_question_name
|
@@ -47,7 +47,12 @@ class SurveyFlowVisualization:
|
|
47
47
|
for param in question.detailed_parameters:
|
48
48
|
if "agent." in param:
|
49
49
|
# Handle agent trait references
|
50
|
-
trait_name = param.replace("agent.", "")
|
50
|
+
#trait_name = param.replace("agent.", "")
|
51
|
+
params_and_refs.add(param)
|
52
|
+
if param not in param_to_questions:
|
53
|
+
param_to_questions[param] = []
|
54
|
+
param_to_questions[param].append(index)
|
55
|
+
if "scenario." in param:
|
51
56
|
params_and_refs.add(param)
|
52
57
|
if param not in param_to_questions:
|
53
58
|
param_to_questions[param] = []
|
@@ -108,7 +113,7 @@ class SurveyFlowVisualization:
|
|
108
113
|
"label": f"Agent Trait\n{{{{ {param} }}}}"
|
109
114
|
})
|
110
115
|
# Check if parameter exists in scenario
|
111
|
-
elif self.scenario and param
|
116
|
+
elif self.scenario and param.startswith("scenario."):
|
112
117
|
node_attrs.update({
|
113
118
|
"fillcolor": "lightgreen",
|
114
119
|
"label": f"Scenario\n{{{{ {param} }}}}"
|
@@ -207,6 +212,10 @@ class SurveyFlowVisualization:
|
|
207
212
|
"""File not found. Most likely it's because you don't have graphviz installed. Please install it and try again.
|
208
213
|
On Ubuntu, you can install it by running:
|
209
214
|
$ sudo apt-get install graphviz
|
215
|
+
On Mac, you can install it by running:
|
216
|
+
$ brew install graphviz
|
217
|
+
On Windows, you can install it by running:
|
218
|
+
$ choco install graphviz
|
210
219
|
"""
|
211
220
|
)
|
212
221
|
from edsl.utilities.is_notebook import is_notebook
|
@@ -1,8 +1,15 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
1
2
|
from typing import Callable
|
3
|
+
from edsl.agents import Agent
|
4
|
+
#from edsl.surveys import Survey
|
2
5
|
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from edsl.surveys import Survey
|
8
|
+
from edsl.results import Results
|
9
|
+
from edsl.questions import QuestionBase
|
3
10
|
|
4
11
|
class Simulator:
|
5
|
-
def __init__(self, survey):
|
12
|
+
def __init__(self, survey: "Survey"):
|
6
13
|
self.survey = survey
|
7
14
|
|
8
15
|
@classmethod
|
@@ -10,7 +17,7 @@ class Simulator:
|
|
10
17
|
"""Create a random survey."""
|
11
18
|
from edsl.questions import QuestionMultipleChoice, QuestionFreeText
|
12
19
|
from random import choice
|
13
|
-
from edsl.surveys
|
20
|
+
from edsl.surveys import Survey
|
14
21
|
|
15
22
|
num_questions = 10
|
16
23
|
questions = []
|
@@ -57,7 +64,7 @@ class Simulator:
|
|
57
64
|
def create_agent(self) -> "Agent":
|
58
65
|
"""Create an agent from the simulated answers."""
|
59
66
|
answers_dict = self.survey.simulate()
|
60
|
-
from edsl.agents
|
67
|
+
from edsl.agents import Agent
|
61
68
|
|
62
69
|
def construct_answer_dict_function(traits: dict) -> Callable:
|
63
70
|
def func(self, question: "QuestionBase", scenario=None):
|
edsl/tasks/__init__.py
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
"""
|
2
|
+
The tasks module provides EDSL's task management system for tracking and controlling
|
3
|
+
interview execution.
|
4
|
+
|
5
|
+
This module implements a comprehensive system for creating, scheduling, executing, and
|
6
|
+
monitoring tasks in EDSL. Tasks represent individual units of work, typically answering
|
7
|
+
a question with an LLM, with features for dependency management, error handling, and
|
8
|
+
execution status tracking.
|
9
|
+
|
10
|
+
Key components:
|
11
|
+
|
12
|
+
1. TaskHistory - Records and analyzes the execution history of tasks with error reporting
|
13
|
+
2. QuestionTaskCreator - Creates and manages tasks for individual questions
|
14
|
+
3. TaskCreators - Manages collections of tasks for an entire interview
|
15
|
+
4. TaskStatus - Enumeration of possible task states (running, waiting, success, etc.)
|
16
|
+
5. TaskStatusLog - Records the status changes of tasks over time
|
17
|
+
|
18
|
+
The tasks system helps EDSL manage complex interview workflows by:
|
19
|
+
- Handling dependencies between questions
|
20
|
+
- Managing API rate limits and token usage
|
21
|
+
- Providing detailed execution metrics
|
22
|
+
- Generating error reports and visualizations
|
23
|
+
- Supporting both synchronous and asynchronous execution
|
24
|
+
|
25
|
+
For most users, this module works behind the scenes, but understanding it can
|
26
|
+
be helpful when debugging or optimizing complex EDSL workflows.
|
27
|
+
"""
|
28
|
+
|
29
|
+
from .task_history import TaskHistory
|
30
|
+
from .question_task_creator import QuestionTaskCreator
|
31
|
+
from .task_creators import TaskCreators
|
32
|
+
from .task_status_enum import TaskStatus, TaskStatusDescriptor
|
@@ -1,34 +1,77 @@
|
|
1
|
+
"""
|
2
|
+
This module provides the QuestionTaskCreator class for executing individual questions as tasks.
|
3
|
+
|
4
|
+
The QuestionTaskCreator is responsible for executing a single question within the EDSL system.
|
5
|
+
It manages the entire lifecycle of a question task, including dependency resolution, rate
|
6
|
+
limiting, token management, execution, and status tracking. It serves as the fundamental
|
7
|
+
execution unit in EDSL's task system.
|
8
|
+
"""
|
9
|
+
|
1
10
|
import asyncio
|
2
|
-
from typing import Callable, Union, List, TYPE_CHECKING
|
11
|
+
from typing import Callable, Union, List, Dict, Any, Optional, TYPE_CHECKING
|
3
12
|
from collections import UserList, UserDict
|
4
13
|
|
5
|
-
from
|
14
|
+
from ..jobs.exceptions import InterviewErrorPriorTaskCanceled
|
15
|
+
from ..tokens import TokenUsage
|
16
|
+
from ..data_transfer_models import Answers
|
6
17
|
|
7
|
-
from
|
8
|
-
from
|
9
|
-
from edsl.jobs.tokens.TokenUsage import TokenUsage
|
10
|
-
from edsl.jobs.Answers import Answers
|
18
|
+
from .task_status_enum import TaskStatus, TaskStatusDescriptor
|
19
|
+
from .task_status_log import TaskStatusLog
|
11
20
|
|
12
21
|
if TYPE_CHECKING:
|
13
|
-
from
|
14
|
-
from
|
22
|
+
from ..questions import QuestionBase
|
23
|
+
from ..buckets import ModelBuckets
|
15
24
|
|
16
25
|
|
17
26
|
class TokensUsed(UserDict):
|
18
|
-
"""
|
27
|
+
"""
|
28
|
+
Container for tracking token usage for a task, separating cached and new tokens.
|
29
|
+
|
30
|
+
This class provides a structured way to track token usage for a single task,
|
31
|
+
distinguishing between tokens reused from cache and tokens freshly generated.
|
32
|
+
It uses a UserDict interface for convenient access to the underlying data.
|
33
|
+
|
34
|
+
Attributes:
|
35
|
+
cached_tokens: TokenUsage object tracking reused tokens from cache
|
36
|
+
new_tokens: TokenUsage object tracking freshly generated tokens
|
37
|
+
"""
|
19
38
|
|
20
|
-
def __init__(self, cached_tokens, new_tokens):
|
39
|
+
def __init__(self, cached_tokens: TokenUsage, new_tokens: TokenUsage):
|
40
|
+
"""
|
41
|
+
Initialize a TokensUsed container.
|
42
|
+
|
43
|
+
Parameters:
|
44
|
+
cached_tokens: TokenUsage object for tokens reused from cache
|
45
|
+
new_tokens: TokenUsage object for newly generated tokens
|
46
|
+
"""
|
21
47
|
d = {"cached_tokens": cached_tokens, "new_tokens": new_tokens}
|
22
48
|
super().__init__(d)
|
23
49
|
|
24
50
|
|
25
51
|
class QuestionTaskCreator(UserList):
|
26
|
-
"""Class to create and manage a single question and its dependencies.
|
27
|
-
|
28
|
-
It is a UserList with all the tasks that must be completed before the focal task can be run.
|
29
|
-
The focal task is the question that we are interested in answering.
|
30
52
|
"""
|
31
|
-
|
53
|
+
Creates and manages the execution of a single question as an asyncio task.
|
54
|
+
|
55
|
+
The QuestionTaskCreator is a fundamental component of EDSL's task system,
|
56
|
+
responsible for executing a single question with its dependencies. It extends
|
57
|
+
UserList to maintain a list of dependent tasks that must complete before this
|
58
|
+
task can execute.
|
59
|
+
|
60
|
+
Key responsibilities:
|
61
|
+
1. Task Dependency Management - Tracks prerequisite tasks that must complete first
|
62
|
+
2. Resource Management - Handles rate limiting and token quota management
|
63
|
+
3. Task Status Tracking - Monitors and logs task state transitions
|
64
|
+
4. Token Usage Tracking - Records token consumption for both cached and new tokens
|
65
|
+
5. Task Execution - Runs the question answering function when dependencies are met
|
66
|
+
|
67
|
+
The class follows the state machine pattern, with task_status transitioning through
|
68
|
+
various TaskStatus states (NOT_STARTED, WAITING_FOR_DEPENDENCIES, etc.) as execution
|
69
|
+
progresses. All status changes are automatically logged to enable detailed analysis
|
70
|
+
and visualization.
|
71
|
+
|
72
|
+
This class is designed to work with asyncio for concurrent task execution, enabling
|
73
|
+
efficient processing of interviews with multiple questions and dependencies.
|
74
|
+
"""
|
32
75
|
task_status = TaskStatusDescriptor()
|
33
76
|
|
34
77
|
def __init__(
|
@@ -37,17 +80,24 @@ class QuestionTaskCreator(UserList):
|
|
37
80
|
question: "QuestionBase",
|
38
81
|
answer_question_func: Callable,
|
39
82
|
model_buckets: "ModelBuckets",
|
40
|
-
token_estimator:
|
83
|
+
token_estimator: Optional[Callable] = None,
|
41
84
|
iteration: int = 0,
|
42
85
|
):
|
43
|
-
"""
|
44
|
-
|
45
|
-
|
46
|
-
:
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
86
|
+
"""
|
87
|
+
Initialize a QuestionTaskCreator for a specific question.
|
88
|
+
|
89
|
+
Parameters:
|
90
|
+
question: The Question object to be answered
|
91
|
+
answer_question_func: Function that will execute the LLM call to answer the question
|
92
|
+
model_buckets: Container for rate limiting buckets (requests and tokens)
|
93
|
+
token_estimator: Function to estimate token usage for the question (for quota management)
|
94
|
+
iteration: The iteration number of this question (for repeated questions)
|
95
|
+
|
96
|
+
Notes:
|
97
|
+
- The QuestionTaskCreator starts in the NOT_STARTED state
|
98
|
+
- Dependencies can be added after initialization with add_dependency()
|
99
|
+
- Token usage is tracked separately for cached vs. new tokens
|
100
|
+
- This class works with asyncio for concurrent execution
|
51
101
|
"""
|
52
102
|
super().__init__([])
|
53
103
|
self.answer_question_func = answer_question_func
|
@@ -159,8 +209,8 @@ class QuestionTaskCreator(UserList):
|
|
159
209
|
@classmethod
|
160
210
|
def example(cls):
|
161
211
|
"""Return an example instance of the class."""
|
162
|
-
from
|
163
|
-
from
|
212
|
+
from ..questions import QuestionFreeText
|
213
|
+
from ..buckets import ModelBuckets
|
164
214
|
|
165
215
|
m = ModelBuckets.infinity_bucket()
|
166
216
|
|
@@ -180,37 +230,45 @@ class QuestionTaskCreator(UserList):
|
|
180
230
|
iteration=0,
|
181
231
|
)
|
182
232
|
|
183
|
-
async def _run_task_async(self) ->
|
184
|
-
"""
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
If any
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
233
|
+
async def _run_task_async(self) -> Answers:
|
234
|
+
"""
|
235
|
+
Execute the task with its dependencies in an async workflow.
|
236
|
+
|
237
|
+
This method implements the core task execution logic with dependency handling.
|
238
|
+
It manages the complete lifecycle of a task:
|
239
|
+
|
240
|
+
1. Waiting for dependencies to complete
|
241
|
+
2. Handling dependency failures appropriately
|
242
|
+
3. Executing the task itself when dependencies are satisfied
|
243
|
+
4. Tracking status transitions throughout execution
|
244
|
+
|
245
|
+
The method maintains the state machine pattern by updating task_status
|
246
|
+
at each stage of execution, allowing for detailed monitoring and visualization
|
247
|
+
of task progress.
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
Answers object containing the question's answer and metadata
|
251
|
+
|
252
|
+
Raises:
|
253
|
+
asyncio.CancelledError: If the task is cancelled
|
254
|
+
InterviewErrorPriorTaskCanceled: If any dependency task fails
|
255
|
+
|
256
|
+
Example:
|
257
|
+
>>> qt1 = QuestionTaskCreator.example()
|
258
|
+
>>> qt2 = QuestionTaskCreator.example()
|
259
|
+
>>> qt2.add_dependency(qt1)
|
260
|
+
|
261
|
+
Implementation details:
|
262
|
+
|
263
|
+
1. Set status to WAITING_FOR_DEPENDENCIES and await all dependencies
|
264
|
+
- Using gather with return_exceptions=True allows collecting all results
|
265
|
+
|
266
|
+
2. Check dependency results for exceptions:
|
267
|
+
- If CancelledError: Set status to CANCELLED and propagate the cancellation
|
268
|
+
- If other exception: Set status to PARENT_FAILED and wrap in InterviewErrorPriorTaskCanceled
|
269
|
+
|
270
|
+
3. If all dependencies succeed, execute the focal task (_run_focal_task)
|
271
|
+
- The focal task handles its own status transitions during execution
|
214
272
|
"""
|
215
273
|
try:
|
216
274
|
self.task_status = TaskStatus.WAITING_FOR_DEPENDENCIES
|
@@ -0,0 +1,135 @@
|
|
1
|
+
"""
|
2
|
+
This module provides the TaskCreators class, which manages all task creators for an interview.
|
3
|
+
|
4
|
+
The TaskCreators class maintains a dictionary of QuestionTaskCreator objects, each responsible
|
5
|
+
for executing a single question within an interview. It aggregates status and token usage
|
6
|
+
information across all tasks, providing a complete view of interview execution.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Callable, Union, List, Dict, TYPE_CHECKING
|
10
|
+
from collections import UserDict
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from ..tokens import TokenUsage
|
14
|
+
from ..tokens import InterviewTokenUsage
|
15
|
+
from ..interviews import InterviewStatusDictionary
|
16
|
+
from .task_status_log import TaskStatusLog
|
17
|
+
from .question_task_creator import QuestionTaskCreator
|
18
|
+
|
19
|
+
class TaskCreators(UserDict):
|
20
|
+
"""
|
21
|
+
A collection manager for all question tasks within an interview.
|
22
|
+
|
23
|
+
The TaskCreators class maintains a dictionary of QuestionTaskCreator objects,
|
24
|
+
where each key is a question name and each value is the corresponding task creator.
|
25
|
+
This class provides methods to aggregate information across all tasks, such as
|
26
|
+
token usage and status counts, enabling a holistic view of interview execution.
|
27
|
+
|
28
|
+
In the EDSL architecture, an interview consists of multiple questions, each executed
|
29
|
+
as a separate task. The TaskCreators class helps track and manage these tasks,
|
30
|
+
maintaining their execution status and resource usage.
|
31
|
+
|
32
|
+
Key features:
|
33
|
+
- Maintains a mapping of question names to their task creators
|
34
|
+
- Aggregates token usage across all tasks
|
35
|
+
- Tracks the status of all tasks in the interview
|
36
|
+
- Provides access to status logs for visualization and analysis
|
37
|
+
|
38
|
+
This class is typically used by the Interview class to manage task execution
|
39
|
+
and track the overall status of the interview.
|
40
|
+
"""
|
41
|
+
|
42
|
+
def __init__(self, *args, **kwargs):
|
43
|
+
super().__init__(*args, **kwargs)
|
44
|
+
|
45
|
+
@property
|
46
|
+
def token_usage(self) -> 'InterviewTokenUsage':
|
47
|
+
"""
|
48
|
+
Calculate the total token usage across all tasks in the interview.
|
49
|
+
|
50
|
+
This property aggregates token usage statistics from all task creators,
|
51
|
+
separating cached tokens (reused from cache) from new tokens (freshly generated).
|
52
|
+
The resulting InterviewTokenUsage object provides a complete picture of token
|
53
|
+
consumption for the entire interview.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
An InterviewTokenUsage object containing:
|
57
|
+
- Cached token usage (tokens reused from cache)
|
58
|
+
- New token usage (tokens freshly generated)
|
59
|
+
|
60
|
+
Notes:
|
61
|
+
- This is useful for cost estimation and quota management
|
62
|
+
- The separation of cached vs. new tokens helps analyze caching effectiveness
|
63
|
+
- Token usage is tracked separately for prompts and completions
|
64
|
+
"""
|
65
|
+
from ..tokens import TokenUsage
|
66
|
+
from ..tokens import InterviewTokenUsage
|
67
|
+
|
68
|
+
cached_tokens = TokenUsage(from_cache=True)
|
69
|
+
new_tokens = TokenUsage(from_cache=False)
|
70
|
+
for task_creator in self.values():
|
71
|
+
token_usage = task_creator.token_usage()
|
72
|
+
cached_tokens += token_usage["cached_tokens"]
|
73
|
+
new_tokens += token_usage["new_tokens"]
|
74
|
+
return InterviewTokenUsage(
|
75
|
+
new_token_usage=new_tokens, cached_token_usage=cached_tokens
|
76
|
+
)
|
77
|
+
|
78
|
+
@property
|
79
|
+
def interview_status(self) -> 'InterviewStatusDictionary':
|
80
|
+
"""
|
81
|
+
Get a summary of task statuses across the entire interview.
|
82
|
+
|
83
|
+
This property counts how many tasks are in each possible status state,
|
84
|
+
providing a snapshot of the interview's current execution state. The
|
85
|
+
resulting InterviewStatusDictionary maps each TaskStatus to a count
|
86
|
+
of tasks in that state, plus a special 'number_from_cache' counter.
|
87
|
+
|
88
|
+
Returns:
|
89
|
+
An InterviewStatusDictionary with counts for each task status
|
90
|
+
|
91
|
+
Notes:
|
92
|
+
- Used for monitoring interview progress
|
93
|
+
- Helps identify bottlenecks (many tasks waiting for capacity)
|
94
|
+
- Tracks cache utilization via the 'number_from_cache' count
|
95
|
+
- Useful for status dashboards and progress reporting
|
96
|
+
|
97
|
+
Example:
|
98
|
+
>>> t = TaskCreators()
|
99
|
+
>>> status = t.interview_status
|
100
|
+
>>> 'number_from_cache' in status
|
101
|
+
True
|
102
|
+
>>> status['number_from_cache'] # Check the cache count
|
103
|
+
0
|
104
|
+
"""
|
105
|
+
from ..interviews import InterviewStatusDictionary
|
106
|
+
status_dict = InterviewStatusDictionary()
|
107
|
+
for task_creator in self.values():
|
108
|
+
status_dict[task_creator.task_status] += 1
|
109
|
+
status_dict["number_from_cache"] += task_creator.from_cache
|
110
|
+
return status_dict
|
111
|
+
|
112
|
+
def status_logs(self) -> List['TaskStatusLog']:
|
113
|
+
"""
|
114
|
+
Get all task status logs for the interview.
|
115
|
+
|
116
|
+
This method collects the status logs from all task creators, providing
|
117
|
+
a complete history of status changes for every task in the interview.
|
118
|
+
The resulting list can be used for detailed analysis of task execution
|
119
|
+
patterns, timing, and visualization.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
A list of TaskStatusLog objects, one for each task in the interview
|
123
|
+
|
124
|
+
Notes:
|
125
|
+
- Used by visualization tools like task timeline charts
|
126
|
+
- Helpful for performance analysis and bottleneck identification
|
127
|
+
- Provides data for execution reports and dashboards
|
128
|
+
"""
|
129
|
+
return [task_creator.status_log for task_creator in self.values()]
|
130
|
+
|
131
|
+
|
132
|
+
if __name__ == "__main__":
|
133
|
+
import doctest
|
134
|
+
|
135
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|