edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev4__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 (344) hide show
  1. edsl/Base.py +413 -332
  2. edsl/BaseDiff.py +260 -260
  3. edsl/TemplateLoader.py +24 -24
  4. edsl/__init__.py +57 -49
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +1071 -867
  7. edsl/agents/AgentList.py +551 -413
  8. edsl/agents/Invigilator.py +284 -233
  9. edsl/agents/InvigilatorBase.py +257 -270
  10. edsl/agents/PromptConstructor.py +272 -354
  11. edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
  12. edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
  13. edsl/agents/__init__.py +2 -3
  14. edsl/agents/descriptors.py +99 -99
  15. edsl/agents/prompt_helpers.py +129 -129
  16. edsl/agents/question_option_processor.py +172 -0
  17. edsl/auto/AutoStudy.py +130 -117
  18. edsl/auto/StageBase.py +243 -230
  19. edsl/auto/StageGenerateSurvey.py +178 -178
  20. edsl/auto/StageLabelQuestions.py +125 -125
  21. edsl/auto/StagePersona.py +61 -61
  22. edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
  23. edsl/auto/StagePersonaDimensionValues.py +74 -74
  24. edsl/auto/StagePersonaDimensions.py +69 -69
  25. edsl/auto/StageQuestions.py +74 -73
  26. edsl/auto/SurveyCreatorPipeline.py +21 -21
  27. edsl/auto/utilities.py +218 -224
  28. edsl/base/Base.py +279 -279
  29. edsl/config.py +177 -157
  30. edsl/conversation/Conversation.py +290 -290
  31. edsl/conversation/car_buying.py +59 -58
  32. edsl/conversation/chips.py +95 -95
  33. edsl/conversation/mug_negotiation.py +81 -81
  34. edsl/conversation/next_speaker_utilities.py +93 -93
  35. edsl/coop/CoopFunctionsMixin.py +15 -0
  36. edsl/coop/ExpectedParrotKeyHandler.py +125 -0
  37. edsl/coop/PriceFetcher.py +54 -54
  38. edsl/coop/__init__.py +2 -2
  39. edsl/coop/coop.py +1106 -1028
  40. edsl/coop/utils.py +131 -131
  41. edsl/data/Cache.py +573 -555
  42. edsl/data/CacheEntry.py +230 -233
  43. edsl/data/CacheHandler.py +168 -149
  44. edsl/data/RemoteCacheSync.py +186 -78
  45. edsl/data/SQLiteDict.py +292 -292
  46. edsl/data/__init__.py +5 -4
  47. edsl/data/hack.py +10 -0
  48. edsl/data/orm.py +10 -10
  49. edsl/data_transfer_models.py +74 -73
  50. edsl/enums.py +202 -175
  51. edsl/exceptions/BaseException.py +21 -21
  52. edsl/exceptions/__init__.py +54 -54
  53. edsl/exceptions/agents.py +54 -42
  54. edsl/exceptions/cache.py +5 -5
  55. edsl/exceptions/configuration.py +16 -16
  56. edsl/exceptions/coop.py +10 -10
  57. edsl/exceptions/data.py +14 -14
  58. edsl/exceptions/general.py +34 -34
  59. edsl/exceptions/inference_services.py +5 -0
  60. edsl/exceptions/jobs.py +33 -33
  61. edsl/exceptions/language_models.py +63 -63
  62. edsl/exceptions/prompts.py +15 -15
  63. edsl/exceptions/questions.py +109 -91
  64. edsl/exceptions/results.py +29 -29
  65. edsl/exceptions/scenarios.py +29 -22
  66. edsl/exceptions/surveys.py +37 -37
  67. edsl/inference_services/AnthropicService.py +106 -87
  68. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  69. edsl/inference_services/AvailableModelFetcher.py +215 -0
  70. edsl/inference_services/AwsBedrock.py +118 -120
  71. edsl/inference_services/AzureAI.py +215 -217
  72. edsl/inference_services/DeepInfraService.py +18 -18
  73. edsl/inference_services/GoogleService.py +143 -148
  74. edsl/inference_services/GroqService.py +20 -20
  75. edsl/inference_services/InferenceServiceABC.py +80 -147
  76. edsl/inference_services/InferenceServicesCollection.py +138 -97
  77. edsl/inference_services/MistralAIService.py +120 -123
  78. edsl/inference_services/OllamaService.py +18 -18
  79. edsl/inference_services/OpenAIService.py +236 -224
  80. edsl/inference_services/PerplexityService.py +160 -163
  81. edsl/inference_services/ServiceAvailability.py +135 -0
  82. edsl/inference_services/TestService.py +90 -89
  83. edsl/inference_services/TogetherAIService.py +172 -170
  84. edsl/inference_services/data_structures.py +134 -0
  85. edsl/inference_services/models_available_cache.py +118 -118
  86. edsl/inference_services/rate_limits_cache.py +25 -25
  87. edsl/inference_services/registry.py +41 -41
  88. edsl/inference_services/write_available.py +10 -10
  89. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  90. edsl/jobs/Answers.py +43 -56
  91. edsl/jobs/FetchInvigilator.py +47 -0
  92. edsl/jobs/InterviewTaskManager.py +98 -0
  93. edsl/jobs/InterviewsConstructor.py +50 -0
  94. edsl/jobs/Jobs.py +823 -898
  95. edsl/jobs/JobsChecks.py +172 -147
  96. edsl/jobs/JobsComponentConstructor.py +189 -0
  97. edsl/jobs/JobsPrompts.py +270 -268
  98. edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
  99. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  100. edsl/jobs/RequestTokenEstimator.py +30 -0
  101. edsl/jobs/__init__.py +1 -1
  102. edsl/jobs/async_interview_runner.py +138 -0
  103. edsl/jobs/buckets/BucketCollection.py +104 -63
  104. edsl/jobs/buckets/ModelBuckets.py +65 -65
  105. edsl/jobs/buckets/TokenBucket.py +283 -251
  106. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  107. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  108. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  109. edsl/jobs/data_structures.py +120 -0
  110. edsl/jobs/decorators.py +35 -0
  111. edsl/jobs/interviews/Interview.py +396 -661
  112. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
  113. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
  114. edsl/jobs/interviews/InterviewStatistic.py +63 -63
  115. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
  116. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
  117. edsl/jobs/interviews/InterviewStatusLog.py +92 -92
  118. edsl/jobs/interviews/ReportErrors.py +66 -66
  119. edsl/jobs/interviews/interview_status_enum.py +9 -9
  120. edsl/jobs/jobs_status_enums.py +9 -0
  121. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  122. edsl/jobs/results_exceptions_handler.py +98 -0
  123. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
  124. edsl/jobs/runners/JobsRunnerStatus.py +297 -330
  125. edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
  126. edsl/jobs/tasks/TaskCreators.py +64 -64
  127. edsl/jobs/tasks/TaskHistory.py +470 -450
  128. edsl/jobs/tasks/TaskStatusLog.py +23 -23
  129. edsl/jobs/tasks/task_status_enum.py +161 -163
  130. edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
  131. edsl/jobs/tokens/TokenUsage.py +34 -34
  132. edsl/language_models/ComputeCost.py +63 -0
  133. edsl/language_models/LanguageModel.py +626 -668
  134. edsl/language_models/ModelList.py +164 -155
  135. edsl/language_models/PriceManager.py +127 -0
  136. edsl/language_models/RawResponseHandler.py +106 -0
  137. edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
  138. edsl/language_models/ServiceDataSources.py +0 -0
  139. edsl/language_models/__init__.py +2 -3
  140. edsl/language_models/fake_openai_call.py +15 -15
  141. edsl/language_models/fake_openai_service.py +61 -61
  142. edsl/language_models/key_management/KeyLookup.py +63 -0
  143. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  144. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  145. edsl/language_models/key_management/__init__.py +0 -0
  146. edsl/language_models/key_management/models.py +131 -0
  147. edsl/language_models/model.py +256 -0
  148. edsl/language_models/repair.py +156 -156
  149. edsl/language_models/utilities.py +65 -64
  150. edsl/notebooks/Notebook.py +263 -258
  151. edsl/notebooks/NotebookToLaTeX.py +142 -0
  152. edsl/notebooks/__init__.py +1 -1
  153. edsl/prompts/Prompt.py +352 -362
  154. edsl/prompts/__init__.py +2 -2
  155. edsl/questions/ExceptionExplainer.py +77 -0
  156. edsl/questions/HTMLQuestion.py +103 -0
  157. edsl/questions/QuestionBase.py +518 -664
  158. edsl/questions/QuestionBasePromptsMixin.py +221 -217
  159. edsl/questions/QuestionBudget.py +227 -227
  160. edsl/questions/QuestionCheckBox.py +359 -359
  161. edsl/questions/QuestionExtract.py +180 -182
  162. edsl/questions/QuestionFreeText.py +113 -114
  163. edsl/questions/QuestionFunctional.py +166 -166
  164. edsl/questions/QuestionList.py +223 -231
  165. edsl/questions/QuestionMatrix.py +265 -0
  166. edsl/questions/QuestionMultipleChoice.py +330 -286
  167. edsl/questions/QuestionNumerical.py +151 -153
  168. edsl/questions/QuestionRank.py +314 -324
  169. edsl/questions/Quick.py +41 -41
  170. edsl/questions/SimpleAskMixin.py +74 -73
  171. edsl/questions/__init__.py +27 -26
  172. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
  173. edsl/questions/compose_questions.py +98 -98
  174. edsl/questions/data_structures.py +20 -0
  175. edsl/questions/decorators.py +21 -21
  176. edsl/questions/derived/QuestionLikertFive.py +76 -76
  177. edsl/questions/derived/QuestionLinearScale.py +90 -87
  178. edsl/questions/derived/QuestionTopK.py +93 -93
  179. edsl/questions/derived/QuestionYesNo.py +82 -82
  180. edsl/questions/descriptors.py +427 -413
  181. edsl/questions/loop_processor.py +149 -0
  182. edsl/questions/prompt_templates/question_budget.jinja +13 -13
  183. edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
  184. edsl/questions/prompt_templates/question_extract.jinja +11 -11
  185. edsl/questions/prompt_templates/question_free_text.jinja +3 -3
  186. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
  187. edsl/questions/prompt_templates/question_list.jinja +17 -17
  188. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
  189. edsl/questions/prompt_templates/question_numerical.jinja +36 -36
  190. edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
  191. edsl/questions/question_registry.py +177 -177
  192. edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
  193. edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
  194. edsl/questions/response_validator_factory.py +34 -0
  195. edsl/questions/settings.py +12 -12
  196. edsl/questions/templates/budget/answering_instructions.jinja +7 -7
  197. edsl/questions/templates/budget/question_presentation.jinja +7 -7
  198. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
  199. edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
  200. edsl/questions/templates/extract/answering_instructions.jinja +7 -7
  201. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
  202. edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
  203. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
  204. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
  205. edsl/questions/templates/list/answering_instructions.jinja +3 -3
  206. edsl/questions/templates/list/question_presentation.jinja +5 -5
  207. edsl/questions/templates/matrix/__init__.py +1 -0
  208. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  209. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  210. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
  211. edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
  212. edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
  213. edsl/questions/templates/numerical/question_presentation.jinja +6 -6
  214. edsl/questions/templates/rank/answering_instructions.jinja +11 -11
  215. edsl/questions/templates/rank/question_presentation.jinja +15 -15
  216. edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
  217. edsl/questions/templates/top_k/question_presentation.jinja +22 -22
  218. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
  219. edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
  220. edsl/results/CSSParameterizer.py +108 -108
  221. edsl/results/Dataset.py +587 -424
  222. edsl/results/DatasetExportMixin.py +594 -731
  223. edsl/results/DatasetTree.py +295 -275
  224. edsl/results/MarkdownToDocx.py +122 -0
  225. edsl/results/MarkdownToPDF.py +111 -0
  226. edsl/results/Result.py +557 -465
  227. edsl/results/Results.py +1183 -1165
  228. edsl/results/ResultsExportMixin.py +45 -43
  229. edsl/results/ResultsGGMixin.py +121 -121
  230. edsl/results/TableDisplay.py +125 -198
  231. edsl/results/TextEditor.py +50 -0
  232. edsl/results/__init__.py +2 -2
  233. edsl/results/file_exports.py +252 -0
  234. edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
  235. edsl/results/{Selector.py → results_selector.py} +145 -135
  236. edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
  237. edsl/results/smart_objects.py +96 -0
  238. edsl/results/table_data_class.py +12 -0
  239. edsl/results/table_display.css +77 -77
  240. edsl/results/table_renderers.py +118 -0
  241. edsl/results/tree_explore.py +115 -115
  242. edsl/scenarios/ConstructDownloadLink.py +109 -0
  243. edsl/scenarios/DocumentChunker.py +102 -0
  244. edsl/scenarios/DocxScenario.py +16 -0
  245. edsl/scenarios/FileStore.py +511 -632
  246. edsl/scenarios/PdfExtractor.py +40 -0
  247. edsl/scenarios/Scenario.py +498 -601
  248. edsl/scenarios/ScenarioHtmlMixin.py +65 -64
  249. edsl/scenarios/ScenarioList.py +1458 -1287
  250. edsl/scenarios/ScenarioListExportMixin.py +45 -52
  251. edsl/scenarios/ScenarioListPdfMixin.py +239 -261
  252. edsl/scenarios/__init__.py +3 -4
  253. edsl/scenarios/directory_scanner.py +96 -0
  254. edsl/scenarios/file_methods.py +85 -0
  255. edsl/scenarios/handlers/__init__.py +13 -0
  256. edsl/scenarios/handlers/csv.py +38 -0
  257. edsl/scenarios/handlers/docx.py +76 -0
  258. edsl/scenarios/handlers/html.py +37 -0
  259. edsl/scenarios/handlers/json.py +111 -0
  260. edsl/scenarios/handlers/latex.py +5 -0
  261. edsl/scenarios/handlers/md.py +51 -0
  262. edsl/scenarios/handlers/pdf.py +68 -0
  263. edsl/scenarios/handlers/png.py +39 -0
  264. edsl/scenarios/handlers/pptx.py +105 -0
  265. edsl/scenarios/handlers/py.py +294 -0
  266. edsl/scenarios/handlers/sql.py +313 -0
  267. edsl/scenarios/handlers/sqlite.py +149 -0
  268. edsl/scenarios/handlers/txt.py +33 -0
  269. edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
  270. edsl/scenarios/scenario_selector.py +156 -0
  271. edsl/shared.py +1 -1
  272. edsl/study/ObjectEntry.py +173 -173
  273. edsl/study/ProofOfWork.py +113 -113
  274. edsl/study/SnapShot.py +80 -80
  275. edsl/study/Study.py +521 -528
  276. edsl/study/__init__.py +4 -4
  277. edsl/surveys/ConstructDAG.py +92 -0
  278. edsl/surveys/DAG.py +148 -148
  279. edsl/surveys/EditSurvey.py +221 -0
  280. edsl/surveys/InstructionHandler.py +100 -0
  281. edsl/surveys/Memory.py +31 -31
  282. edsl/surveys/MemoryManagement.py +72 -0
  283. edsl/surveys/MemoryPlan.py +244 -244
  284. edsl/surveys/Rule.py +327 -326
  285. edsl/surveys/RuleCollection.py +385 -387
  286. edsl/surveys/RuleManager.py +172 -0
  287. edsl/surveys/Simulator.py +75 -0
  288. edsl/surveys/Survey.py +1280 -1801
  289. edsl/surveys/SurveyCSS.py +273 -261
  290. edsl/surveys/SurveyExportMixin.py +259 -259
  291. edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
  292. edsl/surveys/SurveyQualtricsImport.py +284 -284
  293. edsl/surveys/SurveyToApp.py +141 -0
  294. edsl/surveys/__init__.py +5 -3
  295. edsl/surveys/base.py +53 -53
  296. edsl/surveys/descriptors.py +60 -56
  297. edsl/surveys/instructions/ChangeInstruction.py +48 -49
  298. edsl/surveys/instructions/Instruction.py +56 -65
  299. edsl/surveys/instructions/InstructionCollection.py +82 -77
  300. edsl/templates/error_reporting/base.html +23 -23
  301. edsl/templates/error_reporting/exceptions_by_model.html +34 -34
  302. edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
  303. edsl/templates/error_reporting/exceptions_by_type.html +16 -16
  304. edsl/templates/error_reporting/interview_details.html +115 -115
  305. edsl/templates/error_reporting/interviews.html +19 -19
  306. edsl/templates/error_reporting/overview.html +4 -4
  307. edsl/templates/error_reporting/performance_plot.html +1 -1
  308. edsl/templates/error_reporting/report.css +73 -73
  309. edsl/templates/error_reporting/report.html +117 -117
  310. edsl/templates/error_reporting/report.js +25 -25
  311. edsl/test_h +1 -0
  312. edsl/tools/__init__.py +1 -1
  313. edsl/tools/clusters.py +192 -192
  314. edsl/tools/embeddings.py +27 -27
  315. edsl/tools/embeddings_plotting.py +118 -118
  316. edsl/tools/plotting.py +112 -112
  317. edsl/tools/summarize.py +18 -18
  318. edsl/utilities/PrettyList.py +56 -0
  319. edsl/utilities/SystemInfo.py +28 -28
  320. edsl/utilities/__init__.py +22 -22
  321. edsl/utilities/ast_utilities.py +25 -25
  322. edsl/utilities/data/Registry.py +6 -6
  323. edsl/utilities/data/__init__.py +1 -1
  324. edsl/utilities/data/scooter_results.json +1 -1
  325. edsl/utilities/decorators.py +77 -77
  326. edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
  327. edsl/utilities/gcp_bucket/example.py +50 -0
  328. edsl/utilities/interface.py +627 -627
  329. edsl/utilities/is_notebook.py +18 -0
  330. edsl/utilities/is_valid_variable_name.py +11 -0
  331. edsl/utilities/naming_utilities.py +263 -263
  332. edsl/utilities/remove_edsl_version.py +24 -0
  333. edsl/utilities/repair_functions.py +28 -28
  334. edsl/utilities/restricted_python.py +70 -70
  335. edsl/utilities/utilities.py +436 -424
  336. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/LICENSE +21 -21
  337. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/METADATA +13 -11
  338. edsl-0.1.39.dev4.dist-info/RECORD +361 -0
  339. edsl/language_models/KeyLookup.py +0 -30
  340. edsl/language_models/registry.py +0 -190
  341. edsl/language_models/unused/ReplicateBase.py +0 -83
  342. edsl/results/ResultsDBMixin.py +0 -238
  343. edsl-0.1.39.dev3.dist-info/RECORD +0 -277
  344. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,141 @@
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel, create_model
3
+ from typing import Callable, Optional, Type, Dict, Any, List, Union
4
+
5
+
6
+ class SurveyToApp:
7
+ def __init__(self, survey):
8
+ self.survey = survey
9
+ self.app = FastAPI()
10
+
11
+ def parameters(self):
12
+ return self.survey.parameters
13
+
14
+ def create_input(self) -> Type[BaseModel]:
15
+ """
16
+ Creates a Pydantic model based on the survey parameters.
17
+ Returns:
18
+ Type[BaseModel]: A dynamically created Pydantic model class
19
+ """
20
+ # Get parameters from survey - now calling the method
21
+ params = self.parameters()
22
+
23
+ # Create field definitions dictionary
24
+ fields: Dict[str, Any] = {}
25
+
26
+ # Since params is a set, we'll handle each parameter directly
27
+ # Assuming each parameter in the set has the necessary attributes
28
+ for param in params:
29
+ # You might need to adjust these based on the actual parameter object structure
30
+ param_name = getattr(param, "name", str(param))
31
+ param_type = getattr(param, "type", "string")
32
+ is_required = getattr(param, "required", True)
33
+
34
+ # Map survey parameter types to Python types
35
+ type_mapping = {
36
+ "string": str,
37
+ "integer": int,
38
+ "float": float,
39
+ "boolean": bool,
40
+ "array": List,
41
+ # Add more type mappings as needed
42
+ }
43
+
44
+ # Get the Python type from mapping
45
+ python_type = type_mapping.get(param_type, str)
46
+
47
+ if is_required:
48
+ fields[param_name] = (python_type, ...)
49
+ else:
50
+ fields[param_name] = (Optional[python_type], None)
51
+
52
+ # Add the template variable 'name' that's used in the question text
53
+ fields["name"] = (str, ...)
54
+
55
+ # Create and return the Pydantic model
56
+ model_name = f"{self.survey.__class__.__name__}Model"
57
+ return create_model(model_name, **fields)
58
+
59
+ def create_route(self) -> Callable:
60
+ """
61
+ Creates a FastAPI route handler for the survey.
62
+ Returns:
63
+ Callable: A route handler function
64
+ """
65
+ input_model = self.create_input()
66
+
67
+ async def route_handler(input_data: input_model):
68
+ """
69
+ Handles the API route by processing the input data through the survey.
70
+ Args:
71
+ input_data: The validated input data matching the created Pydantic model
72
+ Returns:
73
+ dict: The processed survey results
74
+ """
75
+ # Convert Pydantic model to dict
76
+ data = input_data.dict()
77
+ print(data)
78
+ from edsl.scenarios.Scenario import Scenario
79
+
80
+ # Process the data through the survey
81
+ try:
82
+ s = Scenario(data)
83
+ results = self.survey.by(s).run()
84
+ return {
85
+ "status": "success",
86
+ "data": results.select("answer.*").to_scenario_list().to_dict(),
87
+ }
88
+ except Exception as e:
89
+ return {"status": "error", "message": str(e)}
90
+
91
+ return route_handler
92
+
93
+ def add_to_app(
94
+ self, app: FastAPI, path: str = "/survey", methods: List[str] = ["POST", "GET"]
95
+ ):
96
+ """
97
+ Adds the survey route to a FastAPI application.
98
+ Args:
99
+ app (FastAPI): The FastAPI application instance
100
+ path (str): The API endpoint path
101
+ methods (List[str]): HTTP methods to support
102
+ """
103
+ route_handler = self.create_route()
104
+ input_model = self.create_input()
105
+
106
+ app.add_api_route(
107
+ path, route_handler, methods=methods, response_model=Dict[str, Any]
108
+ )
109
+
110
+ def create_app(self, path: str = "/survey", methods: List[str] = ["POST", "GET"]):
111
+ """
112
+ Creates a FastAPI application with the survey route.
113
+ Args:
114
+ path (str): The API endpoint path
115
+ methods (List[str]): HTTP methods to support
116
+ Returns:
117
+ FastAPI: The FastAPI application instance
118
+ """
119
+ app = FastAPI()
120
+ self.add_to_app(app, path=path, methods=methods)
121
+ return app
122
+
123
+
124
+ from edsl import QuestionFreeText, QuestionList
125
+
126
+ # q = QuestionFreeText(
127
+ # question_name="name_gender",
128
+ # question_text="Is this customarily a boy's name or a girl's name: {{ name}}",
129
+ # )
130
+
131
+ q = QuestionList(
132
+ question_name="examples",
133
+ question_text="Give me {{ num }} examples of {{ thing }}",
134
+ )
135
+
136
+ survey_app = SurveyToApp(q.to_survey())
137
+
138
+ if __name__ == "__main__":
139
+ import uvicorn
140
+
141
+ uvicorn.run(survey_app.create_app(path="/examples"), host="127.0.0.1", port=8000)
edsl/surveys/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
- from edsl.surveys.Survey import Survey
2
- from edsl.surveys.Rule import Rule
3
- from edsl.surveys.RuleCollection import RuleCollection
1
+ from edsl.surveys.Survey import Survey
2
+ from edsl.surveys.instructions.Instruction import Instruction
3
+
4
+ # from edsl.surveys.Rule import Rule
5
+ # from edsl.surveys.RuleCollection import RuleCollection
edsl/surveys/base.py CHANGED
@@ -1,53 +1,53 @@
1
- """Base classes and enumerations for the surveyor package."""
2
-
3
- from enum import Enum
4
-
5
-
6
- class RulePriority(Enum):
7
- """Enumeration of the priority of a rule."""
8
-
9
- DEFAULT = -1
10
-
11
-
12
- class EndOfSurveyParent:
13
- """A named object that represents the end of the survey."""
14
-
15
- pass
16
-
17
- def __repr__(self):
18
- """Return a string representation of the object."""
19
- return "EndOfSurvey"
20
-
21
- def __str__(self):
22
- """Return a string representation of the object."""
23
- return "EndOfSurvey"
24
-
25
- def __bool__(self):
26
- """Return False."""
27
- return False
28
-
29
- def __add__(self, other):
30
- """Add the object to another object.
31
-
32
- Example:
33
- >>> e = EndOfSurveyParent()
34
- >>> e + 1
35
- EndOfSurvey
36
- """
37
- return self
38
-
39
- def __deepcopy__(self, memo):
40
- # Return the same instance when deepcopy is called
41
- return self
42
-
43
- def __radd__(self, other):
44
- """Add the object to another object.
45
-
46
- Example:
47
- >>> 1 + EndOfSurveyParent()
48
- EndOfSurvey
49
- """
50
- return self
51
-
52
-
53
- EndOfSurvey = EndOfSurveyParent()
1
+ """Base classes and enumerations for the surveyor package."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class RulePriority(Enum):
7
+ """Enumeration of the priority of a rule."""
8
+
9
+ DEFAULT = -1
10
+
11
+
12
+ class EndOfSurveyParent:
13
+ """A named object that represents the end of the survey."""
14
+
15
+ pass
16
+
17
+ def __repr__(self):
18
+ """Return a string representation of the object."""
19
+ return "EndOfSurvey"
20
+
21
+ def __str__(self):
22
+ """Return a string representation of the object."""
23
+ return "EndOfSurvey"
24
+
25
+ def __bool__(self):
26
+ """Return False."""
27
+ return False
28
+
29
+ def __add__(self, other):
30
+ """Add the object to another object.
31
+
32
+ Example:
33
+ >>> e = EndOfSurveyParent()
34
+ >>> e + 1
35
+ EndOfSurvey
36
+ """
37
+ return self
38
+
39
+ def __deepcopy__(self, memo):
40
+ # Return the same instance when deepcopy is called
41
+ return self
42
+
43
+ def __radd__(self, other):
44
+ """Add the object to another object.
45
+
46
+ Example:
47
+ >>> 1 + EndOfSurveyParent()
48
+ EndOfSurvey
49
+ """
50
+ return self
51
+
52
+
53
+ EndOfSurvey = EndOfSurveyParent()
@@ -1,56 +1,60 @@
1
- """This module contains the descriptors for the classes in the edsl package."""
2
-
3
- from abc import ABC, abstractmethod
4
- from typing import Any
5
- from edsl.questions.QuestionBase import QuestionBase
6
-
7
-
8
- class BaseDescriptor(ABC):
9
- """ABC for something."""
10
-
11
- @abstractmethod
12
- def validate(self, value: Any) -> None:
13
- """Validate the value. If it is invalid, raise an exception. If it is valid, do nothing."""
14
- pass
15
-
16
- def __get__(self, instance, owner):
17
- """Get the value of the attribute."""
18
- return instance.__dict__[self.name]
19
-
20
- def __set__(self, instance, value: Any) -> None:
21
- """Set the value of the attribute."""
22
- self.validate(value, instance)
23
- instance.__dict__[self.name] = value
24
-
25
- def __set_name__(self, owner, name: str) -> None:
26
- """Set the name of the attribute."""
27
- self.name = "_" + name
28
-
29
-
30
- class QuestionsDescriptor(BaseDescriptor):
31
- """Descriptor for questions."""
32
-
33
- def __get__(self, instance, owner):
34
- """Get the value of the attribute."""
35
- return instance.__dict__[self.name]
36
-
37
- def validate(self, value: Any, instance) -> None:
38
- """Validate the value. If it is invalid, raise an exception. If it is valid, do nothing."""
39
- if not isinstance(value, list):
40
- raise TypeError("Questions must be a list.")
41
- if not all(isinstance(question, QuestionBase) for question in value):
42
- raise TypeError("Questions must be a list of Question objects.")
43
- question_names = [question.question_name for question in value]
44
- if len(question_names) != len(set(question_names)):
45
- raise ValueError("Question names must be unique.")
46
-
47
- def __set__(self, instance, value: Any) -> None:
48
- """Set the value of the attribute."""
49
- self.validate(value, instance)
50
- instance.__dict__[self.name] = []
51
- for question in value:
52
- instance.add_question(question)
53
-
54
- def __set_name__(self, owner, name: str) -> None:
55
- """Set the name of the attribute."""
56
- self.name = "_" + name
1
+ """This module contains the descriptors for the classes in the edsl package."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any, TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from edsl.questions.QuestionBase import QuestionBase
8
+
9
+
10
+ class BaseDescriptor(ABC):
11
+ """ABC for something."""
12
+
13
+ @abstractmethod
14
+ def validate(self, value: Any) -> None:
15
+ """Validate the value. If it is invalid, raise an exception. If it is valid, do nothing."""
16
+ pass
17
+
18
+ def __get__(self, instance, owner):
19
+ """Get the value of the attribute."""
20
+ return instance.__dict__[self.name]
21
+
22
+ def __set__(self, instance, value: Any) -> None:
23
+ """Set the value of the attribute."""
24
+ self.validate(value, instance)
25
+ instance.__dict__[self.name] = value
26
+
27
+ def __set_name__(self, owner, name: str) -> None:
28
+ """Set the name of the attribute."""
29
+ self.name = "_" + name
30
+
31
+
32
+ class QuestionsDescriptor(BaseDescriptor):
33
+ """Descriptor for questions."""
34
+
35
+ def __get__(self, instance, owner):
36
+ """Get the value of the attribute."""
37
+ return instance.__dict__[self.name]
38
+
39
+ def validate(self, value: Any, instance) -> None:
40
+ """Validate the value. If it is invalid, raise an exception. If it is valid, do nothing."""
41
+ from edsl.questions.QuestionBase import QuestionBase
42
+
43
+ if not isinstance(value, list):
44
+ raise TypeError("Questions must be a list.")
45
+ if not all(isinstance(question, QuestionBase) for question in value):
46
+ raise TypeError("Questions must be a list of Question objects.")
47
+ question_names = [question.question_name for question in value]
48
+ if len(question_names) != len(set(question_names)):
49
+ raise ValueError("Question names must be unique.")
50
+
51
+ def __set__(self, instance, value: Any) -> None:
52
+ """Set the value of the attribute."""
53
+ self.validate(value, instance)
54
+ instance.__dict__[self.name] = []
55
+ for question in value:
56
+ instance.add_question(question)
57
+
58
+ def __set_name__(self, owner, name: str) -> None:
59
+ """Set the name of the attribute."""
60
+ self.name = "_" + name
@@ -1,49 +1,48 @@
1
- from typing import List, Optional
2
-
3
- from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
4
-
5
-
6
- class ChangeInstruction:
7
- def __init__(
8
- self,
9
- keep: Optional[List[str]] = None,
10
- drop: Optional[List[str]] = None,
11
- ):
12
- if keep is None and drop is None:
13
- raise ValueError("Keep and drop cannot both be None")
14
-
15
- self.keep = keep or []
16
- self.drop = drop or []
17
-
18
- def include_instruction(self, instruction_name) -> bool:
19
- return (instruction_name in self.keep) or (not instruction_name in self.drop)
20
-
21
- def add_name(self, index) -> None:
22
- self.name = "change_instruction_{}".format(index)
23
-
24
- def __str__(self):
25
- return self.text
26
-
27
- def to_dict(self, add_edsl_version=True):
28
- d = {
29
- "keep": self.keep,
30
- "drop": self.drop,
31
- }
32
- if add_edsl_version:
33
- from edsl import __version__
34
-
35
- d["edsl_version"] = __version__
36
- d["edsl_class_name"] = "ChangeInstruction"
37
-
38
- return d
39
-
40
- def __hash__(self) -> int:
41
- """Return a hash of the question."""
42
- from edsl.utilities.utilities import dict_hash
43
-
44
- return dict_hash(self.to_dict(add_edsl_version=False))
45
-
46
- @classmethod
47
- @remove_edsl_version
48
- def from_dict(cls, data):
49
- return cls(data["keep"], data["drop"])
1
+ from typing import List, Optional
2
+ from edsl.utilities.remove_edsl_version import remove_edsl_version
3
+
4
+
5
+ class ChangeInstruction:
6
+ def __init__(
7
+ self,
8
+ keep: Optional[List[str]] = None,
9
+ drop: Optional[List[str]] = None,
10
+ ):
11
+ if keep is None and drop is None:
12
+ raise ValueError("Keep and drop cannot both be None")
13
+
14
+ self.keep = keep or []
15
+ self.drop = drop or []
16
+
17
+ def include_instruction(self, instruction_name) -> bool:
18
+ return (instruction_name in self.keep) or (not instruction_name in self.drop)
19
+
20
+ def add_name(self, index) -> None:
21
+ self.name = "change_instruction_{}".format(index)
22
+
23
+ def __str__(self):
24
+ return self.text
25
+
26
+ def to_dict(self, add_edsl_version=True):
27
+ d = {
28
+ "keep": self.keep,
29
+ "drop": self.drop,
30
+ }
31
+ if add_edsl_version:
32
+ from edsl import __version__
33
+
34
+ d["edsl_version"] = __version__
35
+ d["edsl_class_name"] = "ChangeInstruction"
36
+
37
+ return d
38
+
39
+ def __hash__(self) -> int:
40
+ """Return a hash of the question."""
41
+ from edsl.utilities.utilities import dict_hash
42
+
43
+ return dict_hash(self.to_dict(add_edsl_version=False))
44
+
45
+ @classmethod
46
+ @remove_edsl_version
47
+ def from_dict(cls, data):
48
+ return cls(data["keep"], data["drop"])
@@ -1,65 +1,56 @@
1
- from typing import Union, Optional, List, Generator, Dict
2
- from edsl.questions import QuestionBase
3
-
4
- from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
5
-
6
-
7
- class Instruction:
8
- def __init__(
9
- self, name, text, preamble="You were given the following instructions:"
10
- ):
11
- self.name = name
12
- self.text = text
13
- self.preamble = preamble
14
-
15
- def __str__(self):
16
- return self.text
17
-
18
- def __repr__(self):
19
- return """Instruction(name="{}", text="{}")""".format(self.name, self.text)
20
-
21
- def _repr_html_(self):
22
- d = self.to_dict(add_edsl_version=False)
23
- data = [[k, v] for k, v in d.items()]
24
- from tabulate import tabulate
25
-
26
- table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
27
- return f"<pre>{table}</pre>"
28
-
29
- @classmethod
30
- def example(cls) -> "Instruction":
31
- return cls(name="example", text="This is an example instruction.")
32
-
33
- def to_dict(self, add_edsl_version=True):
34
- d = {
35
- "name": self.name,
36
- "text": self.text,
37
- "edsl_class_name": "Instruction",
38
- "preamble": self.preamble,
39
- }
40
- if add_edsl_version:
41
- from edsl import __version__
42
-
43
- d["edsl_version"] = __version__
44
- d["edsl_class_name"] = "Instruction"
45
- return d
46
-
47
- def add_question(self, question) -> "Survey":
48
- from edsl import Survey
49
-
50
- return Survey([self, question])
51
-
52
- def __hash__(self) -> int:
53
- """Return a hash of the question."""
54
- from edsl.utilities.utilities import dict_hash
55
-
56
- return dict_hash(self.to_dict(add_edsl_version=False))
57
-
58
- @classmethod
59
- @remove_edsl_version
60
- def from_dict(cls, data):
61
- return cls(
62
- data["name"],
63
- data["text"],
64
- data.get("preamble", "You were given the following instructions:"),
65
- )
1
+ from typing import Union, Optional, List, Generator, Dict
2
+ from edsl.utilities.remove_edsl_version import remove_edsl_version
3
+ from edsl.Base import RepresentationMixin
4
+
5
+
6
+ class Instruction(RepresentationMixin):
7
+ def __init__(
8
+ self, name, text, preamble="You were given the following instructions:"
9
+ ):
10
+ self.name = name
11
+ self.text = text
12
+ self.preamble = preamble
13
+
14
+ def __str__(self):
15
+ return self.text
16
+
17
+ def __repr__(self):
18
+ return """Instruction(name="{}", text="{}")""".format(self.name, self.text)
19
+
20
+ @classmethod
21
+ def example(cls) -> "Instruction":
22
+ return cls(name="example", text="This is an example instruction.")
23
+
24
+ def to_dict(self, add_edsl_version=True):
25
+ d = {
26
+ "name": self.name,
27
+ "text": self.text,
28
+ "edsl_class_name": "Instruction",
29
+ "preamble": self.preamble,
30
+ }
31
+ if add_edsl_version:
32
+ from edsl import __version__
33
+
34
+ d["edsl_version"] = __version__
35
+ d["edsl_class_name"] = "Instruction"
36
+ return d
37
+
38
+ def add_question(self, question) -> "Survey":
39
+ from edsl.surveys.Survey import Survey
40
+
41
+ return Survey([self, question])
42
+
43
+ def __hash__(self) -> int:
44
+ """Return a hash of the question."""
45
+ from edsl.utilities.utilities import dict_hash
46
+
47
+ return dict_hash(self.to_dict(add_edsl_version=False))
48
+
49
+ @classmethod
50
+ @remove_edsl_version
51
+ def from_dict(cls, data):
52
+ return cls(
53
+ data["name"],
54
+ data["text"],
55
+ data.get("preamble", "You were given the following instructions:"),
56
+ )