edsl 0.1.15__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.
Files changed (407) hide show
  1. edsl/Base.py +348 -38
  2. edsl/BaseDiff.py +260 -0
  3. edsl/TemplateLoader.py +24 -0
  4. edsl/__init__.py +45 -10
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +842 -144
  7. edsl/agents/AgentList.py +521 -25
  8. edsl/agents/Invigilator.py +250 -374
  9. edsl/agents/InvigilatorBase.py +257 -0
  10. edsl/agents/PromptConstructor.py +272 -0
  11. edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
  12. edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
  13. edsl/agents/descriptors.py +43 -13
  14. edsl/agents/prompt_helpers.py +129 -0
  15. edsl/agents/question_option_processor.py +172 -0
  16. edsl/auto/AutoStudy.py +130 -0
  17. edsl/auto/StageBase.py +243 -0
  18. edsl/auto/StageGenerateSurvey.py +178 -0
  19. edsl/auto/StageLabelQuestions.py +125 -0
  20. edsl/auto/StagePersona.py +61 -0
  21. edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
  22. edsl/auto/StagePersonaDimensionValues.py +74 -0
  23. edsl/auto/StagePersonaDimensions.py +69 -0
  24. edsl/auto/StageQuestions.py +74 -0
  25. edsl/auto/SurveyCreatorPipeline.py +21 -0
  26. edsl/auto/utilities.py +218 -0
  27. edsl/base/Base.py +279 -0
  28. edsl/config.py +115 -113
  29. edsl/conversation/Conversation.py +290 -0
  30. edsl/conversation/car_buying.py +59 -0
  31. edsl/conversation/chips.py +95 -0
  32. edsl/conversation/mug_negotiation.py +81 -0
  33. edsl/conversation/next_speaker_utilities.py +93 -0
  34. edsl/coop/CoopFunctionsMixin.py +15 -0
  35. edsl/coop/ExpectedParrotKeyHandler.py +125 -0
  36. edsl/coop/PriceFetcher.py +54 -0
  37. edsl/coop/__init__.py +1 -0
  38. edsl/coop/coop.py +1029 -134
  39. edsl/coop/utils.py +131 -0
  40. edsl/data/Cache.py +560 -89
  41. edsl/data/CacheEntry.py +230 -0
  42. edsl/data/CacheHandler.py +168 -0
  43. edsl/data/RemoteCacheSync.py +186 -0
  44. edsl/data/SQLiteDict.py +292 -0
  45. edsl/data/__init__.py +5 -3
  46. edsl/data/orm.py +6 -33
  47. edsl/data_transfer_models.py +74 -27
  48. edsl/enums.py +165 -8
  49. edsl/exceptions/BaseException.py +21 -0
  50. edsl/exceptions/__init__.py +52 -46
  51. edsl/exceptions/agents.py +33 -15
  52. edsl/exceptions/cache.py +5 -0
  53. edsl/exceptions/coop.py +8 -0
  54. edsl/exceptions/general.py +34 -0
  55. edsl/exceptions/inference_services.py +5 -0
  56. edsl/exceptions/jobs.py +15 -0
  57. edsl/exceptions/language_models.py +46 -1
  58. edsl/exceptions/questions.py +80 -5
  59. edsl/exceptions/results.py +16 -5
  60. edsl/exceptions/scenarios.py +29 -0
  61. edsl/exceptions/surveys.py +13 -10
  62. edsl/inference_services/AnthropicService.py +106 -0
  63. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  64. edsl/inference_services/AvailableModelFetcher.py +215 -0
  65. edsl/inference_services/AwsBedrock.py +118 -0
  66. edsl/inference_services/AzureAI.py +215 -0
  67. edsl/inference_services/DeepInfraService.py +18 -0
  68. edsl/inference_services/GoogleService.py +143 -0
  69. edsl/inference_services/GroqService.py +20 -0
  70. edsl/inference_services/InferenceServiceABC.py +80 -0
  71. edsl/inference_services/InferenceServicesCollection.py +138 -0
  72. edsl/inference_services/MistralAIService.py +120 -0
  73. edsl/inference_services/OllamaService.py +18 -0
  74. edsl/inference_services/OpenAIService.py +236 -0
  75. edsl/inference_services/PerplexityService.py +160 -0
  76. edsl/inference_services/ServiceAvailability.py +135 -0
  77. edsl/inference_services/TestService.py +90 -0
  78. edsl/inference_services/TogetherAIService.py +172 -0
  79. edsl/inference_services/data_structures.py +134 -0
  80. edsl/inference_services/models_available_cache.py +118 -0
  81. edsl/inference_services/rate_limits_cache.py +25 -0
  82. edsl/inference_services/registry.py +41 -0
  83. edsl/inference_services/write_available.py +10 -0
  84. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  85. edsl/jobs/Answers.py +21 -20
  86. edsl/jobs/FetchInvigilator.py +47 -0
  87. edsl/jobs/InterviewTaskManager.py +98 -0
  88. edsl/jobs/InterviewsConstructor.py +50 -0
  89. edsl/jobs/Jobs.py +684 -206
  90. edsl/jobs/JobsChecks.py +172 -0
  91. edsl/jobs/JobsComponentConstructor.py +189 -0
  92. edsl/jobs/JobsPrompts.py +270 -0
  93. edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
  94. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  95. edsl/jobs/RequestTokenEstimator.py +30 -0
  96. edsl/jobs/async_interview_runner.py +138 -0
  97. edsl/jobs/buckets/BucketCollection.py +104 -0
  98. edsl/jobs/buckets/ModelBuckets.py +65 -0
  99. edsl/jobs/buckets/TokenBucket.py +283 -0
  100. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  101. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  102. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  103. edsl/jobs/data_structures.py +120 -0
  104. edsl/jobs/decorators.py +35 -0
  105. edsl/jobs/interviews/Interview.py +392 -0
  106. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
  107. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
  108. edsl/jobs/interviews/InterviewStatistic.py +63 -0
  109. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
  110. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
  111. edsl/jobs/interviews/InterviewStatusLog.py +92 -0
  112. edsl/jobs/interviews/ReportErrors.py +66 -0
  113. edsl/jobs/interviews/interview_status_enum.py +9 -0
  114. edsl/jobs/jobs_status_enums.py +9 -0
  115. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  116. edsl/jobs/results_exceptions_handler.py +98 -0
  117. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -110
  118. edsl/jobs/runners/JobsRunnerStatus.py +298 -0
  119. edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
  120. edsl/jobs/tasks/TaskCreators.py +64 -0
  121. edsl/jobs/tasks/TaskHistory.py +470 -0
  122. edsl/jobs/tasks/TaskStatusLog.py +23 -0
  123. edsl/jobs/tasks/task_status_enum.py +161 -0
  124. edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
  125. edsl/jobs/tokens/TokenUsage.py +34 -0
  126. edsl/language_models/ComputeCost.py +63 -0
  127. edsl/language_models/LanguageModel.py +507 -386
  128. edsl/language_models/ModelList.py +164 -0
  129. edsl/language_models/PriceManager.py +127 -0
  130. edsl/language_models/RawResponseHandler.py +106 -0
  131. edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
  132. edsl/language_models/__init__.py +1 -8
  133. edsl/language_models/fake_openai_call.py +15 -0
  134. edsl/language_models/fake_openai_service.py +61 -0
  135. edsl/language_models/key_management/KeyLookup.py +63 -0
  136. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  137. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  138. edsl/language_models/key_management/__init__.py +0 -0
  139. edsl/language_models/key_management/models.py +131 -0
  140. edsl/language_models/model.py +256 -0
  141. edsl/language_models/repair.py +109 -41
  142. edsl/language_models/utilities.py +65 -0
  143. edsl/notebooks/Notebook.py +263 -0
  144. edsl/notebooks/NotebookToLaTeX.py +142 -0
  145. edsl/notebooks/__init__.py +1 -0
  146. edsl/prompts/Prompt.py +222 -93
  147. edsl/prompts/__init__.py +1 -1
  148. edsl/questions/ExceptionExplainer.py +77 -0
  149. edsl/questions/HTMLQuestion.py +103 -0
  150. edsl/questions/QuestionBase.py +518 -0
  151. edsl/questions/QuestionBasePromptsMixin.py +221 -0
  152. edsl/questions/QuestionBudget.py +164 -67
  153. edsl/questions/QuestionCheckBox.py +281 -62
  154. edsl/questions/QuestionDict.py +343 -0
  155. edsl/questions/QuestionExtract.py +136 -50
  156. edsl/questions/QuestionFreeText.py +79 -55
  157. edsl/questions/QuestionFunctional.py +138 -41
  158. edsl/questions/QuestionList.py +184 -57
  159. edsl/questions/QuestionMatrix.py +265 -0
  160. edsl/questions/QuestionMultipleChoice.py +293 -69
  161. edsl/questions/QuestionNumerical.py +109 -56
  162. edsl/questions/QuestionRank.py +244 -49
  163. edsl/questions/Quick.py +41 -0
  164. edsl/questions/SimpleAskMixin.py +74 -0
  165. edsl/questions/__init__.py +9 -6
  166. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
  167. edsl/questions/compose_questions.py +13 -7
  168. edsl/questions/data_structures.py +20 -0
  169. edsl/questions/decorators.py +21 -0
  170. edsl/questions/derived/QuestionLikertFive.py +28 -26
  171. edsl/questions/derived/QuestionLinearScale.py +41 -28
  172. edsl/questions/derived/QuestionTopK.py +34 -26
  173. edsl/questions/derived/QuestionYesNo.py +40 -27
  174. edsl/questions/descriptors.py +228 -74
  175. edsl/questions/loop_processor.py +149 -0
  176. edsl/questions/prompt_templates/question_budget.jinja +13 -0
  177. edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
  178. edsl/questions/prompt_templates/question_extract.jinja +11 -0
  179. edsl/questions/prompt_templates/question_free_text.jinja +3 -0
  180. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
  181. edsl/questions/prompt_templates/question_list.jinja +17 -0
  182. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
  183. edsl/questions/prompt_templates/question_numerical.jinja +37 -0
  184. edsl/questions/question_base_gen_mixin.py +168 -0
  185. edsl/questions/question_registry.py +130 -46
  186. edsl/questions/register_questions_meta.py +71 -0
  187. edsl/questions/response_validator_abc.py +188 -0
  188. edsl/questions/response_validator_factory.py +34 -0
  189. edsl/questions/settings.py +5 -2
  190. edsl/questions/templates/__init__.py +0 -0
  191. edsl/questions/templates/budget/__init__.py +0 -0
  192. edsl/questions/templates/budget/answering_instructions.jinja +7 -0
  193. edsl/questions/templates/budget/question_presentation.jinja +7 -0
  194. edsl/questions/templates/checkbox/__init__.py +0 -0
  195. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
  196. edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
  197. edsl/questions/templates/dict/__init__.py +0 -0
  198. edsl/questions/templates/dict/answering_instructions.jinja +21 -0
  199. edsl/questions/templates/dict/question_presentation.jinja +1 -0
  200. edsl/questions/templates/extract/__init__.py +0 -0
  201. edsl/questions/templates/extract/answering_instructions.jinja +7 -0
  202. edsl/questions/templates/extract/question_presentation.jinja +1 -0
  203. edsl/questions/templates/free_text/__init__.py +0 -0
  204. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  205. edsl/questions/templates/free_text/question_presentation.jinja +1 -0
  206. edsl/questions/templates/likert_five/__init__.py +0 -0
  207. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
  208. edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
  209. edsl/questions/templates/linear_scale/__init__.py +0 -0
  210. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
  211. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
  212. edsl/questions/templates/list/__init__.py +0 -0
  213. edsl/questions/templates/list/answering_instructions.jinja +4 -0
  214. edsl/questions/templates/list/question_presentation.jinja +5 -0
  215. edsl/questions/templates/matrix/__init__.py +1 -0
  216. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  217. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  218. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  219. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
  220. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  221. edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
  222. edsl/questions/templates/numerical/__init__.py +0 -0
  223. edsl/questions/templates/numerical/answering_instructions.jinja +7 -0
  224. edsl/questions/templates/numerical/question_presentation.jinja +7 -0
  225. edsl/questions/templates/rank/__init__.py +0 -0
  226. edsl/questions/templates/rank/answering_instructions.jinja +11 -0
  227. edsl/questions/templates/rank/question_presentation.jinja +15 -0
  228. edsl/questions/templates/top_k/__init__.py +0 -0
  229. edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
  230. edsl/questions/templates/top_k/question_presentation.jinja +22 -0
  231. edsl/questions/templates/yes_no/__init__.py +0 -0
  232. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
  233. edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
  234. edsl/results/CSSParameterizer.py +108 -0
  235. edsl/results/Dataset.py +550 -19
  236. edsl/results/DatasetExportMixin.py +594 -0
  237. edsl/results/DatasetTree.py +295 -0
  238. edsl/results/MarkdownToDocx.py +122 -0
  239. edsl/results/MarkdownToPDF.py +111 -0
  240. edsl/results/Result.py +477 -173
  241. edsl/results/Results.py +987 -269
  242. edsl/results/ResultsExportMixin.py +28 -125
  243. edsl/results/ResultsGGMixin.py +83 -15
  244. edsl/results/TableDisplay.py +125 -0
  245. edsl/results/TextEditor.py +50 -0
  246. edsl/results/__init__.py +1 -1
  247. edsl/results/file_exports.py +252 -0
  248. edsl/results/results_fetch_mixin.py +33 -0
  249. edsl/results/results_selector.py +145 -0
  250. edsl/results/results_tools_mixin.py +98 -0
  251. edsl/results/smart_objects.py +96 -0
  252. edsl/results/table_data_class.py +12 -0
  253. edsl/results/table_display.css +78 -0
  254. edsl/results/table_renderers.py +118 -0
  255. edsl/results/tree_explore.py +115 -0
  256. edsl/scenarios/ConstructDownloadLink.py +109 -0
  257. edsl/scenarios/DocumentChunker.py +102 -0
  258. edsl/scenarios/DocxScenario.py +16 -0
  259. edsl/scenarios/FileStore.py +543 -0
  260. edsl/scenarios/PdfExtractor.py +40 -0
  261. edsl/scenarios/Scenario.py +431 -62
  262. edsl/scenarios/ScenarioHtmlMixin.py +65 -0
  263. edsl/scenarios/ScenarioList.py +1415 -45
  264. edsl/scenarios/ScenarioListExportMixin.py +45 -0
  265. edsl/scenarios/ScenarioListPdfMixin.py +239 -0
  266. edsl/scenarios/__init__.py +2 -0
  267. edsl/scenarios/directory_scanner.py +96 -0
  268. edsl/scenarios/file_methods.py +85 -0
  269. edsl/scenarios/handlers/__init__.py +13 -0
  270. edsl/scenarios/handlers/csv.py +49 -0
  271. edsl/scenarios/handlers/docx.py +76 -0
  272. edsl/scenarios/handlers/html.py +37 -0
  273. edsl/scenarios/handlers/json.py +111 -0
  274. edsl/scenarios/handlers/latex.py +5 -0
  275. edsl/scenarios/handlers/md.py +51 -0
  276. edsl/scenarios/handlers/pdf.py +68 -0
  277. edsl/scenarios/handlers/png.py +39 -0
  278. edsl/scenarios/handlers/pptx.py +105 -0
  279. edsl/scenarios/handlers/py.py +294 -0
  280. edsl/scenarios/handlers/sql.py +313 -0
  281. edsl/scenarios/handlers/sqlite.py +149 -0
  282. edsl/scenarios/handlers/txt.py +33 -0
  283. edsl/scenarios/scenario_join.py +131 -0
  284. edsl/scenarios/scenario_selector.py +156 -0
  285. edsl/shared.py +1 -0
  286. edsl/study/ObjectEntry.py +173 -0
  287. edsl/study/ProofOfWork.py +113 -0
  288. edsl/study/SnapShot.py +80 -0
  289. edsl/study/Study.py +521 -0
  290. edsl/study/__init__.py +4 -0
  291. edsl/surveys/ConstructDAG.py +92 -0
  292. edsl/surveys/DAG.py +92 -11
  293. edsl/surveys/EditSurvey.py +221 -0
  294. edsl/surveys/InstructionHandler.py +100 -0
  295. edsl/surveys/Memory.py +9 -4
  296. edsl/surveys/MemoryManagement.py +72 -0
  297. edsl/surveys/MemoryPlan.py +156 -35
  298. edsl/surveys/Rule.py +221 -74
  299. edsl/surveys/RuleCollection.py +241 -61
  300. edsl/surveys/RuleManager.py +172 -0
  301. edsl/surveys/Simulator.py +75 -0
  302. edsl/surveys/Survey.py +1079 -339
  303. edsl/surveys/SurveyCSS.py +273 -0
  304. edsl/surveys/SurveyExportMixin.py +235 -40
  305. edsl/surveys/SurveyFlowVisualization.py +181 -0
  306. edsl/surveys/SurveyQualtricsImport.py +284 -0
  307. edsl/surveys/SurveyToApp.py +141 -0
  308. edsl/surveys/__init__.py +4 -2
  309. edsl/surveys/base.py +19 -3
  310. edsl/surveys/descriptors.py +17 -6
  311. edsl/surveys/instructions/ChangeInstruction.py +48 -0
  312. edsl/surveys/instructions/Instruction.py +56 -0
  313. edsl/surveys/instructions/InstructionCollection.py +82 -0
  314. edsl/surveys/instructions/__init__.py +0 -0
  315. edsl/templates/error_reporting/base.html +24 -0
  316. edsl/templates/error_reporting/exceptions_by_model.html +35 -0
  317. edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
  318. edsl/templates/error_reporting/exceptions_by_type.html +17 -0
  319. edsl/templates/error_reporting/interview_details.html +116 -0
  320. edsl/templates/error_reporting/interviews.html +19 -0
  321. edsl/templates/error_reporting/overview.html +5 -0
  322. edsl/templates/error_reporting/performance_plot.html +2 -0
  323. edsl/templates/error_reporting/report.css +74 -0
  324. edsl/templates/error_reporting/report.html +118 -0
  325. edsl/templates/error_reporting/report.js +25 -0
  326. edsl/tools/__init__.py +1 -0
  327. edsl/tools/clusters.py +192 -0
  328. edsl/tools/embeddings.py +27 -0
  329. edsl/tools/embeddings_plotting.py +118 -0
  330. edsl/tools/plotting.py +112 -0
  331. edsl/tools/summarize.py +18 -0
  332. edsl/utilities/PrettyList.py +56 -0
  333. edsl/utilities/SystemInfo.py +5 -0
  334. edsl/utilities/__init__.py +21 -20
  335. edsl/utilities/ast_utilities.py +3 -0
  336. edsl/utilities/data/Registry.py +2 -0
  337. edsl/utilities/decorators.py +41 -0
  338. edsl/utilities/gcp_bucket/__init__.py +0 -0
  339. edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
  340. edsl/utilities/interface.py +310 -60
  341. edsl/utilities/is_notebook.py +18 -0
  342. edsl/utilities/is_valid_variable_name.py +11 -0
  343. edsl/utilities/naming_utilities.py +263 -0
  344. edsl/utilities/remove_edsl_version.py +24 -0
  345. edsl/utilities/repair_functions.py +28 -0
  346. edsl/utilities/restricted_python.py +70 -0
  347. edsl/utilities/utilities.py +203 -13
  348. edsl-0.1.40.dist-info/METADATA +111 -0
  349. edsl-0.1.40.dist-info/RECORD +362 -0
  350. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
  351. edsl/agents/AgentListExportMixin.py +0 -24
  352. edsl/coop/old.py +0 -31
  353. edsl/data/Database.py +0 -141
  354. edsl/data/crud.py +0 -121
  355. edsl/jobs/Interview.py +0 -435
  356. edsl/jobs/JobsRunner.py +0 -63
  357. edsl/jobs/JobsRunnerStatusMixin.py +0 -115
  358. edsl/jobs/base.py +0 -47
  359. edsl/jobs/buckets.py +0 -178
  360. edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
  361. edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
  362. edsl/jobs/task_management.py +0 -215
  363. edsl/jobs/token_tracking.py +0 -78
  364. edsl/language_models/DeepInfra.py +0 -69
  365. edsl/language_models/OpenAI.py +0 -98
  366. edsl/language_models/model_interfaces/GeminiPro.py +0 -66
  367. edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
  368. edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
  369. edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
  370. edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
  371. edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
  372. edsl/language_models/registry.py +0 -81
  373. edsl/language_models/schemas.py +0 -15
  374. edsl/language_models/unused/ReplicateBase.py +0 -83
  375. edsl/prompts/QuestionInstructionsBase.py +0 -6
  376. edsl/prompts/library/agent_instructions.py +0 -29
  377. edsl/prompts/library/agent_persona.py +0 -17
  378. edsl/prompts/library/question_budget.py +0 -26
  379. edsl/prompts/library/question_checkbox.py +0 -32
  380. edsl/prompts/library/question_extract.py +0 -19
  381. edsl/prompts/library/question_freetext.py +0 -14
  382. edsl/prompts/library/question_linear_scale.py +0 -20
  383. edsl/prompts/library/question_list.py +0 -22
  384. edsl/prompts/library/question_multiple_choice.py +0 -44
  385. edsl/prompts/library/question_numerical.py +0 -31
  386. edsl/prompts/library/question_rank.py +0 -21
  387. edsl/prompts/prompt_config.py +0 -33
  388. edsl/prompts/registry.py +0 -185
  389. edsl/questions/Question.py +0 -240
  390. edsl/report/InputOutputDataTypes.py +0 -134
  391. edsl/report/RegressionMixin.py +0 -28
  392. edsl/report/ReportOutputs.py +0 -1228
  393. edsl/report/ResultsFetchMixin.py +0 -106
  394. edsl/report/ResultsOutputMixin.py +0 -14
  395. edsl/report/demo.ipynb +0 -645
  396. edsl/results/ResultsDBMixin.py +0 -184
  397. edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
  398. edsl/trackers/Tracker.py +0 -91
  399. edsl/trackers/TrackerAPI.py +0 -196
  400. edsl/trackers/TrackerTasks.py +0 -70
  401. edsl/utilities/pastebin.py +0 -141
  402. edsl-0.1.15.dist-info/METADATA +0 -69
  403. edsl-0.1.15.dist-info/RECORD +0 -142
  404. /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
  405. /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
  406. /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
  407. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -1,32 +0,0 @@
