edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev5__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 (341) 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/orm.py +10 -10
  48. edsl/data_transfer_models.py +74 -73
  49. edsl/enums.py +202 -175
  50. edsl/exceptions/BaseException.py +21 -21
  51. edsl/exceptions/__init__.py +54 -54
  52. edsl/exceptions/agents.py +54 -42
  53. edsl/exceptions/cache.py +5 -5
  54. edsl/exceptions/configuration.py +16 -16
  55. edsl/exceptions/coop.py +10 -10
  56. edsl/exceptions/data.py +14 -14
  57. edsl/exceptions/general.py +34 -34
  58. edsl/exceptions/inference_services.py +5 -0
  59. edsl/exceptions/jobs.py +33 -33
  60. edsl/exceptions/language_models.py +63 -63
  61. edsl/exceptions/prompts.py +15 -15
  62. edsl/exceptions/questions.py +109 -91
  63. edsl/exceptions/results.py +29 -29
  64. edsl/exceptions/scenarios.py +29 -22
  65. edsl/exceptions/surveys.py +37 -37
  66. edsl/inference_services/AnthropicService.py +106 -87
  67. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  68. edsl/inference_services/AvailableModelFetcher.py +215 -0
  69. edsl/inference_services/AwsBedrock.py +118 -120
  70. edsl/inference_services/AzureAI.py +215 -217
  71. edsl/inference_services/DeepInfraService.py +18 -18
  72. edsl/inference_services/GoogleService.py +143 -148
  73. edsl/inference_services/GroqService.py +20 -20
  74. edsl/inference_services/InferenceServiceABC.py +80 -147
  75. edsl/inference_services/InferenceServicesCollection.py +138 -97
  76. edsl/inference_services/MistralAIService.py +120 -123
  77. edsl/inference_services/OllamaService.py +18 -18
  78. edsl/inference_services/OpenAIService.py +236 -224
  79. edsl/inference_services/PerplexityService.py +160 -163
  80. edsl/inference_services/ServiceAvailability.py +135 -0
  81. edsl/inference_services/TestService.py +90 -89
  82. edsl/inference_services/TogetherAIService.py +172 -170
  83. edsl/inference_services/data_structures.py +134 -0
  84. edsl/inference_services/models_available_cache.py +118 -118
  85. edsl/inference_services/rate_limits_cache.py +25 -25
  86. edsl/inference_services/registry.py +41 -41
  87. edsl/inference_services/write_available.py +10 -10
  88. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  89. edsl/jobs/Answers.py +43 -56
  90. edsl/jobs/FetchInvigilator.py +47 -0
  91. edsl/jobs/InterviewTaskManager.py +98 -0
  92. edsl/jobs/InterviewsConstructor.py +50 -0
  93. edsl/jobs/Jobs.py +823 -898
  94. edsl/jobs/JobsChecks.py +172 -147
  95. edsl/jobs/JobsComponentConstructor.py +189 -0
  96. edsl/jobs/JobsPrompts.py +270 -268
  97. edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
  98. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  99. edsl/jobs/RequestTokenEstimator.py +30 -0
  100. edsl/jobs/__init__.py +1 -1
  101. edsl/jobs/async_interview_runner.py +138 -0
  102. edsl/jobs/buckets/BucketCollection.py +104 -63
  103. edsl/jobs/buckets/ModelBuckets.py +65 -65
  104. edsl/jobs/buckets/TokenBucket.py +283 -251
  105. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  106. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  107. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  108. edsl/jobs/data_structures.py +120 -0
  109. edsl/jobs/decorators.py +35 -0
  110. edsl/jobs/interviews/Interview.py +396 -661
  111. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
  112. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
  113. edsl/jobs/interviews/InterviewStatistic.py +63 -63
  114. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
  115. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
  116. edsl/jobs/interviews/InterviewStatusLog.py +92 -92
  117. edsl/jobs/interviews/ReportErrors.py +66 -66
  118. edsl/jobs/interviews/interview_status_enum.py +9 -9
  119. edsl/jobs/jobs_status_enums.py +9 -0
  120. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  121. edsl/jobs/results_exceptions_handler.py +98 -0
  122. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
  123. edsl/jobs/runners/JobsRunnerStatus.py +297 -330
  124. edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
  125. edsl/jobs/tasks/TaskCreators.py +64 -64
  126. edsl/jobs/tasks/TaskHistory.py +470 -450
  127. edsl/jobs/tasks/TaskStatusLog.py +23 -23
  128. edsl/jobs/tasks/task_status_enum.py +161 -163
  129. edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
  130. edsl/jobs/tokens/TokenUsage.py +34 -34
  131. edsl/language_models/ComputeCost.py +63 -0
  132. edsl/language_models/LanguageModel.py +626 -668
  133. edsl/language_models/ModelList.py +164 -155
  134. edsl/language_models/PriceManager.py +127 -0
  135. edsl/language_models/RawResponseHandler.py +106 -0
  136. edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
  137. edsl/language_models/ServiceDataSources.py +0 -0
  138. edsl/language_models/__init__.py +2 -3
  139. edsl/language_models/fake_openai_call.py +15 -15
  140. edsl/language_models/fake_openai_service.py +61 -61
  141. edsl/language_models/key_management/KeyLookup.py +63 -0
  142. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  143. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  144. edsl/language_models/key_management/__init__.py +0 -0
  145. edsl/language_models/key_management/models.py +131 -0
  146. edsl/language_models/model.py +256 -0
  147. edsl/language_models/repair.py +156 -156
  148. edsl/language_models/utilities.py +65 -64
  149. edsl/notebooks/Notebook.py +263 -258
  150. edsl/notebooks/NotebookToLaTeX.py +142 -0
  151. edsl/notebooks/__init__.py +1 -1
  152. edsl/prompts/Prompt.py +352 -362
  153. edsl/prompts/__init__.py +2 -2
  154. edsl/questions/ExceptionExplainer.py +77 -0
  155. edsl/questions/HTMLQuestion.py +103 -0
  156. edsl/questions/QuestionBase.py +518 -664
  157. edsl/questions/QuestionBasePromptsMixin.py +221 -217
  158. edsl/questions/QuestionBudget.py +227 -227
  159. edsl/questions/QuestionCheckBox.py +359 -359
  160. edsl/questions/QuestionExtract.py +180 -182
  161. edsl/questions/QuestionFreeText.py +113 -114
  162. edsl/questions/QuestionFunctional.py +166 -166
  163. edsl/questions/QuestionList.py +223 -231
  164. edsl/questions/QuestionMatrix.py +265 -0
  165. edsl/questions/QuestionMultipleChoice.py +330 -286
  166. edsl/questions/QuestionNumerical.py +151 -153
  167. edsl/questions/QuestionRank.py +314 -324
  168. edsl/questions/Quick.py +41 -41
  169. edsl/questions/SimpleAskMixin.py +74 -73
  170. edsl/questions/__init__.py +27 -26
  171. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
  172. edsl/questions/compose_questions.py +98 -98
  173. edsl/questions/data_structures.py +20 -0
  174. edsl/questions/decorators.py +21 -21
  175. edsl/questions/derived/QuestionLikertFive.py +76 -76
  176. edsl/questions/derived/QuestionLinearScale.py +90 -87
  177. edsl/questions/derived/QuestionTopK.py +93 -93
  178. edsl/questions/derived/QuestionYesNo.py +82 -82
  179. edsl/questions/descriptors.py +427 -413
  180. edsl/questions/loop_processor.py +149 -0
  181. edsl/questions/prompt_templates/question_budget.jinja +13 -13
  182. edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
  183. edsl/questions/prompt_templates/question_extract.jinja +11 -11
  184. edsl/questions/prompt_templates/question_free_text.jinja +3 -3
  185. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
  186. edsl/questions/prompt_templates/question_list.jinja +17 -17
  187. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
  188. edsl/questions/prompt_templates/question_numerical.jinja +36 -36
  189. edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
  190. edsl/questions/question_registry.py +177 -177
  191. edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
  192. edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
  193. edsl/questions/response_validator_factory.py +34 -0
  194. edsl/questions/settings.py +12 -12
  195. edsl/questions/templates/budget/answering_instructions.jinja +7 -7
  196. edsl/questions/templates/budget/question_presentation.jinja +7 -7
  197. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
  198. edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
  199. edsl/questions/templates/extract/answering_instructions.jinja +7 -7
  200. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
  201. edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
  202. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
  203. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
  204. edsl/questions/templates/list/answering_instructions.jinja +3 -3
  205. edsl/questions/templates/list/question_presentation.jinja +5 -5
  206. edsl/questions/templates/matrix/__init__.py +1 -0
  207. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  208. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  209. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
  210. edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
  211. edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
  212. edsl/questions/templates/numerical/question_presentation.jinja +6 -6
  213. edsl/questions/templates/rank/answering_instructions.jinja +11 -11
  214. edsl/questions/templates/rank/question_presentation.jinja +15 -15
  215. edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
  216. edsl/questions/templates/top_k/question_presentation.jinja +22 -22
  217. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
  218. edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
  219. edsl/results/CSSParameterizer.py +108 -108
  220. edsl/results/Dataset.py +587 -424
  221. edsl/results/DatasetExportMixin.py +594 -731
  222. edsl/results/DatasetTree.py +295 -275
  223. edsl/results/MarkdownToDocx.py +122 -0
  224. edsl/results/MarkdownToPDF.py +111 -0
  225. edsl/results/Result.py +557 -465
  226. edsl/results/Results.py +1183 -1165
  227. edsl/results/ResultsExportMixin.py +45 -43
  228. edsl/results/ResultsGGMixin.py +121 -121
  229. edsl/results/TableDisplay.py +125 -198
  230. edsl/results/TextEditor.py +50 -0
  231. edsl/results/__init__.py +2 -2
  232. edsl/results/file_exports.py +252 -0
  233. edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
  234. edsl/results/{Selector.py → results_selector.py} +145 -135
  235. edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
  236. edsl/results/smart_objects.py +96 -0
  237. edsl/results/table_data_class.py +12 -0
  238. edsl/results/table_display.css +77 -77
  239. edsl/results/table_renderers.py +118 -0
  240. edsl/results/tree_explore.py +115 -115
  241. edsl/scenarios/ConstructDownloadLink.py +109 -0
  242. edsl/scenarios/DocumentChunker.py +102 -0
  243. edsl/scenarios/DocxScenario.py +16 -0
  244. edsl/scenarios/FileStore.py +511 -632
  245. edsl/scenarios/PdfExtractor.py +40 -0
  246. edsl/scenarios/Scenario.py +498 -601
  247. edsl/scenarios/ScenarioHtmlMixin.py +65 -64
  248. edsl/scenarios/ScenarioList.py +1458 -1287
  249. edsl/scenarios/ScenarioListExportMixin.py +45 -52
  250. edsl/scenarios/ScenarioListPdfMixin.py +239 -261
  251. edsl/scenarios/__init__.py +3 -4
  252. edsl/scenarios/directory_scanner.py +96 -0
  253. edsl/scenarios/file_methods.py +85 -0
  254. edsl/scenarios/handlers/__init__.py +13 -0
  255. edsl/scenarios/handlers/csv.py +38 -0
  256. edsl/scenarios/handlers/docx.py +76 -0
  257. edsl/scenarios/handlers/html.py +37 -0
  258. edsl/scenarios/handlers/json.py +111 -0
  259. edsl/scenarios/handlers/latex.py +5 -0
  260. edsl/scenarios/handlers/md.py +51 -0
  261. edsl/scenarios/handlers/pdf.py +68 -0
  262. edsl/scenarios/handlers/png.py +39 -0
  263. edsl/scenarios/handlers/pptx.py +105 -0
  264. edsl/scenarios/handlers/py.py +294 -0
  265. edsl/scenarios/handlers/sql.py +313 -0
  266. edsl/scenarios/handlers/sqlite.py +149 -0
  267. edsl/scenarios/handlers/txt.py +33 -0
  268. edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
  269. edsl/scenarios/scenario_selector.py +156 -0
  270. edsl/shared.py +1 -1
  271. edsl/study/ObjectEntry.py +173 -173
  272. edsl/study/ProofOfWork.py +113 -113
  273. edsl/study/SnapShot.py +80 -80
  274. edsl/study/Study.py +521 -528
  275. edsl/study/__init__.py +4 -4
  276. edsl/surveys/ConstructDAG.py +92 -0
  277. edsl/surveys/DAG.py +148 -148
  278. edsl/surveys/EditSurvey.py +221 -0
  279. edsl/surveys/InstructionHandler.py +100 -0
  280. edsl/surveys/Memory.py +31 -31
  281. edsl/surveys/MemoryManagement.py +72 -0
  282. edsl/surveys/MemoryPlan.py +244 -244
  283. edsl/surveys/Rule.py +327 -326
  284. edsl/surveys/RuleCollection.py +385 -387
  285. edsl/surveys/RuleManager.py +172 -0
  286. edsl/surveys/Simulator.py +75 -0
  287. edsl/surveys/Survey.py +1280 -1801
  288. edsl/surveys/SurveyCSS.py +273 -261
  289. edsl/surveys/SurveyExportMixin.py +259 -259
  290. edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
  291. edsl/surveys/SurveyQualtricsImport.py +284 -284
  292. edsl/surveys/SurveyToApp.py +141 -0
  293. edsl/surveys/__init__.py +5 -3
  294. edsl/surveys/base.py +53 -53
  295. edsl/surveys/descriptors.py +60 -56
  296. edsl/surveys/instructions/ChangeInstruction.py +48 -49
  297. edsl/surveys/instructions/Instruction.py +56 -65
  298. edsl/surveys/instructions/InstructionCollection.py +82 -77
  299. edsl/templates/error_reporting/base.html +23 -23
  300. edsl/templates/error_reporting/exceptions_by_model.html +34 -34
  301. edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
  302. edsl/templates/error_reporting/exceptions_by_type.html +16 -16
  303. edsl/templates/error_reporting/interview_details.html +115 -115
  304. edsl/templates/error_reporting/interviews.html +19 -19
  305. edsl/templates/error_reporting/overview.html +4 -4
  306. edsl/templates/error_reporting/performance_plot.html +1 -1
  307. edsl/templates/error_reporting/report.css +73 -73
  308. edsl/templates/error_reporting/report.html +117 -117
  309. edsl/templates/error_reporting/report.js +25 -25
  310. edsl/tools/__init__.py +1 -1
  311. edsl/tools/clusters.py +192 -192
  312. edsl/tools/embeddings.py +27 -27
  313. edsl/tools/embeddings_plotting.py +118 -118
  314. edsl/tools/plotting.py +112 -112
  315. edsl/tools/summarize.py +18 -18
  316. edsl/utilities/PrettyList.py +56 -0
  317. edsl/utilities/SystemInfo.py +28 -28
  318. edsl/utilities/__init__.py +22 -22
  319. edsl/utilities/ast_utilities.py +25 -25
  320. edsl/utilities/data/Registry.py +6 -6
  321. edsl/utilities/data/__init__.py +1 -1
  322. edsl/utilities/data/scooter_results.json +1 -1
  323. edsl/utilities/decorators.py +77 -77
  324. edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
  325. edsl/utilities/interface.py +627 -627
  326. edsl/utilities/is_notebook.py +18 -0
  327. edsl/utilities/is_valid_variable_name.py +11 -0
  328. edsl/utilities/naming_utilities.py +263 -263
  329. edsl/utilities/remove_edsl_version.py +24 -0
  330. edsl/utilities/repair_functions.py +28 -28
  331. edsl/utilities/restricted_python.py +70 -70
  332. edsl/utilities/utilities.py +436 -424
  333. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/LICENSE +21 -21
  334. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/METADATA +13 -11
  335. edsl-0.1.39.dev5.dist-info/RECORD +358 -0
  336. {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/WHEEL +1 -1
  337. edsl/language_models/KeyLookup.py +0 -30
  338. edsl/language_models/registry.py +0 -190
  339. edsl/language_models/unused/ReplicateBase.py +0 -83
  340. edsl/results/ResultsDBMixin.py +0 -238
  341. edsl-0.1.39.dev3.dist-info/RECORD +0 -277
@@ -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
+ )