edsl 0.1.39.dev1__py3-none-any.whl → 0.1.39.dev3__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.
- edsl/Base.py +332 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +49 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +867 -867
- edsl/agents/AgentList.py +413 -413
- edsl/agents/Invigilator.py +233 -233
- edsl/agents/InvigilatorBase.py +270 -265
- edsl/agents/PromptConstructor.py +354 -354
- edsl/agents/__init__.py +3 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/auto/AutoStudy.py +117 -117
- edsl/auto/StageBase.py +230 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +73 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +224 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +157 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +58 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1028 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +555 -555
- edsl/data/CacheEntry.py +233 -233
- edsl/data/CacheHandler.py +149 -149
- edsl/data/RemoteCacheSync.py +78 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +4 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +73 -73
- edsl/enums.py +175 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +42 -42
- edsl/exceptions/cache.py +5 -5
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +91 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +22 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +87 -87
- edsl/inference_services/AwsBedrock.py +120 -120
- edsl/inference_services/AzureAI.py +217 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +148 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +147 -147
- edsl/inference_services/InferenceServicesCollection.py +97 -97
- edsl/inference_services/MistralAIService.py +123 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +224 -224
- edsl/inference_services/PerplexityService.py +163 -163
- edsl/inference_services/TestService.py +89 -89
- edsl/inference_services/TogetherAIService.py +170 -170
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/Answers.py +56 -56
- edsl/jobs/Jobs.py +898 -898
- edsl/jobs/JobsChecks.py +147 -147
- edsl/jobs/JobsPrompts.py +268 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +239 -239
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/buckets/BucketCollection.py +63 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +251 -251
- edsl/jobs/interviews/Interview.py +661 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/runners/JobsRunnerAsyncio.py +466 -466
- edsl/jobs/runners/JobsRunnerStatus.py +330 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +242 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +450 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +163 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/KeyLookup.py +30 -30
- edsl/language_models/LanguageModel.py +668 -668
- edsl/language_models/ModelList.py +155 -155
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/__init__.py +3 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/registry.py +190 -190
- edsl/language_models/repair.py +156 -156
- edsl/language_models/unused/ReplicateBase.py +83 -83
- edsl/language_models/utilities.py +64 -64
- edsl/notebooks/Notebook.py +258 -258
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +362 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/AnswerValidatorMixin.py +289 -289
- edsl/questions/QuestionBase.py +664 -664
- edsl/questions/QuestionBaseGenMixin.py +161 -161
- edsl/questions/QuestionBasePromptsMixin.py +217 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +182 -182
- edsl/questions/QuestionFreeText.py +114 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +231 -231
- edsl/questions/QuestionMultipleChoice.py +286 -286
- edsl/questions/QuestionNumerical.py +153 -153
- edsl/questions/QuestionRank.py +324 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/RegisterQuestionsMeta.py +71 -71
- edsl/questions/ResponseValidatorABC.py +174 -174
- edsl/questions/SimpleAskMixin.py +73 -73
- edsl/questions/__init__.py +26 -26
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +87 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +413 -413
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/question_registry.py +177 -177
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -108
- edsl/results/Dataset.py +424 -424
- edsl/results/DatasetExportMixin.py +731 -731
- edsl/results/DatasetTree.py +275 -275
- edsl/results/Result.py +465 -465
- edsl/results/Results.py +1165 -1165
- edsl/results/ResultsDBMixin.py +238 -238
- edsl/results/ResultsExportMixin.py +43 -43
- edsl/results/ResultsFetchMixin.py +33 -33
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/ResultsToolsMixin.py +98 -98
- edsl/results/Selector.py +135 -135
- edsl/results/TableDisplay.py +198 -198
- edsl/results/__init__.py +2 -2
- edsl/results/table_display.css +77 -77
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/FileStore.py +632 -632
- edsl/scenarios/Scenario.py +601 -601
- edsl/scenarios/ScenarioHtmlMixin.py +64 -64
- edsl/scenarios/ScenarioJoin.py +127 -127
- edsl/scenarios/ScenarioList.py +1287 -1287
- edsl/scenarios/ScenarioListExportMixin.py +52 -52
- edsl/scenarios/ScenarioListPdfMixin.py +261 -261
- edsl/scenarios/__init__.py +4 -4
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +528 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +326 -326
- edsl/surveys/RuleCollection.py +387 -387
- edsl/surveys/Survey.py +1801 -1801
- edsl/surveys/SurveyCSS.py +261 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/SurveyFlowVisualizationMixin.py +179 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/__init__.py +3 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +56 -56
- edsl/surveys/instructions/ChangeInstruction.py +49 -49
- edsl/surveys/instructions/Instruction.py +65 -65
- edsl/surveys/instructions/InstructionCollection.py +77 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -19
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +424 -424
- {edsl-0.1.39.dev1.dist-info → edsl-0.1.39.dev3.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev1.dist-info → edsl-0.1.39.dev3.dist-info}/METADATA +1 -1
- edsl-0.1.39.dev3.dist-info/RECORD +277 -0
- edsl-0.1.39.dev1.dist-info/RECORD +0 -277
- {edsl-0.1.39.dev1.dist-info → edsl-0.1.39.dev3.dist-info}/WHEEL +0 -0
edsl/results/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from edsl.results.Result import Result
|
2
|
-
from edsl.results.Results import Results
|
1
|
+
from edsl.results.Result import Result
|
2
|
+
from edsl.results.Results import Results
|
edsl/results/table_display.css
CHANGED
@@ -1,78 +1,78 @@
|
|
1
|
-
.table-container {
|
2
|
-
height: var(--containerHeight) !important;
|
3
|
-
width: 100%;
|
4
|
-
overflow: auto; /* This enables both horizontal and vertical scrolling */
|
5
|
-
border: 1px solid #d4d4d4;
|
6
|
-
background: transparent;
|
7
|
-
position: relative; /* Create stacking context for sticky header */
|
8
|
-
}
|
9
|
-
|
10
|
-
.scroll-table {
|
11
|
-
/* Remove width: 100% to prevent table from being constrained */
|
12
|
-
/* min-width: 100% ensures table takes at least full container width */
|
13
|
-
min-width: 100%;
|
14
|
-
border-collapse: separate;
|
15
|
-
border-spacing: 4px;
|
16
|
-
background: transparent;
|
17
|
-
table-layout: auto; /* Allow table to size based on content */
|
18
|
-
}
|
19
|
-
|
20
|
-
.scroll-table th {
|
21
|
-
background: transparent; /* Semi-transparent background to ensure text readability */
|
22
|
-
position: sticky;
|
23
|
-
top: 0;
|
24
|
-
z-index: 1;
|
25
|
-
text-align: left !important;
|
26
|
-
padding: 8px;
|
27
|
-
font-weight: bold;
|
28
|
-
white-space: nowrap; /* Prevent header text from wrapping */
|
29
|
-
min-width: 100px; /* Ensure minimum column width */
|
30
|
-
backdrop-filter: blur(8px); /* Optional: adds extra clarity */
|
31
|
-
color: var(--headerColor);
|
32
|
-
}
|
33
|
-
|
34
|
-
.scroll-table td {
|
35
|
-
padding: 8px;
|
36
|
-
text-align: left !important;
|
37
|
-
white-space: pre-wrap;
|
38
|
-
word-wrap: break-word;
|
39
|
-
vertical-align: top;
|
40
|
-
color: inherit;
|
41
|
-
border-bottom: none;
|
42
|
-
background: transparent;
|
43
|
-
min-width: 100px; /* Match header minimum width */
|
44
|
-
}
|
45
|
-
|
46
|
-
.scroll-table tbody tr:hover {
|
47
|
-
background: transparent;
|
48
|
-
}
|
49
|
-
|
50
|
-
/* Additional rule to ensure header background is truly transparent */
|
51
|
-
.scroll-table thead tr {
|
52
|
-
background: transparent !important;
|
53
|
-
}
|
54
|
-
|
55
|
-
/* Add shadow to indicate scrollable content */
|
56
|
-
.table-container::after {
|
57
|
-
content: '';
|
58
|
-
position: absolute;
|
59
|
-
top: 0;
|
60
|
-
right: 0;
|
61
|
-
bottom: 0;
|
62
|
-
width: 5px;
|
63
|
-
background: linear-gradient(to right, transparent, rgba(242, 6, 6, 0.1));
|
64
|
-
pointer-events: none;
|
65
|
-
opacity: 0;
|
66
|
-
transition: opacity 0.3s;
|
67
|
-
}
|
68
|
-
|
69
|
-
.table-container:hover::after {
|
70
|
-
opacity: 1;
|
71
|
-
}
|
72
|
-
|
73
|
-
/* Handle Jupyter notebook specific styling */
|
74
|
-
.jp-OutputArea-output .table-container {
|
75
|
-
max-width: 100%;
|
76
|
-
margin: 0;
|
77
|
-
overflow-x: auto;
|
1
|
+
.table-container {
|
2
|
+
height: var(--containerHeight) !important;
|
3
|
+
width: 100%;
|
4
|
+
overflow: auto; /* This enables both horizontal and vertical scrolling */
|
5
|
+
border: 1px solid #d4d4d4;
|
6
|
+
background: transparent;
|
7
|
+
position: relative; /* Create stacking context for sticky header */
|
8
|
+
}
|
9
|
+
|
10
|
+
.scroll-table {
|
11
|
+
/* Remove width: 100% to prevent table from being constrained */
|
12
|
+
/* min-width: 100% ensures table takes at least full container width */
|
13
|
+
min-width: 100%;
|
14
|
+
border-collapse: separate;
|
15
|
+
border-spacing: 4px;
|
16
|
+
background: transparent;
|
17
|
+
table-layout: auto; /* Allow table to size based on content */
|
18
|
+
}
|
19
|
+
|
20
|
+
.scroll-table th {
|
21
|
+
background: transparent; /* Semi-transparent background to ensure text readability */
|
22
|
+
position: sticky;
|
23
|
+
top: 0;
|
24
|
+
z-index: 1;
|
25
|
+
text-align: left !important;
|
26
|
+
padding: 8px;
|
27
|
+
font-weight: bold;
|
28
|
+
white-space: nowrap; /* Prevent header text from wrapping */
|
29
|
+
min-width: 100px; /* Ensure minimum column width */
|
30
|
+
backdrop-filter: blur(8px); /* Optional: adds extra clarity */
|
31
|
+
color: var(--headerColor);
|
32
|
+
}
|
33
|
+
|
34
|
+
.scroll-table td {
|
35
|
+
padding: 8px;
|
36
|
+
text-align: left !important;
|
37
|
+
white-space: pre-wrap;
|
38
|
+
word-wrap: break-word;
|
39
|
+
vertical-align: top;
|
40
|
+
color: inherit;
|
41
|
+
border-bottom: none;
|
42
|
+
background: transparent;
|
43
|
+
min-width: 100px; /* Match header minimum width */
|
44
|
+
}
|
45
|
+
|
46
|
+
.scroll-table tbody tr:hover {
|
47
|
+
background: transparent;
|
48
|
+
}
|
49
|
+
|
50
|
+
/* Additional rule to ensure header background is truly transparent */
|
51
|
+
.scroll-table thead tr {
|
52
|
+
background: transparent !important;
|
53
|
+
}
|
54
|
+
|
55
|
+
/* Add shadow to indicate scrollable content */
|
56
|
+
.table-container::after {
|
57
|
+
content: '';
|
58
|
+
position: absolute;
|
59
|
+
top: 0;
|
60
|
+
right: 0;
|
61
|
+
bottom: 0;
|
62
|
+
width: 5px;
|
63
|
+
background: linear-gradient(to right, transparent, rgba(242, 6, 6, 0.1));
|
64
|
+
pointer-events: none;
|
65
|
+
opacity: 0;
|
66
|
+
transition: opacity 0.3s;
|
67
|
+
}
|
68
|
+
|
69
|
+
.table-container:hover::after {
|
70
|
+
opacity: 1;
|
71
|
+
}
|
72
|
+
|
73
|
+
/* Handle Jupyter notebook specific styling */
|
74
|
+
.jp-OutputArea-output .table-container {
|
75
|
+
max-width: 100%;
|
76
|
+
margin: 0;
|
77
|
+
overflow-x: auto;
|
78
78
|
}
|
edsl/results/tree_explore.py
CHANGED
@@ -1,115 +1,115 @@
|
|
1
|
-
from collections import defaultdict
|
2
|
-
from typing import List, Dict, Any
|
3
|
-
import json
|
4
|
-
|
5
|
-
|
6
|
-
class FoldableHTMLTableGenerator:
|
7
|
-
def __init__(self, data: List[Dict[str, Any]]):
|
8
|
-
self.data = data
|
9
|
-
|
10
|
-
def tree(self, fold_attributes: List[str], drop: List[str] = None) -> Dict:
|
11
|
-
def nested_dict():
|
12
|
-
return defaultdict(nested_dict)
|
13
|
-
|
14
|
-
result = nested_dict()
|
15
|
-
drop = drop or [] # Use an empty list if drop is None
|
16
|
-
|
17
|
-
for item in self.data:
|
18
|
-
current = result
|
19
|
-
for attr in fold_attributes:
|
20
|
-
current = current[item[attr]]
|
21
|
-
|
22
|
-
row = {
|
23
|
-
k: v
|
24
|
-
for k, v in item.items()
|
25
|
-
if k not in fold_attributes and k not in drop
|
26
|
-
}
|
27
|
-
if "_rows" not in current:
|
28
|
-
current["_rows"] = []
|
29
|
-
current["_rows"].append(row)
|
30
|
-
|
31
|
-
return result
|
32
|
-
|
33
|
-
def generate_html(self, tree, fold_attributes: List[str]) -> str:
|
34
|
-
html_content = """
|
35
|
-
<!DOCTYPE html>
|
36
|
-
<html lang="en">
|
37
|
-
<head>
|
38
|
-
<meta charset="UTF-8">
|
39
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
40
|
-
<title>Foldable Nested Table</title>
|
41
|
-
<style>
|
42
|
-
.folding-section { margin-left: 20px; }
|
43
|
-
.fold-button { cursor: pointer; margin: 5px 0; }
|
44
|
-
table { border-collapse: collapse; margin-top: 10px; }
|
45
|
-
th, td { border: 1px solid black; padding: 5px; }
|
46
|
-
.attribute-label { font-weight: bold; }
|
47
|
-
</style>
|
48
|
-
</head>
|
49
|
-
<body>
|
50
|
-
<div id="root"></div>
|
51
|
-
<script>
|
52
|
-
function toggleFold(id) {
|
53
|
-
const element = document.getElementById(id);
|
54
|
-
element.style.display = element.style.display === 'none' ? 'block' : 'none';
|
55
|
-
}
|
56
|
-
|
57
|
-
function createFoldableSection(data, path = [], attributes = %s) {
|
58
|
-
const container = document.createElement('div');
|
59
|
-
container.className = 'folding-section';
|
60
|
-
|
61
|
-
for (const [key, value] of Object.entries(data)) {
|
62
|
-
if (key === '_rows') {
|
63
|
-
const table = document.createElement('table');
|
64
|
-
const headerRow = table.insertRow();
|
65
|
-
const headers = Object.keys(value[0]);
|
66
|
-
headers.forEach(header => {
|
67
|
-
const th = document.createElement('th');
|
68
|
-
th.textContent = header;
|
69
|
-
headerRow.appendChild(th);
|
70
|
-
});
|
71
|
-
value.forEach(row => {
|
72
|
-
const tableRow = table.insertRow();
|
73
|
-
headers.forEach(header => {
|
74
|
-
const cell = tableRow.insertCell();
|
75
|
-
cell.textContent = row[header];
|
76
|
-
});
|
77
|
-
});
|
78
|
-
container.appendChild(table);
|
79
|
-
} else {
|
80
|
-
const button = document.createElement('button');
|
81
|
-
const attributeType = attributes[path.length];
|
82
|
-
button.innerHTML = `<span class="attribute-label">${attributeType}:</span> ${key}`;
|
83
|
-
button.className = 'fold-button';
|
84
|
-
const sectionId = `section-${path.join('-')}-${key}`;
|
85
|
-
button.onclick = () => toggleFold(sectionId);
|
86
|
-
container.appendChild(button);
|
87
|
-
|
88
|
-
const section = document.createElement('div');
|
89
|
-
section.id = sectionId;
|
90
|
-
section.style.display = 'none';
|
91
|
-
section.appendChild(createFoldableSection(value, [...path, key], attributes));
|
92
|
-
container.appendChild(section);
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
return container;
|
97
|
-
}
|
98
|
-
|
99
|
-
const treeData = %s;
|
100
|
-
document.getElementById('root').appendChild(createFoldableSection(treeData));
|
101
|
-
</script>
|
102
|
-
</body>
|
103
|
-
</html>
|
104
|
-
"""
|
105
|
-
|
106
|
-
return html_content % (json.dumps(fold_attributes), json.dumps(tree))
|
107
|
-
|
108
|
-
def save_html(self, fold_attributes: List[str], filename: str = "output.html"):
|
109
|
-
tree = self.tree(fold_attributes)
|
110
|
-
html_content = self.generate_html(tree, fold_attributes)
|
111
|
-
|
112
|
-
with open(filename, "w", encoding="utf-8") as f:
|
113
|
-
f.write(html_content)
|
114
|
-
|
115
|
-
print(f"HTML file has been generated: {filename}")
|
1
|
+
from collections import defaultdict
|
2
|
+
from typing import List, Dict, Any
|
3
|
+
import json
|
4
|
+
|
5
|
+
|
6
|
+
class FoldableHTMLTableGenerator:
|
7
|
+
def __init__(self, data: List[Dict[str, Any]]):
|
8
|
+
self.data = data
|
9
|
+
|
10
|
+
def tree(self, fold_attributes: List[str], drop: List[str] = None) -> Dict:
|
11
|
+
def nested_dict():
|
12
|
+
return defaultdict(nested_dict)
|
13
|
+
|
14
|
+
result = nested_dict()
|
15
|
+
drop = drop or [] # Use an empty list if drop is None
|
16
|
+
|
17
|
+
for item in self.data:
|
18
|
+
current = result
|
19
|
+
for attr in fold_attributes:
|
20
|
+
current = current[item[attr]]
|
21
|
+
|
22
|
+
row = {
|
23
|
+
k: v
|
24
|
+
for k, v in item.items()
|
25
|
+
if k not in fold_attributes and k not in drop
|
26
|
+
}
|
27
|
+
if "_rows" not in current:
|
28
|
+
current["_rows"] = []
|
29
|
+
current["_rows"].append(row)
|
30
|
+
|
31
|
+
return result
|
32
|
+
|
33
|
+
def generate_html(self, tree, fold_attributes: List[str]) -> str:
|
34
|
+
html_content = """
|
35
|
+
<!DOCTYPE html>
|
36
|
+
<html lang="en">
|
37
|
+
<head>
|
38
|
+
<meta charset="UTF-8">
|
39
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
40
|
+
<title>Foldable Nested Table</title>
|
41
|
+
<style>
|
42
|
+
.folding-section { margin-left: 20px; }
|
43
|
+
.fold-button { cursor: pointer; margin: 5px 0; }
|
44
|
+
table { border-collapse: collapse; margin-top: 10px; }
|
45
|
+
th, td { border: 1px solid black; padding: 5px; }
|
46
|
+
.attribute-label { font-weight: bold; }
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
<body>
|
50
|
+
<div id="root"></div>
|
51
|
+
<script>
|
52
|
+
function toggleFold(id) {
|
53
|
+
const element = document.getElementById(id);
|
54
|
+
element.style.display = element.style.display === 'none' ? 'block' : 'none';
|
55
|
+
}
|
56
|
+
|
57
|
+
function createFoldableSection(data, path = [], attributes = %s) {
|
58
|
+
const container = document.createElement('div');
|
59
|
+
container.className = 'folding-section';
|
60
|
+
|
61
|
+
for (const [key, value] of Object.entries(data)) {
|
62
|
+
if (key === '_rows') {
|
63
|
+
const table = document.createElement('table');
|
64
|
+
const headerRow = table.insertRow();
|
65
|
+
const headers = Object.keys(value[0]);
|
66
|
+
headers.forEach(header => {
|
67
|
+
const th = document.createElement('th');
|
68
|
+
th.textContent = header;
|
69
|
+
headerRow.appendChild(th);
|
70
|
+
});
|
71
|
+
value.forEach(row => {
|
72
|
+
const tableRow = table.insertRow();
|
73
|
+
headers.forEach(header => {
|
74
|
+
const cell = tableRow.insertCell();
|
75
|
+
cell.textContent = row[header];
|
76
|
+
});
|
77
|
+
});
|
78
|
+
container.appendChild(table);
|
79
|
+
} else {
|
80
|
+
const button = document.createElement('button');
|
81
|
+
const attributeType = attributes[path.length];
|
82
|
+
button.innerHTML = `<span class="attribute-label">${attributeType}:</span> ${key}`;
|
83
|
+
button.className = 'fold-button';
|
84
|
+
const sectionId = `section-${path.join('-')}-${key}`;
|
85
|
+
button.onclick = () => toggleFold(sectionId);
|
86
|
+
container.appendChild(button);
|
87
|
+
|
88
|
+
const section = document.createElement('div');
|
89
|
+
section.id = sectionId;
|
90
|
+
section.style.display = 'none';
|
91
|
+
section.appendChild(createFoldableSection(value, [...path, key], attributes));
|
92
|
+
container.appendChild(section);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
return container;
|
97
|
+
}
|
98
|
+
|
99
|
+
const treeData = %s;
|
100
|
+
document.getElementById('root').appendChild(createFoldableSection(treeData));
|
101
|
+
</script>
|
102
|
+
</body>
|
103
|
+
</html>
|
104
|
+
"""
|
105
|
+
|
106
|
+
return html_content % (json.dumps(fold_attributes), json.dumps(tree))
|
107
|
+
|
108
|
+
def save_html(self, fold_attributes: List[str], filename: str = "output.html"):
|
109
|
+
tree = self.tree(fold_attributes)
|
110
|
+
html_content = self.generate_html(tree, fold_attributes)
|
111
|
+
|
112
|
+
with open(filename, "w", encoding="utf-8") as f:
|
113
|
+
f.write(html_content)
|
114
|
+
|
115
|
+
print(f"HTML file has been generated: {filename}")
|