deepeval 3.7.4__py3-none-any.whl → 3.7.6__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/config/settings.py +35 -1
- deepeval/dataset/api.py +23 -1
- deepeval/dataset/golden.py +139 -2
- deepeval/evaluate/evaluate.py +16 -11
- deepeval/evaluate/execute.py +13 -181
- deepeval/evaluate/utils.py +6 -26
- deepeval/integrations/pydantic_ai/agent.py +19 -2
- deepeval/integrations/pydantic_ai/instrumentator.py +62 -23
- deepeval/key_handler.py +3 -0
- deepeval/metrics/__init__.py +14 -16
- deepeval/metrics/answer_relevancy/answer_relevancy.py +118 -116
- deepeval/metrics/answer_relevancy/template.py +22 -3
- deepeval/metrics/arena_g_eval/arena_g_eval.py +98 -96
- deepeval/metrics/arena_g_eval/template.py +17 -1
- deepeval/metrics/argument_correctness/argument_correctness.py +81 -87
- deepeval/metrics/argument_correctness/template.py +19 -2
- deepeval/metrics/base_metric.py +13 -44
- deepeval/metrics/bias/bias.py +102 -108
- deepeval/metrics/bias/template.py +14 -2
- deepeval/metrics/contextual_precision/contextual_precision.py +96 -94
- deepeval/metrics/contextual_precision/template.py +115 -66
- deepeval/metrics/contextual_recall/contextual_recall.py +94 -84
- deepeval/metrics/contextual_recall/template.py +106 -55
- deepeval/metrics/contextual_relevancy/contextual_relevancy.py +86 -84
- deepeval/metrics/contextual_relevancy/template.py +87 -58
- deepeval/metrics/conversation_completeness/conversation_completeness.py +101 -119
- deepeval/metrics/conversation_completeness/template.py +23 -3
- deepeval/metrics/conversational_dag/conversational_dag.py +12 -8
- deepeval/metrics/conversational_dag/nodes.py +66 -123
- deepeval/metrics/conversational_dag/templates.py +16 -0
- deepeval/metrics/conversational_g_eval/conversational_g_eval.py +47 -66
- deepeval/metrics/dag/dag.py +10 -0
- deepeval/metrics/dag/nodes.py +63 -126
- deepeval/metrics/dag/templates.py +16 -2
- deepeval/metrics/exact_match/exact_match.py +9 -1
- deepeval/metrics/faithfulness/faithfulness.py +138 -149
- deepeval/metrics/faithfulness/schema.py +1 -1
- deepeval/metrics/faithfulness/template.py +200 -115
- deepeval/metrics/g_eval/g_eval.py +87 -78
- deepeval/metrics/g_eval/template.py +18 -1
- deepeval/metrics/g_eval/utils.py +7 -6
- deepeval/metrics/goal_accuracy/goal_accuracy.py +91 -76
- deepeval/metrics/goal_accuracy/template.py +21 -3
- deepeval/metrics/hallucination/hallucination.py +60 -75
- deepeval/metrics/hallucination/template.py +13 -0
- deepeval/metrics/indicator.py +7 -10
- deepeval/metrics/json_correctness/json_correctness.py +40 -38
- deepeval/metrics/json_correctness/template.py +10 -0
- deepeval/metrics/knowledge_retention/knowledge_retention.py +60 -97
- deepeval/metrics/knowledge_retention/schema.py +9 -3
- deepeval/metrics/knowledge_retention/template.py +12 -0
- deepeval/metrics/mcp/mcp_task_completion.py +68 -38
- deepeval/metrics/mcp/multi_turn_mcp_use_metric.py +92 -74
- deepeval/metrics/mcp/template.py +52 -0
- deepeval/metrics/mcp_use_metric/mcp_use_metric.py +58 -64
- deepeval/metrics/mcp_use_metric/template.py +12 -0
- deepeval/metrics/misuse/misuse.py +77 -97
- deepeval/metrics/misuse/template.py +15 -0
- deepeval/metrics/multimodal_metrics/__init__.py +0 -19
- deepeval/metrics/multimodal_metrics/image_coherence/image_coherence.py +59 -53
- deepeval/metrics/multimodal_metrics/image_editing/image_editing.py +79 -95
- deepeval/metrics/multimodal_metrics/image_helpfulness/image_helpfulness.py +59 -53
- deepeval/metrics/multimodal_metrics/image_reference/image_reference.py +59 -53
- deepeval/metrics/multimodal_metrics/text_to_image/text_to_image.py +111 -109
- deepeval/metrics/non_advice/non_advice.py +79 -105
- deepeval/metrics/non_advice/template.py +12 -0
- deepeval/metrics/pattern_match/pattern_match.py +12 -4
- deepeval/metrics/pii_leakage/pii_leakage.py +75 -106
- deepeval/metrics/pii_leakage/template.py +14 -0
- deepeval/metrics/plan_adherence/plan_adherence.py +63 -89
- deepeval/metrics/plan_adherence/template.py +11 -0
- deepeval/metrics/plan_quality/plan_quality.py +63 -87
- deepeval/metrics/plan_quality/template.py +9 -0
- deepeval/metrics/prompt_alignment/prompt_alignment.py +72 -83
- deepeval/metrics/prompt_alignment/template.py +12 -0
- deepeval/metrics/ragas.py +3 -3
- deepeval/metrics/role_adherence/role_adherence.py +48 -71
- deepeval/metrics/role_adherence/template.py +14 -0
- deepeval/metrics/role_violation/role_violation.py +75 -108
- deepeval/metrics/role_violation/template.py +12 -0
- deepeval/metrics/step_efficiency/step_efficiency.py +55 -65
- deepeval/metrics/step_efficiency/template.py +11 -0
- deepeval/metrics/summarization/summarization.py +115 -183
- deepeval/metrics/summarization/template.py +19 -0
- deepeval/metrics/task_completion/task_completion.py +67 -73
- deepeval/metrics/tool_correctness/tool_correctness.py +45 -44
- deepeval/metrics/tool_use/tool_use.py +42 -66
- deepeval/metrics/topic_adherence/template.py +13 -0
- deepeval/metrics/topic_adherence/topic_adherence.py +53 -67
- deepeval/metrics/toxicity/template.py +13 -0
- deepeval/metrics/toxicity/toxicity.py +80 -99
- deepeval/metrics/turn_contextual_precision/schema.py +21 -0
- deepeval/metrics/turn_contextual_precision/template.py +187 -0
- deepeval/metrics/turn_contextual_precision/turn_contextual_precision.py +592 -0
- deepeval/metrics/turn_contextual_recall/schema.py +21 -0
- deepeval/metrics/turn_contextual_recall/template.py +178 -0
- deepeval/metrics/turn_contextual_recall/turn_contextual_recall.py +563 -0
- deepeval/metrics/{multimodal_metrics/multimodal_contextual_relevancy → turn_contextual_relevancy}/schema.py +7 -1
- deepeval/metrics/turn_contextual_relevancy/template.py +161 -0
- deepeval/metrics/turn_contextual_relevancy/turn_contextual_relevancy.py +576 -0
- deepeval/metrics/{multimodal_metrics/multimodal_faithfulness → turn_faithfulness}/schema.py +11 -3
- deepeval/metrics/turn_faithfulness/template.py +218 -0
- deepeval/metrics/turn_faithfulness/turn_faithfulness.py +627 -0
- deepeval/metrics/turn_relevancy/template.py +14 -0
- deepeval/metrics/turn_relevancy/turn_relevancy.py +56 -69
- deepeval/metrics/utils.py +158 -122
- deepeval/models/__init__.py +0 -12
- deepeval/models/base_model.py +49 -33
- deepeval/models/embedding_models/__init__.py +7 -0
- deepeval/models/embedding_models/azure_embedding_model.py +79 -33
- deepeval/models/embedding_models/local_embedding_model.py +39 -20
- deepeval/models/embedding_models/ollama_embedding_model.py +52 -19
- deepeval/models/embedding_models/openai_embedding_model.py +42 -22
- deepeval/models/llms/amazon_bedrock_model.py +226 -72
- deepeval/models/llms/anthropic_model.py +178 -63
- deepeval/models/llms/azure_model.py +218 -60
- deepeval/models/llms/constants.py +2032 -0
- deepeval/models/llms/deepseek_model.py +95 -40
- deepeval/models/llms/gemini_model.py +209 -64
- deepeval/models/llms/grok_model.py +139 -68
- deepeval/models/llms/kimi_model.py +140 -90
- deepeval/models/llms/litellm_model.py +131 -37
- deepeval/models/llms/local_model.py +125 -21
- deepeval/models/llms/ollama_model.py +147 -24
- deepeval/models/llms/openai_model.py +222 -269
- deepeval/models/llms/portkey_model.py +81 -22
- deepeval/models/llms/utils.py +8 -3
- deepeval/models/retry_policy.py +17 -14
- deepeval/models/utils.py +106 -5
- deepeval/optimizer/__init__.py +5 -0
- deepeval/optimizer/algorithms/__init__.py +6 -0
- deepeval/optimizer/algorithms/base.py +29 -0
- deepeval/optimizer/algorithms/configs.py +18 -0
- deepeval/optimizer/algorithms/copro/__init__.py +5 -0
- deepeval/{optimization/copro/loop.py → optimizer/algorithms/copro/copro.py} +112 -113
- deepeval/optimizer/algorithms/gepa/__init__.py +5 -0
- deepeval/{optimization/gepa/loop.py → optimizer/algorithms/gepa/gepa.py} +175 -115
- deepeval/optimizer/algorithms/miprov2/__init__.py +17 -0
- deepeval/optimizer/algorithms/miprov2/bootstrapper.py +435 -0
- deepeval/optimizer/algorithms/miprov2/miprov2.py +752 -0
- deepeval/optimizer/algorithms/miprov2/proposer.py +301 -0
- deepeval/optimizer/algorithms/simba/__init__.py +5 -0
- deepeval/{optimization/simba/loop.py → optimizer/algorithms/simba/simba.py} +128 -112
- deepeval/{optimization → optimizer}/configs.py +5 -8
- deepeval/{optimization/policies/selection.py → optimizer/policies.py} +63 -2
- deepeval/optimizer/prompt_optimizer.py +263 -0
- deepeval/optimizer/rewriter/__init__.py +5 -0
- deepeval/optimizer/rewriter/rewriter.py +124 -0
- deepeval/optimizer/rewriter/utils.py +214 -0
- deepeval/optimizer/scorer/__init__.py +5 -0
- deepeval/optimizer/scorer/base.py +86 -0
- deepeval/optimizer/scorer/scorer.py +316 -0
- deepeval/optimizer/scorer/utils.py +30 -0
- deepeval/optimizer/types.py +148 -0
- deepeval/{optimization → optimizer}/utils.py +47 -165
- deepeval/prompt/prompt.py +5 -9
- deepeval/simulator/conversation_simulator.py +43 -0
- deepeval/simulator/template.py +13 -0
- deepeval/test_case/__init__.py +1 -3
- deepeval/test_case/api.py +26 -45
- deepeval/test_case/arena_test_case.py +7 -2
- deepeval/test_case/conversational_test_case.py +68 -1
- deepeval/test_case/llm_test_case.py +206 -1
- deepeval/test_case/utils.py +4 -8
- deepeval/test_run/api.py +18 -14
- deepeval/test_run/test_run.py +3 -3
- deepeval/tracing/patchers.py +9 -4
- deepeval/tracing/tracing.py +2 -2
- deepeval/utils.py +65 -0
- {deepeval-3.7.4.dist-info → deepeval-3.7.6.dist-info}/METADATA +1 -4
- {deepeval-3.7.4.dist-info → deepeval-3.7.6.dist-info}/RECORD +180 -193
- deepeval/metrics/multimodal_metrics/multimodal_answer_relevancy/multimodal_answer_relevancy.py +0 -343
- deepeval/metrics/multimodal_metrics/multimodal_answer_relevancy/schema.py +0 -19
- deepeval/metrics/multimodal_metrics/multimodal_answer_relevancy/template.py +0 -122
- deepeval/metrics/multimodal_metrics/multimodal_contextual_precision/multimodal_contextual_precision.py +0 -301
- deepeval/metrics/multimodal_metrics/multimodal_contextual_precision/schema.py +0 -15
- deepeval/metrics/multimodal_metrics/multimodal_contextual_precision/template.py +0 -132
- deepeval/metrics/multimodal_metrics/multimodal_contextual_recall/multimodal_contextual_recall.py +0 -285
- deepeval/metrics/multimodal_metrics/multimodal_contextual_recall/schema.py +0 -15
- deepeval/metrics/multimodal_metrics/multimodal_contextual_recall/template.py +0 -112
- deepeval/metrics/multimodal_metrics/multimodal_contextual_relevancy/multimodal_contextual_relevancy.py +0 -282
- deepeval/metrics/multimodal_metrics/multimodal_contextual_relevancy/template.py +0 -102
- deepeval/metrics/multimodal_metrics/multimodal_faithfulness/__init__.py +0 -0
- deepeval/metrics/multimodal_metrics/multimodal_faithfulness/multimodal_faithfulness.py +0 -356
- deepeval/metrics/multimodal_metrics/multimodal_faithfulness/template.py +0 -175
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/__init__.py +0 -0
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/multimodal_g_eval.py +0 -386
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/schema.py +0 -11
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/template.py +0 -148
- deepeval/metrics/multimodal_metrics/multimodal_g_eval/utils.py +0 -68
- deepeval/metrics/multimodal_metrics/multimodal_tool_correctness/__init__.py +0 -0
- deepeval/metrics/multimodal_metrics/multimodal_tool_correctness/multimodal_tool_correctness.py +0 -290
- deepeval/models/mlllms/__init__.py +0 -4
- deepeval/models/mlllms/azure_model.py +0 -343
- deepeval/models/mlllms/gemini_model.py +0 -313
- deepeval/models/mlllms/ollama_model.py +0 -175
- deepeval/models/mlllms/openai_model.py +0 -309
- deepeval/optimization/__init__.py +0 -13
- deepeval/optimization/adapters/__init__.py +0 -2
- deepeval/optimization/adapters/deepeval_scoring_adapter.py +0 -588
- deepeval/optimization/aggregates.py +0 -14
- deepeval/optimization/copro/configs.py +0 -31
- deepeval/optimization/gepa/__init__.py +0 -7
- deepeval/optimization/gepa/configs.py +0 -115
- deepeval/optimization/miprov2/configs.py +0 -134
- deepeval/optimization/miprov2/loop.py +0 -785
- deepeval/optimization/mutations/__init__.py +0 -0
- deepeval/optimization/mutations/prompt_rewriter.py +0 -458
- deepeval/optimization/policies/__init__.py +0 -16
- deepeval/optimization/policies/tie_breaker.py +0 -67
- deepeval/optimization/prompt_optimizer.py +0 -462
- deepeval/optimization/simba/__init__.py +0 -0
- deepeval/optimization/simba/configs.py +0 -33
- deepeval/optimization/types.py +0 -361
- deepeval/test_case/mllm_test_case.py +0 -170
- /deepeval/metrics/{multimodal_metrics/multimodal_answer_relevancy → turn_contextual_precision}/__init__.py +0 -0
- /deepeval/metrics/{multimodal_metrics/multimodal_contextual_precision → turn_contextual_recall}/__init__.py +0 -0
- /deepeval/metrics/{multimodal_metrics/multimodal_contextual_recall → turn_contextual_relevancy}/__init__.py +0 -0
- /deepeval/metrics/{multimodal_metrics/multimodal_contextual_relevancy → turn_faithfulness}/__init__.py +0 -0
- /deepeval/{optimization → optimizer/algorithms}/simba/types.py +0 -0
- {deepeval-3.7.4.dist-info → deepeval-3.7.6.dist-info}/LICENSE.md +0 -0
- {deepeval-3.7.4.dist-info → deepeval-3.7.6.dist-info}/WHEEL +0 -0
- {deepeval-3.7.4.dist-info → deepeval-3.7.6.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Optional, Tuple, Union, Dict
|
|
1
|
+
from typing import TYPE_CHECKING, Optional, Tuple, Union, Dict, List
|
|
3
2
|
from pydantic import BaseModel
|
|
3
|
+
import base64
|
|
4
4
|
|
|
5
|
+
from deepeval.errors import DeepEvalError
|
|
5
6
|
from deepeval.config.settings import get_settings
|
|
7
|
+
from deepeval.utils import require_dependency, require_param
|
|
6
8
|
from deepeval.models.retry_policy import (
|
|
7
9
|
create_retry_decorator,
|
|
8
10
|
)
|
|
11
|
+
from deepeval.utils import convert_to_multi_modal_array, check_if_multimodal
|
|
12
|
+
from deepeval.test_case import MLLMImage
|
|
9
13
|
from deepeval.models import DeepEvalBaseLLM
|
|
10
14
|
from deepeval.constants import ProviderSlug as PS
|
|
15
|
+
from deepeval.models.llms.constants import OLLAMA_MODELS_DATA
|
|
11
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from ollama import ChatResponse
|
|
12
19
|
|
|
13
20
|
retry_ollama = create_retry_decorator(PS.OLLAMA)
|
|
14
21
|
|
|
@@ -18,27 +25,47 @@ class OllamaModel(DeepEvalBaseLLM):
|
|
|
18
25
|
self,
|
|
19
26
|
model: Optional[str] = None,
|
|
20
27
|
base_url: Optional[str] = None,
|
|
21
|
-
temperature: float =
|
|
28
|
+
temperature: Optional[float] = None,
|
|
22
29
|
generation_kwargs: Optional[Dict] = None,
|
|
23
30
|
**kwargs,
|
|
24
31
|
):
|
|
25
32
|
settings = get_settings()
|
|
26
|
-
|
|
27
|
-
self.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
|
|
33
|
+
model = model or settings.OLLAMA_MODEL_NAME
|
|
34
|
+
self.model_data = OLLAMA_MODELS_DATA.get(model)
|
|
35
|
+
|
|
36
|
+
if base_url is not None:
|
|
37
|
+
self.base_url = str(base_url).rstrip("/")
|
|
38
|
+
elif settings.LOCAL_MODEL_BASE_URL is not None:
|
|
39
|
+
self.base_url = str(settings.LOCAL_MODEL_BASE_URL).rstrip("/")
|
|
40
|
+
else:
|
|
41
|
+
self.base_url = "http://localhost:11434"
|
|
42
|
+
|
|
43
|
+
if temperature is not None:
|
|
44
|
+
temperature = float(temperature)
|
|
45
|
+
elif settings.TEMPERATURE is not None:
|
|
46
|
+
temperature = settings.TEMPERATURE
|
|
47
|
+
else:
|
|
48
|
+
temperature = 0.0
|
|
49
|
+
|
|
50
|
+
# validation
|
|
51
|
+
model = require_param(
|
|
52
|
+
model,
|
|
53
|
+
provider_label="OllamaModel",
|
|
54
|
+
env_var_name="LOCAL_MODEL_NAME",
|
|
55
|
+
param_hint="model",
|
|
34
56
|
)
|
|
57
|
+
|
|
35
58
|
if temperature < 0:
|
|
36
|
-
raise
|
|
59
|
+
raise DeepEvalError("Temperature must be >= 0.")
|
|
37
60
|
self.temperature = temperature
|
|
38
|
-
#
|
|
61
|
+
# Keep sanitized kwargs for client call to strip legacy keys
|
|
39
62
|
self.kwargs = kwargs
|
|
40
|
-
self.
|
|
41
|
-
|
|
63
|
+
self.kwargs.pop("temperature", None)
|
|
64
|
+
|
|
65
|
+
self.generation_kwargs = dict(generation_kwargs or {})
|
|
66
|
+
self.generation_kwargs.pop("temperature", None)
|
|
67
|
+
|
|
68
|
+
super().__init__(model)
|
|
42
69
|
|
|
43
70
|
###############################################
|
|
44
71
|
# Other generate functions
|
|
@@ -47,11 +74,18 @@ class OllamaModel(DeepEvalBaseLLM):
|
|
|
47
74
|
@retry_ollama
|
|
48
75
|
def generate(
|
|
49
76
|
self, prompt: str, schema: Optional[BaseModel] = None
|
|
50
|
-
) -> Tuple[Union[str,
|
|
77
|
+
) -> Tuple[Union[str, BaseModel], float]:
|
|
51
78
|
chat_model = self.load_model()
|
|
79
|
+
|
|
80
|
+
if check_if_multimodal(prompt):
|
|
81
|
+
prompt = convert_to_multi_modal_array(prompt)
|
|
82
|
+
messages = self.generate_messages(prompt)
|
|
83
|
+
else:
|
|
84
|
+
messages = [{"role": "user", "content": prompt}]
|
|
85
|
+
|
|
52
86
|
response: ChatResponse = chat_model.chat(
|
|
53
|
-
model=self.
|
|
54
|
-
messages=
|
|
87
|
+
model=self.name,
|
|
88
|
+
messages=messages,
|
|
55
89
|
format=schema.model_json_schema() if schema else None,
|
|
56
90
|
options={
|
|
57
91
|
**{"temperature": self.temperature},
|
|
@@ -70,11 +104,18 @@ class OllamaModel(DeepEvalBaseLLM):
|
|
|
70
104
|
@retry_ollama
|
|
71
105
|
async def a_generate(
|
|
72
106
|
self, prompt: str, schema: Optional[BaseModel] = None
|
|
73
|
-
) -> Tuple[str, float]:
|
|
107
|
+
) -> Tuple[Union[str, BaseModel], float]:
|
|
74
108
|
chat_model = self.load_model(async_mode=True)
|
|
109
|
+
|
|
110
|
+
if check_if_multimodal(prompt):
|
|
111
|
+
prompt = convert_to_multi_modal_array(prompt)
|
|
112
|
+
messages = self.generate_messages(prompt)
|
|
113
|
+
else:
|
|
114
|
+
messages = [{"role": "user", "content": prompt}]
|
|
115
|
+
|
|
75
116
|
response: ChatResponse = await chat_model.chat(
|
|
76
|
-
model=self.
|
|
77
|
-
messages=
|
|
117
|
+
model=self.name,
|
|
118
|
+
messages=messages,
|
|
78
119
|
format=schema.model_json_schema() if schema else None,
|
|
79
120
|
options={
|
|
80
121
|
**{"temperature": self.temperature},
|
|
@@ -90,14 +131,96 @@ class OllamaModel(DeepEvalBaseLLM):
|
|
|
90
131
|
0,
|
|
91
132
|
)
|
|
92
133
|
|
|
134
|
+
def generate_messages(
|
|
135
|
+
self, multimodal_input: List[Union[str, MLLMImage]] = []
|
|
136
|
+
):
|
|
137
|
+
messages = []
|
|
138
|
+
|
|
139
|
+
for element in multimodal_input:
|
|
140
|
+
if isinstance(element, str):
|
|
141
|
+
messages.append(
|
|
142
|
+
{
|
|
143
|
+
"role": "user",
|
|
144
|
+
"content": element,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
elif isinstance(element, MLLMImage):
|
|
148
|
+
if element.url and not element.local:
|
|
149
|
+
import requests
|
|
150
|
+
from PIL import Image
|
|
151
|
+
import io
|
|
152
|
+
|
|
153
|
+
settings = get_settings()
|
|
154
|
+
try:
|
|
155
|
+
response = requests.get(
|
|
156
|
+
element.url,
|
|
157
|
+
stream=True,
|
|
158
|
+
timeout=(
|
|
159
|
+
settings.MEDIA_IMAGE_CONNECT_TIMEOUT_SECONDS,
|
|
160
|
+
settings.MEDIA_IMAGE_READ_TIMEOUT_SECONDS,
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
response.raise_for_status()
|
|
164
|
+
|
|
165
|
+
# Convert to JPEG and encode
|
|
166
|
+
image = Image.open(io.BytesIO(response.content))
|
|
167
|
+
buffered = io.BytesIO()
|
|
168
|
+
|
|
169
|
+
# Convert RGBA/LA/P to RGB for JPEG
|
|
170
|
+
if image.mode in ("RGBA", "LA", "P"):
|
|
171
|
+
image = image.convert("RGB")
|
|
172
|
+
|
|
173
|
+
image.save(buffered, format="JPEG")
|
|
174
|
+
img_b64 = base64.b64encode(buffered.getvalue()).decode()
|
|
175
|
+
|
|
176
|
+
except (requests.exceptions.RequestException, OSError) as e:
|
|
177
|
+
print(f"Image fetch/encode failed: {e}")
|
|
178
|
+
raise
|
|
179
|
+
else:
|
|
180
|
+
element.ensure_images_loaded()
|
|
181
|
+
img_b64 = element.dataBase64
|
|
182
|
+
|
|
183
|
+
messages.append(
|
|
184
|
+
{
|
|
185
|
+
"role": "user",
|
|
186
|
+
"images": [img_b64],
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return messages
|
|
191
|
+
|
|
192
|
+
###############################################
|
|
193
|
+
# Capabilities
|
|
194
|
+
###############################################
|
|
195
|
+
|
|
196
|
+
def supports_log_probs(self) -> Union[bool, None]:
|
|
197
|
+
return self.model_data.supports_log_probs
|
|
198
|
+
|
|
199
|
+
def supports_temperature(self) -> Union[bool, None]:
|
|
200
|
+
return self.model_data.supports_temperature
|
|
201
|
+
|
|
202
|
+
def supports_multimodal(self) -> Union[bool, None]:
|
|
203
|
+
return self.model_data.supports_multimodal
|
|
204
|
+
|
|
205
|
+
def supports_structured_outputs(self) -> Union[bool, None]:
|
|
206
|
+
return self.model_data.supports_structured_outputs
|
|
207
|
+
|
|
208
|
+
def supports_json_mode(self) -> Union[bool, None]:
|
|
209
|
+
return self.model_data.supports_json
|
|
210
|
+
|
|
93
211
|
###############################################
|
|
94
212
|
# Model
|
|
95
213
|
###############################################
|
|
96
214
|
|
|
97
215
|
def load_model(self, async_mode: bool = False):
|
|
216
|
+
ollama = require_dependency(
|
|
217
|
+
"ollama",
|
|
218
|
+
provider_label="OllamaModel",
|
|
219
|
+
install_hint="Install it with `pip install ollama`.",
|
|
220
|
+
)
|
|
98
221
|
if not async_mode:
|
|
99
|
-
return self._build_client(Client)
|
|
100
|
-
return self._build_client(AsyncClient)
|
|
222
|
+
return self._build_client(ollama.Client)
|
|
223
|
+
return self._build_client(ollama.AsyncClient)
|
|
101
224
|
|
|
102
225
|
def _client_kwargs(self) -> Dict:
|
|
103
226
|
"""Return kwargs forwarded to the underlying Ollama Client/AsyncClient."""
|
|
@@ -111,4 +234,4 @@ class OllamaModel(DeepEvalBaseLLM):
|
|
|
111
234
|
return cls(**kw)
|
|
112
235
|
|
|
113
236
|
def get_model_name(self):
|
|
114
|
-
return f"{self.
|
|
237
|
+
return f"{self.name} (Ollama)"
|