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
edsl/data/crud.py DELETED
@@ -1,121 +0,0 @@
1
- from sqlalchemy import desc
2
- from typing import Union
3
- from edsl.data import Database, database, LLMOutputDataDB
4
- from edsl.data.orm import ResultDB
5
-
6
-
7
- class CRUDOperations:
8
- """
9
- A class that implementes CRUD operations for the EDSL package.
10
-
11
- Initalization:
12
- - `database`: A Database object.
13
-
14
- Methods:
15
- - `get_LLMOutputData(model, parameters, system_prompt, prompt)`: Retrieves a cached LLM output from the database.
16
- - `write_LLMOutputData(model, parameters, system_prompt, prompt, output)`: Writes an LLM output to the database.
17
- """
18
-
19
- def __init__(self, database: Database) -> None:
20
- self.database = database
21
-
22
- def get_LLMOutputData(
23
- self, model: str, parameters: str, system_prompt: str, prompt: str
24
- ) -> Union[str, None]:
25
- """
26
- Retrieves a cached LLM output from the database. Arguments: in string format, the model, parameters, system_prompt, and prompt used to generate the output. Returns the output (json string) if it exists, otherwise None.
27
- """
28
- with self.database.get_db() as db:
29
- record = (
30
- db.query(LLMOutputDataDB)
31
- .filter_by(
32
- prompt=prompt,
33
- system_prompt=system_prompt,
34
- model=model,
35
- parameters=parameters,
36
- )
37
- .order_by(desc(LLMOutputDataDB.id))
38
- .first()
39
- )
40
- return record.output if record else None
41
-
42
- def write_LLMOutputData(
43
- self, model: str, parameters: str, system_prompt: str, prompt: str, output: str
44
- ) -> None:
45
- """
46
- Writes an LLM output to the database. Arguments: in string format, the model, parameters, system_prompt, prompt, and the generated output.
47
- """
48
- record = LLMOutputDataDB(
49
- model=model,
50
- parameters=parameters,
51
- system_prompt=system_prompt,
52
- prompt=prompt,
53
- output=output,
54
- )
55
-
56
- with self.database.get_db() as db:
57
- db.add(record)
58
- db.commit()
59
-
60
- def clear_LLMOutputData(self) -> None:
61
- """
62
- Clears all LLM output data from the database.
63
- """
64
- with self.database.get_db() as db:
65
- db.query(LLMOutputDataDB).delete()
66
- db.commit()
67
-
68
- def get_all_LLMOutputData(self) -> list:
69
- """
70
- Retrieves all LLM output data from the database and returns them as a list of dictionaries.
71
- """
72
- with self.database.get_db() as db:
73
- records = db.query(LLMOutputDataDB).all()
74
- return [
75
- {
76
- "id": record.id,
77
- "model": record.model,
78
- "parameters": record.parameters,
79
- "system_prompt": record.system_prompt,
80
- "prompt": record.prompt,
81
- "output": record.output,
82
- }
83
- for record in records
84
- ]
85
-
86
- def write_result(
87
- self,
88
- job_uuid: str,
89
- result_uuid: str,
90
- agent: str,
91
- scenario: str,
92
- model: str,
93
- answer: str,
94
- ) -> None:
95
- """Writes a Result record to the database."""
96
- record = ResultDB(
97
- job_uuid=job_uuid,
98
- result_uuid=result_uuid,
99
- agent=agent,
100
- scenario=scenario,
101
- model=model,
102
- answer=answer,
103
- )
104
-
105
- with self.database.get_db() as db:
106
- db.add(record)
107
- db.commit()
108
-
109
- def read_results(self, job_uuid: str) -> list[ResultDB]:
110
- """Reads all Result records associated with job_uuid from the database."""
111
- with self.database.get_db() as db:
112
- records = (
113
- db.query(ResultDB)
114
- .filter_by(job_uuid=job_uuid)
115
- .order_by(desc(ResultDB.id))
116
- .all()
117
- )
118
- return records
119
-
120
-
121
- CRUD = CRUDOperations(database)
edsl/jobs/Interview.py DELETED
@@ -1,417 +0,0 @@
1
- from __future__ import annotations
2
- import asyncio
3
- import logging
4
- import textwrap
5
- from collections import UserList
6
- from typing import Any, Type, List, Generator, Callable, List
7
- from collections import defaultdict
8
-
9
- from edsl import CONFIG
10
- from edsl.agents import Agent
11
- from edsl.exceptions import InterviewErrorPriorTaskCanceled, InterviewTimeoutError
12
- from edsl.language_models import LanguageModel
13
- from edsl.questions import Question
14
- from edsl.scenarios import Scenario
15
- from edsl.surveys import Survey
16
- from edsl.utilities.decorators import sync_wrapper
17
- from edsl.data_transfer_models import AgentResponseDict
18
- from edsl.jobs.Answers import Answers
19
-
20
- from edsl.surveys.base import EndOfSurvey
21
-
22
- from edsl.jobs.buckets import ModelBuckets
23
- from edsl.jobs.token_tracking import TokenUsage, InterviewTokenUsage
24
-
25
- from edsl.jobs.task_management import (
26
- InterviewStatusDictionary,
27
- QuestionTaskCreator,
28
- TasksList,
29
- )
30
-
31
- import traceback
32
-
33
- # create logger
34
- logger = logging.getLogger(__name__)
35
- logger.setLevel(logging.INFO)
36
- logger.propagate = False
37
- # create file handler
38
- fh = logging.FileHandler(CONFIG.get("EDSL_LOGGING_PATH"))
39
- fh.setLevel(logging.INFO)
40
- # add formatter to the handlers
41
- formatter = logging.Formatter(
42
- "%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(funcName)s - %(message)s"
43
- )
44
- fh.setFormatter(formatter)
45
- # add handler to logger
46
- logger.addHandler(fh)
47
-
48
- # start loggin'
49
- logger.info("Interview.py loaded")
50
-
51
- TIMEOUT = float(CONFIG.get("API_CALL_TIMEOUT_SEC"))
52
-
53
-
54
- class Interview:
55
- """
56
- A class that has an Agent answer Survey Questions with a particular Scenario and using a LanguageModel.
57
- """
58
-
59
- def __init__(
60
- self,
61
- agent: Agent,
62
- survey: Survey,
63
- scenario: Scenario,
64
- model: Type[LanguageModel],
65
- verbose: bool = False,
66
- debug: bool = False,
67
- ):
68
- self.agent = agent
69
- self.survey = survey
70
- self.scenario = scenario
71
- self.model = model
72
- self.debug = debug
73
- self.verbose = verbose
74
- self.answers: dict[str, str] = Answers() # will get filled in
75
-
76
- self.dag = self.survey.dag(textify=True)
77
- self.to_index = {
78
- name: index for index, name in enumerate(self.survey.question_names)
79
- }
80
-
81
- logger.info(f"Interview instantiated")
82
- self.task_creators = {}
83
-
84
- @property
85
- def token_usage(self) -> InterviewTokenUsage:
86
- "Determins how many tokens were used for the interview."
87
- cached_tokens = TokenUsage(from_cache=True)
88
- new_tokens = TokenUsage(from_cache=False)
89
- for task_creator in self.task_creators.values():
90
- token_usage = task_creator.token_usage()
91
- cached_tokens += token_usage["cached_tokens"]
92
- new_tokens += token_usage["new_tokens"]
93
- return InterviewTokenUsage(
94
- new_token_usage=new_tokens, cached_token_usage=cached_tokens
95
- )
96
-
97
- @property
98
- def interview_status(self) -> InterviewStatusDictionary:
99
- """Returns a dictionary mapping task status codes to counts"""
100
- status_dict = InterviewStatusDictionary()
101
- for task_creator in self.task_creators.values():
102
- status_dict[task_creator.task_status] += 1
103
- status_dict["number_from_cache"] += task_creator.from_cache
104
- return status_dict
105
-
106
- async def async_conduct_interview(
107
- self,
108
- model_buckets: ModelBuckets,
109
- debug: bool = False,
110
- replace_missing: bool = True,
111
- ) -> tuple["Answers", List[dict[str, Any]]]:
112
- """
113
- Conducts an 'interview' asynchronously.
114
- """
115
-
116
- # we create both tasks and invigilators lists.
117
- # this is because it's easier to extract info
118
- # we need from the invigilators list when a task fails.
119
- # it's challenging to get info from failed asyncio tasks.
120
- self.tasks, self.invigilators = self._build_question_tasks(
121
- debug=debug, model_buckets=model_buckets
122
- )
123
-
124
- await asyncio.gather(*self.tasks, return_exceptions=not debug)
125
-
126
- if replace_missing:
127
- self.answers.replace_missing_answers_with_none(self.survey)
128
-
129
- valid_results = list(self._extract_valid_results(self.tasks, self.invigilators))
130
-
131
- return self.answers, valid_results
132
-
133
- def _extract_valid_results(
134
- self, tasks, invigialtors
135
- ) -> Generator["Answers", None, None]:
136
- """Extracts the valid results from the list of results."""
137
-
138
- # we only need to print the warning once if a task failed.
139
- warning_printed = False
140
- warning_header = textwrap.dedent(
141
- """\
142
- WARNING: At least one question in the survey was not answered.
143
- """
144
- )
145
- # there should be one one invigilator for each task
146
- assert len(self.tasks) == len(self.invigilators)
147
-
148
- for task, invigilator in zip(self.tasks, self.invigilators):
149
- logger.info(f"Iterating through task: {task}")
150
- if task.done():
151
- try:
152
- result = task.result()
153
- except asyncio.CancelledError:
154
- logger.info(f"Task `{task.edsl_name}` was cancelled.")
155
- result = invigilator.get_failed_task_result()
156
- except Exception as exception:
157
- if not warning_printed:
158
- warning_printed = True
159
- print(warning_header)
160
-
161
- error_message = f"Task `{task.edsl_name}` failed with `{exception.__class__.__name__}`:`{exception}`."
162
- logger.error(error_message)
163
- print(error_message)
164
- traceback.print_exc()
165
- # if task failed, we use the invigilator to get the failed task result
166
- result = invigilator.get_failed_task_result()
167
- else:
168
- # No exception means the task completed successfully
169
- pass
170
-
171
- yield result
172
-
173
- def _build_question_tasks(self, debug, model_buckets) -> List[asyncio.Task]:
174
- """Creates a task for each question, with dependencies on the questions that must be answered before this one can be answered."""
175
- logger.info("Creating tasks for each question")
176
- tasks = []
177
- invigilators = []
178
- for question in self.survey.questions:
179
- # finds dependency tasks for that question
180
- tasks_that_must_be_completed_before = (
181
- self._get_tasks_that_must_be_completed_before(tasks, question)
182
- )
183
- # creates the task for that question
184
- question_task = self._create_question_task(
185
- question=question,
186
- tasks_that_must_be_completed_before=tasks_that_must_be_completed_before,
187
- model_buckets=model_buckets,
188
- debug=debug,
189
- )
190
- # adds the task to the list of tasks
191
- tasks.append(question_task)
192
- invigilators.append(self.get_invigilator(question, debug))
193
- return TasksList(tasks), invigilators
194
-
195
- def _get_tasks_that_must_be_completed_before(
196
- self, tasks, question
197
- ) -> List[asyncio.Task]:
198
- """Returns the tasks that must be completed before the given question can be answered.
199
- If a question has no dependencies, this will be an empty list, [].
200
- """
201
- parents_of_focal_question: List[str] = self.dag.get(question.question_name, [])
202
- return [
203
- tasks[self.to_index[parent_question_name]]
204
- for parent_question_name in parents_of_focal_question
205
- ]
206
-
207
- def _create_question_task(
208
- self,
209
- question: Question,
210
- tasks_that_must_be_completed_before: List[asyncio.Task],
211
- model_buckets: ModelBuckets,
212
- debug,
213
- ):
214
- """Creates a task that depends on the passed-in dependencies that are awaited before the task is run."""
215
- task_creator = QuestionTaskCreator(
216
- question=question,
217
- answer_question_func=self._answer_question_and_record_task,
218
- token_estimator=self._get_estimated_request_tokens,
219
- model_buckets=model_buckets,
220
- )
221
- [task_creator.add_dependency(x) for x in tasks_that_must_be_completed_before]
222
- self.task_creators[question.question_name] = task_creator
223
- return task_creator.generate_task(debug)
224
-
225
- def async_timeout_handler(timeout):
226
- def decorator(func):
227
- async def wrapper(*args, **kwargs):
228
- try:
229
- return await asyncio.wait_for(func(*args, **kwargs), timeout)
230
- except asyncio.TimeoutError:
231
- raise InterviewTimeoutError(
232
- f"Task timed out after {timeout} seconds."
233
- )
234
-
235
- return wrapper
236
-
237
- return decorator
238
-
239
- def get_invigilator(self, question, debug) -> "Invigilator":
240
- invigilator = self.agent.create_invigilator(
241
- question=question,
242
- scenario=self.scenario,
243
- model=self.model,
244
- debug=debug,
245
- memory_plan=self.survey.memory_plan,
246
- current_answers=self.answers,
247
- )
248
- return invigilator
249
-
250
- def _get_estimated_request_tokens(self, question) -> float:
251
- """Estimates the number of tokens that will be required to run the focal task."""
252
- invigilator = self.get_invigilator(question, debug=False)
253
- # TODO: There should be a way to get a more accurate estimate.
254
- combined_text = ""
255
- for prompt in invigilator.get_prompts().values():
256
- if hasattr(prompt, "text"):
257
- combined_text += prompt.text
258
- elif isinstance(prompt, str):
259
- combined_text += prompt
260
- else:
261
- raise ValueError(f"Prompt is of type {type(prompt)}")
262
- return len(combined_text) / 4.0
263
-
264
- @async_timeout_handler(TIMEOUT)
265
- async def _answer_question_and_record_task(
266
- self,
267
- question,
268
- debug,
269
- ) -> AgentResponseDict:
270
- """Answers a question and records the task.
271
- This in turn calls the the passed-in agent's async_answer_question method, which returns a response dictionary.
272
- """
273
- invigilator = self.get_invigilator(question, debug=debug)
274
- response: AgentResponseDict = await invigilator.async_answer_question()
275
- # TODO: Move this back into actual agent response dict and enforce it.
276
- response["question_name"] = question.question_name
277
-
278
- self.answers.add_answer(response, question)
279
-
280
- self._cancel_skipped_questions(question)
281
-
282
- # TODO: This should be forced to be a data-exchange model to cement attributes.
283
- return response
284
-
285
- def _cancel_skipped_questions(self, current_question) -> None:
286
- """Cancels the tasks for questions that are skipped."""
287
- logger.info(f"Current question is {current_question.question_name}")
288
- current_question_index = self.to_index[current_question.question_name]
289
- next_question = self.survey.rule_collection.next_question(
290
- q_now=current_question_index, answers=self.answers
291
- )
292
- next_question_index = next_question.next_q
293
-
294
- def cancel_between(start, end):
295
- for i in range(start, end):
296
- logger.info(
297
- f"Cancelling task for question {i}; {self.tasks[i].edsl_name}"
298
- )
299
- self.tasks[i].cancel()
300
- skipped_question_name = self.survey.question_names[i]
301
- logger.info(f"{skipped_question_name} skipped.")
302
-
303
- if next_question_index == EndOfSurvey:
304
- cancel_between(current_question_index + 1, len(self.survey.questions))
305
- return
306
-
307
- if next_question_index > (current_question_index + 1):
308
- cancel_between(current_question_index + 1, next_question_index)
309
-
310
- self.tasks.status()
311
-
312
- #######################
313
- # Dunder methods
314
- #######################
315
- def __repr__(self) -> str:
316
- """Returns a string representation of the Interview instance."""
317
- return f"Interview(agent = {self.agent}, survey = {self.survey}, scenario = {self.scenario}, model = {self.model})"
318
-
319
-
320
- # def main():
321
- # from edsl.language_models import LanguageModelOpenAIThreeFiveTurbo
322
- # from edsl.agents import Agent
323
- # from edsl.surveys import Survey
324
- # from edsl.scenarios import Scenario
325
- # from edsl.questions import QuestionMultipleChoice
326
-
327
- # # from edsl.jobs.Interview import Interview
328
-
329
- # # a survey with skip logic
330
- # q0 = QuestionMultipleChoice(
331
- # question_text="Do you like school?",
332
- # question_options=["yes", "no"],
333
- # question_name="q0",
334
- # )
335
- # q1 = QuestionMultipleChoice(
336
- # question_text="Why not?",
337
- # question_options=["killer bees in cafeteria", "other"],
338
- # question_name="q1",
339
- # )
340
- # q2 = QuestionMultipleChoice(
341
- # question_text="Why?",
342
- # question_options=["**lack*** of killer bees in cafeteria", "other"],
343
- # question_name="q2",
344
- # )
345
- # s = Survey(questions=[q0, q1, q2])
346
- # s = s.add_rule(q0, "q0 == 'yes'", q2)
347
-
348
- # # create an interview
349
- # a = Agent(traits=None)
350
-
351
- # def direct_question_answering_method(self, question, scenario):
352
- # return "yes"
353
-
354
- # a.add_direct_question_answering_method(direct_question_answering_method)
355
- # scenario = Scenario()
356
- # m = LanguageModelOpenAIThreeFiveTurbo(use_cache=False)
357
- # I = Interview(agent=a, survey=s, scenario=scenario, model=m)
358
-
359
- # I.conduct_interview()
360
- # # # conduct five interviews
361
- # # for _ in range(5):
362
- # # I.conduct_interview(debug=True)
363
-
364
- # # # replace missing answers
365
- # # I
366
- # # repr(I)
367
- # # eval(repr(I))
368
-
369
-
370
- if __name__ == "__main__":
371
- from edsl.language_models import LanguageModelOpenAIThreeFiveTurbo
372
- from edsl.agents import Agent
373
- from edsl.surveys import Survey
374
- from edsl.scenarios import Scenario
375
- from edsl.questions import QuestionMultipleChoice
376
-
377
- # from edsl.jobs.Interview import Interview
378
-
379
- # a survey with skip logic
380
- q0 = QuestionMultipleChoice(
381
- question_text="Do you like school?",
382
- question_options=["yes", "no"],
383
- question_name="q0",
384
- )
385
- q1 = QuestionMultipleChoice(
386
- question_text="Why not?",
387
- question_options=["killer bees in cafeteria", "other"],
388
- question_name="q1",
389
- )
390
- q2 = QuestionMultipleChoice(
391
- question_text="Why?",
392
- question_options=["**lack*** of killer bees in cafeteria", "other"],
393
- question_name="q2",
394
- )
395
- s = Survey(questions=[q0, q1, q2])
396
- s = s.add_rule(q0, "q0 == 'yes'", q2)
397
-
398
- # create an interview
399
- a = Agent(traits=None)
400
-
401
- def direct_question_answering_method(self, question, scenario):
402
- return "yes"
403
-
404
- a.add_direct_question_answering_method(direct_question_answering_method)
405
- scenario = Scenario()
406
- m = LanguageModelOpenAIThreeFiveTurbo(use_cache=False)
407
- I = Interview(agent=a, survey=s, scenario=scenario, model=m)
408
-
409
- I.conduct_interview()
410
- # # conduct five interviews
411
- # for _ in range(5):
412
- # I.conduct_interview(debug=True)
413
-
414
- # # replace missing answers
415
- # I
416
- # repr(I)
417
- # eval(repr(I))
edsl/jobs/JobsRunner.py DELETED
@@ -1,63 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections import UserDict
4
-
5
- from abc import ABC, ABCMeta, abstractmethod
6
- from edsl.jobs import Jobs
7
- from edsl.results import Results
8
-
9
-
10
- class RegisterJobsRunnerMeta(ABCMeta):
11
- "Metaclass to register output elements in a registry i.e., those that have a parent"
12
- _registry = {} # Initialize the registry as a dictionary
13
-
14
- def __init__(cls, name, bases, dct):
15
- super(RegisterJobsRunnerMeta, cls).__init__(name, bases, dct)
16
- if name != "JobsRunner":
17
- RegisterJobsRunnerMeta._registry[name] = cls
18
-
19
- @classmethod
20
- def get_registered_classes(cls):
21
- return cls._registry
22
-
23
- @classmethod
24
- def lookup(cls):
25
- d = {}
26
- for classname, cls in cls._registry.items():
27
- if hasattr(cls, "runner_name"):
28
- d[cls.runner_name] = cls
29
- else:
30
- raise Exception(
31
- f"Class {classname} does not have a runner_name attribute"
32
- )
33
- return d
34
-
35
-
36
- class JobsRunner(ABC, metaclass=RegisterJobsRunnerMeta):
37
- """ABC for JobRunners, which take in a job, conduct interviews, and return their results."""
38
-
39
- def __init__(self, jobs: Jobs):
40
- self.jobs = jobs
41
- # create the interviews here so children can use them
42
- self.interviews = jobs.interviews()
43
- self.bucket_collection = jobs.bucket_collection
44
- # self.bucket_collection = self.jobs.bucket_collection
45
- # for model in self.jobs.models:
46
- # self.bucket_collection.add_model(model)
47
-
48
- @abstractmethod
49
- def run(
50
- self,
51
- n: int = 1,
52
- debug: bool = False,
53
- verbose: bool = False,
54
- progress_bar: bool = True,
55
- ) -> Results: # pragma: no cover
56
- """
57
- Runs the job: conducts Interviews and returns their results.
58
- - `n`: how many times to run each interview
59
- - `debug`: prints debug messages
60
- - `verbose`: prints messages
61
- - `progress_bar`: shows a progress bar
62
- """
63
- raise NotImplementedError