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.
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 +46 -10
  5. edsl/__version__.py +1 -0
  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 +121 -104
  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 -204
  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.14.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 -417
  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 -166
  360. edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
  361. edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
  362. edsl/jobs/task_management.py +0 -218
  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.14.dist-info/METADATA +0 -69
  403. edsl-0.1.14.dist-info/RECORD +0 -141
  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.14.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -1,40 +1,187 @@
1
1
  from __future__ import annotations
2
2
  import random
3
- import textwrap
4
- from jinja2 import Template
5
3
  from typing import Any, Optional, Union
6
- from edsl.questions import Question
4
+
5
+ from jinja2 import Template
6
+
7
+ from edsl.questions.QuestionBase import QuestionBase
7
8
  from edsl.questions.descriptors import (
8
9
  IntegerDescriptor,
9
10
  QuestionOptionsDescriptor,
10
11
  )
11
- from edsl.scenarios import Scenario
12
- from edsl.utilities import random_string
13
12
 
13
+ from edsl.questions.decorators import inject_exception
14
14
 
15
- class QuestionCheckBox(Question):
16
- """
17
- This question asks the user to select options from a list.
15
+ from pydantic import field_validator
16
+ from edsl.questions.response_validator_abc import ResponseValidatorABC
17
+ from edsl.questions.data_structures import BaseResponse
18
+
19
+ from edsl.exceptions.questions import QuestionAnswerValidationError
18
20
 
19
- Arguments:
20
- - `question_name` is the name of the question (string)
21
- - `question_options` are the options the user should select from (list of strings)
22
- - `question_text` is the text of the question (string)
21
+ from pydantic import BaseModel, Field, conlist
22
+ from typing import List, Literal, Optional, Annotated
23
23
 
24
- Optional arguments:
25
- - `min_selections` is the minimum number of options that must be selected (positive integer)
26
- - `max_selections` is the maximum number of options that must be selected (positive integer)
27
- - `instructions` are the instructions for the question (string). If not provided, the default instructions are used. To view them, run `QuestionCheckBox.default_instructions`
28
- - `short_names_dict` maps question_options to short names (dictionary mapping strings to strings)
29
24
 
30
- For an example, run `QuestionCheckBox.example()`
25
+ def create_checkbox_response_model(
26
+ choices: list,
27
+ min_selections: Optional[int] = None,
28
+ max_selections: Optional[int] = None,
29
+ permissive: bool = False,
30
+ ):
31
31
  """
