deepeval 3.7.3__py3-none-any.whl → 3.7.4__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.
- deepeval/_version.py +1 -1
- deepeval/cli/test.py +1 -1
- deepeval/config/settings.py +102 -13
- deepeval/evaluate/configs.py +1 -1
- deepeval/evaluate/execute.py +4 -1
- deepeval/metrics/answer_relevancy/template.py +4 -4
- deepeval/metrics/argument_correctness/template.py +2 -2
- deepeval/metrics/bias/template.py +3 -3
- deepeval/metrics/contextual_precision/template.py +6 -6
- deepeval/metrics/contextual_recall/template.py +2 -2
- deepeval/metrics/contextual_relevancy/template.py +3 -3
- deepeval/metrics/conversation_completeness/template.py +2 -2
- deepeval/metrics/conversational_dag/templates.py +4 -4
- deepeval/metrics/conversational_g_eval/template.py +4 -3
- deepeval/metrics/dag/templates.py +4 -4
- deepeval/metrics/faithfulness/template.py +4 -4
- deepeval/metrics/hallucination/template.py +4 -4
- deepeval/metrics/misuse/template.py +2 -2
- deepeval/metrics/multimodal_metrics/multimodal_answer_relevancy/template.py +7 -7
- deepeval/metrics/multimodal_metrics/multimodal_contextual_precision/template.py +6 -6
- deepeval/metrics/multimodal_metrics/multimodal_contextual_recall/template.py +2 -2
- deepeval/metrics/multimodal_metrics/multimodal_contextual_relevancy/template.py +3 -3
- deepeval/metrics/multimodal_metrics/multimodal_faithfulness/template.py +9 -9
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/template.py +4 -4
- deepeval/metrics/non_advice/template.py +2 -2
- deepeval/metrics/pii_leakage/template.py +2 -2
- deepeval/metrics/prompt_alignment/template.py +4 -4
- deepeval/metrics/role_violation/template.py +2 -2
- deepeval/metrics/step_efficiency/step_efficiency.py +1 -1
- deepeval/metrics/toxicity/template.py +4 -4
- deepeval/metrics/turn_relevancy/template.py +2 -2
- deepeval/models/embedding_models/azure_embedding_model.py +28 -15
- deepeval/models/embedding_models/local_embedding_model.py +23 -10
- deepeval/models/embedding_models/ollama_embedding_model.py +8 -6
- deepeval/models/embedding_models/openai_embedding_model.py +18 -2
- deepeval/models/llms/anthropic_model.py +17 -5
- deepeval/models/llms/azure_model.py +30 -18
- deepeval/models/llms/deepseek_model.py +22 -12
- deepeval/models/llms/gemini_model.py +120 -87
- deepeval/models/llms/grok_model.py +23 -16
- deepeval/models/llms/kimi_model.py +23 -12
- deepeval/models/llms/litellm_model.py +63 -25
- deepeval/models/llms/local_model.py +26 -18
- deepeval/models/llms/ollama_model.py +17 -7
- deepeval/models/llms/openai_model.py +22 -17
- deepeval/models/llms/portkey_model.py +132 -0
- deepeval/models/mlllms/azure_model.py +28 -19
- deepeval/models/mlllms/gemini_model.py +102 -73
- deepeval/models/mlllms/ollama_model.py +40 -9
- deepeval/models/mlllms/openai_model.py +65 -14
- deepeval/models/utils.py +48 -3
- deepeval/optimization/__init__.py +13 -0
- deepeval/optimization/adapters/__init__.py +2 -0
- deepeval/optimization/adapters/deepeval_scoring_adapter.py +588 -0
- deepeval/optimization/aggregates.py +14 -0
- deepeval/optimization/configs.py +34 -0
- deepeval/optimization/copro/configs.py +31 -0
- deepeval/optimization/copro/loop.py +837 -0
- deepeval/optimization/gepa/__init__.py +7 -0
- deepeval/optimization/gepa/configs.py +115 -0
- deepeval/optimization/gepa/loop.py +677 -0
- deepeval/optimization/miprov2/configs.py +134 -0
- deepeval/optimization/miprov2/loop.py +785 -0
- deepeval/optimization/mutations/__init__.py +0 -0
- deepeval/optimization/mutations/prompt_rewriter.py +458 -0
- deepeval/optimization/policies/__init__.py +16 -0
- deepeval/optimization/policies/selection.py +166 -0
- deepeval/optimization/policies/tie_breaker.py +67 -0
- deepeval/optimization/prompt_optimizer.py +462 -0
- deepeval/optimization/simba/__init__.py +0 -0
- deepeval/optimization/simba/configs.py +33 -0
- deepeval/optimization/simba/loop.py +983 -0
- deepeval/optimization/simba/types.py +15 -0
- deepeval/optimization/types.py +361 -0
- deepeval/optimization/utils.py +598 -0
- deepeval/prompt/prompt.py +10 -5
- deepeval/test_run/cache.py +2 -0
- deepeval/test_run/test_run.py +6 -1
- deepeval/utils.py +24 -0
- {deepeval-3.7.3.dist-info → deepeval-3.7.4.dist-info}/METADATA +1 -1
- {deepeval-3.7.3.dist-info → deepeval-3.7.4.dist-info}/RECORD +84 -59
- {deepeval-3.7.3.dist-info → deepeval-3.7.4.dist-info}/LICENSE.md +0 -0
- {deepeval-3.7.3.dist-info → deepeval-3.7.4.dist-info}/WHEEL +0 -0
- {deepeval-3.7.3.dist-info → deepeval-3.7.4.dist-info}/entry_points.txt +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, SecretStr
|
|
2
4
|
from google.genai import types, Client
|
|
3
5
|
from typing import Optional, Dict
|
|
4
6
|
|
|
7
|
+
from deepeval.config.settings import get_settings
|
|
8
|
+
from deepeval.models.utils import require_secret_api_key
|
|
5
9
|
from deepeval.models.retry_policy import (
|
|
6
10
|
create_retry_decorator,
|
|
7
11
|
)
|
|
8
|
-
from deepeval.key_handler import ModelKeyValues, KEY_FILE_HANDLER
|
|
9
12
|
from deepeval.models.base_model import DeepEvalBaseLLM
|
|
10
13
|
from deepeval.constants import ProviderSlug as PS
|
|
11
14
|
from google.oauth2 import service_account
|
|
12
|
-
import json
|
|
13
15
|
|
|
14
16
|
default_gemini_model = "gemini-1.5-pro"
|
|
15
17
|
|
|
@@ -57,31 +59,32 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
57
59
|
generation_kwargs: Optional[Dict] = None,
|
|
58
60
|
**kwargs,
|
|
59
61
|
):
|
|
62
|
+
|
|
63
|
+
settings = get_settings()
|
|
64
|
+
|
|
60
65
|
model_name = (
|
|
61
|
-
model_name
|
|
62
|
-
or KEY_FILE_HANDLER.fetch_data(ModelKeyValues.GEMINI_MODEL_NAME)
|
|
63
|
-
or default_gemini_model
|
|
66
|
+
model_name or settings.GEMINI_MODEL_NAME or default_gemini_model
|
|
64
67
|
)
|
|
65
68
|
|
|
66
|
-
# Get API key from
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
# Get API key from settings if not provided
|
|
70
|
+
if api_key is not None:
|
|
71
|
+
# keep it secret, keep it safe from serializings, logging and aolike
|
|
72
|
+
self.api_key: SecretStr | None = SecretStr(api_key)
|
|
73
|
+
else:
|
|
74
|
+
self.api_key = settings.GOOGLE_API_KEY
|
|
75
|
+
|
|
76
|
+
self.project = project or settings.GOOGLE_CLOUD_PROJECT
|
|
77
|
+
self.location = (
|
|
78
|
+
location
|
|
79
|
+
or settings.GOOGLE_CLOUD_LOCATION is not None
|
|
80
|
+
and str(settings.GOOGLE_CLOUD_LOCATION)
|
|
78
81
|
)
|
|
82
|
+
self.use_vertexai = settings.GOOGLE_GENAI_USE_VERTEXAI
|
|
83
|
+
|
|
79
84
|
if service_account_key:
|
|
80
85
|
self.service_account_key = service_account_key
|
|
81
86
|
else:
|
|
82
|
-
service_account_key_data =
|
|
83
|
-
ModelKeyValues.GOOGLE_SERVICE_ACCOUNT_KEY
|
|
84
|
-
)
|
|
87
|
+
service_account_key_data = settings.GOOGLE_SERVICE_ACCOUNT_KEY
|
|
85
88
|
if service_account_key_data is None:
|
|
86
89
|
self.service_account_key = None
|
|
87
90
|
elif isinstance(service_account_key_data, str):
|
|
@@ -90,69 +93,10 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
90
93
|
if temperature < 0:
|
|
91
94
|
raise ValueError("Temperature must be >= 0.")
|
|
92
95
|
self.temperature = temperature
|
|
96
|
+
|
|
97
|
+
# Raw kwargs destined for the underlying Client
|
|
93
98
|
self.kwargs = kwargs
|
|
94
99
|
self.generation_kwargs = generation_kwargs or {}
|
|
95
|
-
super().__init__(model_name, **kwargs)
|
|
96
|
-
|
|
97
|
-
def should_use_vertexai(self):
|
|
98
|
-
"""Checks if the model should use Vertex AI for generation.
|
|
99
|
-
|
|
100
|
-
This is determined first by the value of `GOOGLE_GENAI_USE_VERTEXAI`
|
|
101
|
-
environment variable. If not set, it checks for the presence of the
|
|
102
|
-
project and location.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
True if the model should use Vertex AI, False otherwise
|
|
106
|
-
"""
|
|
107
|
-
if self.use_vertexai is not None:
|
|
108
|
-
return self.use_vertexai.lower() == "yes"
|
|
109
|
-
if self.project and self.location:
|
|
110
|
-
return True
|
|
111
|
-
else:
|
|
112
|
-
return False
|
|
113
|
-
|
|
114
|
-
def load_model(self, *args, **kwargs):
|
|
115
|
-
"""Creates a client.
|
|
116
|
-
With Gen AI SDK, model is set at inference time, so there is no
|
|
117
|
-
model to load and initialize.
|
|
118
|
-
This method name is kept for compatibility with other LLMs.
|
|
119
|
-
|
|
120
|
-
Returns:
|
|
121
|
-
A GenerativeModel instance configured for evaluation.
|
|
122
|
-
"""
|
|
123
|
-
if self.should_use_vertexai():
|
|
124
|
-
if not self.project or not self.location:
|
|
125
|
-
raise ValueError(
|
|
126
|
-
"When using Vertex AI API, both project and location are required."
|
|
127
|
-
"Either provide them as arguments or set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables, "
|
|
128
|
-
"or set them in your DeepEval configuration."
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
# Create client for Vertex AI
|
|
132
|
-
self.client = Client(
|
|
133
|
-
vertexai=True,
|
|
134
|
-
project=self.project,
|
|
135
|
-
location=self.location,
|
|
136
|
-
credentials=(
|
|
137
|
-
service_account.Credentials.from_service_account_info(
|
|
138
|
-
self.service_account_key,
|
|
139
|
-
scopes=[
|
|
140
|
-
"https://www.googleapis.com/auth/cloud-platform"
|
|
141
|
-
],
|
|
142
|
-
)
|
|
143
|
-
if self.service_account_key
|
|
144
|
-
else None
|
|
145
|
-
),
|
|
146
|
-
**self.kwargs,
|
|
147
|
-
)
|
|
148
|
-
else:
|
|
149
|
-
if not self.api_key:
|
|
150
|
-
raise ValueError(
|
|
151
|
-
"Google API key is required. Either provide it directly, set GOOGLE_API_KEY environment variable, "
|
|
152
|
-
"or set it in your DeepEval configuration."
|
|
153
|
-
)
|
|
154
|
-
# Create client for Gemini API
|
|
155
|
-
self.client = Client(api_key=self.api_key, **self.kwargs)
|
|
156
100
|
|
|
157
101
|
# Configure default model generation settings
|
|
158
102
|
self.model_safety_settings = [
|
|
@@ -173,7 +117,29 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
173
117
|
threshold=types.HarmBlockThreshold.BLOCK_NONE,
|
|
174
118
|
),
|
|
175
119
|
]
|
|
176
|
-
|
|
120
|
+
|
|
121
|
+
super().__init__(model_name, **kwargs)
|
|
122
|
+
|
|
123
|
+
def should_use_vertexai(self) -> bool:
|
|
124
|
+
"""Checks if the model should use Vertex AI for generation.
|
|
125
|
+
|
|
126
|
+
This is determined first by the value of `GOOGLE_GENAI_USE_VERTEXAI`
|
|
127
|
+
environment variable. If not set, it checks for the presence of the
|
|
128
|
+
project and location.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
True if the model should use Vertex AI, False otherwise
|
|
132
|
+
"""
|
|
133
|
+
if self.use_vertexai is not None:
|
|
134
|
+
return self.use_vertexai.lower() == "yes"
|
|
135
|
+
if self.project and self.location:
|
|
136
|
+
return True
|
|
137
|
+
else:
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
###############################################
|
|
141
|
+
# Generate functions
|
|
142
|
+
###############################################
|
|
177
143
|
|
|
178
144
|
@retry_gemini
|
|
179
145
|
def generate(self, prompt: str, schema: Optional[BaseModel] = None) -> str:
|
|
@@ -186,8 +152,10 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
186
152
|
Returns:
|
|
187
153
|
Generated text response or structured output as Pydantic model
|
|
188
154
|
"""
|
|
155
|
+
client = self.load_model()
|
|
156
|
+
|
|
189
157
|
if schema is not None:
|
|
190
|
-
response =
|
|
158
|
+
response = client.models.generate_content(
|
|
191
159
|
model=self.model_name,
|
|
192
160
|
contents=prompt,
|
|
193
161
|
config=types.GenerateContentConfig(
|
|
@@ -200,7 +168,7 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
200
168
|
)
|
|
201
169
|
return response.parsed, 0
|
|
202
170
|
else:
|
|
203
|
-
response =
|
|
171
|
+
response = client.models.generate_content(
|
|
204
172
|
model=self.model_name,
|
|
205
173
|
contents=prompt,
|
|
206
174
|
config=types.GenerateContentConfig(
|
|
@@ -224,8 +192,10 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
224
192
|
Returns:
|
|
225
193
|
Generated text response or structured output as Pydantic model
|
|
226
194
|
"""
|
|
195
|
+
client = self.load_model()
|
|
196
|
+
|
|
227
197
|
if schema is not None:
|
|
228
|
-
response = await
|
|
198
|
+
response = await client.aio.models.generate_content(
|
|
229
199
|
model=self.model_name,
|
|
230
200
|
contents=prompt,
|
|
231
201
|
config=types.GenerateContentConfig(
|
|
@@ -238,7 +208,7 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
238
208
|
)
|
|
239
209
|
return response.parsed, 0
|
|
240
210
|
else:
|
|
241
|
-
response = await
|
|
211
|
+
response = await client.aio.models.generate_content(
|
|
242
212
|
model=self.model_name,
|
|
243
213
|
contents=prompt,
|
|
244
214
|
config=types.GenerateContentConfig(
|
|
@@ -249,6 +219,69 @@ class GeminiModel(DeepEvalBaseLLM):
|
|
|
249
219
|
)
|
|
250
220
|
return response.text, 0
|
|
251
221
|
|
|
222
|
+
#########
|
|
223
|
+
# Model #
|
|
224
|
+
#########
|
|
225
|
+
|
|
252
226
|
def get_model_name(self) -> str:
|
|
253
227
|
"""Returns the name of the Gemini model being used."""
|
|
254
228
|
return self.model_name
|
|
229
|
+
|
|
230
|
+
def load_model(self, *args, **kwargs):
|
|
231
|
+
"""Creates a client.
|
|
232
|
+
With Gen AI SDK, model is set at inference time, so there is no
|
|
233
|
+
model to load and initialize.
|
|
234
|
+
This method name is kept for compatibility with other LLMs.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
A GenerativeModel instance configured for evaluation.
|
|
238
|
+
"""
|
|
239
|
+
return self._build_client(**kwargs)
|
|
240
|
+
|
|
241
|
+
def _client_kwargs(self, **override_kwargs) -> Dict:
|
|
242
|
+
"""Merge ctor kwargs with any overrides passed at load_model time."""
|
|
243
|
+
client_kwargs = dict(self.kwargs or {})
|
|
244
|
+
if override_kwargs:
|
|
245
|
+
client_kwargs.update(override_kwargs)
|
|
246
|
+
return client_kwargs
|
|
247
|
+
|
|
248
|
+
def _build_client(self, **override_kwargs) -> Client:
|
|
249
|
+
client_kwargs = self._client_kwargs(**override_kwargs)
|
|
250
|
+
|
|
251
|
+
if self.should_use_vertexai():
|
|
252
|
+
if not self.project or not self.location:
|
|
253
|
+
raise ValueError(
|
|
254
|
+
"When using Vertex AI API, both project and location are required. "
|
|
255
|
+
"Either provide them as arguments or set GOOGLE_CLOUD_PROJECT and "
|
|
256
|
+
"GOOGLE_CLOUD_LOCATION in your DeepEval configuration."
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
credentials = (
|
|
260
|
+
service_account.Credentials.from_service_account_info(
|
|
261
|
+
self.service_account_key,
|
|
262
|
+
scopes=[
|
|
263
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
264
|
+
],
|
|
265
|
+
)
|
|
266
|
+
if self.service_account_key
|
|
267
|
+
else None
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
client = Client(
|
|
271
|
+
vertexai=True,
|
|
272
|
+
project=self.project,
|
|
273
|
+
location=self.location,
|
|
274
|
+
credentials=credentials,
|
|
275
|
+
**client_kwargs,
|
|
276
|
+
)
|
|
277
|
+
else:
|
|
278
|
+
api_key = require_secret_api_key(
|
|
279
|
+
self.api_key,
|
|
280
|
+
provider_label="Google Gemini",
|
|
281
|
+
env_var_name="GOOGLE_API_KEY",
|
|
282
|
+
param_hint="`api_key` to GeminiModel(...)",
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
client = Client(api_key=api_key, **client_kwargs)
|
|
286
|
+
|
|
287
|
+
return client
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
1
|
from typing import Optional, Tuple, Union, Dict
|
|
4
|
-
from pydantic import BaseModel
|
|
2
|
+
from pydantic import BaseModel, SecretStr
|
|
5
3
|
|
|
4
|
+
from deepeval.config.settings import get_settings
|
|
6
5
|
from deepeval.models.retry_policy import (
|
|
7
6
|
create_retry_decorator,
|
|
8
7
|
sdk_retries_for,
|
|
9
8
|
)
|
|
10
|
-
from deepeval.key_handler import ModelKeyValues, KEY_FILE_HANDLER
|
|
11
9
|
from deepeval.models.llms.utils import trim_and_load_json
|
|
10
|
+
from deepeval.models.utils import require_secret_api_key
|
|
12
11
|
from deepeval.models import DeepEvalBaseLLM
|
|
13
12
|
from deepeval.constants import ProviderSlug as PS
|
|
14
13
|
|
|
@@ -62,27 +61,28 @@ class GrokModel(DeepEvalBaseLLM):
|
|
|
62
61
|
generation_kwargs: Optional[Dict] = None,
|
|
63
62
|
**kwargs,
|
|
64
63
|
):
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
settings = get_settings()
|
|
65
|
+
|
|
66
|
+
model_name = model or settings.GROK_MODEL_NAME
|
|
67
|
+
|
|
68
68
|
if model_name not in model_pricing:
|
|
69
69
|
raise ValueError(
|
|
70
70
|
f"Invalid model. Available Grok models: {', '.join(model_pricing.keys())}"
|
|
71
71
|
)
|
|
72
|
-
temperature_from_key =
|
|
73
|
-
ModelKeyValues.TEMPERATURE
|
|
74
|
-
)
|
|
72
|
+
temperature_from_key = settings.TEMPERATURE
|
|
75
73
|
if temperature_from_key is None:
|
|
76
74
|
self.temperature = temperature
|
|
77
75
|
else:
|
|
78
76
|
self.temperature = float(temperature_from_key)
|
|
79
77
|
if self.temperature < 0:
|
|
80
78
|
raise ValueError("Temperature must be >= 0.")
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
|
|
80
|
+
if api_key is not None:
|
|
81
|
+
# keep it secret, keep it safe from serializings, logging and alike
|
|
82
|
+
self.api_key: SecretStr | None = SecretStr(api_key)
|
|
83
|
+
else:
|
|
84
|
+
self.api_key = settings.GROK_API_KEY
|
|
85
|
+
|
|
86
86
|
self.kwargs = kwargs
|
|
87
87
|
self.generation_kwargs = generation_kwargs or {}
|
|
88
88
|
super().__init__(model_name)
|
|
@@ -226,7 +226,14 @@ class GrokModel(DeepEvalBaseLLM):
|
|
|
226
226
|
return kwargs
|
|
227
227
|
|
|
228
228
|
def _build_client(self, cls):
|
|
229
|
-
|
|
229
|
+
api_key = require_secret_api_key(
|
|
230
|
+
self.api_key,
|
|
231
|
+
provider_label="Grok",
|
|
232
|
+
env_var_name="GROK_API_KEY",
|
|
233
|
+
param_hint="`api_key` to GrokModel(...)",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
kw = dict(api_key=api_key, **self._client_kwargs())
|
|
230
237
|
try:
|
|
231
238
|
return cls(**kw)
|
|
232
239
|
except TypeError as e:
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from typing import Optional, Tuple, Union, Dict
|
|
2
2
|
from openai import OpenAI, AsyncOpenAI
|
|
3
|
-
from pydantic import BaseModel
|
|
3
|
+
from pydantic import BaseModel, SecretStr
|
|
4
4
|
|
|
5
|
+
from deepeval.config.settings import get_settings
|
|
5
6
|
from deepeval.models.retry_policy import (
|
|
6
7
|
create_retry_decorator,
|
|
7
8
|
sdk_retries_for,
|
|
8
9
|
)
|
|
9
|
-
from deepeval.key_handler import ModelKeyValues, KEY_FILE_HANDLER
|
|
10
10
|
from deepeval.models.llms.utils import trim_and_load_json
|
|
11
|
+
from deepeval.models.utils import require_secret_api_key
|
|
11
12
|
from deepeval.models import DeepEvalBaseLLM
|
|
12
13
|
from deepeval.constants import ProviderSlug as PS
|
|
13
14
|
|
|
@@ -79,25 +80,28 @@ class KimiModel(DeepEvalBaseLLM):
|
|
|
79
80
|
generation_kwargs: Optional[Dict] = None,
|
|
80
81
|
**kwargs,
|
|
81
82
|
):
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
settings = get_settings()
|
|
84
|
+
|
|
85
|
+
model_name = model or settings.MOONSHOT_MODEL_NAME
|
|
85
86
|
if model_name not in model_pricing:
|
|
86
87
|
raise ValueError(
|
|
87
88
|
f"Invalid model. Available Moonshot models: {', '.join(model_pricing.keys())}"
|
|
88
89
|
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
90
|
+
|
|
91
|
+
temperature_from_key = settings.TEMPERATURE
|
|
92
92
|
if temperature_from_key is None:
|
|
93
93
|
self.temperature = temperature
|
|
94
94
|
else:
|
|
95
95
|
self.temperature = float(temperature_from_key)
|
|
96
96
|
if self.temperature < 0:
|
|
97
97
|
raise ValueError("Temperature must be >= 0.")
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
|
|
99
|
+
if api_key is not None:
|
|
100
|
+
# keep it secret, keep it safe from serializings, logging and alike
|
|
101
|
+
self.api_key: SecretStr | None = SecretStr(api_key)
|
|
102
|
+
else:
|
|
103
|
+
self.api_key = settings.MOONSHOT_API_KEY
|
|
104
|
+
|
|
101
105
|
self.base_url = "https://api.moonshot.cn/v1"
|
|
102
106
|
self.kwargs = kwargs
|
|
103
107
|
self.generation_kwargs = generation_kwargs or {}
|
|
@@ -218,8 +222,15 @@ class KimiModel(DeepEvalBaseLLM):
|
|
|
218
222
|
return kwargs
|
|
219
223
|
|
|
220
224
|
def _build_client(self, cls):
|
|
225
|
+
api_key = require_secret_api_key(
|
|
226
|
+
self.api_key,
|
|
227
|
+
provider_label="Kimi",
|
|
228
|
+
env_var_name="MOONSHOT_API_KEY",
|
|
229
|
+
param_hint="`api_key` to KimiModel(...)",
|
|
230
|
+
)
|
|
231
|
+
|
|
221
232
|
kw = dict(
|
|
222
|
-
api_key=
|
|
233
|
+
api_key=api_key,
|
|
223
234
|
base_url=self.base_url,
|
|
224
235
|
**self._client_kwargs(),
|
|
225
236
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from typing import Optional, Tuple, Union, Dict, List, Any
|
|
2
|
-
from pydantic import BaseModel
|
|
3
1
|
import logging
|
|
2
|
+
from typing import Optional, Tuple, Union, Dict, List, Any
|
|
3
|
+
from pydantic import BaseModel, SecretStr
|
|
4
4
|
from tenacity import (
|
|
5
5
|
retry,
|
|
6
6
|
stop_after_attempt,
|
|
@@ -8,11 +8,11 @@ from tenacity import (
|
|
|
8
8
|
wait_exponential_jitter,
|
|
9
9
|
RetryCallState,
|
|
10
10
|
)
|
|
11
|
-
import os
|
|
12
11
|
|
|
12
|
+
from deepeval.config.settings import get_settings
|
|
13
|
+
from deepeval.models.utils import require_secret_api_key
|
|
13
14
|
from deepeval.models import DeepEvalBaseLLM
|
|
14
15
|
from deepeval.models.llms.utils import trim_and_load_json
|
|
15
|
-
from deepeval.key_handler import ModelKeyValues, KEY_FILE_HANDLER
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def log_retry_error(retry_state: RetryCallState):
|
|
@@ -44,33 +44,41 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
44
44
|
generation_kwargs: Optional[Dict] = None,
|
|
45
45
|
**kwargs,
|
|
46
46
|
):
|
|
47
|
-
from litellm import completion, acompletion, get_llm_provider
|
|
48
47
|
|
|
48
|
+
settings = get_settings()
|
|
49
49
|
# Get model name from parameter or key file
|
|
50
|
-
model_name = model or
|
|
51
|
-
ModelKeyValues.LITELLM_MODEL_NAME
|
|
52
|
-
)
|
|
50
|
+
model_name = model or settings.LITELLM_MODEL_NAME
|
|
53
51
|
if not model_name:
|
|
54
52
|
raise ValueError(
|
|
55
53
|
"Model name must be provided either through parameter or set-litellm command"
|
|
56
54
|
)
|
|
57
55
|
|
|
58
|
-
# Get API key from parameter,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
# Get API key from parameter, or settings
|
|
57
|
+
if api_key is not None:
|
|
58
|
+
# keep it secret, keep it safe from serializings, logging and aolike
|
|
59
|
+
self.api_key: SecretStr | None = SecretStr(api_key)
|
|
60
|
+
else:
|
|
61
|
+
self.api_key = (
|
|
62
|
+
settings.LITELLM_API_KEY
|
|
63
|
+
or settings.LITELLM_PROXY_API_KEY
|
|
64
|
+
or settings.OPENAI_API_KEY
|
|
65
|
+
or settings.ANTHROPIC_API_KEY
|
|
66
|
+
or settings.GOOGLE_API_KEY
|
|
67
|
+
)
|
|
67
68
|
|
|
68
69
|
# Get API base from parameter, key file, or environment variable
|
|
69
70
|
self.api_base = (
|
|
70
71
|
api_base
|
|
71
|
-
or
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
or (
|
|
73
|
+
str(settings.LITELLM_API_BASE)
|
|
74
|
+
if settings.LITELLM_API_BASE is not None
|
|
75
|
+
else None
|
|
76
|
+
)
|
|
77
|
+
or (
|
|
78
|
+
str(settings.LITELLM_PROXY_API_BASE)
|
|
79
|
+
if settings.LITELLM_PROXY_API_BASE is not None
|
|
80
|
+
else None
|
|
81
|
+
)
|
|
74
82
|
)
|
|
75
83
|
|
|
76
84
|
if temperature < 0:
|
|
@@ -101,7 +109,13 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
if self.api_key:
|
|
104
|
-
|
|
112
|
+
api_key = require_secret_api_key(
|
|
113
|
+
self.api_key,
|
|
114
|
+
provider_label="LiteLLM",
|
|
115
|
+
env_var_name="LITELLM_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY",
|
|
116
|
+
param_hint="`api_key` to LiteLLMModel(...)",
|
|
117
|
+
)
|
|
118
|
+
completion_params["api_key"] = api_key
|
|
105
119
|
if self.api_base:
|
|
106
120
|
completion_params["api_base"] = self.api_base
|
|
107
121
|
|
|
@@ -150,7 +164,13 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
150
164
|
}
|
|
151
165
|
|
|
152
166
|
if self.api_key:
|
|
153
|
-
|
|
167
|
+
api_key = require_secret_api_key(
|
|
168
|
+
self.api_key,
|
|
169
|
+
provider_label="LiteLLM",
|
|
170
|
+
env_var_name="LITELLM_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY",
|
|
171
|
+
param_hint="`api_key` to LiteLLMModel(...)",
|
|
172
|
+
)
|
|
173
|
+
completion_params["api_key"] = api_key
|
|
154
174
|
if self.api_base:
|
|
155
175
|
completion_params["api_base"] = self.api_base
|
|
156
176
|
|
|
@@ -195,11 +215,17 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
195
215
|
from litellm import completion
|
|
196
216
|
|
|
197
217
|
try:
|
|
218
|
+
api_key = require_secret_api_key(
|
|
219
|
+
self.api_key,
|
|
220
|
+
provider_label="LiteLLM",
|
|
221
|
+
env_var_name="LITELLM_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY",
|
|
222
|
+
param_hint="`api_key` to LiteLLMModel(...)",
|
|
223
|
+
)
|
|
198
224
|
completion_params = {
|
|
199
225
|
"model": self.model_name,
|
|
200
226
|
"messages": [{"role": "user", "content": prompt}],
|
|
201
227
|
"temperature": self.temperature,
|
|
202
|
-
"api_key":
|
|
228
|
+
"api_key": api_key,
|
|
203
229
|
"api_base": self.api_base,
|
|
204
230
|
"logprobs": True,
|
|
205
231
|
"top_logprobs": top_logprobs,
|
|
@@ -230,11 +256,17 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
230
256
|
from litellm import acompletion
|
|
231
257
|
|
|
232
258
|
try:
|
|
259
|
+
api_key = require_secret_api_key(
|
|
260
|
+
self.api_key,
|
|
261
|
+
provider_label="LiteLLM",
|
|
262
|
+
env_var_name="LITELLM_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY",
|
|
263
|
+
param_hint="`api_key` to LiteLLMModel(...)",
|
|
264
|
+
)
|
|
233
265
|
completion_params = {
|
|
234
266
|
"model": self.model_name,
|
|
235
267
|
"messages": [{"role": "user", "content": prompt}],
|
|
236
268
|
"temperature": self.temperature,
|
|
237
|
-
"api_key":
|
|
269
|
+
"api_key": api_key,
|
|
238
270
|
"api_base": self.api_base,
|
|
239
271
|
"logprobs": True,
|
|
240
272
|
"top_logprobs": top_logprobs,
|
|
@@ -263,12 +295,18 @@ class LiteLLMModel(DeepEvalBaseLLM):
|
|
|
263
295
|
from litellm import completion
|
|
264
296
|
|
|
265
297
|
try:
|
|
298
|
+
api_key = require_secret_api_key(
|
|
299
|
+
self.api_key,
|
|
300
|
+
provider_label="LiteLLM",
|
|
301
|
+
env_var_name="LITELLM_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY",
|
|
302
|
+
param_hint="`api_key` to LiteLLMModel(...)",
|
|
303
|
+
)
|
|
266
304
|
completion_params = {
|
|
267
305
|
"model": self.model_name,
|
|
268
306
|
"messages": [{"role": "user", "content": prompt}],
|
|
269
307
|
"temperature": temperature,
|
|
270
308
|
"n": n,
|
|
271
|
-
"api_key":
|
|
309
|
+
"api_key": api_key,
|
|
272
310
|
"api_base": self.api_base,
|
|
273
311
|
}
|
|
274
312
|
completion_params.update(self.kwargs)
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
from typing import Optional, Tuple, Union, Dict
|
|
2
|
-
from pydantic import BaseModel
|
|
2
|
+
from pydantic import BaseModel, SecretStr
|
|
3
3
|
from openai import OpenAI, AsyncOpenAI
|
|
4
4
|
from openai.types.chat import ChatCompletion
|
|
5
5
|
|
|
6
|
+
from deepeval.config.settings import get_settings
|
|
6
7
|
from deepeval.models.retry_policy import (
|
|
7
8
|
create_retry_decorator,
|
|
8
9
|
sdk_retries_for,
|
|
9
10
|
)
|
|
10
11
|
from deepeval.models.llms.utils import trim_and_load_json
|
|
12
|
+
from deepeval.models.utils import require_secret_api_key
|
|
11
13
|
from deepeval.models import DeepEvalBaseLLM
|
|
12
|
-
from deepeval.key_handler import ModelKeyValues, KEY_FILE_HANDLER
|
|
13
14
|
from deepeval.constants import ProviderSlug as PS
|
|
14
15
|
|
|
15
16
|
|
|
@@ -28,18 +29,21 @@ class LocalModel(DeepEvalBaseLLM):
|
|
|
28
29
|
generation_kwargs: Optional[Dict] = None,
|
|
29
30
|
**kwargs,
|
|
30
31
|
):
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
self.
|
|
41
|
-
|
|
32
|
+
settings = get_settings()
|
|
33
|
+
|
|
34
|
+
model_name = model or settings.LOCAL_MODEL_NAME
|
|
35
|
+
if api_key is not None:
|
|
36
|
+
# keep it secret, keep it safe from serializings, logging and alike
|
|
37
|
+
self.local_model_api_key: SecretStr | None = SecretStr(api_key)
|
|
38
|
+
else:
|
|
39
|
+
self.local_model_api_key = settings.LOCAL_MODEL_API_KEY
|
|
40
|
+
|
|
41
|
+
self.base_url = (
|
|
42
|
+
base_url
|
|
43
|
+
or settings.LOCAL_MODEL_BASE_URL
|
|
44
|
+
and str(settings.LOCAL_MODEL_BASE_URL)
|
|
42
45
|
)
|
|
46
|
+
self.format = format or settings.LOCAL_MODEL_FORMAT
|
|
43
47
|
if temperature < 0:
|
|
44
48
|
raise ValueError("Temperature must be >= 0.")
|
|
45
49
|
self.temperature = temperature
|
|
@@ -94,10 +98,7 @@ class LocalModel(DeepEvalBaseLLM):
|
|
|
94
98
|
###############################################
|
|
95
99
|
|
|
96
100
|
def get_model_name(self):
|
|
97
|
-
model_name
|
|
98
|
-
ModelKeyValues.LOCAL_MODEL_NAME
|
|
99
|
-
)
|
|
100
|
-
return f"{model_name} (Local Model)"
|
|
101
|
+
return f"{self.model_name} (Local Model)"
|
|
101
102
|
|
|
102
103
|
def load_model(self, async_mode: bool = False):
|
|
103
104
|
if not async_mode:
|
|
@@ -115,8 +116,15 @@ class LocalModel(DeepEvalBaseLLM):
|
|
|
115
116
|
return kwargs
|
|
116
117
|
|
|
117
118
|
def _build_client(self, cls):
|
|
119
|
+
local_model_api_key = require_secret_api_key(
|
|
120
|
+
self.local_model_api_key,
|
|
121
|
+
provider_label="Local",
|
|
122
|
+
env_var_name="LOCAL_MODEL_API_KEY",
|
|
123
|
+
param_hint="`api_key` to LocalModel(...)",
|
|
124
|
+
)
|
|
125
|
+
|
|
118
126
|
kw = dict(
|
|
119
|
-
api_key=
|
|
127
|
+
api_key=local_model_api_key,
|
|
120
128
|
base_url=self.base_url,
|
|
121
129
|
**self._client_kwargs(),
|
|
122
130
|
)
|