edsl 0.1.38.dev4__py3-none-any.whl → 0.1.39__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 +197 -116
- edsl/__init__.py +15 -7
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +351 -147
- edsl/agents/AgentList.py +211 -73
- edsl/agents/Invigilator.py +101 -50
- edsl/agents/InvigilatorBase.py +62 -70
- edsl/agents/PromptConstructor.py +143 -225
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +0 -1
- edsl/agents/prompt_helpers.py +3 -3
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +18 -5
- edsl/auto/StageBase.py +53 -40
- edsl/auto/StageQuestions.py +2 -1
- edsl/auto/utilities.py +0 -6
- edsl/config.py +22 -2
- edsl/conversation/car_buying.py +2 -1
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +1 -1
- edsl/coop/coop.py +125 -47
- edsl/coop/utils.py +14 -14
- edsl/data/Cache.py +45 -27
- edsl/data/CacheEntry.py +12 -15
- edsl/data/CacheHandler.py +31 -12
- edsl/data/RemoteCacheSync.py +154 -46
- edsl/data/__init__.py +4 -3
- edsl/data_transfer_models.py +2 -1
- edsl/enums.py +27 -0
- edsl/exceptions/__init__.py +50 -50
- edsl/exceptions/agents.py +12 -0
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/questions.py +24 -6
- edsl/exceptions/scenarios.py +7 -0
- edsl/inference_services/AnthropicService.py +38 -19
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +0 -2
- edsl/inference_services/AzureAI.py +0 -2
- edsl/inference_services/GoogleService.py +7 -12
- edsl/inference_services/InferenceServiceABC.py +18 -85
- edsl/inference_services/InferenceServicesCollection.py +120 -79
- edsl/inference_services/MistralAIService.py +0 -3
- edsl/inference_services/OpenAIService.py +47 -35
- edsl/inference_services/PerplexityService.py +0 -3
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +11 -10
- edsl/inference_services/TogetherAIService.py +5 -3
- edsl/inference_services/data_structures.py +134 -0
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +1 -14
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +356 -431
- edsl/jobs/JobsChecks.py +35 -10
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +6 -4
- edsl/jobs/JobsRemoteInferenceHandler.py +205 -133
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +44 -3
- edsl/jobs/buckets/TokenBucket.py +53 -21
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +143 -408
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +88 -403
- edsl/jobs/runners/JobsRunnerStatus.py +133 -165
- edsl/jobs/tasks/QuestionTaskCreator.py +21 -19
- edsl/jobs/tasks/TaskHistory.py +38 -18
- edsl/jobs/tasks/task_status_enum.py +0 -2
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +194 -236
- edsl/language_models/ModelList.py +28 -19
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +1 -2
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +2 -2
- edsl/language_models/utilities.py +5 -4
- edsl/notebooks/Notebook.py +19 -14
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/prompts/Prompt.py +29 -39
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +68 -214
- edsl/questions/QuestionBasePromptsMixin.py +7 -3
- edsl/questions/QuestionBudget.py +1 -1
- edsl/questions/QuestionCheckBox.py +3 -3
- edsl/questions/QuestionExtract.py +5 -7
- edsl/questions/QuestionFreeText.py +2 -3
- edsl/questions/QuestionList.py +10 -18
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +67 -23
- edsl/questions/QuestionNumerical.py +2 -4
- edsl/questions/QuestionRank.py +7 -17
- edsl/questions/SimpleAskMixin.py +4 -3
- edsl/questions/__init__.py +2 -1
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +47 -2
- edsl/questions/data_structures.py +20 -0
- edsl/questions/derived/QuestionLinearScale.py +6 -3
- edsl/questions/derived/QuestionTopK.py +1 -1
- edsl/questions/descriptors.py +17 -3
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +57 -50
- edsl/questions/question_registry.py +1 -1
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +40 -26
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/results/CSSParameterizer.py +1 -1
- edsl/results/Dataset.py +170 -7
- edsl/results/DatasetExportMixin.py +168 -305
- edsl/results/DatasetTree.py +28 -8
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +298 -206
- edsl/results/Results.py +149 -131
- edsl/results/ResultsExportMixin.py +2 -0
- edsl/results/TableDisplay.py +98 -171
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +1 -1
- edsl/results/file_exports.py +252 -0
- edsl/results/{Selector.py → results_selector.py} +23 -13
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_renderers.py +118 -0
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +150 -239
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +90 -193
- edsl/scenarios/ScenarioHtmlMixin.py +4 -3
- edsl/scenarios/ScenarioList.py +415 -244
- edsl/scenarios/ScenarioListExportMixin.py +0 -7
- edsl/scenarios/ScenarioListPdfMixin.py +15 -37
- edsl/scenarios/__init__.py +1 -2
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +49 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +10 -6
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/study/ObjectEntry.py +1 -1
- edsl/study/SnapShot.py +1 -1
- edsl/study/Study.py +5 -12
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/Rule.py +5 -4
- edsl/surveys/RuleCollection.py +25 -27
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +270 -791
- edsl/surveys/SurveyCSS.py +20 -8
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +11 -9
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +4 -2
- edsl/surveys/descriptors.py +6 -2
- edsl/surveys/instructions/ChangeInstruction.py +1 -2
- edsl/surveys/instructions/Instruction.py +4 -13
- edsl/surveys/instructions/InstructionCollection.py +11 -6
- edsl/templates/error_reporting/interview_details.html +1 -1
- edsl/templates/error_reporting/report.html +1 -1
- edsl/tools/plotting.py +1 -1
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/utilities.py +35 -23
- {edsl-0.1.38.dev4.dist-info → edsl-0.1.39.dist-info}/METADATA +12 -10
- edsl-0.1.39.dist-info/RECORD +358 -0
- {edsl-0.1.38.dev4.dist-info → edsl-0.1.39.dist-info}/WHEEL +1 -1
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.38.dev4.dist-info/RECORD +0 -277
- /edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +0 -0
- /edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +0 -0
- /edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +0 -0
- {edsl-0.1.38.dev4.dist-info → edsl-0.1.39.dist-info}/LICENSE +0 -0
edsl/data/CacheEntry.py
CHANGED
@@ -5,8 +5,12 @@ import hashlib
|
|
5
5
|
from typing import Optional
|
6
6
|
from uuid import uuid4
|
7
7
|
|
8
|
+
from edsl.utilities.decorators import remove_edsl_version
|
8
9
|
|
9
|
-
|
10
|
+
from edsl.Base import RepresentationMixin
|
11
|
+
|
12
|
+
|
13
|
+
class CacheEntry(RepresentationMixin):
|
10
14
|
"""
|
11
15
|
A Class to represent a cache entry.
|
12
16
|
"""
|
@@ -78,11 +82,11 @@ class CacheEntry:
|
|
78
82
|
d = {k: value for k, value in self.__dict__.items() if k in self.key_fields}
|
79
83
|
return self.gen_key(**d)
|
80
84
|
|
81
|
-
def to_dict(self) -> dict:
|
85
|
+
def to_dict(self, add_edsl_version=True) -> dict:
|
82
86
|
"""
|
83
87
|
Returns a dictionary representation of a CacheEntry.
|
84
88
|
"""
|
85
|
-
|
89
|
+
d = {
|
86
90
|
"model": self.model,
|
87
91
|
"parameters": self.parameters,
|
88
92
|
"system_prompt": self.system_prompt,
|
@@ -91,19 +95,12 @@ class CacheEntry:
|
|
91
95
|
"iteration": self.iteration,
|
92
96
|
"timestamp": self.timestamp,
|
93
97
|
}
|
98
|
+
# if add_edsl_version:
|
99
|
+
# from edsl import __version__
|
94
100
|
|
95
|
-
|
96
|
-
""
|
97
|
-
|
98
|
-
"""
|
99
|
-
# from edsl.utilities.utilities import data_to_html
|
100
|
-
# return data_to_html(self.to_dict())
|
101
|
-
d = self.to_dict()
|
102
|
-
data = [[k, v] for k, v in d.items()]
|
103
|
-
from tabulate import tabulate
|
104
|
-
|
105
|
-
table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
|
106
|
-
return f"<pre>{table}</pre>"
|
101
|
+
# d["edsl_version"] = __version__
|
102
|
+
# d["edsl_class_name"] = self.__class__.__name__
|
103
|
+
return d
|
107
104
|
|
108
105
|
def keys(self):
|
109
106
|
return list(self.to_dict().keys())
|
edsl/data/CacheHandler.py
CHANGED
@@ -3,19 +3,19 @@ import ast
|
|
3
3
|
import json
|
4
4
|
import os
|
5
5
|
import shutil
|
6
|
-
import
|
7
|
-
from edsl.config import CONFIG
|
8
|
-
from edsl.data.Cache import Cache
|
9
|
-
from edsl.data.CacheEntry import CacheEntry
|
10
|
-
from edsl.data.SQLiteDict import SQLiteDict
|
6
|
+
from typing import TYPE_CHECKING
|
11
7
|
|
12
|
-
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from edsl.data.Cache import Cache
|
10
|
+
from edsl.data.CacheEntry import CacheEntry
|
13
11
|
|
14
12
|
|
15
|
-
def set_session_cache(cache: Cache) -> None:
|
13
|
+
def set_session_cache(cache: "Cache") -> None:
|
16
14
|
"""
|
17
15
|
Set the session cache.
|
18
16
|
"""
|
17
|
+
from edsl.config import CONFIG
|
18
|
+
|
19
19
|
CONFIG.EDSL_SESSION_CACHE = cache
|
20
20
|
|
21
21
|
|
@@ -23,6 +23,8 @@ def unset_session_cache() -> None:
|
|
23
23
|
"""
|
24
24
|
Unset the session cache.
|
25
25
|
"""
|
26
|
+
from edsl.config import CONFIG
|
27
|
+
|
26
28
|
if hasattr(CONFIG, "EDSL_SESSION_CACHE"):
|
27
29
|
del CONFIG.EDSL_SESSION_CACHE
|
28
30
|
|
@@ -32,7 +34,11 @@ class CacheHandler:
|
|
32
34
|
This CacheHandler figures out what caches are available and does migrations, as needed.
|
33
35
|
"""
|
34
36
|
|
35
|
-
|
37
|
+
@property
|
38
|
+
def CACHE_PATH(self):
|
39
|
+
from edsl.config import CONFIG
|
40
|
+
|
41
|
+
return CONFIG.get("EDSL_DATABASE_PATH")
|
36
42
|
|
37
43
|
def __init__(self, test: bool = False):
|
38
44
|
self.test = test
|
@@ -52,16 +58,22 @@ class CacheHandler:
|
|
52
58
|
if notify:
|
53
59
|
print(f"Created cache directory: {dir_path}")
|
54
60
|
|
55
|
-
def gen_cache(self) -> Cache:
|
61
|
+
def gen_cache(self) -> "Cache":
|
56
62
|
"""
|
57
63
|
Generate a Cache object.
|
58
64
|
"""
|
65
|
+
from edsl.data.Cache import Cache
|
66
|
+
|
59
67
|
if self.test:
|
60
68
|
return Cache(data={})
|
61
69
|
|
70
|
+
from edsl.config import CONFIG
|
71
|
+
|
62
72
|
if hasattr(CONFIG, "EDSL_SESSION_CACHE"):
|
63
73
|
return CONFIG.EDSL_SESSION_CACHE
|
64
74
|
|
75
|
+
from edsl.data.SQLiteDict import SQLiteDict
|
76
|
+
|
65
77
|
cache = Cache(data=SQLiteDict(self.CACHE_PATH))
|
66
78
|
return cache
|
67
79
|
|
@@ -76,6 +88,8 @@ class CacheHandler:
|
|
76
88
|
if not os.path.exists(os.path.join(os.getcwd(), path)):
|
77
89
|
return old_data
|
78
90
|
try:
|
91
|
+
import sqlite3
|
92
|
+
|
79
93
|
conn = sqlite3.connect(path)
|
80
94
|
with conn:
|
81
95
|
cur = conn.cursor()
|
@@ -108,6 +122,8 @@ class CacheHandler:
|
|
108
122
|
entry_dict["user_prompt"] = entry_dict.pop("prompt")
|
109
123
|
parameters = entry_dict["parameters"]
|
110
124
|
entry_dict["parameters"] = ast.literal_eval(parameters)
|
125
|
+
from edsl.data.CacheEntry import CacheEntry
|
126
|
+
|
111
127
|
entry = CacheEntry(**entry_dict)
|
112
128
|
return entry
|
113
129
|
|
@@ -117,7 +133,7 @@ class CacheHandler:
|
|
117
133
|
###############
|
118
134
|
# NOT IN USE
|
119
135
|
###############
|
120
|
-
def from_sqlite(uri="new_edsl_cache.db") -> dict[str, CacheEntry]:
|
136
|
+
def from_sqlite(uri="new_edsl_cache.db") -> dict[str, "CacheEntry"]:
|
121
137
|
"""
|
122
138
|
Read in a new-style sqlite cache and return a dictionary of dictionaries.
|
123
139
|
"""
|
@@ -131,7 +147,7 @@ class CacheHandler:
|
|
131
147
|
newdata[entry.key] = entry
|
132
148
|
return newdata
|
133
149
|
|
134
|
-
def from_jsonl(filename="edsl_cache.jsonl") -> dict[str, CacheEntry]:
|
150
|
+
def from_jsonl(filename="edsl_cache.jsonl") -> dict[str, "CacheEntry"]:
|
135
151
|
"""Read in a jsonl file and return a dictionary of CacheEntry objects."""
|
136
152
|
with open(filename, "a+") as f:
|
137
153
|
f.seek(0)
|
@@ -146,4 +162,7 @@ class CacheHandler:
|
|
146
162
|
|
147
163
|
|
148
164
|
if __name__ == "__main__":
|
149
|
-
ch = CacheHandler()
|
165
|
+
# ch = CacheHandler()
|
166
|
+
import doctest
|
167
|
+
|
168
|
+
doctest.testmod()
|
edsl/data/RemoteCacheSync.py
CHANGED
@@ -1,71 +1,166 @@
|
|
1
|
-
|
1
|
+
from typing import List, Dict, Any, Optional, TYPE_CHECKING, Callable
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from contextlib import AbstractContextManager
|
4
|
+
from collections import UserList
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from .Cache import Cache
|
8
|
+
from edsl.coop.coop import Coop
|
9
|
+
from .CacheEntry import CacheEntry
|
10
|
+
|
11
|
+
from logging import Logger
|
12
|
+
|
13
|
+
|
14
|
+
class CacheKeyList(UserList):
|
15
|
+
def __init__(self, data: List[str]):
|
16
|
+
super().__init__(data)
|
17
|
+
self.data = data
|
18
|
+
|
19
|
+
def __repr__(self):
|
20
|
+
import reprlib
|
21
|
+
|
22
|
+
keys_repr = reprlib.repr(self.data)
|
23
|
+
return f"CacheKeyList({keys_repr})"
|
24
|
+
|
25
|
+
|
26
|
+
class CacheEntriesList(UserList):
|
27
|
+
def __init__(self, data: List["CacheEntry"]):
|
28
|
+
super().__init__(data)
|
29
|
+
self.data = data
|
30
|
+
|
31
|
+
def __repr__(self):
|
32
|
+
import reprlib
|
33
|
+
|
34
|
+
entries_repr = reprlib.repr(self.data)
|
35
|
+
return f"CacheEntries({entries_repr})"
|
36
|
+
|
37
|
+
def to_cache(self) -> "Cache":
|
38
|
+
from edsl.data.Cache import Cache
|
39
|
+
|
40
|
+
return Cache({entry.key: entry for entry in self.data})
|
41
|
+
|
42
|
+
|
43
|
+
@dataclass
|
44
|
+
class CacheDifference:
|
45
|
+
client_missing_entries: CacheEntriesList
|
46
|
+
server_missing_keys: List[str]
|
47
|
+
|
48
|
+
def __repr__(self):
|
49
|
+
"""Returns a string representation of the CacheDifference object."""
|
50
|
+
import reprlib
|
51
|
+
|
52
|
+
missing_entries_repr = reprlib.repr(self.client_missing_entries)
|
53
|
+
missing_keys_repr = reprlib.repr(self.server_missing_keys)
|
54
|
+
return f"CacheDifference(client_missing_entries={missing_entries_repr}, server_missing_keys={missing_keys_repr})"
|
55
|
+
|
56
|
+
|
57
|
+
class RemoteCacheSync(AbstractContextManager):
|
58
|
+
"""Synchronizes a local cache with a remote cache.
|
59
|
+
|
60
|
+
Handles bidirectional synchronization:
|
61
|
+
- Downloads missing entries from remote to local cache
|
62
|
+
- Uploads new local entries to remote cache
|
63
|
+
"""
|
64
|
+
|
2
65
|
def __init__(
|
3
|
-
self,
|
66
|
+
self,
|
67
|
+
coop: "Coop",
|
68
|
+
cache: "Cache",
|
69
|
+
output_func: Callable,
|
70
|
+
remote_cache: bool = True,
|
71
|
+
remote_cache_description: str = "",
|
4
72
|
):
|
73
|
+
"""
|
74
|
+
Initializes a RemoteCacheSync object.
|
75
|
+
|
76
|
+
:param coop: Coop object for interacting with the remote cache
|
77
|
+
:param cache: Cache object for local cache
|
78
|
+
:param output_func: Function for outputting messages
|
79
|
+
:param remote_cache: Whether to enable remote cache synchronization
|
80
|
+
:param remote_cache_description: Description for remote cache entries
|
81
|
+
|
82
|
+
"""
|
5
83
|
self.coop = coop
|
6
84
|
self.cache = cache
|
7
85
|
self._output = output_func
|
8
|
-
self.
|
9
|
-
self.old_entry_keys = []
|
10
|
-
self.new_cache_entries = []
|
86
|
+
self.remote_cache_enabled = remote_cache
|
11
87
|
self.remote_cache_description = remote_cache_description
|
88
|
+
self.initial_cache_keys = []
|
12
89
|
|
13
|
-
def __enter__(self):
|
14
|
-
if self.
|
90
|
+
def __enter__(self) -> "RemoteCacheSync":
|
91
|
+
if self.remote_cache_enabled:
|
15
92
|
self._sync_from_remote()
|
16
|
-
self.
|
93
|
+
self.initial_cache_keys = list(self.cache.keys())
|
17
94
|
return self
|
18
95
|
|
19
96
|
def __exit__(self, exc_type, exc_value, traceback):
|
20
|
-
if self.
|
97
|
+
if self.remote_cache_enabled:
|
21
98
|
self._sync_to_remote()
|
22
99
|
return False # Propagate exceptions
|
23
100
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
101
|
+
def _get_cache_difference(self) -> CacheDifference:
|
102
|
+
"""Retrieves differences between local and remote caches."""
|
103
|
+
diff = self.coop.remote_cache_get_diff(self.cache.keys())
|
104
|
+
return CacheDifference(
|
105
|
+
client_missing_entries=diff.get("client_missing_cacheentries", []),
|
106
|
+
server_missing_keys=diff.get("server_missing_cacheentry_keys", []),
|
28
107
|
)
|
29
|
-
missing_entry_count = len(client_missing_cacheentries)
|
30
108
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
{entry.key: entry for entry in client_missing_cacheentries}
|
38
|
-
)
|
39
|
-
self._output("Local cache updated!")
|
40
|
-
else:
|
109
|
+
def _sync_from_remote(self) -> None:
|
110
|
+
"""Downloads missing entries from remote cache to local cache."""
|
111
|
+
diff: CacheDifference = self._get_cache_difference()
|
112
|
+
missing_count = len(diff.client_missing_entries)
|
113
|
+
|
114
|
+
if missing_count == 0:
|
41
115
|
self._output("No new entries to add to local cache.")
|
116
|
+
return
|
42
117
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"server_missing_cacheentry_keys", []
|
118
|
+
self._output(
|
119
|
+
f"Updating local cache with {missing_count:,} new "
|
120
|
+
f"{'entry' if missing_count == 1 else 'entries'} from remote..."
|
47
121
|
)
|
48
|
-
|
49
|
-
|
50
|
-
for
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
122
|
+
|
123
|
+
self.cache.add_from_dict(
|
124
|
+
{entry.key: entry for entry in diff.client_missing_entries}
|
125
|
+
)
|
126
|
+
self._output("Local cache updated!")
|
127
|
+
|
128
|
+
def _get_entries_to_upload(self, diff: CacheDifference) -> CacheEntriesList:
|
129
|
+
"""Determines which entries need to be uploaded to remote cache."""
|
130
|
+
# Get entries for keys missing from server
|
131
|
+
server_missing_entries = CacheEntriesList(
|
132
|
+
[
|
133
|
+
entry
|
134
|
+
for key in diff.server_missing_keys
|
135
|
+
if (entry := self.cache.data.get(key)) is not None
|
136
|
+
]
|
137
|
+
)
|
138
|
+
|
139
|
+
# Get newly added entries since sync started
|
140
|
+
new_entries = CacheEntriesList(
|
141
|
+
[
|
142
|
+
entry
|
143
|
+
for entry in self.cache.values()
|
144
|
+
if entry.key not in self.initial_cache_keys
|
145
|
+
]
|
146
|
+
)
|
147
|
+
|
148
|
+
return server_missing_entries + new_entries
|
149
|
+
|
150
|
+
def _sync_to_remote(self) -> None:
|
151
|
+
"""Uploads new local entries to remote cache."""
|
152
|
+
diff: CacheDifference = self._get_cache_difference()
|
153
|
+
entries_to_upload: CacheEntriesList = self._get_entries_to_upload(diff)
|
154
|
+
upload_count = len(entries_to_upload)
|
155
|
+
|
156
|
+
if upload_count > 0:
|
63
157
|
self._output(
|
64
|
-
f"Updating remote cache with {
|
65
|
-
f"{'entry' if
|
158
|
+
f"Updating remote cache with {upload_count:,} new "
|
159
|
+
f"{'entry' if upload_count == 1 else 'entries'}..."
|
66
160
|
)
|
161
|
+
|
67
162
|
self.coop.remote_cache_create_many(
|
68
|
-
|
163
|
+
entries_to_upload,
|
69
164
|
visibility="private",
|
70
165
|
description=self.remote_cache_description,
|
71
166
|
)
|
@@ -76,3 +171,16 @@ class RemoteCacheSync:
|
|
76
171
|
self._output(
|
77
172
|
f"There are {len(self.cache.keys()):,} entries in the local cache."
|
78
173
|
)
|
174
|
+
|
175
|
+
|
176
|
+
if __name__ == "__main__":
|
177
|
+
import doctest
|
178
|
+
|
179
|
+
doctest.testmod()
|
180
|
+
|
181
|
+
from edsl.coop.coop import Coop
|
182
|
+
from edsl.data.Cache import Cache
|
183
|
+
from edsl.data.CacheEntry import CacheEntry
|
184
|
+
|
185
|
+
r = RemoteCacheSync(Coop(), Cache(), print)
|
186
|
+
diff = r._get_cache_difference()
|
edsl/data/__init__.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from edsl.data.CacheEntry import CacheEntry
|
2
|
-
from edsl.data.SQLiteDict import SQLiteDict
|
1
|
+
# from edsl.data.CacheEntry import CacheEntry
|
2
|
+
# from edsl.data.SQLiteDict import SQLiteDict
|
3
3
|
from edsl.data.Cache import Cache
|
4
|
-
|
4
|
+
|
5
|
+
# from edsl.data.CacheHandler import CacheHandler
|
edsl/data_transfer_models.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from typing import NamedTuple, Dict, List, Optional, Any
|
2
2
|
from dataclasses import dataclass, fields
|
3
|
-
import reprlib
|
4
3
|
|
5
4
|
|
6
5
|
class ModelInputs(NamedTuple):
|
@@ -56,6 +55,8 @@ class ImageInfo:
|
|
56
55
|
encoded_image: str
|
57
56
|
|
58
57
|
def __repr__(self):
|
58
|
+
import reprlib
|
59
|
+
|
59
60
|
reprlib_instance = reprlib.Repr()
|
60
61
|
reprlib_instance.maxstring = 30 # Limit the string length for the encoded image
|
61
62
|
|
edsl/enums.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Enums for the different types of questions, language models, and inference services."""
|
2
2
|
|
3
3
|
from enum import Enum
|
4
|
+
from typing import Literal
|
4
5
|
|
5
6
|
|
6
7
|
class EnumWithChecks(Enum):
|
@@ -67,6 +68,32 @@ class InferenceServiceType(EnumWithChecks):
|
|
67
68
|
PERPLEXITY = "perplexity"
|
68
69
|
|
69
70
|
|
71
|
+
# unavoidable violation of the DRY principle but it is necessary
|
72
|
+
# checked w/ a unit test to make sure consistent with services in enums.py
|
73
|
+
InferenceServiceLiteral = Literal[
|
74
|
+
"bedrock",
|
75
|
+
"deep_infra",
|
76
|
+
"replicate",
|
77
|
+
"openai",
|
78
|
+
"google",
|
79
|
+
"test",
|
80
|
+
"anthropic",
|
81
|
+
"groq",
|
82
|
+
"azure",
|
83
|
+
"ollama",
|
84
|
+
"mistral",
|
85
|
+
"together",
|
86
|
+
"perplexity",
|
87
|
+
]
|
88
|
+
|
89
|
+
available_models_urls = {
|
90
|
+
"anthropic": "https://docs.anthropic.com/en/docs/about-claude/models",
|
91
|
+
"openai": "https://platform.openai.com/docs/models/gp",
|
92
|
+
"groq": "https://console.groq.com/docs/models",
|
93
|
+
"google": "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models",
|
94
|
+
}
|
95
|
+
|
96
|
+
|
70
97
|
service_to_api_keyname = {
|
71
98
|
InferenceServiceType.BEDROCK.value: "TBD",
|
72
99
|
InferenceServiceType.DEEP_INFRA.value: "DEEP_INFRA_API_KEY",
|
edsl/exceptions/__init__.py
CHANGED
@@ -1,54 +1,54 @@
|
|
1
|
-
from .agents import (
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
)
|
7
|
-
from .configuration import (
|
8
|
-
|
9
|
-
|
10
|
-
)
|
11
|
-
from .data import (
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
)
|
1
|
+
# from .agents import (
|
2
|
+
# # AgentAttributeLookupCallbackError,
|
3
|
+
# AgentCombinationError,
|
4
|
+
# # AgentLacksLLMError,
|
5
|
+
# # AgentRespondedWithBadJSONError,
|
6
|
+
# )
|
7
|
+
# from .configuration import (
|
8
|
+
# InvalidEnvironmentVariableError,
|
9
|
+
# MissingEnvironmentVariableError,
|
10
|
+
# )
|
11
|
+
# from .data import (
|
12
|
+
# DatabaseConnectionError,
|
13
|
+
# DatabaseCRUDError,
|
14
|
+
# DatabaseIntegrityError,
|
15
|
+
# )
|
16
16
|
|
17
|
-
from .scenarios import (
|
18
|
-
|
19
|
-
)
|
17
|
+
# from .scenarios import (
|
18
|
+
# ScenarioError,
|
19
|
+
# )
|
20
20
|
|
21
|
-
from .general import MissingAPIKeyError
|
21
|
+
# from .general import MissingAPIKeyError
|
22
22
|
|
23
|
-
from .jobs import JobsRunError, InterviewErrorPriorTaskCanceled, InterviewTimeoutError
|
23
|
+
# from .jobs import JobsRunError, InterviewErrorPriorTaskCanceled, InterviewTimeoutError
|
24
24
|
|
25
|
-
from .language_models import (
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
)
|
31
|
-
from .questions import (
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
)
|
39
|
-
from .results import (
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
)
|
45
|
-
from .surveys import (
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
)
|
25
|
+
# from .language_models import (
|
26
|
+
# LanguageModelResponseNotJSONError,
|
27
|
+
# LanguageModelMissingAttributeError,
|
28
|
+
# LanguageModelAttributeTypeError,
|
29
|
+
# LanguageModelDoNotAddError,
|
30
|
+
# )
|
31
|
+
# from .questions import (
|
32
|
+
# QuestionAnswerValidationError,
|
33
|
+
# QuestionAttributeMissing,
|
34
|
+
# QuestionCreationValidationError,
|
35
|
+
# QuestionResponseValidationError,
|
36
|
+
# QuestionSerializationError,
|
37
|
+
# QuestionScenarioRenderError,
|
38
|
+
# )
|
39
|
+
# from .results import (
|
40
|
+
# ResultsBadMutationstringError,
|
41
|
+
# ResultsColumnNotFoundError,
|
42
|
+
# ResultsInvalidNameError,
|
43
|
+
# ResultsMutateError,
|
44
|
+
# )
|
45
|
+
# from .surveys import (
|
46
|
+
# SurveyCreationError,
|
47
|
+
# SurveyHasNoRulesError,
|
48
|
+
# SurveyRuleCannotEvaluateError,
|
49
|
+
# SurveyRuleCollectionHasNoRulesAtNodeError,
|
50
|
+
# SurveyRuleReferenceInRuleToUnknownQuestionError,
|
51
|
+
# SurveyRuleRefersToFutureStateError,
|
52
|
+
# SurveyRuleSendsYouBackwardsError,
|
53
|
+
# SurveyRuleSkipLogicSyntaxError,
|
54
|
+
# )
|
edsl/exceptions/agents.py
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
from edsl.exceptions.BaseException import BaseException
|
2
2
|
|
3
3
|
|
4
|
+
# from edsl.utilities.utilities import is_notebook
|
5
|
+
|
6
|
+
# from IPython.core.error import UsageError
|
7
|
+
|
8
|
+
# class AgentListErrorAlternative(UsageError):
|
9
|
+
# def __init__(self, message):
|
10
|
+
# super().__init__(message)
|
11
|
+
|
12
|
+
import sys
|
13
|
+
from edsl.utilities.is_notebook import is_notebook
|
14
|
+
|
15
|
+
|
4
16
|
class AgentListError(BaseException):
|
5
17
|
relevant_doc = "https://docs.expectedparrot.com/en/latest/agents.html#agent-lists"
|
6
18
|
|
edsl/exceptions/questions.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Any, SupportsIndex
|
2
|
-
from jinja2 import Template
|
3
2
|
import json
|
3
|
+
from pydantic import ValidationError
|
4
4
|
|
5
5
|
|
6
6
|
class QuestionErrors(Exception):
|
@@ -20,17 +20,35 @@ class QuestionAnswerValidationError(QuestionErrors):
|
|
20
20
|
For example, if the question is a multiple choice question, the answer should be drawn from the list of options provided.
|
21
21
|
"""
|
22
22
|
|
23
|
-
def __init__(
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
message="Invalid answer.",
|
26
|
+
pydantic_error: ValidationError = None,
|
27
|
+
data: dict = None,
|
28
|
+
model=None,
|
29
|
+
):
|
24
30
|
self.message = message
|
31
|
+
self.pydantic_error = pydantic_error
|
25
32
|
self.data = data
|
26
33
|
self.model = model
|
27
34
|
super().__init__(self.message)
|
28
35
|
|
29
36
|
def __str__(self):
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
if isinstance(self.message, ValidationError):
|
38
|
+
# If it's a ValidationError, just return the core error message
|
39
|
+
return str(self.message)
|
40
|
+
elif hasattr(self.message, "errors"):
|
41
|
+
# Handle the case where it's already been converted to a string but has errors
|
42
|
+
error_list = self.message.errors()
|
43
|
+
if error_list:
|
44
|
+
return str(error_list[0].get("msg", "Unknown error"))
|
45
|
+
return str(self.message)
|
46
|
+
|
47
|
+
# def __str__(self):
|
48
|
+
# return f"""{repr(self)}
|
49
|
+
# Data being validated: {self.data}
|
50
|
+
# Pydnantic Model: {self.model}.
|
51
|
+
# Reported error: {self.message}."""
|
34
52
|
|
35
53
|
def to_html_dict(self):
|
36
54
|
return {
|
edsl/exceptions/scenarios.py
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
import re
|
2
2
|
import textwrap
|
3
3
|
|
4
|
+
# from IPython.core.error import UsageError
|
5
|
+
|
6
|
+
|
7
|
+
class AgentListError(Exception):
|
8
|
+
def __init__(self, message):
|
9
|
+
super().__init__(message)
|
10
|
+
|
4
11
|
|
5
12
|
class ScenarioError(Exception):
|
6
13
|
documentation = "https://docs.expectedparrot.com/en/latest/scenarios.html#module-edsl.scenarios.Scenario"
|