32
+ Dynamically create a CheckboxResponse model with a predefined list of choices.
33
+
34
+ :param choices: A list of allowed values for the answer field.
35
+ :param include_comment: Whether to include a comment field in the model.
36
+ :return: A new Pydantic model class.
37
+ """
38
+ # Convert the choices list to a tuple for use with Literal
39
+ choice_tuple = tuple(choices)
40
+
41
+ field_params = {}
42
+ if min_selections is not None and not permissive:
43
+ field_params["min_items"] = min_selections
44
+ if max_selections is not None and not permissive:
45
+ field_params["max_items"] = max_selections
46
+
47
+ class CheckboxResponse(BaseModel):
48
+ answer: Annotated[
49
+ List[Literal[choice_tuple]],
50
+ Field(..., **field_params),
51
+ ] = Field(..., description="List of selected choices")
52
+ comment: Optional[str] = Field(None, description="Optional comment field")
53
+ generated_tokens: Optional[Any] = Field(default=None)
54
+
55
+ class Config:
56
+ @staticmethod
57
+ def json_schema_extra(schema: dict, model: BaseModel) -> None:
58
+ # Add the list of choices to the schema for better documentation
59
+ for prop in schema.get("properties", {}).values():
60
+ if prop.get("title") == "answer":
61
+ prop["items"] = {"enum": choices}
62
+
63
+ return CheckboxResponse
64
+
65
+
66
+ class CheckBoxResponseValidator(ResponseValidatorABC):
67
+ required_params = [
68
+ "question_options",
69
+ "min_selections",
70
+ "max_selections",
71
+ "use_code",
72
+ "permissive",
73
+ ]
74
+
75
+ valid_examples = [
76
+ ({"answer": [1, 2]}, {"question_options": ["Good", "Great", "OK", "Bad"]})
77
+ ]
78
+
79
+ invalid_examples = [
80
+ (
81
+ {"answer": [-1]},
82
+ {"question_options": ["Good", "Great", "OK", "Bad"]},
83
+ "Answer code must be a non-negative integer",
84
+ ),
85
+ (
86
+ {"answer": 1},
87
+ {"question_options": ["Good", "Great", "OK", "Bad"]},
88
+ "Answer code must be a list",
89
+ ),
90
+ (
91
+ {"answer": [1, 2, 3, 4]},
92
+ {
93
+ "question_options": ["Good", "Great", "OK", "Bad"],
94
+ "min_selections": 1,
95
+ "max_selections": 2,
96
+ },
97
+ "Too many options selected",
98
+ ),
99
+ ]
100
+
101
+ def fix(self, response, verbose=False):
102
+ if verbose:
103
+ print("Invalid response of QuestionCheckBox was: ", response)
104
+ response_text = response.get("generated_tokens")
105
+ if response_text is None or response_text == "": # nothing to be done
106
+ return response
107
+ # Maybe it's a comma separated list?
108
+ proposed_list = response_text.split(",")
109
+ proposed_list = [item.strip() for item in proposed_list]
110
+ if verbose:
111
+ print("Using code? ", self.use_code)
112
+ if self.use_code:
113
+ try:
114
+ proposed_list = [int(i) for i in proposed_list]
115
+ except ValueError:
116
+ # print("Could not convert to int")
117
+ pass
118
+
119
+ if verbose:
120
+ print("Proposed solution is: ", proposed_list)
121
+
122
+ # print(f"Ivalid generated tokens was was: {response_text}")
123
+ if "comment" in response:
124
+ proposed_data = {
125
+ "answer": proposed_list,
126
+ "comment": response["comment"],
127
+ "generated_tokens": response.get("generated_tokens", None),
128
+ }
129
+ else:
130
+ proposed_data = {
131
+ "answer": proposed_list,
132
+ "generated_tokens": response.get("generated_tokens", None),
133
+ }
134
+
135
+ try:
136
+ self.response_model(**proposed_data)
137
+ print("Proposed solution is valid")
138
+ print("Returning proposed data: ", proposed_data)
139
+ return proposed_data
140
+ except Exception as e:
141
+ if verbose:
142
+ print(f"Proposed solution {proposed_data} is invalid. Error: {e}")
143
+ # return response
144
+ if verbose:
145
+ print("Now seeing if responses show up in the answer")
146
+ matches = []
147
+ for index, option in enumerate(self.question_options):
148
+ if self.use_code:
149
+ if str(index) in response_text:
150
+ matches.append(index)
151
+ else:
152
+ if option in response_text:
153
+ matches.append(index)
154
+ proposed_data = {
155
+ "answer": matches,
156
+ "comment": response.get("comment", None),
157
+ "generated_tokens": response.get("generated_tokens", None),
158
+ }
159
+ try:
160
+ self.response_model(**proposed_data)
161
+ return proposed_data
162
+ except Exception as e:
163
+ if verbose:
164
+ print(f"Proposed solution {proposed_data} is invalid. Error: {e}")
165
+ return response
166
+
167
+ def custom_validate(self, response) -> BaseResponse:
168
+ if response.answer is None:
169
+ raise QuestionAnswerValidationError("Answer is missing.")
170
+ return response.dict()
171
+
172
+
173
+ class QuestionCheckBox(QuestionBase):
174
+ """This question prompts the agent to select options from a list."""
32
175
 
33
176
  question_type = "checkbox"
177
+ purpose = "When options are known and limited"
34
178
  question_options: list[str] = QuestionOptionsDescriptor()
35
179
  min_selections = IntegerDescriptor(none_allowed=True)
36
180
  max_selections = IntegerDescriptor(none_allowed=True)
37
181
 
182
+ _response_model = None
183
+ response_validator_class = CheckBoxResponseValidator
184
+
38
185
  def __init__(
39
186
  self,
40
187
  question_name: str,
@@ -42,68 +189,128 @@ class QuestionCheckBox(Question):
42
189
  question_options: list[str],
43
190
  min_selections: Optional[int] = None,
44
191
  max_selections: Optional[int] = None,
45
- short_names_dict: Optional[dict[str, str]] = None,
192
+ include_comment: bool = True,
193
+ use_code: bool = True,
194
+ question_presentation: Optional[str] = None,
195
+ answering_instructions: Optional[str] = None,
196
+ permissive: bool = False,
46
197
  ):
198
+ """Instantiate a new QuestionCheckBox.
199
+
200
+ :param question_name: The name of the question.
201
+ :param question_text: The text of the question.
202
+ :param question_options: The options the respondent should select from.
203
+ :param min_selections: The minimum number of options that must be selected.
204
+ :param max_selections: The maximum number of options that must be selected.
205
+ """
47
206
  self.question_name = question_name
48
207
  self.question_text = question_text
49
208
  self.min_selections = min_selections
50
209
  self.max_selections = max_selections
51
210
  self.question_options = question_options
52
- self.short_names_dict = short_names_dict or dict()
53
211
 
54
- ################
55
- # Answer methods
56
- ################
57
- def validate_answer(self, answer: Any) -> dict[str, Union[int, str]]:
58
- self.validate_answer_template_basic(answer)
59
- self.validate_answer_key_value(answer, "answer", list)
60
- self.validate_answer_checkbox(answer)
61
- return answer
212
+ self._include_comment = include_comment
213
+ self._use_code = use_code
214
+ self.permissive = permissive
215
+
216
+ self.question_presentation = question_presentation
217
+ self.answering_instructions = answering_instructions
62
218
 
63
- def translate_answer_code_to_answer(self, answer_codes, scenario: Scenario = None):
219
+ def create_response_model(self):
220
+ if not self._use_code:
221
+ return create_checkbox_response_model(
222
+ self.question_options,
223
+ min_selections=self.min_selections,
224
+ max_selections=self.max_selections, # include_comment=self._include_comment
225
+ permissive=self.permissive,
226
+ )
227
+ else:
228
+ return create_checkbox_response_model(
229
+ list(range(len(self.question_options))),
230
+ min_selections=self.min_selections,
231
+ max_selections=self.max_selections, # include_comment=self._include_comment
232
+ permissive=self.permissive,
233
+ )
234
+
235
+ def _translate_answer_code_to_answer(
236
+ self, answer_codes, scenario: "Scenario" = None
237
+ ):
64
238
  """
