edsl 0.1.39__py3-none-any.whl → 0.1.39.dev1__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 +116 -197
- edsl/__init__.py +7 -15
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +147 -351
- edsl/agents/AgentList.py +73 -211
- edsl/agents/Invigilator.py +50 -101
- edsl/agents/InvigilatorBase.py +70 -62
- edsl/agents/PromptConstructor.py +225 -143
- edsl/agents/__init__.py +1 -0
- edsl/agents/prompt_helpers.py +3 -3
- edsl/auto/AutoStudy.py +5 -18
- edsl/auto/StageBase.py +40 -53
- edsl/auto/StageQuestions.py +1 -2
- edsl/auto/utilities.py +6 -0
- edsl/config.py +2 -22
- edsl/conversation/car_buying.py +1 -2
- edsl/coop/PriceFetcher.py +1 -1
- edsl/coop/coop.py +47 -125
- edsl/coop/utils.py +14 -14
- edsl/data/Cache.py +27 -45
- edsl/data/CacheEntry.py +15 -12
- edsl/data/CacheHandler.py +12 -31
- edsl/data/RemoteCacheSync.py +46 -154
- edsl/data/__init__.py +3 -4
- edsl/data_transfer_models.py +1 -2
- edsl/enums.py +0 -27
- edsl/exceptions/__init__.py +50 -50
- edsl/exceptions/agents.py +0 -12
- edsl/exceptions/questions.py +6 -24
- edsl/exceptions/scenarios.py +0 -7
- edsl/inference_services/AnthropicService.py +19 -38
- edsl/inference_services/AwsBedrock.py +2 -0
- edsl/inference_services/AzureAI.py +2 -0
- edsl/inference_services/GoogleService.py +12 -7
- edsl/inference_services/InferenceServiceABC.py +85 -18
- edsl/inference_services/InferenceServicesCollection.py +79 -120
- edsl/inference_services/MistralAIService.py +3 -0
- edsl/inference_services/OpenAIService.py +35 -47
- edsl/inference_services/PerplexityService.py +3 -0
- edsl/inference_services/TestService.py +10 -11
- edsl/inference_services/TogetherAIService.py +3 -5
- edsl/jobs/Answers.py +14 -1
- edsl/jobs/Jobs.py +431 -356
- edsl/jobs/JobsChecks.py +10 -35
- edsl/jobs/JobsPrompts.py +4 -6
- edsl/jobs/JobsRemoteInferenceHandler.py +133 -205
- edsl/jobs/buckets/BucketCollection.py +3 -44
- edsl/jobs/buckets/TokenBucket.py +21 -53
- edsl/jobs/interviews/Interview.py +408 -143
- edsl/jobs/runners/JobsRunnerAsyncio.py +403 -88
- edsl/jobs/runners/JobsRunnerStatus.py +165 -133
- edsl/jobs/tasks/QuestionTaskCreator.py +19 -21
- edsl/jobs/tasks/TaskHistory.py +18 -38
- edsl/jobs/tasks/task_status_enum.py +2 -0
- edsl/language_models/KeyLookup.py +30 -0
- edsl/language_models/LanguageModel.py +236 -194
- edsl/language_models/ModelList.py +19 -28
- edsl/language_models/__init__.py +2 -1
- edsl/language_models/registry.py +190 -0
- edsl/language_models/repair.py +2 -2
- edsl/language_models/unused/ReplicateBase.py +83 -0
- edsl/language_models/utilities.py +4 -5
- edsl/notebooks/Notebook.py +14 -19
- edsl/prompts/Prompt.py +39 -29
- edsl/questions/{answer_validator_mixin.py → AnswerValidatorMixin.py} +2 -47
- edsl/questions/QuestionBase.py +214 -68
- edsl/questions/{question_base_gen_mixin.py → QuestionBaseGenMixin.py} +50 -57
- edsl/questions/QuestionBasePromptsMixin.py +3 -7
- edsl/questions/QuestionBudget.py +1 -1
- edsl/questions/QuestionCheckBox.py +3 -3
- edsl/questions/QuestionExtract.py +7 -5
- edsl/questions/QuestionFreeText.py +3 -2
- edsl/questions/QuestionList.py +18 -10
- edsl/questions/QuestionMultipleChoice.py +23 -67
- edsl/questions/QuestionNumerical.py +4 -2
- edsl/questions/QuestionRank.py +17 -7
- edsl/questions/{response_validator_abc.py → ResponseValidatorABC.py} +26 -40
- edsl/questions/SimpleAskMixin.py +3 -4
- edsl/questions/__init__.py +1 -2
- edsl/questions/derived/QuestionLinearScale.py +3 -6
- edsl/questions/derived/QuestionTopK.py +1 -1
- edsl/questions/descriptors.py +3 -17
- edsl/questions/question_registry.py +1 -1
- edsl/results/CSSParameterizer.py +1 -1
- edsl/results/Dataset.py +7 -170
- edsl/results/DatasetExportMixin.py +305 -168
- edsl/results/DatasetTree.py +8 -28
- edsl/results/Result.py +206 -298
- edsl/results/Results.py +131 -149
- edsl/results/ResultsDBMixin.py +238 -0
- edsl/results/ResultsExportMixin.py +0 -2
- edsl/results/{results_selector.py → Selector.py} +13 -23
- edsl/results/TableDisplay.py +171 -98
- edsl/results/__init__.py +1 -1
- edsl/scenarios/FileStore.py +239 -150
- edsl/scenarios/Scenario.py +193 -90
- edsl/scenarios/ScenarioHtmlMixin.py +3 -4
- edsl/scenarios/{scenario_join.py → ScenarioJoin.py} +6 -10
- edsl/scenarios/ScenarioList.py +244 -415
- edsl/scenarios/ScenarioListExportMixin.py +7 -0
- edsl/scenarios/ScenarioListPdfMixin.py +37 -15
- edsl/scenarios/__init__.py +2 -1
- edsl/study/ObjectEntry.py +1 -1
- edsl/study/SnapShot.py +1 -1
- edsl/study/Study.py +12 -5
- edsl/surveys/Rule.py +4 -5
- edsl/surveys/RuleCollection.py +27 -25
- edsl/surveys/Survey.py +791 -270
- edsl/surveys/SurveyCSS.py +8 -20
- edsl/surveys/{SurveyFlowVisualization.py → SurveyFlowVisualizationMixin.py} +9 -11
- edsl/surveys/__init__.py +2 -4
- edsl/surveys/descriptors.py +2 -6
- edsl/surveys/instructions/ChangeInstruction.py +2 -1
- edsl/surveys/instructions/Instruction.py +13 -4
- edsl/surveys/instructions/InstructionCollection.py +6 -11
- 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/utilities.py +23 -35
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/METADATA +10 -12
- edsl-0.1.39.dev1.dist-info/RECORD +277 -0
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/WHEEL +1 -1
- edsl/agents/QuestionInstructionPromptBuilder.py +0 -128
- edsl/agents/QuestionTemplateReplacementsBuilder.py +0 -137
- edsl/agents/question_option_processor.py +0 -172
- edsl/coop/CoopFunctionsMixin.py +0 -15
- edsl/coop/ExpectedParrotKeyHandler.py +0 -125
- edsl/exceptions/inference_services.py +0 -5
- edsl/inference_services/AvailableModelCacheHandler.py +0 -184
- edsl/inference_services/AvailableModelFetcher.py +0 -215
- edsl/inference_services/ServiceAvailability.py +0 -135
- edsl/inference_services/data_structures.py +0 -134
- edsl/jobs/AnswerQuestionFunctionConstructor.py +0 -223
- edsl/jobs/FetchInvigilator.py +0 -47
- edsl/jobs/InterviewTaskManager.py +0 -98
- edsl/jobs/InterviewsConstructor.py +0 -50
- edsl/jobs/JobsComponentConstructor.py +0 -189
- edsl/jobs/JobsRemoteInferenceLogger.py +0 -239
- edsl/jobs/RequestTokenEstimator.py +0 -30
- edsl/jobs/async_interview_runner.py +0 -138
- edsl/jobs/buckets/TokenBucketAPI.py +0 -211
- edsl/jobs/buckets/TokenBucketClient.py +0 -191
- edsl/jobs/check_survey_scenario_compatibility.py +0 -85
- edsl/jobs/data_structures.py +0 -120
- edsl/jobs/decorators.py +0 -35
- edsl/jobs/jobs_status_enums.py +0 -9
- edsl/jobs/loggers/HTMLTableJobLogger.py +0 -304
- edsl/jobs/results_exceptions_handler.py +0 -98
- edsl/language_models/ComputeCost.py +0 -63
- edsl/language_models/PriceManager.py +0 -127
- edsl/language_models/RawResponseHandler.py +0 -106
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/key_management/KeyLookup.py +0 -63
- edsl/language_models/key_management/KeyLookupBuilder.py +0 -273
- edsl/language_models/key_management/KeyLookupCollection.py +0 -38
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +0 -131
- edsl/language_models/model.py +0 -256
- edsl/notebooks/NotebookToLaTeX.py +0 -142
- edsl/questions/ExceptionExplainer.py +0 -77
- edsl/questions/HTMLQuestion.py +0 -103
- edsl/questions/QuestionMatrix.py +0 -265
- edsl/questions/data_structures.py +0 -20
- edsl/questions/loop_processor.py +0 -149
- edsl/questions/response_validator_factory.py +0 -34
- edsl/questions/templates/matrix/__init__.py +0 -1
- edsl/questions/templates/matrix/answering_instructions.jinja +0 -5
- edsl/questions/templates/matrix/question_presentation.jinja +0 -20
- edsl/results/MarkdownToDocx.py +0 -122
- edsl/results/MarkdownToPDF.py +0 -111
- edsl/results/TextEditor.py +0 -50
- edsl/results/file_exports.py +0 -252
- edsl/results/smart_objects.py +0 -96
- edsl/results/table_data_class.py +0 -12
- edsl/results/table_renderers.py +0 -118
- edsl/scenarios/ConstructDownloadLink.py +0 -109
- edsl/scenarios/DocumentChunker.py +0 -102
- edsl/scenarios/DocxScenario.py +0 -16
- edsl/scenarios/PdfExtractor.py +0 -40
- edsl/scenarios/directory_scanner.py +0 -96
- edsl/scenarios/file_methods.py +0 -85
- edsl/scenarios/handlers/__init__.py +0 -13
- edsl/scenarios/handlers/csv.py +0 -49
- edsl/scenarios/handlers/docx.py +0 -76
- edsl/scenarios/handlers/html.py +0 -37
- edsl/scenarios/handlers/json.py +0 -111
- edsl/scenarios/handlers/latex.py +0 -5
- edsl/scenarios/handlers/md.py +0 -51
- edsl/scenarios/handlers/pdf.py +0 -68
- edsl/scenarios/handlers/png.py +0 -39
- edsl/scenarios/handlers/pptx.py +0 -105
- edsl/scenarios/handlers/py.py +0 -294
- edsl/scenarios/handlers/sql.py +0 -313
- edsl/scenarios/handlers/sqlite.py +0 -149
- edsl/scenarios/handlers/txt.py +0 -33
- edsl/scenarios/scenario_selector.py +0 -156
- edsl/surveys/ConstructDAG.py +0 -92
- edsl/surveys/EditSurvey.py +0 -221
- edsl/surveys/InstructionHandler.py +0 -100
- edsl/surveys/MemoryManagement.py +0 -72
- edsl/surveys/RuleManager.py +0 -172
- edsl/surveys/Simulator.py +0 -75
- edsl/surveys/SurveyToApp.py +0 -141
- edsl/utilities/PrettyList.py +0 -56
- edsl/utilities/is_notebook.py +0 -18
- edsl/utilities/is_valid_variable_name.py +0 -11
- edsl/utilities/remove_edsl_version.py +0 -24
- edsl-0.1.39.dist-info/RECORD +0 -358
- /edsl/questions/{register_questions_meta.py → RegisterQuestionsMeta.py} +0 -0
- /edsl/results/{results_fetch_mixin.py → ResultsFetchMixin.py} +0 -0
- /edsl/results/{results_tools_mixin.py → ResultsToolsMixin.py} +0 -0
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/LICENSE +0 -0
@@ -1,138 +1,97 @@
|
|
1
|
-
from functools import lru_cache
|
2
|
-
from collections import defaultdict
|
3
|
-
from typing import Optional, Protocol, Dict, List, Tuple, TYPE_CHECKING, Literal
|
4
|
-
|
5
1
|
from edsl.inference_services.InferenceServiceABC import InferenceServiceABC
|
6
|
-
|
7
|
-
from edsl.exceptions.inference_services import InferenceServiceError
|
8
|
-
|
9
|
-
if TYPE_CHECKING:
|
10
|
-
from edsl.language_models.LanguageModel import LanguageModel
|
11
|
-
from edsl.inference_services.InferenceServiceABC import InferenceServiceABC
|
12
|
-
|
13
|
-
|
14
|
-
class ModelCreator(Protocol):
|
15
|
-
def create_model(self, model_name: str) -> "LanguageModel":
|
16
|
-
...
|
17
|
-
|
18
|
-
|
19
|
-
from edsl.enums import InferenceServiceLiteral
|
20
|
-
|
21
|
-
|
22
|
-
class ModelResolver:
|
23
|
-
def __init__(
|
24
|
-
self,
|
25
|
-
services: List[InferenceServiceLiteral],
|
26
|
-
models_to_services: Dict[InferenceServiceLiteral, InferenceServiceABC],
|
27
|
-
availability_fetcher: "AvailableModelFetcher",
|
28
|
-
):
|
29
|
-
"""
|
30
|
-
Class for determining which service to use for a given model.
|
31
|
-
"""
|
32
|
-
self.services = services
|
33
|
-
self._models_to_services = models_to_services
|
34
|
-
self.availability_fetcher = availability_fetcher
|
35
|
-
self._service_names_to_classes = {
|
36
|
-
service._inference_service_: service for service in services
|
37
|
-
}
|
38
|
-
|
39
|
-
def resolve_model(
|
40
|
-
self, model_name: str, service_name: Optional[InferenceServiceLiteral] = None
|
41
|
-
) -> InferenceServiceABC:
|
42
|
-
"""Returns an InferenceServiceABC object for the given model name.
|
43
|
-
|
44
|
-
:param model_name: The name of the model to resolve. E.g., 'gpt-4o'
|
45
|
-
:param service_name: The name of the service to use. E.g., 'openai'
|
46
|
-
:return: An InferenceServiceABC object
|
47
|
-
|
48
|
-
"""
|
49
|
-
if model_name == "test":
|
50
|
-
from edsl.inference_services.TestService import TestService
|
51
|
-
|
52
|
-
return TestService()
|
53
|
-
|
54
|
-
if service_name is not None:
|
55
|
-
service: InferenceServiceABC = self._service_names_to_classes.get(
|
56
|
-
service_name
|
57
|
-
)
|
58
|
-
if not service:
|
59
|
-
raise InferenceServiceError(f"Service {service_name} not found")
|
60
|
-
return service
|
61
|
-
|
62
|
-
if model_name in self._models_to_services: # maybe we've seen it before!
|
63
|
-
return self._models_to_services[model_name]
|
64
|
-
|
65
|
-
for service in self.services:
|
66
|
-
(
|
67
|
-
available_models,
|
68
|
-
service_name,
|
69
|
-
) = self.availability_fetcher.get_available_models_by_service(service)
|
70
|
-
if model_name in available_models:
|
71
|
-
self._models_to_services[model_name] = service
|
72
|
-
return service
|
73
|
-
|
74
|
-
raise InferenceServiceError(
|
75
|
-
f"""Model {model_name} not found in any services.
|
76
|
-
If you know the service that has this model, use the service_name parameter directly.
|
77
|
-
E.g., Model("gpt-4o", service_name="openai")
|
78
|
-
"""
|
79
|
-
)
|
2
|
+
import warnings
|
80
3
|
|
81
4
|
|
82
5
|
class InferenceServicesCollection:
|
83
|
-
added_models =
|
6
|
+
added_models = {}
|
84
7
|
|
85
|
-
def __init__(self, services:
|
8
|
+
def __init__(self, services: list[InferenceServiceABC] = None):
|
86
9
|
self.services = services or []
|
87
|
-
self._models_to_services: Dict[str, InferenceServiceABC] = {}
|
88
|
-
|
89
|
-
self.availability_fetcher = AvailableModelFetcher(
|
90
|
-
self.services, self.added_models
|
91
|
-
)
|
92
|
-
self.resolver = ModelResolver(
|
93
|
-
self.services, self._models_to_services, self.availability_fetcher
|
94
|
-
)
|
95
10
|
|
96
11
|
@classmethod
|
97
|
-
def add_model(cls, service_name
|
12
|
+
def add_model(cls, service_name, model_name):
|
98
13
|
if service_name not in cls.added_models:
|
99
|
-
cls.added_models[service_name]
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
14
|
+
cls.added_models[service_name] = []
|
15
|
+
cls.added_models[service_name].append(model_name)
|
16
|
+
|
17
|
+
@staticmethod
|
18
|
+
def _get_service_available(service, warn: bool = False) -> list[str]:
|
19
|
+
try:
|
20
|
+
service_models = service.available()
|
21
|
+
except Exception:
|
22
|
+
if warn:
|
23
|
+
warnings.warn(
|
24
|
+
f"""Error getting models for {service._inference_service_}.
|
25
|
+
Check that you have properly stored your Expected Parrot API key and activated remote inference, or stored your own API keys for the language models that you want to use.
|
26
|
+
See https://docs.expectedparrot.com/en/latest/api_keys.html for instructions on storing API keys.
|
27
|
+
Relying on Coop.""",
|
28
|
+
UserWarning,
|
29
|
+
)
|
30
|
+
|
31
|
+
# Use the list of models on Coop as a fallback
|
32
|
+
try:
|
33
|
+
from edsl import Coop
|
34
|
+
|
35
|
+
c = Coop()
|
36
|
+
models_from_coop = c.fetch_models()
|
37
|
+
service_models = models_from_coop.get(service._inference_service_, [])
|
38
|
+
|
39
|
+
# cache results
|
40
|
+
service._models_list_cache = service_models
|
41
|
+
|
42
|
+
# Finally, use the available models cache from the Python file
|
43
|
+
except Exception:
|
44
|
+
if warn:
|
45
|
+
warnings.warn(
|
46
|
+
f"""Error getting models for {service._inference_service_}.
|
47
|
+
Relying on EDSL cache.""",
|
48
|
+
UserWarning,
|
49
|
+
)
|
50
|
+
|
51
|
+
from edsl.inference_services.models_available_cache import (
|
52
|
+
models_available,
|
53
|
+
)
|
54
|
+
|
55
|
+
service_models = models_available.get(service._inference_service_, [])
|
56
|
+
|
57
|
+
# cache results
|
58
|
+
service._models_list_cache = service_models
|
59
|
+
|
60
|
+
return service_models
|
61
|
+
|
62
|
+
def available(self):
|
63
|
+
total_models = []
|
64
|
+
for service in self.services:
|
65
|
+
service_models = self._get_service_available(service)
|
66
|
+
for model in service_models:
|
67
|
+
total_models.append([model, service._inference_service_, -1])
|
109
68
|
|
110
|
-
|
111
|
-
|
69
|
+
for model in self.added_models.get(service._inference_service_, []):
|
70
|
+
total_models.append([model, service._inference_service_, -1])
|
112
71
|
|
113
|
-
|
114
|
-
|
115
|
-
|
72
|
+
sorted_models = sorted(total_models)
|
73
|
+
for i, model in enumerate(sorted_models):
|
74
|
+
model[2] = i
|
75
|
+
model = tuple(model)
|
76
|
+
return sorted_models
|
116
77
|
|
117
|
-
def register(self, service
|
78
|
+
def register(self, service):
|
118
79
|
self.services.append(service)
|
119
80
|
|
120
|
-
def create_model_factory(
|
121
|
-
|
122
|
-
) -> "LanguageModel":
|
123
|
-
|
124
|
-
if service_name is None: # we try to find the right service
|
125
|
-
service = self.resolver.resolve_model(model_name, service_name)
|
126
|
-
else: # if they passed a service, we'll use that
|
127
|
-
service = self.service_names_to_classes().get(service_name)
|
81
|
+
def create_model_factory(self, model_name: str, service_name=None, index=None):
|
82
|
+
from edsl.inference_services.TestService import TestService
|
128
83
|
|
129
|
-
if
|
130
|
-
|
131
|
-
|
132
|
-
return service.create_model(model_name)
|
84
|
+
if model_name == "test":
|
85
|
+
return TestService.create_model(model_name)
|
133
86
|
|
87
|
+
if service_name:
|
88
|
+
for service in self.services:
|
89
|
+
if service_name == service._inference_service_:
|
90
|
+
return service.create_model(model_name)
|
134
91
|
|
135
|
-
|
136
|
-
|
92
|
+
for service in self.services:
|
93
|
+
if model_name in self._get_service_available(service):
|
94
|
+
if service_name is None or service_name == service._inference_service_:
|
95
|
+
return service.create_model(model_name)
|
137
96
|
|
138
|
-
|
97
|
+
raise Exception(f"Model {model_name} not found in any of the services")
|
@@ -1,19 +1,16 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import Any, List, Optional
|
2
|
+
from typing import Any, List, Optional
|
3
3
|
import os
|
4
4
|
|
5
|
-
|
6
5
|
import openai
|
7
6
|
|
8
7
|
from edsl.inference_services.InferenceServiceABC import InferenceServiceABC
|
9
|
-
from edsl.language_models
|
8
|
+
from edsl.language_models import LanguageModel
|
10
9
|
from edsl.inference_services.rate_limits_cache import rate_limits
|
11
10
|
from edsl.utilities.utilities import fix_partial_correct_response
|
12
11
|
|
13
12
|
from edsl.config import CONFIG
|
14
13
|
|
15
|
-
APIToken = NewType("APIToken", str)
|
16
|
-
|
17
14
|
|
18
15
|
class OpenAIService(InferenceServiceABC):
|
19
16
|
"""OpenAI service class."""
|
@@ -25,43 +22,35 @@ class OpenAIService(InferenceServiceABC):
|
|
25
22
|
_sync_client_ = openai.OpenAI
|
26
23
|
_async_client_ = openai.AsyncOpenAI
|
27
24
|
|
28
|
-
|
29
|
-
|
25
|
+
_sync_client_instance = None
|
26
|
+
_async_client_instance = None
|
30
27
|
|
31
28
|
key_sequence = ["choices", 0, "message", "content"]
|
32
29
|
usage_sequence = ["usage"]
|
33
30
|
input_token_name = "prompt_tokens"
|
34
31
|
output_token_name = "completion_tokens"
|
35
32
|
|
36
|
-
available_models_url = "https://platform.openai.com/docs/models/gp"
|
37
|
-
|
38
33
|
def __init_subclass__(cls, **kwargs):
|
39
34
|
super().__init_subclass__(**kwargs)
|
40
|
-
# so subclasses
|
41
|
-
cls.
|
42
|
-
cls.
|
35
|
+
# so subclasses have to create their own instances of the clients
|
36
|
+
cls._sync_client_instance = None
|
37
|
+
cls._async_client_instance = None
|
43
38
|
|
44
39
|
@classmethod
|
45
|
-
def sync_client(cls
|
46
|
-
if
|
47
|
-
|
48
|
-
api_key=
|
49
|
-
base_url=cls._base_url_,
|
40
|
+
def sync_client(cls):
|
41
|
+
if cls._sync_client_instance is None:
|
42
|
+
cls._sync_client_instance = cls._sync_client_(
|
43
|
+
api_key=os.getenv(cls._env_key_name_), base_url=cls._base_url_
|
50
44
|
)
|
51
|
-
|
52
|
-
client = cls._sync_client_instances[api_key]
|
53
|
-
return client
|
45
|
+
return cls._sync_client_instance
|
54
46
|
|
55
47
|
@classmethod
|
56
|
-
def async_client(cls
|
57
|
-
if
|
58
|
-
|
59
|
-
api_key=
|
60
|
-
base_url=cls._base_url_,
|
48
|
+
def async_client(cls):
|
49
|
+
if cls._async_client_instance is None:
|
50
|
+
cls._async_client_instance = cls._async_client_(
|
51
|
+
api_key=os.getenv(cls._env_key_name_), base_url=cls._base_url_
|
61
52
|
)
|
62
|
-
|
63
|
-
client = cls._async_client_instances[api_key]
|
64
|
-
return client
|
53
|
+
return cls._async_client_instance
|
65
54
|
|
66
55
|
model_exclude_list = [
|
67
56
|
"whisper-1",
|
@@ -83,24 +72,20 @@ class OpenAIService(InferenceServiceABC):
|
|
83
72
|
_models_list_cache: List[str] = []
|
84
73
|
|
85
74
|
@classmethod
|
86
|
-
def get_model_list(cls
|
87
|
-
|
88
|
-
api_key = os.getenv(cls._env_key_name_)
|
89
|
-
raw_list = cls.sync_client(api_key).models.list()
|
75
|
+
def get_model_list(cls):
|
76
|
+
raw_list = cls.sync_client().models.list()
|
90
77
|
if hasattr(raw_list, "data"):
|
91
78
|
return raw_list.data
|
92
79
|
else:
|
93
80
|
return raw_list
|
94
81
|
|
95
82
|
@classmethod
|
96
|
-
def available(cls
|
97
|
-
if api_token is None:
|
98
|
-
api_token = os.getenv(cls._env_key_name_)
|
83
|
+
def available(cls) -> List[str]:
|
99
84
|
if not cls._models_list_cache:
|
100
85
|
try:
|
101
86
|
cls._models_list_cache = [
|
102
87
|
m.id
|
103
|
-
for m in cls.get_model_list(
|
88
|
+
for m in cls.get_model_list()
|
104
89
|
if m.id not in cls.model_exclude_list
|
105
90
|
]
|
106
91
|
except Exception as e:
|
@@ -122,6 +107,9 @@ class OpenAIService(InferenceServiceABC):
|
|
122
107
|
input_token_name = cls.input_token_name
|
123
108
|
output_token_name = cls.output_token_name
|
124
109
|
|
110
|
+
_rpm = cls.get_rpm(cls)
|
111
|
+
_tpm = cls.get_tpm(cls)
|
112
|
+
|
125
113
|
_inference_service_ = cls._inference_service_
|
126
114
|
_model_ = model_name
|
127
115
|
_parameters_ = {
|
@@ -135,10 +123,10 @@ class OpenAIService(InferenceServiceABC):
|
|
135
123
|
}
|
136
124
|
|
137
125
|
def sync_client(self):
|
138
|
-
return cls.sync_client(
|
126
|
+
return cls.sync_client()
|
139
127
|
|
140
128
|
def async_client(self):
|
141
|
-
return cls.async_client(
|
129
|
+
return cls.async_client()
|
142
130
|
|
143
131
|
@classmethod
|
144
132
|
def available(cls) -> list[str]:
|
@@ -187,16 +175,16 @@ class OpenAIService(InferenceServiceABC):
|
|
187
175
|
) -> dict[str, Any]:
|
188
176
|
"""Calls the OpenAI API and returns the API response."""
|
189
177
|
if files_list:
|
178
|
+
encoded_image = files_list[0].base64_string
|
190
179
|
content = [{"type": "text", "text": user_prompt}]
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
"
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
)
|
180
|
+
content.append(
|
181
|
+
{
|
182
|
+
"type": "image_url",
|
183
|
+
"image_url": {
|
184
|
+
"url": f"data:image/jpeg;base64,{encoded_image}"
|
185
|
+
},
|
186
|
+
}
|
187
|
+
)
|
200
188
|
else:
|
201
189
|
content = user_prompt
|
202
190
|
client = self.async_client()
|
@@ -51,6 +51,9 @@ class PerplexityService(OpenAIService):
|
|
51
51
|
input_token_name = cls.input_token_name
|
52
52
|
output_token_name = cls.output_token_name
|
53
53
|
|
54
|
+
_rpm = cls.get_rpm(cls)
|
55
|
+
_tpm = cls.get_tpm(cls)
|
56
|
+
|
54
57
|
_inference_service_ = cls._inference_service_
|
55
58
|
_model_ = model_name
|
56
59
|
|
@@ -2,7 +2,7 @@ from typing import Any, List, Optional
|
|
2
2
|
import os
|
3
3
|
import asyncio
|
4
4
|
from edsl.inference_services.InferenceServiceABC import InferenceServiceABC
|
5
|
-
from edsl.language_models
|
5
|
+
from edsl.language_models import LanguageModel
|
6
6
|
from edsl.inference_services.rate_limits_cache import rate_limits
|
7
7
|
from edsl.utilities.utilities import fix_partial_correct_response
|
8
8
|
|
@@ -51,7 +51,6 @@ class TestService(InferenceServiceABC):
|
|
51
51
|
@property
|
52
52
|
def _canned_response(self):
|
53
53
|
if hasattr(self, "canned_response"):
|
54
|
-
|
55
54
|
return self.canned_response
|
56
55
|
else:
|
57
56
|
return "Hello, world"
|
@@ -64,15 +63,7 @@ class TestService(InferenceServiceABC):
|
|
64
63
|
files_list: Optional[List["File"]] = None,
|
65
64
|
) -> dict[str, Any]:
|
66
65
|
await asyncio.sleep(0.1)
|
67
|
-
|
68
|
-
if hasattr(self, "throw_exception") and self.throw_exception:
|
69
|
-
if hasattr(self, "exception_probability"):
|
70
|
-
p = self.exception_probability
|
71
|
-
else:
|
72
|
-
p = 1
|
73
|
-
|
74
|
-
if random.random() < p:
|
75
|
-
raise Exception("This is a test error")
|
66
|
+
# return {"message": """{"answer": "Hello, world"}"""}
|
76
67
|
|
77
68
|
if hasattr(self, "func"):
|
78
69
|
return {
|
@@ -82,6 +73,14 @@ class TestService(InferenceServiceABC):
|
|
82
73
|
"usage": {"prompt_tokens": 1, "completion_tokens": 1},
|
83
74
|
}
|
84
75
|
|
76
|
+
if hasattr(self, "throw_exception") and self.throw_exception:
|
77
|
+
if hasattr(self, "exception_probability"):
|
78
|
+
p = self.exception_probability
|
79
|
+
else:
|
80
|
+
p = 1
|
81
|
+
|
82
|
+
if random.random() < p:
|
83
|
+
raise Exception("This is a test error")
|
85
84
|
return {
|
86
85
|
"message": [{"text": f"{self._canned_response}"}],
|
87
86
|
"usage": {"prompt_tokens": 1, "completion_tokens": 1},
|
@@ -143,17 +143,15 @@ class TogetherAIService(OpenAIService):
|
|
143
143
|
_async_client_ = openai.AsyncOpenAI
|
144
144
|
|
145
145
|
@classmethod
|
146
|
-
def get_model_list(cls
|
146
|
+
def get_model_list(cls):
|
147
147
|
# Togheter.ai has a different response in model list then openai
|
148
148
|
# and the OpenAI class returns an error when calling .models.list()
|
149
149
|
import requests
|
150
150
|
import os
|
151
151
|
|
152
152
|
url = "https://api.together.xyz/v1/models?filter=serverless"
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
headers = {"accept": "application/json", "authorization": f"Bearer {api_token}"}
|
153
|
+
token = os.getenv(cls._env_key_name_)
|
154
|
+
headers = {"accept": "application/json", "authorization": f"Bearer {token}"}
|
157
155
|
|
158
156
|
response = requests.get(url, headers=headers)
|
159
157
|
return response.json()
|
edsl/jobs/Answers.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""This module contains the Answers class, which is a helper class to hold the answers to a survey."""
|
2
2
|
|
3
3
|
from collections import UserDict
|
4
|
+
from rich.table import Table
|
4
5
|
from edsl.data_transfer_models import EDSLResultObjectInput
|
5
6
|
|
6
7
|
|
@@ -21,7 +22,7 @@ class Answers(UserDict):
|
|
21
22
|
if comment:
|
22
23
|
self[question.question_name + "_comment"] = comment
|
23
24
|
|
24
|
-
def replace_missing_answers_with_none(self, survey
|
25
|
+
def replace_missing_answers_with_none(self, survey) -> None:
|
25
26
|
"""Replace missing answers with None. Answers can be missing if the agent skips a question."""
|
26
27
|
for question_name in survey.question_names:
|
27
28
|
if question_name not in self:
|
@@ -36,6 +37,18 @@ class Answers(UserDict):
|
|
36
37
|
"""Return an Answers object from a dictionary."""
|
37
38
|
return cls(d)
|
38
39
|
|
40
|
+
def rich_print(self):
|
41
|
+
"""Display an object as a table."""
|
42
|
+
table = Table(title="Answers")
|
43
|
+
table.add_column("Attribute", style="bold")
|
44
|
+
table.add_column("Value")
|
45
|
+
|
46
|
+
to_display = self
|
47
|
+
for attr_name, attr_value in to_display.items():
|
48
|
+
table.add_row(attr_name, repr(attr_value))
|
49
|
+
|
50
|
+
return table
|
51
|
+
|
39
52
|
|
40
53
|
if __name__ == "__main__":
|
41
54
|
import doctest
|