1
- import textwrap
2
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
3
-
4
-
5
- class CheckBox(QuestionInstuctionsBase):
6
- question_type = "checkbox"
7
- model = "gpt-4-1106-preview"
8
- default_instructions = textwrap.dedent(
9
- """\
10
- You are being asked the following question: {{question_text}}
11
- The options are
12
- {% for option in question_options %}
13
- {{ loop.index0 }}: {{option}}
14
- {% endfor %}
15
- Return a valid JSON formatted like this, selecting only the number of the option:
16
- {"answer": [<put comma-separated list of answer codes here>], "comment": "<put explanation here>"}
17
- {% if min_selections != None and max_selections != None and min_selections == max_selections %}
18
- You must select exactly {{min_selections}} options.
19
- {% elif min_selections != None and max_selections != None %}
20
- Minimum number of options that must be selected: {{min_selections}}.
21
- Maximum number of options that must be selected: {{max_selections}}.
22
- {% elif min_selections != None %}
23
- Minimum number of options that must be selected: {{min_selections}}.
24
- {% elif max_selections != None %}
25
- Maximum number of options that must be selected: {{max_selections}}.
26
- {% endif %}
27
- """
28
- )
29
-
30
-
31
- class TopK(CheckBox):
32
- question_type = "top_k"
@@ -1,19 +0,0 @@
1
- import textwrap
2
-
3
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
4
-
5
-
6
- class Extract(QuestionInstuctionsBase):
7
- question_type = "extract"
8
- model = "gpt-4-1106-preview"
9
- default_instructions = textwrap.dedent(
10
- """\
11
- You are given the following input: "{{question_text}}".
12
- Create an ANSWER should be formatted like this: "{{ answer_template }}",
13
- and it should have the same keys but values extracted from the input.
14
- If the value of a key is not present in the input, fill with "null".
15
- Return a valid JSON formatted like this:
16
- {"answer": <put your ANSWER here>}
17
- ONLY RETURN THE JSON, AND NOTHING ELSE.
18
- """
19
- )
@@ -1,14 +0,0 @@
1
- import textwrap
2
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
3
-
4
-
5
- class FreeText(QuestionInstuctionsBase):
6
- question_type = "free_text"
7
- model = "gpt-4-1106-preview"
8
- default_instructions = textwrap.dedent(
9
- """\
10
- You are being asked the following question: {{question_text}}
11
- Return a valid JSON formatted like this:
12
- {"answer": "<put free text answer here>"}
13
- """
14
- )
@@ -1,20 +0,0 @@
1
- import textwrap
2
-
3
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
4
-
5
-
6
- class LinearScale(QuestionInstuctionsBase):
7
- question_type = "linear_scale"
8
- model = "gpt-4-1106-preview"
9
- default_instructions = textwrap.dedent(
10
- """\
11
- You are being asked the following question: {{question_text}}
12
- The options are
13
- {% for option in question_options %}
14
- {{ loop.index0 }}: {{option}}
15
- {% endfor %}
16
- Return a valid JSON formatted like this, selecting only the code of the option (codes start at 0):
17
- {"answer": <put answer code here>, "comment": "<put explanation here>"}
18
- Only 1 option may be selected.
19
- """
20
- )
@@ -1,22 +0,0 @@
1
- import textwrap
2
-
3
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
4
-
5
-
6
- class ListQuestion(QuestionInstuctionsBase):
7
- question_type = "list"
8
- model = "gpt-4-1106-preview"
9
- default_instructions = textwrap.dedent(
10
- """\
11
- {{question_text}}
12
-
13
- Your response should be only a valid JSON in the following format:
14
- {
15
- "answer": [<comma-separated list of responsive words or phrases as independent strings>],
16
- "comment": "<put comment here>"
17
- }
18
- {% if max_list_items is not none %}
19
- The list must not contain more than {{ max_list_items }} items.
20
- {% endif %}
21
- """
22
- )
@@ -1,44 +0,0 @@
1
- import textwrap
2
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
3
-
4
-
5
- class MultipleChoiceTurbo(QuestionInstuctionsBase):
6
- question_type = "multiple_choice"
7
- model = "gpt-3.5-turbo"
8
- default_instructions = textwrap.dedent(
9
- """\
10
- You are being asked the following question: {{question_text}}
11
- The options are
12
- {% for option in question_options %}
13
- {{ loop.index0 }}: {{option}}
14
- {% endfor %}
15
- Return a valid JSON formatted like this, selecting only the number of the option:
16
- {"answer": <put answer code here>, "comment": "<put explanation here>"}
17
- Only 1 option may be selected.
18
- """
19
- )
20
-
21
-
22
- class MultipleChoice(QuestionInstuctionsBase):
23
- question_type = "multiple_choice"
24
- model = "gpt-4-1106-preview"
25
- default_instructions = textwrap.dedent(
26
- """\
27
- You are being asked the following question: {{question_text}}
28
- The options are
29
- {% for option in question_options %}
30
- {{ loop.index0 }}: {{option}}
31
- {% endfor %}
32
- Return a valid JSON formatted like this, selecting only the number of the option:
33
- {"answer": <put answer code here>, "comment": "<put explanation here>"}
34
- Only 1 option may be selected.
35
- """
36
- )
37
-
38
-
39
- class LikertFive(MultipleChoice):
40
- question_type = "likert_five"
41
-
42
-
43
- class YesNo(MultipleChoice):
44
- question_type = "yes_no"
@@ -1,31 +0,0 @@
1
- import textwrap
2
-
3
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
4
-
5
-
6
- class Numerical(QuestionInstuctionsBase):
7
- question_type = "numerical"
8
- model = "gpt-4-1106-preview"
9
- default_instructions = textwrap.dedent(
10
- """\
11
- You are being asked a question that requires a numerical response
12
- in the form of an integer or decimal (e.g., -12, 0, 1, 2, 3.45, ...).
13
- Your response must be in the following format:
14
- {"answer": "<your numerical answer here>", "comment": "<your explanation here"}
15
- You must only include an integer or decimal in the quoted "answer" part of your response.
16
- Here is an example of a valid response:
17
- {"answer": "100", "comment": "This is my explanation..."}
18
- Here is an example of a response that is invalid because the "answer" includes words:
19
- {"answer": "I don't know.", "comment": "This is my explanation..."}
20
- If your response is equivalent to zero, your formatted response should look like this:
21
- {"answer": "0", "comment": "This is my explanation..."}
22
-
23
- You are being asked the following question: {{question_text}}
24
- {% if min_value is not none %}
25
- Minimum answer value: {{min_value}}
26
- {% endif %}
27
- {% if max_value is not none %}
28
- Maximum answer value: {{max_value}}
29
- {% endif %}
30
- """
31
- )
@@ -1,21 +0,0 @@
1
- import textwrap
2
-
3
- from edsl.prompts.QuestionInstructionsBase import QuestionInstuctionsBase
4
-
5
-
6
- class Rank(QuestionInstuctionsBase):
7
- question_type = "rank"
8
- model = "gpt-4-1106-preview"
9
- default_instructions = textwrap.dedent(
10
- """\
11
- You are being asked the following question: {{question_text}}
12
- The options are
13
- {% for option in question_options %}
14
- {{ loop.index0 }}: {{option}}
15
- {% endfor %}
16
- Return a valid JSON formatted like this, selecting the numbers of the options in order of preference,
17
- with the most preferred option first, and the least preferred option last:
18
- {"answer": [<put comma-separated list of answer codes here>], "comment": "<put explanation here>"}
19
- Exactly {{num_selections}} options must be selected.
20
- """
21
- )
@@ -1,33 +0,0 @@
1
- from enum import Enum
2
-
3
- NEGATIVE_INFINITY = float("-inf")
4
-
5
-
6
- class AttributeTypes(Enum):
7
- COMPONENT_TYPE = "component_type"
8
- MODEL = "model"
9
- QUESTION_TYPE = "question_type"
10
-
11
-
12
- class ComponentTypes(Enum):
13
- """The types of attributes that a prompt can have"""
14
-
15
- TEST = "test"
16
- GENERIC = "generic"
17
- QUESTION_DATA = "question_data"
18
- QUESTION_INSTRUCTIONS = "question_instructions"
19
- AGENT_INSTRUCTIONS = "agent_instructions"
20
- AGENT_PERSONA = "agent_persona"
21
- SURVEY_INSTRUCTIONS = "survey_instructions"
22
- SURVEY_DATA = "survey_data"
23
-
24
-
25
- names_to_component_types = {v.value: v for k, v in ComponentTypes.__members__.items()}
26
-
27
- C2A = {
28
- ComponentTypes.QUESTION_INSTRUCTIONS: [
29
- AttributeTypes.QUESTION_TYPE,
30
- AttributeTypes.MODEL,
31
- ],
32
- ComponentTypes.AGENT_INSTRUCTIONS: [AttributeTypes.MODEL],
33
- }
edsl/prompts/registry.py DELETED
@@ -1,185 +0,0 @@
1
- import traceback
2
- from collections import defaultdict
3
- from typing import List, Any
4
-
5
- from abc import ABCMeta, abstractmethod
6
-
7
- from edsl.prompts.prompt_config import (
8
- C2A,
9
- names_to_component_types,
10
- ComponentTypes,
11
- NEGATIVE_INFINITY,
12
- )
13
-
14
- from edsl.enums import QuestionType, LanguageModelType
15
-
16
- from edsl.exceptions.prompts import (
17
- PromptBadQuestionTypeError,
18
- PromptBadLanguageModelTypeError,
19
- )
20
-
21
-
22
- class RegisterPromptsMeta(ABCMeta):
23
- "Metaclass to register prompts"
24
- _registry = defaultdict(list) # Initialize the registry as a dictionary
25
- _prompts_by_component_type = defaultdict(list)
26
- # _instances = {}
27
-
28
- # def __new__(mcs, name, bases, dct):
29
- # if mcs not in mcs._instances:
30
- # mcs._instances[mcs] = super(RegisterPromptsMeta, mcs).__new__(
31
- # mcs, name, bases, dct
32
- # )
33
- # return mcs._instances[mcs]
34
-
35
- def __init__(cls, name, bases, dct):
36
- """
37
- We can only have one prompt class per name.
38
- Each prompt class must have a component type from the ComponentTypes enum.
39
-
40
- >>> class Prompt1(PromptBase):
41
- ... component_type = ComponentTypes.TEST
42
-
43
- >>> class Prompt1(PromptBase):
44
- ... component_type = ComponentTypes.TEST
45
- Traceback (most recent call last):
46
- ...
47
- Exception: We already have a Prompt class named Prompt1.
48
- """
49
- super(RegisterPromptsMeta, cls).__init__(name, bases, dct)
50
- # print(f"Current state of registry: {RegisterPromptsMeta._registry}")
51
- # print(f"Registry called with {name}")
52
- if "Base" in name or name == "Prompt":
53
- # print("Exiting")
54
- return None # We don't want to register the base class
55
-
56
- if name in RegisterPromptsMeta._registry:
57
- if RegisterPromptsMeta._registry[name] != cls:
58
- raise Exception(f"We already have a Prompt class named {name}.")
59
- else:
60
- # print("It's the same thing - it's fine.")
61
- return None
62
-
63
- RegisterPromptsMeta._registry[name] = cls
64
- # print(f"Current registry: {RegisterPromptsMeta._registry}")
65
- if (
66
- component_type := getattr(cls, "component_type", None)
67
- ) not in ComponentTypes:
68
- raise Exception(f"Prompt {name} is not in the list of component types")
69
-
70
- ## Make sure that the prompt has a question_type class attribute & it's valid
71
- if component_type == ComponentTypes.QUESTION_INSTRUCTIONS:
72
- if not hasattr(cls, "question_type"):
73
- raise PromptBadQuestionTypeError(
74
- "A QuestionInstructions prompt must has a question_type value"
75
- )
76
- if not QuestionType.is_value_valid(cls.question_type):
77
- acceptable_values = [item.value for item in QuestionType]
78
- raise PromptBadQuestionTypeError(
79
- f"""
80
- A Prompt's question_type must be one of {QuestionType} values, which are
81
- currently {acceptable_values}. You passed {cls.question_type}."""
82
- )
83
-
84
- ## Make sure that if the prompt has a model class attribute, it's valid
85
- if hasattr(cls, "model"):
86
- if not LanguageModelType.is_value_valid(cls.model):
87
- acceptable_values = [item.value for item in LanguageModelType]
88
- raise PromptBadLanguageModelTypeError(
89
- f"""
90
- A Prompt's model must be one of {LanguageModelType} values, which are
91
- currently {acceptable_values}. You passed {cls.model}."""
92
- )
93
-
94
- key = cls._create_prompt_class_key(dct, component_type)
95
- cls.data = key
96
- RegisterPromptsMeta._prompts_by_component_type[component_type].append(cls)
97
-
98
- @classmethod
99
- def _create_prompt_class_key(cls, dct, component_type) -> tuple[tuple[str, Any]]:
100
- attributes = [attribute.value for attribute in C2A.get(component_type, [])]
101
- cls_data = {key: value for key, value in dct.items() if key in attributes}
102
- return tuple(cls_data.items())
103
-
104
- @classmethod
105
- def _get_classes_with_scores(cls, **kwargs) -> List[tuple[float, "PromptBase"]]:
106
- """
107
- This how we find matching prompts.
108
- NB that _get_classes_with_scores returns a list of tuples.
109
- The first element of the tuple is the score, and the second element is the prompt class.
110
- There is a public-facing function called get_classes that returns only the prompt classes.
111
-
112
- The kwargs are the attributes that we want to match on. E.g., supposed you
113
- wanted a prompt with component_type = "question_instructions" and question_type = "multiple_choice".
114
- You would run:
115
-
116
- >>> get_classes(component_type="question_instructions", question_type="multiple_choice", model="gpt-4-1106-preview")
117
- [<class '__main__.MultipleChoice'>, <class '__main__.MultipleChoiceTurbo'>]
118
-
119
- In the above example, we have two prompts that match. Note that the order of the prompts is determined by the score and the regular MultipleChoice
120
- is ranked higher because it matches on the model as well.
121
-
122
- Scores are computed by the _score method. The score is the number of attributes that match, with their weights.
123
- However, if a required attribute doesn't match, then the score is -inf and it can never be selected.
124
-
125
- The function will throw an exception if you don't specify a component type that's in the ComponentTypes enum.
126
-
127
- >>> get_classes(component_type="chicken_tenders", question_type="multiple_choice")
128
- Traceback (most recent call last):
129
- ...
130
- Exception: You must specify a component type. It must be one of dict_keys([...])
131
-
132
- >>> get_classes(component_type="generic")
133
- []
134
- """
135
- component_type_string = kwargs.get("component_type", None)
136
- component_type = names_to_component_types.get(component_type_string, None)
137
-
138
- if component_type is None:
139
- raise Exception(
140
- f"You must specify a component type. It must be one of {names_to_component_types.keys()}"
141
- )
142
-
143
- try:
144
- prompts = cls._prompts_by_component_type[component_type]
145
- except KeyError:
146
- raise Exception(f"No prompts for component type {component_type}")
147
-
148
- with_scores = [(cls._score(kwargs, prompt), prompt) for prompt in prompts]
149
- with_scores = sorted(with_scores, key=lambda x: -x[0])
150
- # filter out the ones with -inf
151
- matches_with_scores = cls._filter_out_non_matches(with_scores)
152
- return matches_with_scores
153
-
154
- @classmethod
155
- def _filter_out_non_matches(cls, prompts_with_scores):
156
- return [
157
- (score, prompt)
158
- for score, prompt in prompts_with_scores
159
- if score > NEGATIVE_INFINITY
160
- ]
161
-
162
- @classmethod
163
- def get_classes(cls, **kwargs):
164
- "Public-facing function that returns only the prompt classes and not the scores."
165
- with_scores = cls._get_classes_with_scores(**kwargs)
166
- return [prompt for _, prompt in with_scores]
167
-
168
- @classmethod
169
- def _score(cls, kwargs, prompt):
170
- required_list = ["question_type"]
171
- score = 0
172
- for key, value in kwargs.items():
173
- if prompt_value := getattr(prompt, key, None) == value:
174
- score += 1
175
- else:
176
- if key in required_list:
177
- score += NEGATIVE_INFINITY
178
- return score
179
-
180
- @classmethod
181
- def get_registered_classes(cls):
182
- return cls._registry
183
-
184
-
185
- get_classes = RegisterPromptsMeta.get_classes
@@ -1,240 +0,0 @@
1
- from __future__ import annotations
2
- import textwrap
3
- import io
4
- from abc import ABC, abstractmethod, ABCMeta
5
- from rich.console import Console
6
- from rich.table import Table
7
- from jinja2 import Template, Environment, meta
8
- from typing import Any, Type
9
- from edsl.exceptions import (
10
- QuestionResponseValidationError,
11
- QuestionSerializationError,
12
- QuestionScenarioRenderError,
13
- )
14
- from edsl.questions.descriptors import (
15
- InstructionsDescriptor,
16
- QuestionNameDescriptor,
17
- QuestionTextDescriptor,
18
- ShortNamesDictDescriptor,
19
- )
20
-
21
- from edsl.prompts.Prompt import Prompt
22
-
23
- from edsl.enums import QuestionType
24
-
25
- # from edsl.questions.question_registry import get_question_class
26
- from edsl.questions.AnswerValidatorMixin import AnswerValidatorMixin
27
-
28
- from edsl.exceptions.questions import QuestionMissingTypeError, QuestionBadTypeError
29
-
30
-
31
- class RegisterQuestionsMeta(ABCMeta):
32
- "Metaclass to register output elements in a registry i.e., those that have a parent"
33
- _registry = {} # Initialize the registry as a dictionary
34
-
35
- def __init__(cls, name, bases, dct):
36
- super(RegisterQuestionsMeta, cls).__init__(name, bases, dct)
37
- if name != "Question":
38
- ## Enforce that all questions have a question_type class attribute
39
- ## and it comes from our enum of valid question types.
40
- if not hasattr(cls, "question_type"):
41
- raise QuestionMissingTypeError(
42
- "Question must have a question_type class attribute"
43
- )
44
-
45
- if not QuestionType.is_value_valid(cls.question_type):
46
- acceptable_values = [item.value for item in QuestionType]
47
- raise QuestionBadTypeError(
48
- f"""question_type must be one of {QuestionType} values, which are
49
- currently {acceptable_values}"""
50
- ""
51
- )
52
-
53
- RegisterQuestionsMeta._registry[name] = cls
54
-
55
- @classmethod
56
- def get_registered_classes(cls):
57
- return cls._registry
58
-
59
- @classmethod
60
- def question_types_to_classes(
61
- cls,
62
- ):
63
- d = {}
64
- for classname, cls in cls._registry.items():
65
- if hasattr(cls, "question_type"):
66
- d[cls.question_type] = cls
67
- else:
68
- raise Exception(
69
- f"Class {classname} does not have a question_type class attribute"
70
- )
71
- return d
72
-
73
-
74
- from edsl.Base import PersistenceMixin, RichPrintingMixin
75
-
76
-
77
- class Question(
78
- PersistenceMixin,
79
- RichPrintingMixin,
80
- ABC,
81
- AnswerValidatorMixin,
82
- metaclass=RegisterQuestionsMeta,
83
- ):
84
- """
85
- ABC for the Question class. All questions should inherit from this class.
86
- """
87
-
88
- question_name: str = QuestionNameDescriptor()
89
- question_text: str = QuestionTextDescriptor()
90
- short_names_dict: dict[str, str] = ShortNamesDictDescriptor()
91
-
92
- @property
93
- def data(self) -> dict:
94
- """Returns a dictionary of question attributes **except** for question_type"""
95
- candidate_data = {
96
- k.replace("_", "", 1): v
97
- for k, v in self.__dict__.items()
98
- if k.startswith("_")
99
- }
100
- optional_attributes = {
101
- "set_instructions": "instructions",
102
- }
103
- for boolean_flag, attribute in optional_attributes.items():
104
- if hasattr(self, boolean_flag) and not getattr(self, boolean_flag):
105
- candidate_data.pop(attribute, None)
106
-
107
- return candidate_data
108
-
109
- ############################
110
- # Serialization methods
111
- ############################
112
- def to_dict(self) -> dict[str, Any]:
113
- """Converts the question to a dictionary that includes the question type (used in deserialization)."""
114
- candidate_data = self.data.copy()
115
- candidate_data["question_type"] = self.question_type
116
- return candidate_data
117
-
118
- @classmethod
119
- def from_dict(cls, data: dict) -> Type[Question]:
120
- """Constructs a question object from a dictionary created by that question's `to_dict` method."""
121
- local_data = data.copy()
122
- try:
123
- question_type = local_data.pop("question_type")
124
- except:
125
- raise QuestionSerializationError(
126
- f"Data does not have a 'question_type' field (got {data})."
127
- )
128
- from edsl.questions.question_registry import get_question_class
129
-
130
- try:
131
- question_class = get_question_class(question_type)
132
- except ValueError:
133
- raise QuestionSerializationError(
134
- f"No question registered with question_type {question_type}"
135
- )
136
- return question_class(**local_data)
137
-
138
- ############################
139
- # Dunder methods
140
- ############################
141
- def __repr__(self) -> str:
142
- """Returns a string representation of the question. Should be able to be used to reconstruct the question."""
143
- class_name = self.__class__.__name__
144
- items = [
145
- f"{k} = '{v}'" if isinstance(v, str) else f"{k} = {v}"
146
- for k, v in self.data.items()
147
- if k != "question_type"
148
- ]
149
- return f"{class_name}({', '.join(items)})"
150
-
151
- def __eq__(self, other: Type[Question]) -> bool:
152
- """Checks if two questions are equal. Equality is defined as having the .to_dict()"""
153
- if not isinstance(other, Question):
154
- return False
155
- return self.to_dict() == other.to_dict()
156
-
157
- # TODO: Throws an error that should be addressed at QuestionFunctional
158
- def __add__(self, other_question):
159
- """
160
- Composes two questions into a single question.
161
- >>> from edsl.scenarios.Scenario import Scenario
162
- >>> from edsl.questions.QuestionFreeText import QuestionFreeText
163
- >>> from edsl.questions.QuestionNumerical import QuestionNumerical
164
- >>> q1 = QuestionFreeText(question_text = "What is the capital of {{country}}", question_name = "capital")
165
- >>> q2 = QuestionNumerical(question_text = "What is the population of {{capital}}, in millions. Please round", question_name = "population")
166
- >>> q3 = q1 + q2
167
- """
168
- from edsl.questions import compose_questions
169
-
170
- return compose_questions(self, other_question)
171
-
172
- @abstractmethod
173
- def validate_answer(self, answer: dict[str, str]):
174
- pass
175
-
176
- def validate_response(self, response):
177
- """Validates the response from the LLM"""
178
- if "answer" not in response:
179
- raise QuestionResponseValidationError(
180
- "Response from LLM does not have an answer"
181
- )
182
- return response
183
-
184
- @abstractmethod
185
- def translate_answer_code_to_answer(self): # pragma: no cover
186
- """Translates the answer code to the actual answer. Behavior depends on the question type."""
187
- pass
188
-
189
- @abstractmethod
190
- def simulate_answer(self, human_readable=True) -> dict: # pragma: no cover
191
- """Simulates a valid answer for debugging purposes (what the validator expects)"""
192
- pass
193
-
194
- ############################
195
- # Forward methods
196
- ############################
197
- def add_question(self, other):
198
- "Adds a question to this question by turning them into a survey with two questions"
199
- from edsl.surveys.Survey import Survey
200
-
201
- s = Survey([self, other])
202
- return s
203
-
204
- def run(self, *args, **kwargs):
205
- "Turns a single question into a survey and runs it."
206
- from edsl.surveys.Survey import Survey
207
-
208
- s = Survey([self])
209
- return s.run(*args, **kwargs)
210
-
211
- def by(self, *args):
212
- "Documentation missing."
213
- from edsl.surveys.Survey import Survey
214
-
215
- s = Survey([self])
216
- return s.by(*args)
217
-
218
- def rich_print(self):
219
- table = Table(show_header=True, header_style="bold magenta")
220
- table.add_column("Question Name", style="dim")
221
- table.add_column("Question Type")
222
- table.add_column("Question Text")
223
- table.add_column("Options")
224
-
225
- question = self
226
- if hasattr(question, "question_options"):
227
- options = ", ".join([str(o) for o in question.question_options])
228
- else:
229
- options = "None"
230
- table.add_row(
231
- question.question_name,
232
- question.question_type,
233
- question.question_text,
234
- options,
235
- )
236
- return table
237
-
238
-
239
- if __name__ == "__main__":
240
- q = get_question_class("free_text")