65
- Translates the answer code to the actual answer.
239
+ Translate the answer code to the actual answer.
240
+
66
241
  For example, for question options ["a", "b", "c"],the answer codes are 0, 1, and 2.
67
242
  The LLM will respond with [0,1] and this code will translate it to ["a","b"].
68
243
  """
244
+ from edsl.scenarios.Scenario import Scenario
245
+
69
246
  scenario = scenario or Scenario()
70
247
  translated_options = [
71
- Template(option).render(scenario) for option in self.question_options
248
+ Template(str(option)).render(scenario) for option in self.question_options
72
249
  ]
73
250
  translated_codes = []
74
251
  for answer_code in answer_codes:
75
- translated_codes.append(translated_options[int(answer_code)])
252
+ if self._use_code:
253
+ translated_codes.append(translated_options[int(answer_code)])
254
+ else:
255
+ translated_codes.append(answer_code)
76
256
  return translated_codes
77
257
 
78
- def simulate_answer(self, human_readable=True) -> dict[str, Union[int, str]]:
79
- """Simulates a valid answer for debugging purposes"""
80
-
81
- min_selections = self.min_selections or 1
82
- max_selections = self.max_selections or len(self.question_options)
83
- num_selections = random.randint(min_selections, max_selections)
84
- if human_readable:
85
- # Select a random number of options from self.question_options
86
- selected_options = random.sample(self.question_options, num_selections)
87
- answer = {
88
- "answer": selected_options,
89
- "comment": random_string(),
90
- }
91
- else:
92
- # Select a random number of indices from the range of self.question_options
93
- selected_indices = random.sample(
94
- range(len(self.question_options)), num_selections
95
- )
96
- answer = {
97
- "answer": selected_indices,
98
- "comment": random_string(),
99
- }
100
- return answer
258
+ # def _simulate_answer(self, human_readable=True) -> dict[str, Union[int, str]]:
259
+ # """Simulate a valid answer for debugging purposes."""
260
+ # from edsl.utilities.utilities import random_string
261
+
262
+ # min_selections = self.min_selections or 1
263
+ # max_selections = self.max_selections or len(self.question_options)
264
+ # num_selections = random.randint(min_selections, max_selections)
265
+ # if human_readable:
266
+ # # Select a random number of options from self.question_options
267
+ # selected_options = random.sample(self.question_options, num_selections)
268
+ # answer = {
269
+ # "answer": selected_options,
270
+ # "comment": random_string(),
271
+ # }
272
+ # else:
273
+ # # Select a random number of indices from the range of self.question_options
274
+ # selected_indices = random.sample(
275
+ # range(len(self.question_options)), num_selections
276
+ # )
277
+ # answer = {
278
+ # "answer": selected_indices,
279
+ # "comment": random_string(),
280
+ # }
281
+ # return answer
282
+
283
+ @property
284
+ def question_html_content(self) -> str:
285
+ instructions = ""
286
+ if self.min_selections is not None:
287
+ instructions += f"Select at least {self.min_selections} option(s). "
288
+ if self.max_selections is not None:
289
+ instructions += f"Select at most {self.max_selections} option(s)."
290
+ question_html_content = Template(
291
+ """
292
+ <p>{{ instructions }}</p>
293
+ {% for option in question_options %}
294
+ <div>
295
+ <input type="checkbox" id="{{ option }}" name="{{ question_name }}" value="{{ option }}">
296
+ <label for="{{ option }}">{{ option }}</label>
297
+ </div>
298
+ {% endfor %}
299
+ """
300
+ ).render(
301
+ instructions=instructions,
302
+ question_name=self.question_name,
303
+ question_options=self.question_options,
304
+ )
305
+ return question_html_content
101
306
 
102
307
  ################
103
308
  # Helpful methods
104
309
  ################
105
310
  @classmethod
106
- def example(cls) -> QuestionCheckBox:
311
+ @inject_exception
312
+ def example(cls, include_comment=False, use_code=True) -> QuestionCheckBox:
313
+ """Return an example checkbox question."""
107
314
  return cls(
108
315
  question_name="never_eat",
109
316
  question_text="Which of the following foods would you eat if you had to?",
@@ -116,25 +323,37 @@ class QuestionCheckBox(Question):
116
323
  ],
117
324
  min_selections=2,
118
325
  max_selections=5,
326
+ use_code=use_code,
327
+ include_comment=include_comment,
119
328
  )
120
329
 
121
330
 
122
331
  def main():
332
+ """Create an example QuestionCheckBox and test its methods."""
123
333
  from edsl.questions.QuestionCheckBox import QuestionCheckBox
124
334
 
125
335
  q = QuestionCheckBox.example()
126
336
  q.question_text
127
337
  q.question_options
128
338
  q.question_name
129
- q.short_names_dict
130
339
  # validate an answer
131
- q.validate_answer({"answer": [1, 2], "comment": "I like custard"})
340
+ q._validate_answer({"answer": [1, 2], "comment": "I like custard"})
132
341
  # translate answer code
133
- q.translate_answer_code_to_answer([1, 2])
342
+ q._translate_answer_code_to_answer([1, 2])
134
343
  # simulate answer
135
- q.simulate_answer()
136
- q.simulate_answer(human_readable=False)
137
- q.validate_answer(q.simulate_answer(human_readable=False))
344
+ q._simulate_answer()
345
+ q._simulate_answer(human_readable=False)
346
+ q._validate_answer(q._simulate_answer(human_readable=False))
138
347
  # serialization (inherits from Question)
139
348
  q.to_dict()
140
349
  assert q.from_dict(q.to_dict()) == q
350
+
351
+ import doctest
352
+
353
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
354
+
355
+
356
+ if __name__ == "__main__":
357
+ import doctest
358
+
359
+ doctest.testmod(optionflags=doctest.ELLIPSIS)