lmnr 0.6.19__py3-none-any.whl → 0.6.21__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.
- lmnr/opentelemetry_lib/decorators/__init__.py +188 -138
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +674 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +13 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +211 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +41 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +256 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +295 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +179 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +1 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +485 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +8 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +143 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +41 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +229 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +92 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +1 -0
- lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +3 -3
- lmnr/opentelemetry_lib/tracing/__init__.py +1 -1
- lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +12 -7
- lmnr/opentelemetry_lib/tracing/processor.py +1 -1
- lmnr/opentelemetry_lib/utils/package_check.py +9 -0
- lmnr/sdk/browser/browser_use_otel.py +4 -2
- lmnr/sdk/browser/patchright_otel.py +0 -26
- lmnr/sdk/browser/playwright_otel.py +51 -78
- lmnr/sdk/browser/pw_utils.py +359 -114
- lmnr/sdk/client/asynchronous/async_client.py +13 -0
- lmnr/sdk/client/asynchronous/resources/__init__.py +2 -0
- lmnr/sdk/client/asynchronous/resources/evaluators.py +85 -0
- lmnr/sdk/client/asynchronous/resources/tags.py +4 -10
- lmnr/sdk/client/synchronous/resources/__init__.py +2 -1
- lmnr/sdk/client/synchronous/resources/evaluators.py +85 -0
- lmnr/sdk/client/synchronous/resources/tags.py +4 -10
- lmnr/sdk/client/synchronous/sync_client.py +14 -0
- lmnr/sdk/decorators.py +39 -4
- lmnr/sdk/evaluations.py +23 -9
- lmnr/sdk/laminar.py +75 -48
- lmnr/sdk/utils.py +23 -0
- lmnr/version.py +1 -1
- {lmnr-0.6.19.dist-info → lmnr-0.6.21.dist-info}/METADATA +8 -7
- {lmnr-0.6.19.dist-info → lmnr-0.6.21.dist-info}/RECORD +42 -25
- {lmnr-0.6.19.dist-info → lmnr-0.6.21.dist-info}/WHEEL +1 -1
- {lmnr-0.6.19.dist-info → lmnr-0.6.21.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
"""Evaluators resource for creating evaluator scores."""
|
2
|
+
|
3
|
+
import uuid
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from lmnr.sdk.client.asynchronous.resources.base import BaseAsyncResource
|
7
|
+
from lmnr.sdk.utils import format_id
|
8
|
+
|
9
|
+
|
10
|
+
class AsyncEvaluators(BaseAsyncResource):
|
11
|
+
"""Resource for creating evaluator scores."""
|
12
|
+
|
13
|
+
async def score(
|
14
|
+
self,
|
15
|
+
*,
|
16
|
+
name: str,
|
17
|
+
trace_id: str | int | uuid.UUID | None = None,
|
18
|
+
span_id: str | int | uuid.UUID | None = None,
|
19
|
+
metadata: dict[str, Any] | None = None,
|
20
|
+
score: float,
|
21
|
+
) -> None:
|
22
|
+
"""Create a score for a span.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
name (str): Name of the score
|
26
|
+
trace_id (str | int | uuid.UUID | None, optional): The trace ID to score (will be attached to root span)
|
27
|
+
span_id (str | int | uuid.UUID | None, optional): The span ID to score
|
28
|
+
metadata (dict[str, Any] | None, optional): Additional metadata. Defaults to None.
|
29
|
+
score (float): The score value (float)
|
30
|
+
|
31
|
+
Raises:
|
32
|
+
ValueError: If there's an error creating the score.
|
33
|
+
|
34
|
+
Example:
|
35
|
+
Score by trace ID (will attach to root span):
|
36
|
+
|
37
|
+
>>> await laminar_client.evaluators.score(
|
38
|
+
... name="quality",
|
39
|
+
... trace_id="trace-id-here",
|
40
|
+
... score=0.95,
|
41
|
+
... metadata={"model": "gpt-4"}
|
42
|
+
... )
|
43
|
+
|
44
|
+
Score by span ID:
|
45
|
+
|
46
|
+
>>> await laminar_client.evaluators.score(
|
47
|
+
... name="relevance",
|
48
|
+
... span_id="span-id-here",
|
49
|
+
... score=0.87
|
50
|
+
... )
|
51
|
+
"""
|
52
|
+
if trace_id is not None and span_id is not None:
|
53
|
+
raise ValueError("Cannot provide both trace_id and span_id. Please provide only one.")
|
54
|
+
if trace_id is None and span_id is None:
|
55
|
+
raise ValueError("Either 'trace_id' or 'span_id' must be provided.")
|
56
|
+
|
57
|
+
if trace_id is not None:
|
58
|
+
formatted_trace_id = format_id(trace_id)
|
59
|
+
payload = {
|
60
|
+
"name": name,
|
61
|
+
"traceId": formatted_trace_id,
|
62
|
+
"metadata": metadata,
|
63
|
+
"score": score,
|
64
|
+
"source": "Code",
|
65
|
+
}
|
66
|
+
else:
|
67
|
+
formatted_span_id = format_id(span_id)
|
68
|
+
payload = {
|
69
|
+
"name": name,
|
70
|
+
"spanId": formatted_span_id,
|
71
|
+
"metadata": metadata,
|
72
|
+
"score": score,
|
73
|
+
"source": "Code",
|
74
|
+
}
|
75
|
+
|
76
|
+
response = await self._client.post(
|
77
|
+
self._base_url + "/v1/evaluators/score",
|
78
|
+
json=payload,
|
79
|
+
headers=self._headers(),
|
80
|
+
)
|
81
|
+
|
82
|
+
if response.status_code != 200:
|
83
|
+
if response.status_code == 401:
|
84
|
+
raise ValueError("Unauthorized. Please check your project API key.")
|
85
|
+
raise ValueError(f"Error creating evaluator score: {response.text}")
|
@@ -5,6 +5,7 @@ import uuid
|
|
5
5
|
|
6
6
|
from lmnr.sdk.client.asynchronous.resources.base import BaseAsyncResource
|
7
7
|
from lmnr.sdk.log import get_default_logger
|
8
|
+
from lmnr.sdk.utils import format_id
|
8
9
|
|
9
10
|
logger = get_default_logger(__name__)
|
10
11
|
|
@@ -54,18 +55,11 @@ class AsyncTags(BaseAsyncResource):
|
|
54
55
|
```
|
55
56
|
"""
|
56
57
|
trace_tags = tags if isinstance(tags, list) else [tags]
|
57
|
-
|
58
|
-
trace_id = str(trace_id)
|
59
|
-
elif isinstance(trace_id, int):
|
60
|
-
trace_id = str(uuid.UUID(int=trace_id))
|
61
|
-
elif isinstance(trace_id, str):
|
62
|
-
uuid.UUID(trace_id) # Will raise ValueError if invalid
|
63
|
-
else:
|
64
|
-
raise ValueError(f"Invalid trace id: {trace_id}")
|
58
|
+
formatted_trace_id = format_id(trace_id)
|
65
59
|
|
66
60
|
url = self._base_url + "/v1/tag"
|
67
61
|
payload = {
|
68
|
-
"traceId":
|
62
|
+
"traceId": formatted_trace_id,
|
69
63
|
"names": trace_tags,
|
70
64
|
}
|
71
65
|
response = await self._client.post(
|
@@ -78,7 +72,7 @@ class AsyncTags(BaseAsyncResource):
|
|
78
72
|
|
79
73
|
if response.status_code == 404:
|
80
74
|
logger.warning(
|
81
|
-
f"Trace {
|
75
|
+
f"Trace {formatted_trace_id} not found. The trace may have not been ended yet."
|
82
76
|
)
|
83
77
|
return []
|
84
78
|
|
@@ -2,5 +2,6 @@ from lmnr.sdk.client.synchronous.resources.agent import Agent
|
|
2
2
|
from lmnr.sdk.client.synchronous.resources.browser_events import BrowserEvents
|
3
3
|
from lmnr.sdk.client.synchronous.resources.evals import Evals
|
4
4
|
from lmnr.sdk.client.synchronous.resources.tags import Tags
|
5
|
+
from lmnr.sdk.client.synchronous.resources.evaluators import Evaluators
|
5
6
|
|
6
|
-
__all__ = ["Agent", "Evals", "BrowserEvents", "Tags"]
|
7
|
+
__all__ = ["Agent", "Evals", "Evaluators", "BrowserEvents", "Tags"]
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"""Evaluators resource for creating evaluator scores."""
|
2
|
+
|
3
|
+
import uuid
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from lmnr.sdk.client.synchronous.resources.base import BaseResource
|
7
|
+
from lmnr.sdk.utils import format_id
|
8
|
+
|
9
|
+
|
10
|
+
class Evaluators(BaseResource):
|
11
|
+
"""Resource for creating evaluator scores."""
|
12
|
+
|
13
|
+
def score(
|
14
|
+
self,
|
15
|
+
*,
|
16
|
+
name: str,
|
17
|
+
trace_id: str | int | uuid.UUID | None = None,
|
18
|
+
span_id: str | int | uuid.UUID | None = None,
|
19
|
+
metadata: dict[str, Any] | None = None,
|
20
|
+
score: float,
|
21
|
+
) -> None:
|
22
|
+
"""Create a score for a span.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
name (str): Name of the score
|
26
|
+
trace_id (str | int | uuid.UUID | None, optional): The trace ID to score (will be attached to root span)
|
27
|
+
span_id (str | int | uuid.UUID | None, optional): The span ID to score
|
28
|
+
metadata (dict[str, Any] | None, optional): Additional metadata. Defaults to None.
|
29
|
+
score (float): The score value (float)
|
30
|
+
|
31
|
+
Raises:
|
32
|
+
ValueError: If there's an error creating the score.
|
33
|
+
|
34
|
+
Example:
|
35
|
+
Score by trace ID (will attach to root span):
|
36
|
+
|
37
|
+
>>> laminar_client.evaluators.score(
|
38
|
+
... name="quality",
|
39
|
+
... trace_id="trace-id-here",
|
40
|
+
... score=0.95,
|
41
|
+
... metadata={"model": "gpt-4"}
|
42
|
+
... )
|
43
|
+
|
44
|
+
Score by span ID:
|
45
|
+
|
46
|
+
>>> laminar_client.evaluators.score(
|
47
|
+
... name="relevance",
|
48
|
+
... span_id="span-id-here",
|
49
|
+
... score=0.87
|
50
|
+
... )
|
51
|
+
"""
|
52
|
+
if trace_id is not None and span_id is not None:
|
53
|
+
raise ValueError("Cannot provide both trace_id and span_id. Please provide only one.")
|
54
|
+
if trace_id is None and span_id is None:
|
55
|
+
raise ValueError("Either 'trace_id' or 'span_id' must be provided.")
|
56
|
+
|
57
|
+
if trace_id is not None:
|
58
|
+
formatted_trace_id = format_id(trace_id)
|
59
|
+
payload = {
|
60
|
+
"name": name,
|
61
|
+
"traceId": formatted_trace_id,
|
62
|
+
"metadata": metadata,
|
63
|
+
"score": score,
|
64
|
+
"source": "Code",
|
65
|
+
}
|
66
|
+
else:
|
67
|
+
formatted_span_id = format_id(span_id)
|
68
|
+
payload = {
|
69
|
+
"name": name,
|
70
|
+
"spanId": formatted_span_id,
|
71
|
+
"metadata": metadata,
|
72
|
+
"score": score,
|
73
|
+
"source": "Code",
|
74
|
+
}
|
75
|
+
|
76
|
+
response = self._client.post(
|
77
|
+
self._base_url + "/v1/evaluators/score",
|
78
|
+
json=payload,
|
79
|
+
headers=self._headers(),
|
80
|
+
)
|
81
|
+
|
82
|
+
if response.status_code != 200:
|
83
|
+
if response.status_code == 401:
|
84
|
+
raise ValueError("Unauthorized. Please check your project API key.")
|
85
|
+
raise ValueError(f"Error creating evaluator score: {response.text}")
|
@@ -5,6 +5,7 @@ import uuid
|
|
5
5
|
|
6
6
|
from lmnr.sdk.client.synchronous.resources.base import BaseResource
|
7
7
|
from lmnr.sdk.log import get_default_logger
|
8
|
+
from lmnr.sdk.utils import format_id
|
8
9
|
|
9
10
|
logger = get_default_logger(__name__)
|
10
11
|
|
@@ -54,18 +55,11 @@ class Tags(BaseResource):
|
|
54
55
|
```
|
55
56
|
"""
|
56
57
|
trace_tags = tags if isinstance(tags, list) else [tags]
|
57
|
-
|
58
|
-
trace_id = str(trace_id)
|
59
|
-
elif isinstance(trace_id, int):
|
60
|
-
trace_id = str(uuid.UUID(int=trace_id))
|
61
|
-
elif isinstance(trace_id, str):
|
62
|
-
uuid.UUID(trace_id)
|
63
|
-
else:
|
64
|
-
raise ValueError(f"Invalid trace id: {trace_id}")
|
58
|
+
formatted_trace_id = format_id(trace_id)
|
65
59
|
|
66
60
|
url = self._base_url + "/v1/tag"
|
67
61
|
payload = {
|
68
|
-
"traceId":
|
62
|
+
"traceId": formatted_trace_id,
|
69
63
|
"names": trace_tags,
|
70
64
|
}
|
71
65
|
response = self._client.post(
|
@@ -78,7 +72,7 @@ class Tags(BaseResource):
|
|
78
72
|
|
79
73
|
if response.status_code == 404:
|
80
74
|
logger.warning(
|
81
|
-
f"Trace {
|
75
|
+
f"Trace {formatted_trace_id} not found. The trace may have not been ended yet."
|
82
76
|
)
|
83
77
|
return []
|
84
78
|
|
@@ -11,6 +11,7 @@ from lmnr.sdk.client.synchronous.resources import (
|
|
11
11
|
Agent,
|
12
12
|
BrowserEvents,
|
13
13
|
Evals,
|
14
|
+
Evaluators,
|
14
15
|
Tags,
|
15
16
|
)
|
16
17
|
from lmnr.sdk.utils import from_env
|
@@ -27,6 +28,7 @@ class LaminarClient:
|
|
27
28
|
__agent: Agent | None = None
|
28
29
|
__evals: Evals | None = None
|
29
30
|
__tags: Tags | None = None
|
31
|
+
__evaluators: Evaluators | None = None
|
30
32
|
|
31
33
|
def __init__(
|
32
34
|
self,
|
@@ -74,6 +76,9 @@ class LaminarClient:
|
|
74
76
|
# Initialize resource objects
|
75
77
|
self.__agent = Agent(self.__client, self.__base_url, self.__project_api_key)
|
76
78
|
self.__evals = Evals(self.__client, self.__base_url, self.__project_api_key)
|
79
|
+
self.__evaluators = Evaluators(
|
80
|
+
self.__client, self.__base_url, self.__project_api_key
|
81
|
+
)
|
77
82
|
self.__browser_events = BrowserEvents(
|
78
83
|
self.__client, self.__base_url, self.__project_api_key
|
79
84
|
)
|
@@ -115,6 +120,15 @@ class LaminarClient:
|
|
115
120
|
"""
|
116
121
|
return self.__tags
|
117
122
|
|
123
|
+
@property
|
124
|
+
def evaluators(self) -> Evaluators:
|
125
|
+
"""Get the Evaluators resource.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
Evaluators: The Evaluators resource instance.
|
129
|
+
"""
|
130
|
+
return self.__evaluators
|
131
|
+
|
118
132
|
def shutdown(self):
|
119
133
|
"""Shutdown the client by closing underlying connections."""
|
120
134
|
self.__client.close()
|
lmnr/sdk/decorators.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from lmnr.opentelemetry_lib.decorators import (
|
2
|
-
|
3
|
-
|
2
|
+
observe_base,
|
3
|
+
async_observe_base,
|
4
4
|
json_dumps,
|
5
5
|
)
|
6
6
|
from opentelemetry.trace import INVALID_SPAN, get_current_span
|
@@ -28,6 +28,8 @@ def observe(
|
|
28
28
|
ignore_output: bool = False,
|
29
29
|
span_type: Literal["DEFAULT", "LLM", "TOOL"] = "DEFAULT",
|
30
30
|
ignore_inputs: list[str] | None = None,
|
31
|
+
input_formatter: Callable[P, str] | None = None,
|
32
|
+
output_formatter: Callable[[R], str] | None = None,
|
31
33
|
metadata: dict[str, Any] | None = None,
|
32
34
|
tags: list[str] | None = None,
|
33
35
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
@@ -53,6 +55,16 @@ def observe(
|
|
53
55
|
def foo(a, b, `sensitive_data`), and you want to ignore the\
|
54
56
|
`sensitive_data` argument, you can pass ["sensitive_data"] to\
|
55
57
|
this argument. Defaults to None.
|
58
|
+
input_formatter (Callable[P, str] | None, optional): A custom function\
|
59
|
+
to format the input of the wrapped function. All function arguments\
|
60
|
+
are passed to this function. Must return a string. Ignored if\
|
61
|
+
`ignore_input` is True. Does not respect `ignore_inputs` argument.
|
62
|
+
Defaults to None.
|
63
|
+
output_formatter (Callable[[R], str] | None, optional): A custom function\
|
64
|
+
to format the output of the wrapped function. The output is passed\
|
65
|
+
to this function. Must return a string. Ignored if `ignore_output`
|
66
|
+
is True. Does not respect `ignore_inputs` argument.
|
67
|
+
Defaults to None.
|
56
68
|
metadata (dict[str, Any] | None, optional): Metadata to associate with\
|
57
69
|
the trace. Must be JSON serializable. Defaults to None.
|
58
70
|
tags (list[str] | None, optional): Tags to associate with the trace.
|
@@ -91,22 +103,45 @@ def observe(
|
|
91
103
|
logger.warning("Tags must be a list of strings. Tags will be ignored.")
|
92
104
|
else:
|
93
105
|
association_properties["tags"] = tags
|
106
|
+
if input_formatter is not None and ignore_input:
|
107
|
+
logger.warning(
|
108
|
+
f"observe, function {func.__name__}: Input formatter"
|
109
|
+
" is ignored because `ignore_input` is True. Specify only one of"
|
110
|
+
" `ignore_input` or `input_formatter`."
|
111
|
+
)
|
112
|
+
if input_formatter is not None and ignore_inputs is not None:
|
113
|
+
logger.warning(
|
114
|
+
f"observe, function {func.__name__}: Both input formatter and"
|
115
|
+
" `ignore_inputs` are specified. Input formatter"
|
116
|
+
" will pass all arguments to the formatter regardless of"
|
117
|
+
" `ignore_inputs`."
|
118
|
+
)
|
119
|
+
if output_formatter is not None and ignore_output:
|
120
|
+
logger.warning(
|
121
|
+
f"observe, function {func.__name__}: Output formatter"
|
122
|
+
" is ignored because `ignore_output` is True. Specify only one of"
|
123
|
+
" `ignore_output` or `output_formatter`."
|
124
|
+
)
|
94
125
|
result = (
|
95
|
-
|
126
|
+
async_observe_base(
|
96
127
|
name=name,
|
97
128
|
ignore_input=ignore_input,
|
98
129
|
ignore_output=ignore_output,
|
99
130
|
span_type=span_type,
|
100
131
|
ignore_inputs=ignore_inputs,
|
132
|
+
input_formatter=input_formatter,
|
133
|
+
output_formatter=output_formatter,
|
101
134
|
association_properties=association_properties,
|
102
135
|
)(func)
|
103
136
|
if is_async(func)
|
104
|
-
else
|
137
|
+
else observe_base(
|
105
138
|
name=name,
|
106
139
|
ignore_input=ignore_input,
|
107
140
|
ignore_output=ignore_output,
|
108
141
|
span_type=span_type,
|
109
142
|
ignore_inputs=ignore_inputs,
|
143
|
+
input_formatter=input_formatter,
|
144
|
+
output_formatter=output_formatter,
|
110
145
|
association_properties=association_properties,
|
111
146
|
)(func)
|
112
147
|
)
|
lmnr/sdk/evaluations.py
CHANGED
@@ -57,7 +57,7 @@ def get_average_scores(results: list[EvaluationResultDatapoint]) -> dict[str, Nu
|
|
57
57
|
average_scores = {}
|
58
58
|
for key, values in per_score_values.items():
|
59
59
|
scores = [v for v in values if v is not None]
|
60
|
-
|
60
|
+
|
61
61
|
# If there are no scores, we don't want to include the key in the average scores
|
62
62
|
if len(scores) > 0:
|
63
63
|
average_scores[key] = sum(scores) / len(scores)
|
@@ -108,6 +108,7 @@ class Evaluation:
|
|
108
108
|
concurrency_limit: int = DEFAULT_BATCH_SIZE,
|
109
109
|
project_api_key: str | None = None,
|
110
110
|
base_url: str | None = None,
|
111
|
+
base_http_url: str | None = None,
|
111
112
|
http_port: int | None = None,
|
112
113
|
grpc_port: int | None = None,
|
113
114
|
instruments: set[Instruments] | None = None,
|
@@ -157,6 +158,10 @@ class Evaluation:
|
|
157
158
|
Useful if self-hosted. Do NOT include the port, use `http_port`\
|
158
159
|
and `grpc_port` instead.
|
159
160
|
Defaults to "https://api.lmnr.ai".
|
161
|
+
base_http_url (str | None, optional): The base HTTP URL for Laminar API.\
|
162
|
+
Only set this if your Laminar backend HTTP is proxied\
|
163
|
+
through a different host. If not specified, defaults\
|
164
|
+
to https://api.lmnr.ai.
|
160
165
|
http_port (int | None, optional): The port for Laminar API\
|
161
166
|
HTTP service. Defaults to 443 if not specified.
|
162
167
|
grpc_port (int | None, optional): The port for Laminar API\
|
@@ -199,7 +204,7 @@ class Evaluation:
|
|
199
204
|
self.batch_size = concurrency_limit
|
200
205
|
self._logger = get_default_logger(self.__class__.__name__)
|
201
206
|
self.upload_tasks = []
|
202
|
-
self.base_http_url = f"{base_url}:{http_port or 443}"
|
207
|
+
self.base_http_url = f"{base_http_url or base_url}:{http_port or 443}"
|
203
208
|
|
204
209
|
api_key = project_api_key or from_env("LMNR_PROJECT_API_KEY")
|
205
210
|
if not api_key and not L.is_initialized():
|
@@ -224,6 +229,7 @@ class Evaluation:
|
|
224
229
|
L.initialize(
|
225
230
|
project_api_key=project_api_key,
|
226
231
|
base_url=base_url,
|
232
|
+
base_http_url=self.base_http_url,
|
227
233
|
http_port=http_port,
|
228
234
|
grpc_port=grpc_port,
|
229
235
|
instruments=instruments,
|
@@ -352,22 +358,24 @@ class Evaluation:
|
|
352
358
|
if isinstance(evaluator, HumanEvaluator):
|
353
359
|
# Create an empty span for human evaluators
|
354
360
|
with L.start_as_current_span(
|
355
|
-
evaluator_name,
|
356
|
-
input={"output": output, "target": target}
|
361
|
+
evaluator_name, input={"output": output, "target": target}
|
357
362
|
) as human_evaluator_span:
|
358
|
-
human_evaluator_span.set_attribute(
|
363
|
+
human_evaluator_span.set_attribute(
|
364
|
+
SPAN_TYPE, SpanType.HUMAN_EVALUATOR.value
|
365
|
+
)
|
359
366
|
# Human evaluators don't execute automatically, just create the span
|
360
367
|
L.set_span_output(None)
|
361
|
-
|
368
|
+
|
362
369
|
# We don't want to save the score for human evaluators
|
363
370
|
scores[evaluator_name] = None
|
364
371
|
else:
|
365
372
|
# Regular evaluator function
|
366
373
|
with L.start_as_current_span(
|
367
|
-
evaluator_name,
|
368
|
-
input={"output": output, "target": target}
|
374
|
+
evaluator_name, input={"output": output, "target": target}
|
369
375
|
) as evaluator_span:
|
370
|
-
evaluator_span.set_attribute(
|
376
|
+
evaluator_span.set_attribute(
|
377
|
+
SPAN_TYPE, SpanType.EVALUATOR.value
|
378
|
+
)
|
371
379
|
if is_async(evaluator):
|
372
380
|
value = await evaluator(output, target)
|
373
381
|
else:
|
@@ -416,6 +424,7 @@ def evaluate(
|
|
416
424
|
concurrency_limit: int = DEFAULT_BATCH_SIZE,
|
417
425
|
project_api_key: str | None = None,
|
418
426
|
base_url: str | None = None,
|
427
|
+
base_http_url: str | None = None,
|
419
428
|
http_port: int | None = None,
|
420
429
|
grpc_port: int | None = None,
|
421
430
|
instruments: set[Instruments] | None = None,
|
@@ -465,6 +474,10 @@ def evaluate(
|
|
465
474
|
Useful if self-hosted elsewhere. Do NOT include the\
|
466
475
|
port, use `http_port` and `grpc_port` instead.
|
467
476
|
Defaults to "https://api.lmnr.ai".
|
477
|
+
base_http_url (str | None, optional): The base HTTP URL for Laminar API.\
|
478
|
+
Only set this if your Laminar backend HTTP is proxied\
|
479
|
+
through a different host. If not specified, defaults\
|
480
|
+
to https://api.lmnr.ai.
|
468
481
|
http_port (int | None, optional): The port for Laminar API's HTTP\
|
469
482
|
service. 443 is used if not specified.
|
470
483
|
Defaults to None.
|
@@ -488,6 +501,7 @@ def evaluate(
|
|
488
501
|
concurrency_limit=concurrency_limit,
|
489
502
|
project_api_key=project_api_key,
|
490
503
|
base_url=base_url,
|
504
|
+
base_http_url=base_http_url,
|
491
505
|
http_port=http_port,
|
492
506
|
grpc_port=grpc_port,
|
493
507
|
instruments=instruments,
|