edsl 0.1.14__py3-none-any.whl → 0.1.40__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 +348 -38
- edsl/BaseDiff.py +260 -0
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +46 -10
- edsl/__version__.py +1 -0
- edsl/agents/Agent.py +842 -144
- edsl/agents/AgentList.py +521 -25
- edsl/agents/Invigilator.py +250 -374
- edsl/agents/InvigilatorBase.py +257 -0
- edsl/agents/PromptConstructor.py +272 -0
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/descriptors.py +43 -13
- edsl/agents/prompt_helpers.py +129 -0
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -0
- edsl/auto/StageBase.py +243 -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 +74 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +218 -0
- edsl/base/Base.py +279 -0
- edsl/config.py +121 -104
- edsl/conversation/Conversation.py +290 -0
- edsl/conversation/car_buying.py +59 -0
- edsl/conversation/chips.py +95 -0
- edsl/conversation/mug_negotiation.py +81 -0
- edsl/conversation/next_speaker_utilities.py +93 -0
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -0
- edsl/coop/__init__.py +1 -0
- edsl/coop/coop.py +1029 -134
- edsl/coop/utils.py +131 -0
- edsl/data/Cache.py +560 -89
- edsl/data/CacheEntry.py +230 -0
- edsl/data/CacheHandler.py +168 -0
- edsl/data/RemoteCacheSync.py +186 -0
- edsl/data/SQLiteDict.py +292 -0
- edsl/data/__init__.py +5 -3
- edsl/data/orm.py +6 -33
- edsl/data_transfer_models.py +74 -27
- edsl/enums.py +165 -8
- edsl/exceptions/BaseException.py +21 -0
- edsl/exceptions/__init__.py +52 -46
- edsl/exceptions/agents.py +33 -15
- edsl/exceptions/cache.py +5 -0
- edsl/exceptions/coop.py +8 -0
- edsl/exceptions/general.py +34 -0
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +15 -0
- edsl/exceptions/language_models.py +46 -1
- edsl/exceptions/questions.py +80 -5
- edsl/exceptions/results.py +16 -5
- edsl/exceptions/scenarios.py +29 -0
- edsl/exceptions/surveys.py +13 -10
- edsl/inference_services/AnthropicService.py +106 -0
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -0
- edsl/inference_services/AzureAI.py +215 -0
- edsl/inference_services/DeepInfraService.py +18 -0
- edsl/inference_services/GoogleService.py +143 -0
- edsl/inference_services/GroqService.py +20 -0
- edsl/inference_services/InferenceServiceABC.py +80 -0
- edsl/inference_services/InferenceServicesCollection.py +138 -0
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +236 -0
- edsl/inference_services/PerplexityService.py +160 -0
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -0
- edsl/inference_services/TogetherAIService.py +172 -0
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -0
- edsl/inference_services/rate_limits_cache.py +25 -0
- edsl/inference_services/registry.py +41 -0
- edsl/inference_services/write_available.py +10 -0
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +21 -20
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +684 -204
- edsl/jobs/JobsChecks.py +172 -0
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -0
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -0
- edsl/jobs/buckets/ModelBuckets.py +65 -0
- edsl/jobs/buckets/TokenBucket.py +283 -0
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +392 -0
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
- edsl/jobs/interviews/InterviewStatistic.py +63 -0
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
- edsl/jobs/interviews/InterviewStatusLog.py +92 -0
- edsl/jobs/interviews/ReportErrors.py +66 -0
- edsl/jobs/interviews/interview_status_enum.py +9 -0
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -110
- edsl/jobs/runners/JobsRunnerStatus.py +298 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
- edsl/jobs/tasks/TaskCreators.py +64 -0
- edsl/jobs/tasks/TaskHistory.py +470 -0
- edsl/jobs/tasks/TaskStatusLog.py +23 -0
- edsl/jobs/tasks/task_status_enum.py +161 -0
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
- edsl/jobs/tokens/TokenUsage.py +34 -0
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +507 -386
- edsl/language_models/ModelList.py +164 -0
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
- edsl/language_models/__init__.py +1 -8
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +109 -41
- edsl/language_models/utilities.py +65 -0
- edsl/notebooks/Notebook.py +263 -0
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -0
- edsl/prompts/Prompt.py +222 -93
- edsl/prompts/__init__.py +1 -1
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -0
- edsl/questions/QuestionBasePromptsMixin.py +221 -0
- edsl/questions/QuestionBudget.py +164 -67
- edsl/questions/QuestionCheckBox.py +281 -62
- edsl/questions/QuestionDict.py +343 -0
- edsl/questions/QuestionExtract.py +136 -50
- edsl/questions/QuestionFreeText.py +79 -55
- edsl/questions/QuestionFunctional.py +138 -41
- edsl/questions/QuestionList.py +184 -57
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +293 -69
- edsl/questions/QuestionNumerical.py +109 -56
- edsl/questions/QuestionRank.py +244 -49
- edsl/questions/Quick.py +41 -0
- edsl/questions/SimpleAskMixin.py +74 -0
- edsl/questions/__init__.py +9 -6
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
- edsl/questions/compose_questions.py +13 -7
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +28 -26
- edsl/questions/derived/QuestionLinearScale.py +41 -28
- edsl/questions/derived/QuestionTopK.py +34 -26
- edsl/questions/derived/QuestionYesNo.py +40 -27
- edsl/questions/descriptors.py +228 -74
- edsl/questions/loop_processor.py +149 -0
- 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_base_gen_mixin.py +168 -0
- edsl/questions/question_registry.py +130 -46
- edsl/questions/register_questions_meta.py +71 -0
- edsl/questions/response_validator_abc.py +188 -0
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +5 -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/dict/__init__.py +0 -0
- edsl/questions/templates/dict/answering_instructions.jinja +21 -0
- edsl/questions/templates/dict/question_presentation.jinja +1 -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/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/__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 +7 -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/CSSParameterizer.py +108 -0
- edsl/results/Dataset.py +550 -19
- edsl/results/DatasetExportMixin.py +594 -0
- edsl/results/DatasetTree.py +295 -0
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +477 -173
- edsl/results/Results.py +987 -269
- edsl/results/ResultsExportMixin.py +28 -125
- edsl/results/ResultsGGMixin.py +83 -15
- edsl/results/TableDisplay.py +125 -0
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +1 -1
- edsl/results/file_exports.py +252 -0
- edsl/results/results_fetch_mixin.py +33 -0
- edsl/results/results_selector.py +145 -0
- edsl/results/results_tools_mixin.py +98 -0
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +78 -0
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +543 -0
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +431 -62
- edsl/scenarios/ScenarioHtmlMixin.py +65 -0
- edsl/scenarios/ScenarioList.py +1415 -45
- edsl/scenarios/ScenarioListExportMixin.py +45 -0
- edsl/scenarios/ScenarioListPdfMixin.py +239 -0
- edsl/scenarios/__init__.py +2 -0
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +49 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/scenario_join.py +131 -0
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -0
- edsl/study/ObjectEntry.py +173 -0
- edsl/study/ProofOfWork.py +113 -0
- edsl/study/SnapShot.py +80 -0
- edsl/study/Study.py +521 -0
- edsl/study/__init__.py +4 -0
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +92 -11
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +9 -4
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +156 -35
- edsl/surveys/Rule.py +221 -74
- edsl/surveys/RuleCollection.py +241 -61
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1079 -339
- edsl/surveys/SurveyCSS.py +273 -0
- edsl/surveys/SurveyExportMixin.py +235 -40
- edsl/surveys/SurveyFlowVisualization.py +181 -0
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +4 -2
- edsl/surveys/base.py +19 -3
- edsl/surveys/descriptors.py +17 -6
- edsl/surveys/instructions/ChangeInstruction.py +48 -0
- edsl/surveys/instructions/Instruction.py +56 -0
- edsl/surveys/instructions/InstructionCollection.py +82 -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 +19 -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/tools/__init__.py +1 -0
- edsl/tools/clusters.py +192 -0
- edsl/tools/embeddings.py +27 -0
- edsl/tools/embeddings_plotting.py +118 -0
- edsl/tools/plotting.py +112 -0
- edsl/tools/summarize.py +18 -0
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +5 -0
- edsl/utilities/__init__.py +21 -20
- edsl/utilities/ast_utilities.py +3 -0
- edsl/utilities/data/Registry.py +2 -0
- edsl/utilities/decorators.py +41 -0
- edsl/utilities/gcp_bucket/__init__.py +0 -0
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
- edsl/utilities/interface.py +310 -60
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -0
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -0
- edsl/utilities/restricted_python.py +70 -0
- edsl/utilities/utilities.py +203 -13
- edsl-0.1.40.dist-info/METADATA +111 -0
- edsl-0.1.40.dist-info/RECORD +362 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
- edsl/agents/AgentListExportMixin.py +0 -24
- edsl/coop/old.py +0 -31
- edsl/data/Database.py +0 -141
- edsl/data/crud.py +0 -121
- edsl/jobs/Interview.py +0 -417
- edsl/jobs/JobsRunner.py +0 -63
- edsl/jobs/JobsRunnerStatusMixin.py +0 -115
- edsl/jobs/base.py +0 -47
- edsl/jobs/buckets.py +0 -166
- edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
- edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
- edsl/jobs/task_management.py +0 -218
- edsl/jobs/token_tracking.py +0 -78
- edsl/language_models/DeepInfra.py +0 -69
- edsl/language_models/OpenAI.py +0 -98
- edsl/language_models/model_interfaces/GeminiPro.py +0 -66
- edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
- edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
- edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
- edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
- edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
- edsl/language_models/registry.py +0 -81
- edsl/language_models/schemas.py +0 -15
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/prompts/QuestionInstructionsBase.py +0 -6
- edsl/prompts/library/agent_instructions.py +0 -29
- edsl/prompts/library/agent_persona.py +0 -17
- edsl/prompts/library/question_budget.py +0 -26
- edsl/prompts/library/question_checkbox.py +0 -32
- edsl/prompts/library/question_extract.py +0 -19
- edsl/prompts/library/question_freetext.py +0 -14
- edsl/prompts/library/question_linear_scale.py +0 -20
- edsl/prompts/library/question_list.py +0 -22
- edsl/prompts/library/question_multiple_choice.py +0 -44
- edsl/prompts/library/question_numerical.py +0 -31
- edsl/prompts/library/question_rank.py +0 -21
- edsl/prompts/prompt_config.py +0 -33
- edsl/prompts/registry.py +0 -185
- edsl/questions/Question.py +0 -240
- edsl/report/InputOutputDataTypes.py +0 -134
- edsl/report/RegressionMixin.py +0 -28
- edsl/report/ReportOutputs.py +0 -1228
- edsl/report/ResultsFetchMixin.py +0 -106
- edsl/report/ResultsOutputMixin.py +0 -14
- edsl/report/demo.ipynb +0 -645
- edsl/results/ResultsDBMixin.py +0 -184
- edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
- edsl/trackers/Tracker.py +0 -91
- edsl/trackers/TrackerAPI.py +0 -196
- edsl/trackers/TrackerTasks.py +0 -70
- edsl/utilities/pastebin.py +0 -141
- edsl-0.1.14.dist-info/METADATA +0 -69
- edsl-0.1.14.dist-info/RECORD +0 -141
- /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
- /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
- /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
edsl/prompts/Prompt.py
CHANGED
@@ -1,52 +1,110 @@
|
|
1
|
-
import
|
2
|
-
from
|
3
|
-
from
|
4
|
-
import io
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Any, List, Union, Dict, Optional
|
3
|
+
from pathlib import Path
|
5
4
|
|
6
|
-
from
|
7
|
-
from rich.table import Table
|
5
|
+
# from jinja2 import Undefined
|
8
6
|
|
9
|
-
from jinja2 import Template, Environment, meta, TemplateSyntaxError
|
10
7
|
|
11
8
|
from edsl.exceptions.prompts import TemplateRenderError
|
12
|
-
from edsl.
|
13
|
-
C2A,
|
14
|
-
names_to_component_types,
|
15
|
-
ComponentTypes,
|
16
|
-
NEGATIVE_INFINITY,
|
17
|
-
)
|
18
|
-
from edsl.prompts.registry import RegisterPromptsMeta
|
19
|
-
|
20
|
-
from edsl.Base import PersistenceMixin, RichPrintingMixin
|
9
|
+
from edsl.Base import PersistenceMixin, RepresentationMixin
|
21
10
|
|
22
11
|
MAX_NESTING = 100
|
23
12
|
|
24
13
|
|
25
|
-
class
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
class Prompt(PersistenceMixin, RepresentationMixin):
|
15
|
+
"""Class for creating a prompt to be used in a survey."""
|
16
|
+
|
17
|
+
default_instructions: Optional[str] = "Do good things, friendly LLM!"
|
18
|
+
|
19
|
+
def __len__(self):
|
20
|
+
"""Return the length of the prompt text."""
|
21
|
+
return len(self.text)
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def prompt_attributes(cls) -> List[str]:
|
25
|
+
"""Return the prompt class attributes."""
|
26
|
+
return {k: v for k, v in cls.__dict__.items() if not k.startswith("_")}
|
27
|
+
|
28
|
+
def __init__(self, text: Optional[str] = None):
|
29
|
+
"""Create a `Prompt` object.
|
29
30
|
|
30
|
-
|
31
|
+
:param text: The text of the prompt.
|
32
|
+
"""
|
31
33
|
if text is None:
|
32
34
|
if hasattr(self, "default_instructions"):
|
33
35
|
text = self.default_instructions
|
34
36
|
else:
|
35
37
|
text = ""
|
38
|
+
if isinstance(text, Prompt):
|
39
|
+
# make it idempotent w/ a prompt
|
40
|
+
text = text.text
|
36
41
|
self._text = text
|
37
42
|
|
43
|
+
@classmethod
|
44
|
+
def from_txt(cls, filename: str) -> PromptBase:
|
45
|
+
"""Create a `Prompt` from text.
|
46
|
+
|
47
|
+
:param text: The text of the prompt.
|
48
|
+
"""
|
49
|
+
with open(filename, "r") as f:
|
50
|
+
text = f.read()
|
51
|
+
return cls(text=text)
|
52
|
+
|
53
|
+
@classmethod
|
54
|
+
def from_template(
|
55
|
+
cls,
|
56
|
+
file_name: str,
|
57
|
+
path_to_folder: Optional[Union[str, Path]] = None,
|
58
|
+
**kwargs: Dict[str, Any],
|
59
|
+
) -> "PromptBase":
|
60
|
+
"""Create a `PromptBase` from a Jinja template.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
file_name (str): The name of the Jinja template file.
|
64
|
+
path_to_folder (Union[str, Path]): The path to the folder containing the template.
|
65
|
+
Can be absolute or relative.
|
66
|
+
**kwargs: Variables to be passed to the template for rendering.
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
PromptBase: An instance of PromptBase with the rendered template as text.
|
70
|
+
"""
|
71
|
+
# if file_name lacks the .j2 extension, add it
|
72
|
+
if not file_name.endswith(".jinja"):
|
73
|
+
file_name += ".jinja"
|
74
|
+
|
75
|
+
# Convert path_to_folder to a Path object if it's a string
|
76
|
+
if path_to_folder is None:
|
77
|
+
from importlib import resources
|
78
|
+
import os
|
79
|
+
|
80
|
+
path_to_folder = resources.path("edsl.questions", "prompt_templates")
|
81
|
+
|
82
|
+
try:
|
83
|
+
folder_path = Path(path_to_folder)
|
84
|
+
except Exception as e:
|
85
|
+
raise ValueError(f"Invalid path: {path_to_folder}. Error: {e}")
|
86
|
+
|
87
|
+
with open(folder_path.joinpath(file_name), "r") as f:
|
88
|
+
text = f.read()
|
89
|
+
return cls(text=text)
|
90
|
+
|
38
91
|
@property
|
39
92
|
def text(self):
|
93
|
+
"""Return the `Prompt` text."""
|
40
94
|
return self._text
|
41
95
|
|
42
96
|
def __add__(self, other_prompt):
|
43
|
-
"""
|
97
|
+
"""Add two prompts together.
|
98
|
+
|
99
|
+
Example:
|
100
|
+
|
44
101
|
>>> p = Prompt("Hello, {{person}}")
|
45
102
|
>>> p2 = Prompt("How are you?")
|
46
103
|
>>> p + p2
|
47
|
-
Prompt(text
|
104
|
+
Prompt(text=\"""Hello, {{person}}How are you?\""")
|
105
|
+
|
48
106
|
>>> p + "How are you?"
|
49
|
-
Prompt(text
|
107
|
+
Prompt(text=\"""Hello, {{person}}How are you?\""")
|
50
108
|
"""
|
51
109
|
if isinstance(other_prompt, str):
|
52
110
|
return self.__class__(self.text + other_prompt)
|
@@ -54,7 +112,9 @@ class PromptBase(
|
|
54
112
|
return self.__class__(text=self.text + other_prompt.text)
|
55
113
|
|
56
114
|
def __str__(self):
|
57
|
-
"""
|
115
|
+
"""Return the `Prompt` text.
|
116
|
+
|
117
|
+
Example:
|
58
118
|
>>> p = Prompt("Hello, {{person}}")
|
59
119
|
>>> str(p)
|
60
120
|
'Hello, {{person}}'
|
@@ -62,7 +122,10 @@ class PromptBase(
|
|
62
122
|
return self.text
|
63
123
|
|
64
124
|
def __contains__(self, text_to_check):
|
65
|
-
"""
|
125
|
+
"""Check if the text_to_check is in the `Prompt` text.
|
126
|
+
|
127
|
+
Example:
|
128
|
+
|
66
129
|
>>> p = Prompt("Hello, {{person}}")
|
67
130
|
>>> "person" in p
|
68
131
|
True
|
@@ -72,42 +135,75 @@ class PromptBase(
|
|
72
135
|
return text_to_check in self.text
|
73
136
|
|
74
137
|
def __repr__(self):
|
75
|
-
"""
|
138
|
+
"""Return the `Prompt` text.
|
139
|
+
|
140
|
+
Example:
|
76
141
|
>>> p = Prompt("Hello, {{person}}")
|
77
142
|
>>> p
|
78
|
-
Prompt(text
|
143
|
+
Prompt(text=\"""Hello, {{person}}\""")
|
79
144
|
"""
|
80
|
-
return f
|
145
|
+
return f'Prompt(text="""{self.text}""")'
|
146
|
+
|
147
|
+
def template_variables(self) -> list[str]:
|
148
|
+
"""Return the the variables in the template.
|
149
|
+
|
150
|
+
Example:
|
81
151
|
|
82
|
-
def template_variables(
|
83
|
-
self,
|
84
|
-
) -> list[str]:
|
85
|
-
"""
|
86
152
|
>>> p = Prompt("Hello, {{person}}")
|
87
153
|
>>> p.template_variables()
|
88
154
|
['person']
|
155
|
+
|
89
156
|
"""
|
90
157
|
return self._template_variables(self.text)
|
91
158
|
|
92
159
|
@staticmethod
|
93
160
|
def _template_variables(template: str) -> list[str]:
|
94
|
-
"""
|
95
|
-
|
161
|
+
"""Find and return the template variables.
|
162
|
+
|
163
|
+
:param template: The template to find the variables in.
|
164
|
+
|
165
|
+
"""
|
166
|
+
from jinja2 import Environment, meta, Undefined
|
167
|
+
|
168
|
+
class PreserveUndefined(Undefined):
|
169
|
+
def __str__(self):
|
170
|
+
return "{{ " + str(self._undefined_name) + " }}"
|
171
|
+
|
172
|
+
env = Environment(undefined=PreserveUndefined)
|
96
173
|
ast = env.parse(template)
|
97
174
|
return list(meta.find_undeclared_variables(ast))
|
98
175
|
|
99
|
-
def undefined_template_variables(self,
|
100
|
-
|
176
|
+
def undefined_template_variables(self, replacement_dict: dict):
|
177
|
+
"""Return the variables in the template that are not in the replacement_dict.
|
178
|
+
|
179
|
+
:param replacement_dict: A dictionary of replacements to populate the template.
|
180
|
+
|
181
|
+
Example:
|
182
|
+
|
183
|
+
>>> p = Prompt("Hello, {{person}}")
|
184
|
+
>>> p.undefined_template_variables({"person": "John"})
|
185
|
+
[]
|
186
|
+
|
187
|
+
>>> p = Prompt("Hello, {{title}} {{person}}")
|
188
|
+
>>> p.undefined_template_variables({"person": "John"})
|
189
|
+
['title']
|
190
|
+
"""
|
191
|
+
return [var for var in self.template_variables() if var not in replacement_dict]
|
101
192
|
|
102
193
|
def unused_traits(self, traits: dict):
|
194
|
+
"""Return the traits that are not used in the template."""
|
103
195
|
return [trait for trait in traits if trait not in self.template_variables()]
|
104
196
|
|
105
197
|
@property
|
106
198
|
def has_variables(self) -> bool:
|
107
|
-
"""
|
199
|
+
"""Return True if the prompt has variables.
|
200
|
+
|
201
|
+
Example:
|
202
|
+
|
108
203
|
>>> p = Prompt("Hello, {{person}}")
|
109
204
|
>>> p.has_variables
|
110
205
|
True
|
206
|
+
|
111
207
|
>>> p = Prompt("Hello, person")
|
112
208
|
>>> p.has_variables
|
113
209
|
False
|
@@ -115,37 +211,64 @@ class PromptBase(
|
|
115
211
|
return len(self.template_variables()) > 0
|
116
212
|
|
117
213
|
def render(self, primary_replacement: dict, **additional_replacements) -> str:
|
118
|
-
"""
|
214
|
+
"""Render the prompt with the replacements.
|
215
|
+
|
216
|
+
:param primary_replacement: The primary replacement dictionary.
|
217
|
+
:param additional_replacements: Additional replacement dictionaries.
|
119
218
|
|
120
219
|
>>> p = Prompt("Hello, {{person}}")
|
121
220
|
>>> p.render({"person": "John"})
|
122
|
-
|
221
|
+
Prompt(text=\"""Hello, John\""")
|
222
|
+
|
123
223
|
>>> p.render({"person": "Mr. {{last_name}}", "last_name": "Horton"})
|
124
|
-
|
224
|
+
Prompt(text=\"""Hello, Mr. Horton\""")
|
225
|
+
|
125
226
|
>>> p.render({"person": "Mr. {{last_name}}", "last_name": "Ho{{letter}}ton"}, max_nesting = 1)
|
126
|
-
|
227
|
+
Prompt(text=\"""Hello, Mr. Ho{{ letter }}ton\""")
|
228
|
+
|
229
|
+
>>> p.render({"person": "Mr. {{last_name}}"})
|
230
|
+
Prompt(text=\"""Hello, Mr. {{ last_name }}\""")
|
127
231
|
"""
|
128
|
-
|
129
|
-
self.
|
130
|
-
|
131
|
-
|
232
|
+
try:
|
233
|
+
new_text = self._render(
|
234
|
+
self.text, primary_replacement, **additional_replacements
|
235
|
+
)
|
236
|
+
return self.__class__(text=new_text)
|
237
|
+
except Exception as e:
|
238
|
+
print(f"Error rendering prompt: {e}")
|
239
|
+
return self
|
132
240
|
|
133
241
|
@staticmethod
|
134
|
-
def _render(
|
135
|
-
|
136
|
-
|
137
|
-
|
242
|
+
def _render(
|
243
|
+
text: str, primary_replacement, **additional_replacements
|
244
|
+
) -> "PromptBase":
|
245
|
+
"""Render the template text with variables replaced from the provided named dictionaries.
|
246
|
+
|
247
|
+
:param text: The text to render.
|
248
|
+
:param primary_replacement: The primary replacement dictionary.
|
249
|
+
:param additional_replacements: Additional replacement dictionaries.
|
250
|
+
|
251
|
+
Allows for nested variable resolution up to a specified maximum nesting depth.
|
252
|
+
|
253
|
+
Example:
|
138
254
|
|
139
255
|
>>> codebook = {"age": "Age"}
|
140
256
|
>>> p = Prompt("You are an agent named {{ name }}. {{ codebook['age']}}: {{ age }}")
|
141
257
|
>>> p.render({"name": "John", "age": 44}, codebook=codebook)
|
142
|
-
|
143
|
-
|
258
|
+
Prompt(text=\"""You are an agent named John. Age: 44\""")
|
144
259
|
"""
|
260
|
+
from jinja2 import Environment, meta, TemplateSyntaxError, Undefined
|
261
|
+
|
262
|
+
class PreserveUndefined(Undefined):
|
263
|
+
def __str__(self):
|
264
|
+
return "{{ " + str(self._undefined_name) + " }}"
|
265
|
+
|
266
|
+
env = Environment(undefined=PreserveUndefined)
|
145
267
|
try:
|
146
268
|
previous_text = None
|
147
269
|
for _ in range(MAX_NESTING):
|
148
|
-
|
270
|
+
# breakpoint()
|
271
|
+
rendered_text = env.from_string(text).render(
|
149
272
|
primary_replacement, **additional_replacements
|
150
273
|
)
|
151
274
|
if rendered_text == previous_text:
|
@@ -159,65 +282,71 @@ class PromptBase(
|
|
159
282
|
"Too much nesting - you created an infinite loop here, pal"
|
160
283
|
)
|
161
284
|
except TemplateSyntaxError as e:
|
162
|
-
raise TemplateRenderError(
|
285
|
+
raise TemplateRenderError(
|
286
|
+
f"Template syntax error: {e}. Bad template: {text}"
|
287
|
+
)
|
288
|
+
|
289
|
+
def to_dict(self, add_edsl_version=False) -> dict[str, Any]:
|
290
|
+
"""Return the `Prompt` as a dictionary.
|
291
|
+
|
292
|
+
Example:
|
163
293
|
|
164
|
-
def to_dict(self):
|
165
|
-
"""
|
166
294
|
>>> p = Prompt("Hello, {{person}}")
|
167
295
|
>>> p.to_dict()
|
168
296
|
{'text': 'Hello, {{person}}', 'class_name': 'Prompt'}
|
297
|
+
|
169
298
|
"""
|
170
299
|
return {"text": self.text, "class_name": self.__class__.__name__}
|
171
300
|
|
172
301
|
@classmethod
|
173
|
-
def from_dict(cls, data):
|
174
|
-
"""
|
302
|
+
def from_dict(cls, data) -> PromptBase:
|
303
|
+
"""Create a `Prompt` from a dictionary.
|
304
|
+
|
305
|
+
Example:
|
306
|
+
|
175
307
|
>>> p = Prompt("Hello, {{person}}")
|
176
308
|
>>> p2 = Prompt.from_dict(p.to_dict())
|
177
309
|
>>> p2
|
178
|
-
Prompt(text
|
310
|
+
Prompt(text=\"""Hello, {{person}}\""")
|
311
|
+
|
179
312
|
"""
|
180
|
-
class_name = data["class_name"]
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
return table
|
313
|
+
# class_name = data["class_name"]
|
314
|
+
return Prompt(text=data["text"])
|
315
|
+
|
316
|
+
# def rich_print(self):
|
317
|
+
# """Display an object as a table."""
|
318
|
+
# table = Table(title="Prompt")
|
319
|
+
# table.add_column("Attribute", style="bold")
|
320
|
+
# table.add_column("Value")
|
321
|
+
|
322
|
+
# to_display = self.__dict__.copy()
|
323
|
+
# for attr_name, attr_value in to_display.items():
|
324
|
+
# table.add_row(attr_name, repr(attr_value))
|
325
|
+
# table.add_row("Component type", str(self.component_type))
|
326
|
+
# table.add_row("Model", str(getattr(self, "model", "Not specified")))
|
327
|
+
# return table
|
196
328
|
|
197
329
|
@classmethod
|
198
330
|
def example(cls):
|
331
|
+
"""Return an example of the prompt."""
|
199
332
|
return cls(cls.default_instructions)
|
200
333
|
|
201
334
|
|
202
|
-
class Prompt(PromptBase):
|
203
|
-
component_type = ComponentTypes.GENERIC
|
204
|
-
|
205
|
-
|
206
|
-
from edsl.prompts.library.question_multiple_choice import *
|
207
|
-
from edsl.prompts.library.agent_instructions import *
|
208
|
-
from edsl.prompts.library.agent_persona import *
|
209
|
-
|
210
|
-
from edsl.prompts.library.question_budget import *
|
211
|
-
from edsl.prompts.library.question_checkbox import *
|
212
|
-
from edsl.prompts.library.question_freetext import *
|
213
|
-
from edsl.prompts.library.question_linear_scale import *
|
214
|
-
from edsl.prompts.library.question_numerical import *
|
215
|
-
from edsl.prompts.library.question_rank import *
|
216
|
-
from edsl.prompts.library.question_extract import *
|
217
|
-
from edsl.prompts.library.question_list import *
|
218
|
-
|
219
|
-
|
220
335
|
if __name__ == "__main__":
|
336
|
+
print("Running doctests...")
|
221
337
|
import doctest
|
222
338
|
|
223
339
|
doctest.testmod()
|
340
|
+
|
341
|
+
# from edsl.prompts.library.question_multiple_choice import *
|
342
|
+
# from edsl.prompts.library.agent_instructions import *
|
343
|
+
# from edsl.prompts.library.agent_persona import *
|
344
|
+
|
345
|
+
# from edsl.prompts.library.question_budget import *
|
346
|
+
# from edsl.prompts.library.question_checkbox import *
|
347
|
+
# from edsl.prompts.library.question_freetext import *
|
348
|
+
# from edsl.prompts.library.question_linear_scale import *
|
349
|
+
# from edsl.prompts.library.question_numerical import *
|
350
|
+
# from edsl.prompts.library.question_rank import *
|
351
|
+
# from edsl.prompts.library.question_extract import *
|
352
|
+
# from edsl.prompts.library.question_list import *
|
edsl/prompts/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from edsl.prompts.registry import get_classes
|
1
|
+
# from edsl.prompts.registry import get_classes
|
2
2
|
from edsl.prompts.Prompt import Prompt
|
@@ -0,0 +1,77 @@
|
|
1
|
+
from pydantic import ValidationError
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
|
5
|
+
class ExceptionExplainer:
|
6
|
+
"""
|
7
|
+
A class that converts validation errors into human-readable explanations,
|
8
|
+
specifically for Language Model responses.
|
9
|
+
"""
|
10
|
+
|
11
|
+
def __init__(self, error: Union[ValidationError, Exception], model_response: str):
|
12
|
+
"""
|
13
|
+
Initialize the explainer with the error and model response.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
error: The validation error that occurred
|
17
|
+
model_response: The raw response from the Language Model
|
18
|
+
"""
|
19
|
+
self.error = error
|
20
|
+
self.model_response = model_response
|
21
|
+
|
22
|
+
def explain(self) -> str:
|
23
|
+
"""
|
24
|
+
Generate a human-readable explanation of why the model's response failed validation.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
A user-friendly explanation of why the model's response was invalid
|
28
|
+
"""
|
29
|
+
self.error = self.error.pydantic_error
|
30
|
+
return self._explain_validation_error()
|
31
|
+
|
32
|
+
# Fallback for unknown errors
|
33
|
+
return self._create_generic_explanation()
|
34
|
+
|
35
|
+
def _explain_validation_error(self) -> str:
|
36
|
+
"""Handle Pydantic ValidationError specifically."""
|
37
|
+
error_dict = self.error.errors()
|
38
|
+
explanations = []
|
39
|
+
|
40
|
+
context = f'The AI model returned "{self.model_response}", but this was invalid for the question you asked and the constraints you provided.\n'
|
41
|
+
explanations.append(context)
|
42
|
+
explanations.append("Reason(s) invalidated:")
|
43
|
+
for e in error_dict:
|
44
|
+
msg = e.get("msg", "Unknown error")
|
45
|
+
explanations.append(f"- {msg}")
|
46
|
+
|
47
|
+
main_message = "\n".join(explanations)
|
48
|
+
return f"{main_message}\n\n{self._get_suggestion()}"
|
49
|
+
|
50
|
+
def _create_generic_explanation(self) -> str:
|
51
|
+
"""Create a generic explanation for non-ValidationError exceptions."""
|
52
|
+
return (
|
53
|
+
f'The AI model returned "{self.model_response}", but this response was invalid. '
|
54
|
+
f"Error: {str(self.error)}"
|
55
|
+
)
|
56
|
+
|
57
|
+
def _get_suggestion(self) -> str:
|
58
|
+
"""Get a suggestion for handling the error."""
|
59
|
+
return (
|
60
|
+
"EDSL Advice:\n"
|
61
|
+
"- Look at the Model comments - often the model will provide a hint about what went wrong.\n"
|
62
|
+
"- If the model's response doesn't make sense, try rephrasing your question.\n"
|
63
|
+
"- Try using 'use_code' parameter of a MultipleChoice.\n"
|
64
|
+
"- A QuestionFreeText will almost always validate.\n"
|
65
|
+
"- Try setting the 'permissive' = True parameter in the Question constructor."
|
66
|
+
)
|
67
|
+
|
68
|
+
|
69
|
+
# Example usage:
|
70
|
+
if __name__ == "__main__":
|
71
|
+
try:
|
72
|
+
# Your validation code here
|
73
|
+
raise ValidationError.parse_obj({"answer": "120"})
|
74
|
+
except ValidationError as e:
|
75
|
+
explainer = ExceptionExplainer(e, "120")
|
76
|
+
explanation = explainer.explain()
|
77
|
+
print(explanation)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from edsl.prompts.Prompt import Prompt
|
3
|
+
|
4
|
+
|
5
|
+
class HTMLQuestion:
|
6
|
+
def __init__(self, question):
|
7
|
+
self.question = question
|
8
|
+
|
9
|
+
def html(
|
10
|
+
self,
|
11
|
+
scenario: Optional[dict] = None,
|
12
|
+
agent: Optional[dict] = {},
|
13
|
+
answers: Optional[dict] = None,
|
14
|
+
include_question_name: bool = False,
|
15
|
+
height: Optional[int] = None,
|
16
|
+
width: Optional[int] = None,
|
17
|
+
iframe=False,
|
18
|
+
):
|
19
|
+
"""Return the question in HTML format."""
|
20
|
+
from jinja2 import Template
|
21
|
+
|
22
|
+
if scenario is None:
|
23
|
+
scenario = {}
|
24
|
+
|
25
|
+
prior_answers_dict = {}
|
26
|
+
|
27
|
+
if isinstance(answers, dict):
|
28
|
+
for key, value in answers.items():
|
29
|
+
if not key.endswith("_comment") and not key.endswith(
|
30
|
+
"_generated_tokens"
|
31
|
+
):
|
32
|
+
prior_answers_dict[key] = {"answer": value}
|
33
|
+
|
34
|
+
base_template = """
|
35
|
+
<div id="{{ question_name }}" class="survey_question" data-type="{{ question_type }}">
|
36
|
+
{% if include_question_name %}
|
37
|
+
<p>question_name: {{ question_name }}</p>
|
38
|
+
{% endif %}
|
39
|
+
<p class="question_text">{{ question_text }}</p>
|
40
|
+
{{ question_content }}
|
41
|
+
</div>
|
42
|
+
"""
|
43
|
+
if not hasattr(self.question, "question_type"):
|
44
|
+
self.question.question_type = "unknown"
|
45
|
+
|
46
|
+
if hasattr(self.question, "question_html_content"):
|
47
|
+
question_content = self.question.question_html_content
|
48
|
+
else:
|
49
|
+
question_content = Template("")
|
50
|
+
|
51
|
+
base_template = Template(base_template)
|
52
|
+
|
53
|
+
context = {
|
54
|
+
"scenario": scenario,
|
55
|
+
"agent": agent,
|
56
|
+
} | prior_answers_dict
|
57
|
+
|
58
|
+
# Render the question text
|
59
|
+
try:
|
60
|
+
question_text = Template(self.question.question_text).render(context)
|
61
|
+
except Exception as e:
|
62
|
+
print(
|
63
|
+
f"Error rendering question: question_text = {self.question.question_text}, error = {e}"
|
64
|
+
)
|
65
|
+
question_text = self.question.question_text
|
66
|
+
|
67
|
+
try:
|
68
|
+
question_content = Template(question_content).render(context)
|
69
|
+
except Exception as e:
|
70
|
+
print(
|
71
|
+
f"Error rendering question: question_content = {question_content}, error = {e}"
|
72
|
+
)
|
73
|
+
question_content = question_content
|
74
|
+
|
75
|
+
try:
|
76
|
+
params = {
|
77
|
+
"question_name": self.question.question_name,
|
78
|
+
"question_text": question_text,
|
79
|
+
"question_type": self.question.question_type,
|
80
|
+
"question_content": question_content,
|
81
|
+
"include_question_name": include_question_name,
|
82
|
+
}
|
83
|
+
except Exception as e:
|
84
|
+
raise ValueError(
|
85
|
+
f"Error rendering question: params = {params}, error = {e}"
|
86
|
+
)
|
87
|
+
rendered_html = base_template.render(**params)
|
88
|
+
|
89
|
+
if iframe:
|
90
|
+
import html
|
91
|
+
from IPython.display import display, HTML
|
92
|
+
|
93
|
+
height = height or 200
|
94
|
+
width = width or 600
|
95
|
+
escaped_output = html.escape(rendered_html)
|
96
|
+
# escaped_output = rendered_html
|
97
|
+
iframe = f""""
|
98
|
+
<iframe srcdoc="{ escaped_output }" style="width: {width}px; height: {height}px;"></iframe>
|
99
|
+
"""
|
100
|
+
display(HTML(iframe))
|
101
|
+
return None
|
102
|
+
|
103
|
+
return rendered_html
|