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
edsl/prompts/Prompt.py CHANGED
@@ -1,52 +1,110 @@
1
- import textwrap
2
- from abc import ABC
3
- from typing import Any, List
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 rich.console import Console
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.prompts.prompt_config import (
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 PromptBase(
26
- PersistenceMixin, RichPrintingMixin, ABC, metaclass=RegisterPromptsMeta
27
- ):
28
- component_type = ComponentTypes.GENERIC
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
- def __init__(self, text=None):
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='Hello, {{person}}How are you?')
104
+ Prompt(text=\"""Hello, {{person}}How are you?\""")
105
+
48
106
  >>> p + "How are you?"
49
- Prompt(text='Hello, {{person}}How are you?')
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='Hello, {{person}}')
143
+ Prompt(text=\"""Hello, {{person}}\""")
79
144
  """
80
- return f"Prompt(text='{self.text}')"
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
- env = Environment()
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, replcement_dict):
100
- return [var for var in self.template_variables() if var not in replcement_dict]
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
- """Renders the prompt with the replacements
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
- 'Hello, John'
221
+ Prompt(text=\"""Hello, John\""")
222
+
123
223
  >>> p.render({"person": "Mr. {{last_name}}", "last_name": "Horton"})
124
- 'Hello, Mr. Horton'
224
+ Prompt(text=\"""Hello, Mr. Horton\""")
225
+
125
226
  >>> p.render({"person": "Mr. {{last_name}}", "last_name": "Ho{{letter}}ton"}, max_nesting = 1)
126
- 'Hello, Mr. Horton'
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
- new_text = self._render(
129
- self.text, primary_replacement, **additional_replacements
130
- )
131
- return self.__class__(text=new_text)
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(text, primary_replacement, **additional_replacements) -> "PromptBase":
135
- """
136
- Renders the template text with variables replaced from the provided named dictionaries.
137
- Allows for nested variable resolution up to a specified maximum nesting depth.
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
- 'You are an agent named John. Age: 44'
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
- rendered_text = Template(text).render(
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(f"Template syntax error: {e}")
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='Hello, {{person}}')
310
+ Prompt(text=\"""Hello, {{person}}\""")
311
+
179
312
  """
180
- class_name = data["class_name"]
181
- cls = RegisterPromptsMeta._registry.get(class_name, Prompt)
182
- return cls(text=data["text"])
183
-
184
- def rich_print(self):
185
- """Displays an object as a table."""
186
- table = Table(title="Prompt")
187
- table.add_column("Attribute", style="bold")
188
- table.add_column("Value")
189
-
190
- to_display = self.__dict__.copy()
191
- for attr_name, attr_value in to_display.items():
192
- table.add_row(attr_name, repr(attr_value))
193
- table.add_row("Component type", str(self.component_type))
194
- table.add_row("Model", str(getattr(self, "model", "Not specified")))
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